feat(mall): run the transaction chain against the live API

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
This commit is contained in:
2026-09-17 16:33:22 +00:00
parent 0ceb4a2b25
commit e1a0a5dbdb
19 changed files with 314 additions and 92 deletions
@@ -0,0 +1,25 @@
# Spec Delta
## MODIFIED Requirements
### Requirement: Shopping flow
A shopper SHALL be able to browse, view detail, add to cart, checkout with a shipping address, pay, track orders/shipments, confirm delivery, and request an invoice against the live API. Cart, order, shipment and invoice state SHALL be the backend's rather than the browser's, and the fixed-data adapter SHALL remain available as a configured fallback rather than the default. Adding to the cart SHALL require an authenticated shopper: an anonymous add SHALL send the shopper to sign in and return them to where they left off.
#### Scenario: end-to-end purchase
- **WHEN** a shopper completes checkout on a non-empty cart
- **THEN** the resulting order appears in the buyer center and the cart is empty
#### Scenario: anonymous add prompts sign-in
- **WHEN** a signed-out shopper adds an in-stock SKU from a product page
- **THEN** they are sent to sign in and, once signed in, returned to that product page
### Requirement: Mock transaction flow
The mall SHALL provide a store-grouped cart, address-selecting checkout preview, payment selection and payment-success result, all reading and writing the live cart and order APIs. Quantity changes, removals, selection totals, checkout and payment SHALL be persisted by the backend for the signed-in shopper, so they survive a page reload.
#### Scenario: complete mock purchase
- **WHEN** a shopper adds an in-stock SKU, checks out with a mock address and confirms a payment
- **THEN** the cart is cleared, the success page is shown and the new order appears in the user order list
#### Scenario: cart survives a reload
- **WHEN** a signed-in shopper adds an item and then reloads the page
- **THEN** the cart still holds that item, priced and stocked from the catalog