docs(backend): harvest platform mechanisms into the contracts (Wave 2, FH-E.1-E.4)

Writes the 14 harvested mechanisms from FORK-ANALYSIS-2026-08-21.md into
the backend contracts. Each section is dated 2026-08-21 and tagged FH-*
so any wording traces back to why it is worded that way.

The through-line: several contracts stated correctness as behaviour
("the webhook must be idempotent"). Behaviour written as an if-statement
gets deleted by a refactor and the failure mode is a double charge. These
sections restate it as schema and mechanism.

PHASE-3  3.1 conditional-write reservation, 409 on zero rows, cart-wide
             rollback, 15 min TTL
         3.2 InventoryMovement append-only journal with resultingAvailable
         6   bulk import idempotent by SKU, rollback while unsold
         6a  digital code pools, revealed only when paid
PHASE-7  5   unique constraints for payment idempotency and webhook
             replay, insert-first handling, signature over raw body,
             24h poll as reconciliation not primary
TRACK-S  2.1 session model - 32 bytes stored as SHA-256 only, HttpOnly,
             one cookie per contour, Argon2id params, mandatory TOTP
         2.2 origin allowlist ahead of routing on every cookie mutation
         4.2 AES-256-GCM envelope for stored secrets, HMAC fingerprints
         8a  order manager as a separate contour, scoped by membership
             rows rather than by configuration
PHASE-9  5.1 revision immutability, version = max+1, pointer flipped
             in-transaction, operational state does not travel
         5.2 clone carry / no-carry list, inventory to zero
         5.3 signed read-only preview, non-GET 404s while previewing
         6   host normalization, verifiedAt required, cache invalidation
PHASE-10 3a  server re-runs the editor's validation, clamp-and-fallback
PHASE-2  3.1 order publicToken, snapshot completeness, never updated

FH-2.12 rejected on the merits: our marketplace lifecycle state machine
is richer than theirs, adopting it would be a downgrade. Recorded in the
TODO so it is not raised again.

Also adds BACKEND-HANDOFF.md sections 0 and 0a - nine falsifiable
invariants as a release gate, each cross-referenced to the contract that
specifies it, plus PR and release discipline. And ADR-0006 recording what
we take, what we reject, what we keep because ours is better, and the
organizational question it deliberately does not settle.

No implementation changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-08-21 11:12:05 +04:00
parent e8fc8480fe
commit f9e09b1757
9 changed files with 353 additions and 38 deletions

View File

@@ -2,10 +2,38 @@
Single entry point for a backend developer picking this up cold. Written 2026-08-18.
## 0. Invariants — the acceptance gate
Added 2026-08-21 (FH-E.1). Nine statements. Each is falsifiable, each has a test, and a release that violates any of them does not ship regardless of what else is finished. They come before the contracts because a contract can be read selectively and these cannot.
1. The public tenant is determined by verified `Host` alone. No public endpoint accepts a `marketplaceId` from the browser.
2. The price of an order is computed by the backend. A price arriving in a request is ignored, never validated-and-used.
3. Stock and reservation change atomically. Two buyers racing for the last unit produce one payable order.
4. Payment creation and webhook receipt are idempotent, enforced by unique constraints rather than by handler logic.
5. Provider credentials never leave the backend — not in a response, not in a bundle, not in a log.
6. A published revision is immutable. Rollback creates a new revision; history is never rewritten.
7. Rolling back design does not roll back live inventory, orders, or payments.
8. No user reads a marketplace they are not assigned to — through the UI or through a direct API call.
9. Every administrative mutation leaves an audit record naming actor, action, before and after.
Where each is specified: 1 and 67 in [Phase 9](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md) §56; 2 in [Phase 1](PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md) §5; 3 in [Phase 3](PHASE-3-CATALOG-OFFER-FULFILLMENT-CONTRACT.md) §3.1; 4 in [Phase 7](PHASE-7-PAYMENTS-RECONCILIATION-CONTRACT.md) §5; 5, 8 and 9 in [Track S](TRACK-S-SECURITY-RBAC-CONTRACT.md) §2, §3, §4.2.
## 0a. How work lands
Added 2026-08-21 (FH-E.2, FH-E.3).
**One functional area per pull request.** A PR carries: what it does, screenshots where there is UI, API changes, migrations, test evidence, security impact, and a rollback plan. Never change a payment, inventory, or order state machine in the same PR as a redesign — those two things fail differently and must be revertable separately.
**Migrations are expand/contract.** A migration and the frontend change that depends on it belong to one release train, but they may be separate PRs, and the expand step must be deployable on its own.
**A release is not "the build passed."** Each one records: version, migrations applied, healthcheck result, post-deploy smoke result, production dependency audit, and the rollback path actually available. A local build succeeding and a UI existing are not evidence of production readiness — the deploy and the smoke check are.
## 1. What this is
`marketplaces` is a multi-tenant marketplace platform frontend (Angular 22). The frontend is built and waiting; **there is no backend yet**. Every wire contract the backend needs to implement is already written and sitting in this directory — see [README.md](README.md) for the full index and build order.
Contract sections dated 2026-08-21 and tagged `FH-*` come from [FORK-ANALYSIS-2026-08-21.md](../FORK-ANALYSIS-2026-08-21.md) — a review of a parallel platform implementation that has a working backend. They are mechanisms that implementation already proved, harvested deliberately; the tag is there so you can trace any one of them back to why it is worded the way it is.
## 1a. Multi-tenancy — the thing that shapes every endpoint
The final executable infrastructure/backend contract is