Skip to Content
ArchitectureBilateral Marketplace

Bilateral Marketplace v2

Onoots Proptech runs a two-sided marketplace with two legs:

  • Side A — Developer. Inventory management and liquidation software: detection of stale units, predictive absorption, and the argument that “a discount costs less than idle inventory.”
  • Side B — Buyer. An automated fiduciary buying desk, monetized with a success fee on the negotiated savings, with anti-bypass (a buyer representation agreement signed before the unit is revealed) and swarm buying (aggregating demand into block offers to developers).

Both legs are operated by the brokerage (a hybrid A+B model), plus a limited B2C intake that feeds the agents.

High-level architecture

Everything asynchronous (absorption, due diligence, post-signature follow-up, block-offer preparation) travels over the swarm engine — see The swarm engine.

The five phases

PhaseNameDelivers
F1Developer Desk + bilateral bridgeInventory absorption, matching briefs against developer lots, an immutable price baseline
F2Anti-bypass + Due DiligenceSign-before-reveal via OnootsSign, candidate masking, a Due-Diligence Auditor agent, discount tokens, handoff to a deal
F3Success feeA savings/fee ledger kept separate from the commission cascade, counsel sign-off
F4Limited B2C intakeA public bilingual form → agent triage → converts into a brief
F5Swarm BuyingBuyer cohorts (all with signed agreements), aggregated block offers, presentation behind a dual-agency checkpoint

Detailed flows

Bilateral bridge + matching (F1)

Buyer outreach scans two sources: individual listings and developer lots (inventory in available state, from the brief’s brokerage). Each candidate — listing or lot — captures an immutable list-price snapshot when it’s created. That snapshot is the baseline for the F3 fee: every day without it, the future fee of today’s candidates becomes impossible to backfill with integrity.

Anti-bypass + Due Diligence (F2)

  • Masking: before the agreement, even a read that passes row-level security receives the masked shape — the listing/lot id and address never leave the server without a signed agreement.
  • Honest “encrypted agreement”: a private (encrypted-at-rest) bucket + SHA-256 + an optional on-chain anchor = access-controlled and tamper-evident.
  • Discount tokens: issued after signature, redeemable exactly once against a deal from the same brief.

Success fee (F3)

fee = fee_rate × max(0, baseline − negotiated_price), where the baseline is the F1 list-price snapshot and the negotiated price is the sale price at close. Currencies must match or the engine refuses (it never fabricates FX). The fee ledger is separate from the commission cascade (existing commission logic is untouched).

If the regulatory pack requires confirmation and the brokerage has not recorded a legal sign-off, the fee event is recorded as waived with a reason — it never accrues silently.

Swarm buying (F5)

  • Anti-bypass invariant at the schema level: a cohort member row must reference a signed agreement (enforced by a non-null foreign key) — no buyer without a signed agreement can enter a cohort, guaranteed by the database.
  • Tenant consistency: a composite key prevents a member or offer from diverging from its cohort’s brokerage.
  • Presentation is the hard gate: presenting a block offer maps to a licensed-broker-only action and requires a recorded dual-agency sign-off. Without it, presentation returns dual_agency_signoff_required (fail-closed).
  • Developers see only aggregated demand: a block offer stores the count, band and total — never member identities.

The swarm engine

All orchestration is an outbox pattern: the app inserts rows into an events table; a relay process reads them and starts the matching durable workflow; the worker runs the workflow, which calls back into the app over an authenticated internal endpoint (a shared secret, constant-time compared). The app never blocks on the workflow engine: if the worker is down, events stay pending and drain when it returns.

EventWorkflowEffectPhase
inventory.syncedabsorptioninventory snapshotsF1
buyer_brief.submittedbuyer outreachmatching → buyer candidatesF1
dd.requestedbuyer due diligenceDD report (Auditor agent)F2
agreement.signedagreement follow-uppost-signature side-effectsF2
buyer_cohort.formedblock-offer prepblock-offer draftF5

Data model (concepts)

The domain model is designed so guarantees hold at the database level, not just in application code:

  • Buyer candidates carry the immutable list-price snapshot (the fee baseline).
  • Buyer agreements are a small state machine (draft → sent → signed).
  • Discount tokens are single-use, tied to one brief.
  • Buyer-fee events are a ledger separate from commissions (brokers can read; sensitive writes are service-role only).
  • Buyer cohorts, members and block offers power swarm buying, with the signed-agreement invariant baked into the schema.

Cross-cutting: row-level security scopes reads to the agent/broker; sensitive writes go through a privileged service role only.

Regulatory gates (fail-closed)

Everything ships blocked until counsel or a licensed professional signs off — the system runs in production but does not “go to market” until these are lifted:

  • Buyer agreement (F2): before revealing a unit’s identity.
  • Fee sign-off (F3): without a recorded legal sign-off, fees are recorded as waived.
  • Dual-agency (F5): without a recorded sign-off, a block offer cannot be presented.
  • Intake terms (F4): consent text is a counsel placeholder until finalized.

Deployment shape

The app, an async worker + relay, and the database run as separate services. A shared internal secret authenticates the callbacks from the worker back into the app. When a new workflow is added, the worker is deployed first so the app never routes to a workflow the worker doesn’t yet know.

Last updated on