# TBD — migrate the mall off the mock API (waves 2+) Wave 1 is planned in the OpenSpec change `openspec/changes/replace-mock-api-wave-1/` (catalog + currency). This file tracks everything after it. **How to use:** check a box only once the behaviour is implemented *and* verified against the live backend (`cargo run -p vmall-api`, `node scripts/seed-demo.mjs`). Wave 1 leaves a per-domain switch in `apps/mall/plugins/api.ts`, so most of these are adding a domain name to the live list — each still needs its own verification below. **Delete this file** once every box in Waves 2 and 3 is checked. Wave 4 is optional: if you decide against it, delete this file anyway and record that decision wherever you like. --- ## Wave 2 — auth + cart - [ ] Flip `auth` to live and verify `login` / `register` / `me` against `:8080` using the seeded `customer@vmall.local` / `customer123`. - [ ] Confirm bad credentials now produce a real 401 — the mock accepted any input (`apps/mall/mock/api.ts:125`), so this is a deliberate UX change. - [ ] Confirm the JWT round-trips through the `vmall.token` localStorage key, shared with shop-admin and admin, and that logout clears it. - [ ] Flip `cart` to live. Cart requires a token (`AuthUser` on all four handlers in `apps/api/src/routes/cart.rs`) and real SKU ids from Wave 1 — both are prerequisites, not optional. - [ ] Remove cart's mock display coupling: `apps/mall/pages/cart.vue:4,34,41,56,60` uses `productById` / `storeById` for shop name, image and stock. The live `CartView` already returns `product_name`, `image` and `unit_price_minor` (`apps/api/src/cart.rs:44-53`). - [ ] Verify: add / qty update / remove / empty cart for a logged-out user, and the out-of-stock 409 path. ## Wave 3 — orders + shipments + invoices - [ ] Flip `orders` to live and verify checkout splits one cart into per-shop orders with a price snapshot and stock decrement. - [ ] Checkout still sources `shipping_address` from `MOCK_ADDRESSES` (`apps/mall/pages/checkout/index.vue:4,23,37,127`) — that is intentional; see the out-of-scope note below. - [ ] Verify cancel restores stock and `payOrder` only accepts `pending_payment` (both are enforced live; the mock only mimicked them). - [ ] Flip `shipments` to live and verify `confirmDelivered` moves the order to `completed`. - [ ] Flip `invoices` to live and verify a company invoice requires a tax number and that one order can hold only one active invoice. - [ ] Fix contract debt so the TS types stop lying: `Shipment.items` is required in `packages/shared/src/types.ts` but the live struct has no `items` field (`apps/api/src/models.rs:172-182`), and `Invoice.invoice_no` is nullable live (`models.rs:194`) but non-null `string` in TS. - [ ] Remove the remaining `storeById` mock usage on the order pages (`apps/mall/pages/user/orders/index.vue:4`). - [ ] Confirm the mall still renders when the live API is down (mock mode remains the fallback for local UI work). ## Wave 4 — optional new backend capabilities Only if you want more of the storefront backed by real data. Each is a new capability, not a flip. - [ ] **Storefront content** — banners, promos, quick links, home floors and floor advert art. Needs real tables, admin CRUD and i18n JSONB. Do this first if you want the home page fully live; it is the most visible remaining mock surface. - [ ] **Public store read** — a buyer-facing shop endpoint so `stores/index` and `stores/[id]` leave mock. Small: products already carry `shop_id`, and the public catalog already joins shops for the active check. - [ ] **Brand model + sales/comments sorts** — restores the brand facet and the sorts removed in Wave 1. Needs a `brands` table (`products.brand_id` + i18n) plus sales and comments data, neither of which exists today. - [ ] Extend the `ORDER BY` whitelist if more sorts are wanted beyond the `sort=price` added in Wave 1. --- ## Deliberately out of scope — not tracked here, and they do not block deleting this file These have no API contract and no backend model. Leaving them on `~/mock/data` is a decision, not a backlog item. - **Addresses** — never a blocker: `Address` is embedded in the order and live checkout takes it in the request body, so no addresses table is needed. `MOCK_ADDRESSES` can stay behind checkout indefinitely. - **Favorites, coupons, account stats** — pure presentation, no transactional impact. - **seckill / collective / integral marketing pages** — display-only mock content. ## Decisions already made (do not relitigate) - Category filtering is by **subtree**; the backend exact-match filter was the bug (fixed in Wave 1). - A migration wave must not change what the UI claims: facets without a backing model are removed rather than left matching nothing. - The mall is the last mock holdout; `shop-admin` and `admin` already run live against the same backend.