Wave 4 of replacing the fixed-data mock adapter, and the first capability the
mall never had a backend for: the home page's banners, promo tiles, quick links
and floor advert art move out of local arrays.
- four explicit tables (`banners`, `promos`, `quick_links`, `floor_adverts`)
rather than one JSONB payload table, so Postgres enforces each shape
- a migration seeds them from the assets the page already rendered, so the flip
is visually a no-op. Destinations are real routes now: the mock's promo links
pointed at dangling `?category=c1` ids and its first banner used `sort=sales`,
which the catalog API rejects
- `GET /api/content/home` is public and returns the four active, ordered lists,
always including a key so a page can render a missing block
- `GET /api/admin/content` and `PUT /api/admin/content/{kind}` let a platform
admin read everything and replace one kind transactionally, with positions
reindexed from the submitted order and a rejected list changing nothing
- the mall's fixed-data adapter learns `getHomeContent`, and a `content` domain
joins the per-domain switch so the rollback path still renders the page
Verified: 23 backend tests green including six new content tests; all three
frontends build; the home page renders the same four blocks as before, an admin
reorder and deactivation change the rendered carousel, and the fixed-data
rollback renders every block with the backend stopped.
OpenSpec change: openspec/changes/replace-mock-api-wave-4
3.3 KiB
3.3 KiB
Tasks
1. Schema and seed
- 1.1 Add a migration creating
banners,promos,quick_linksandfloor_advertswith explicit columns (image,url,position,active, pluslabel/glyphon quick links); verified the tables exist aftercargo run -p vmall-api - 1.2 Seed the same migration from the assets the page uses today, matching
pages/index.vue's arrays; verifiedGET /api/content/homereturns 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=c1ids and itssort=sales, which the catalog API rejects
2. Shared contract
- 2.1 Add
HomeBanner,HomePromo,HomeQuickLink,FloorAdvert,HomeContent,ContentKindandContentInputByKindtopackages/shared/src/types.ts, with the quick-link label asLocalizedText; verified all three frontends build - 2.2 Add
getHomeContent()andadmin.getContent()/admin.replaceContent(kind, list)to theApiClientinterface andcreateApi, and give the fixed-data client matching implementations so the rollback path keeps serving the current arrays. Also registered acontentdomain in the per-domain switch (plugins/api.tsandnuxt.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/homereturning 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/contentreturning every kind including inactive rows, gated toplatform_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 withoutzh) fails without changing the stored list
5. Mall home page
- 5.1 Point
pages/index.vueatgetHomeContent(), 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-apiis 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