Marketplace architecture
Marketplace architecture: the decisions that matter
The architecture of a marketplace comes down to 2 choices: A single order state machine with compare-and-set transitions and postgres full-text and btree search with precomputed ranking. Each is explained below with the alternatives that were rejected and what you accept by choosing it.
Last checked
A single order state machine with compare-and-set transitions
Situation: Orders touch money, deadlines and two parties; concurrent webhook, cron and user actions would otherwise double refund, double release or skip states.
Choice: Every status change goes through transitionOrder using UPDATE ... WHERE status = from in one transaction with an order_events insert; side effects are enqueued as jobs.
- Rejected: Free-form status updates scattered through handlers: race conditions and unauditable history.
- Rejected: Event sourcing: more machinery than phase 1 needs.
- Consequence: Illegal or repeated transitions are no-ops.
- Consequence: Full timeline per order for support and disputes.
- Consequence: New states require a deliberate edit of one transition table.
Postgres full-text and btree search with precomputed ranking
Situation: Search is the main discovery surface and must stay fast to hundreds of thousands of listings without a new datastore.
Choice: Use tsvector + GIN, trigram fallback, btree filters and a cron-refreshed rank_key; keyset pagination; cached facet counts.
- Rejected: Dedicated search engine from day one: extra infrastructure, sync and cost before it is needed.
- Rejected: ILIKE scans: collapse beyond tens of thousands of rows.
- Consequence: One system to operate and back up.
- Consequence: Ranking is coarse until learned ranking arrives.
- Consequence: Clear migration trigger to a search engine.
How the data is indexed
Indexes are chosen from the questions the app asks most often. Each line below names a table and the question its main index answers.
- categories: unique (slug) — category URLs.
- listings: (status, category_id, price_cents) — filtered browse by category and price.
- listing_media: (listing_id, position) — gallery in order.
- orders: unique (idempotency_key) — double-submitted checkout creates one order.
- order_events: (order_id, created_at) — order timeline.
- ledger_entries: (order_id, created_at) — reconcile one order.
- payouts: unique (order_id) — exactly one release transfer per order.
- reviews: unique (order_id, direction) — one review per party per order.
What Forge64 provides underneath
Forge64 matches your description to one of 12 reference architectures, writes the plan and data model into the project, generates the app, and runs a quality gate over the code before you see it. Each app gets its own Postgres database and sign-in with no per-user fee. Hosting on Forge Cloud and Forge Payments are rolling out.
This is a reference design for the category, not a promise that every item is generated today. Built-ins such as email, background jobs, file uploads and search are coming soon, so anything here that needs them is something you add yourself for now.
FAQ
- What is the most important architecture decision for a marketplace?
- A single order state machine with compare-and-set transitions. Every status change goes through transitionOrder using UPDATE ... WHERE status = from in one transaction with an order_events insert; side effects are enqueued as jobs.
- Do I have to make these decisions myself?
- No. Forge AI plans them from your description and writes the decisions into the project as architecture records you can read and change.
- What do the alternatives cost me?
- For example, for "Postgres full-text and btree search with precomputed ranking": Dedicated search engine from day one: extra infrastructure, sync and cost before it is needed. ILIKE scans: collapse beyond tens of thousands of rows.
Build your app with Forge64
One prompt to a running app with auth, database, hosting and payments. Start free, no credit card required.
Start building for free