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
3.9 KiB
3.9 KiB
Tasks
1. Contract and backend cart view
- 1.1 Add
shop_id,shop_nameandstocktoCartItemViewand to thecart_viewSELECT inapps/api/src/cart.rs(the query already joinsproducts,shopsandskus); verifiedGET /api/cartreturns a distinct shop and the SKU's stock per line for a two-shop cart - 1.2 Add
shop_id,shop_nameandstocktoCartIteminpackages/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 tov2, because a cart saved by an older build is no longer a validCartItem[]; verified the mall, shop-admin and admin builds all pass - 1.3 Make
Shipment.itemsoptional andInvoice.invoice_nonullable inpackages/shared/src/types.ts.Invoicewas 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 (noitemskey) and a requested invoice (invoice_no: null) - 1.4 Extend the two-shop cart test in
apps/api/tests/orders.rsto assert each line reports its own shop, a bilingual shop name and the SKU stock; verifiedcargo test -p vmall-api --test ordersis green
2. Anonymous add-to-cart gate
- 2.1 Send a signed-out shopper to
/login?redirect=<current path>whenaddCartItemanswers 401, accepting only same-origin paths; verified the parameter is dropped for//hostand absolute URLs - 2.2 Have
pages/login.vuereturn the shopper to a validredirecttarget after a successful sign-in; verified the round trip from a product page
3. Cart surface
- 3.1 Group
pages/cart.vueby the line's ownshop_idand label each group withshop_name, dropping theproductById/storeByIdlookups; 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
stockinstead of the 999 fallback, and use the line'simagefor the thumbnail; verified the caps read12and25from 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, keepingMOCK_ADDRESSESas the address source; verified the checkout preview groups correctly and the order submits - 4.2
pages/checkout/pay.vueandpages/user/orders/index.vue: drop thestoreByIdlookups 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 wheninvoice_nois null, mirroring the existingorder_nohandling; verified the invoices table shows—for a requested-but-unissued invoice alongside realINV…numbers
5. Flip the domains
- 5.1 Add
cart,orders,shipmentsandinvoicesto the defaultliveDomainsinapps/mall/nuxt.config.tsin 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 buildplus 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-outGET /api/cart401 (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