Wave 4 of replacing the fixed-data mock adapter, and the first capability the
mall never had a backend for: the home page's banners, promo tiles, quick links
and floor advert art move out of local arrays.
- four explicit tables (`banners`, `promos`, `quick_links`, `floor_adverts`)
rather than one JSONB payload table, so Postgres enforces each shape
- a migration seeds them from the assets the page already rendered, so the flip
is visually a no-op. Destinations are real routes now: the mock's promo links
pointed at dangling `?category=c1` ids and its first banner used `sort=sales`,
which the catalog API rejects
- `GET /api/content/home` is public and returns the four active, ordered lists,
always including a key so a page can render a missing block
- `GET /api/admin/content` and `PUT /api/admin/content/{kind}` let a platform
admin read everything and replace one kind transactionally, with positions
reindexed from the submitted order and a rejected list changing nothing
- the mall's fixed-data adapter learns `getHomeContent`, and a `content` domain
joins the per-domain switch so the rollback path still renders the page
Verified: 23 backend tests green including six new content tests; all three
frontends build; the home page renders the same four blocks as before, an admin
reorder and deactivation change the rendered carousel, and the fixed-data
rollback renders every block with the backend stopped.
OpenSpec change: openspec/changes/replace-mock-api-wave-4
Wave 3 of replacing the fixed-data mock adapter: cart, orders, shipments and
invoices flip together, so one purchase runs end to end against the backend.
- cart: CartItemView carries the line's shop and the SKU's stock, so the cart
keeps grouping per shop and the quantity stepper caps at real stock instead
of a hard-coded 999
- contract: Shipment.items is optional and Invoice.invoice_no nullable, both
matching what the API actually returns. Invoice was declared twice in
types.ts and TypeScript merges duplicate interfaces, so the duplicate had to
go for the change to take effect at all
- an anonymous add-to-cart redirects to /login?redirect=..., and sign-in
honours only same-origin paths
- the fixed-data adapter learns the new cart fields, and its persisted state
key moves to v2 because a cart saved by an older build is no longer valid
- order surfaces drop their storeById lookups and keep the generic store label
until the public store read arrives
Verified end to end: two-shop cart grouping with live shop names, stock caps
read from the API, checkout, payment, shipment, delivery confirmation and an
issued invoice. Rollback re-verified with every domain on fixed data and the
backend stopped.
Also checks off Wave 3 in docs/TBD-migrate-wave.md and re-points that file at
the mock content that remains.
OpenSpec change: openspec/changes/replace-mock-api-wave-3