Files
vmall/openspec/changes/archive/2026-09-17-replace-mock-api-wave-4/tasks.md
T
james f6ddfd21cb chore(openspec): archive replace-mock-api-wave-4
The merge creates the storefront-content capability (two requirements, five
scenarios) and updates the mall's home-page requirement so its banner,
promotion, quick-link and floor advert content comes from the content API.

openspec validate --all --strict stays green at 12 passed / 0 failed.
2026-09-17 16:49:35 +00:00

3.3 KiB

Tasks

1. Schema and seed

  • 1.1 Add a migration creating banners, promos, quick_links and floor_adverts with explicit columns (image, url, position, active, plus label/glyph on quick links); verified the tables exist after cargo run -p vmall-api
  • 1.2 Seed the same migration from the assets the page uses today, matching pages/index.vue's arrays; verified GET /api/content/home returns 3 banners, 3 promos, 6 quick links and 6 floor adverts. The seeded destinations are valid routes (/seckill, /collective, /integral, /search?sort=price&order=desc) rather than the mock's dangling ?category=c1 ids and its sort=sales, which the catalog API rejects

2. Shared contract

  • 2.1 Add HomeBanner, HomePromo, HomeQuickLink, FloorAdvert, HomeContent, ContentKind and ContentInputByKind to packages/shared/src/types.ts, with the quick-link label as LocalizedText; verified all three frontends build
  • 2.2 Add getHomeContent() and admin.getContent() / admin.replaceContent(kind, list) to the ApiClient interface and createApi, and give the fixed-data client matching implementations so the rollback path keeps serving the current arrays. Also registered a content domain in the per-domain switch (plugins/api.ts and nuxt.config.ts) — missed on the first pass and caught by the browser check, where the promos still rendered the mock hrefs because the new method had no live pick

3. Public content read

  • 3.1 Add GET /api/content/home returning the four active, position-ordered lists, with no authentication; verified it answers with the seeded counts and omits a row once it is marked inactive
  • 3.2 Return an empty list for any kind with no active entries rather than omitting the key; asserted by home_content_is_public_and_ordered

4. Admin content management

  • 4.1 Add GET /api/admin/content returning every kind including inactive rows, gated to platform_admin; verified a customer and a shop owner are refused with 403
  • 4.2 Add PUT /api/admin/content/{kind} replacing one kind transactionally, validating each entry and reindexing positions from the submitted order; verified a reordered submission reads back in the new order, and that the rendered page follows
  • 4.3 Verify an invalid entry (missing image, or a quick-link label without zh) fails without changing the stored list

5. Mall home page

  • 5.1 Point pages/index.vue at getHomeContent(), delete the three mock arrays from the page, and render the floor advert pool by floor order; verified the page still renders its sidebar and floors, and that a floor renders no advert rather than a broken image when the pool is empty

6. Verification

  • 6.1 Run the mall, shop-admin and admin builds, since the shared contract changed; all three pass, and cargo test -p vmall-api is green at 23 tests
  • 6.2 Compared the home page against the pre-change render: 3 banners, 6 quick links, 3 promo tiles and floor adverts 1-6 across 6 floors, visually unchanged. Reordering banners and marking one inactive through the admin API changed the rendered carousel accordingly, then the seed was restored
  • 6.3 Verified the rollback: with every domain on fixed data and the backend stopped, the home page still renders all four blocks with no console errors