Files
vmall/openspec/changes/archive/2026-09-17-replace-mock-api-wave-3/tasks.md
T
james 2136a48fbe chore(openspec): archive the mock-migration waves and green the spec set
Archive the three completed changes behind replace-mock-api-wave-1/2/3. Each
merge applied cleanly to the main specs:

- catalog gains the Public product browse requirement (subtree filtering and
  price sort)
- frontend-mall picks up the per-domain adapter, the pinned home page, the
  discovery-page changes, the live auth panels and the live transaction flows
- cart's Server-side cart requirement now documents the shop and stock carried
  by every line

Also replace the TBD Purpose placeholder in all eleven specs with a one-line
description of what each capability covers. Those placeholders predate this
work and were the only reason `openspec validate --all --strict` reported
0 passed / 11 failed; it now reports 11 passed / 0 failed.
2026-09-17 16:36:10 +00:00

3.9 KiB

Tasks

1. Contract and backend cart view

  • 1.1 Add shop_id, shop_name and stock to CartItemView and to the cart_view SELECT in apps/api/src/cart.rs (the query already joins products, shops and skus); verified GET /api/cart returns a distinct shop and the SKU's stock per line for a two-shop cart
  • 1.2 Add shop_id, shop_name and stock to CartItem in packages/shared/src/types.ts. Also had to teach the fixed-data adapter to construct the new fields (apps/mall/mock/api.ts) and bump its persisted-state key to v2, because a cart saved by an older build is no longer a valid CartItem[]; verified the mall, shop-admin and admin builds all pass
  • 1.3 Make Shipment.items optional and Invoice.invoice_no nullable in packages/shared/src/types.ts. Invoice was declared twice in that file and TypeScript merges duplicate interfaces, so the duplicate was removed for the change to take effect at all; verified against a live shipment (no items key) and a requested invoice (invoice_no: null)
  • 1.4 Extend the two-shop cart test in apps/api/tests/orders.rs to assert each line reports its own shop, a bilingual shop name and the SKU stock; verified cargo test -p vmall-api --test orders is green

2. Anonymous add-to-cart gate

  • 2.1 Send a signed-out shopper to /login?redirect=<current path> when addCartItem answers 401, accepting only same-origin paths; verified the parameter is dropped for //host and absolute URLs
  • 2.2 Have pages/login.vue return the shopper to a valid redirect target after a successful sign-in; verified the round trip from a product page

3. Cart surface

  • 3.1 Group pages/cart.vue by the line's own shop_id and label each group with shop_name, dropping the productById/storeById lookups; verified a two-shop cart renders two groups labelled with the live names (Aurora Digital, Demo Store)
  • 3.2 Cap the quantity stepper with the line's stock instead of the 999 fallback, and use the line's image for the thumbnail; verified the caps read 12 and 25 from the live cart rather than 999

4. Transaction surfaces

  • 4.1 pages/checkout/index.vue: group by the cart line's shop and image rather than the mock catalog, keeping MOCK_ADDRESSES as the address source; verified the checkout preview groups correctly and the order submits
  • 4.2 pages/checkout/pay.vue and pages/user/orders/index.vue: drop the storeById lookups and keep the existing generic store label until Wave 4; verified order cards render with the placeholder and without errors
  • 4.3 pages/user/invoices.vue: render a placeholder when invoice_no is null, mirroring the existing order_no handling; verified the invoices table shows for a requested-but-unissued invoice alongside real INV… numbers

5. Flip the domains

  • 5.1 Add cart, orders, shipments and invoices to the default liveDomains in apps/mall/nuxt.config.ts in one commit with the page changes above; verified every one of those pages now reads from :8080

6. Verification

  • 6.1 Run pnpm --filter @vmall/mall build plus the shop-admin and admin builds, since the shared contract changed; all three pass
  • 6.2 With the backend seeded, ran one purchase in a browser: signed in, added from a product page, saw a two-shop cart group correctly, checked out, paid, then confirmed the order. The merchant half of the chain (ship → issue invoice) has no mall UI and was driven through the API, after which the order page showed the live shipment, confirming delivery moved the order to completed, and the invoices page listed the issued numbers. The only console entries were the header's signed-out GET /api/cart 401 (caught, count 0) and no hydration warnings
  • 6.3 Verified the rollback: with every domain set to fixed data and the backend stopped, sign-in, add-to-cart, cart grouping, the stock cap and checkout all still work from localStorage