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:
@@ -78,6 +78,15 @@ interface OrderContactSnapshot {
|
||||
}
|
||||
```
|
||||
|
||||
### 3.1 Public addressing and snapshot completeness
|
||||
|
||||
Added 2026-08-21 (FH-2.13).
|
||||
|
||||
- `Order` carries a `publicToken`: at least 24 random bytes, base64url, unique. **Every customer-facing route addresses an order by this token, never by `id`.** Order confirmation links, status polling, and support lookups all use it. A sequential or guessable public identifier turns "check my order" into an enumeration of the tenant's order book.
|
||||
- `GET /api/v2/storefront/orders/{publicToken}` is scoped to the resolved tenant. A valid token from a different marketplace is `404`.
|
||||
- `OrderLine` already snapshots SKU, title and price. Extend that to **everything that must survive a later edit**: currency, per-line discount, delivery option and price, and the tax/fee components. Together with `OrderContactSnapshot`, an order must be fully reconstructable from its own rows — renaming an offer, changing a price, or deleting a delivery option must not alter what a historical order says was bought and charged.
|
||||
- Snapshot fields are written once at order creation and never updated. A correction is a new order event, a refund, or an amendment record — never an in-place rewrite of what the customer agreed to.
|
||||
|
||||
## 4. Endpoints
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user