Planning only: proposal, delta specs, design and tasks for replacing the store surfaces. No code yet. The batch adds a public shop read (profile + products) so the store directory, store home and product-page store card stop reading MOCK_STORES, and so the cart, payment and order surfaces can name a shop instead of printing "Shop". Decisions recorded in the design: - a `shop_profiles` table beside `shops`, so the existing admin and shop-admin contracts are untouched - the four store scores stay stored profile values, because there is no review model and deriving them would dress fabricated numbers as computed ones - `distanceKm` is dropped rather than faked: there is no geo model behind it - profiles are filled by seed-demo.mjs, since they hang off shops that script creates - order surfaces resolve names from one cached shop read rather than growing a denormalised shop name on every order payload openspec validate --strict passes and the change is ready to apply.
2.8 KiB
2.8 KiB
Tasks
1. Schema
- 1.1 Add a migration creating
shop_profileskeyed 1:1 toshops(shop_idprimary key,logo,banner,company,region,addressJSONB,noticeJSONB,after_saleJSONB, four score columns,updated_at); verify the table exists aftercargo run -p vmall-api
2. Shared contract
- 2.1 Add
ShopProfile(shop identity plus the optional profile fields) and aShopProfileInputtopackages/shared/src/types.ts; verify all three frontends build - 2.2 Add
listShops()/getShop(slug)to theApiClientandcreateApi, plusadmin.setShopProfile(id, body); give the fixed-data adapter matching implementations built fromMOCK_STORESso the rollback path still renders; verify the mall build
3. Public shop read
- 3.1 Add
GET /api/shopsreturning active shops with their profile, andGET /api/shops/{slug}returning one, both unauthenticated and both tolerating a missing profile row; verify a suspended shop is absent from the list and an unknown slug is a 404 - 3.2 Add
PUT /api/admin/shops/{id}/profileupserting the profile, validating non-emptyen/zhon bilingual fields and gated toplatform_admin; verify a bad payload is refused without changing the stored row
4. Demo profiles
- 4.1 Teach
scripts/seed-demo.mjsto set a profile for each demo shop using the existing/mock/store-N.svgassets and bilingual copy; verify a re-run is idempotent andGET /api/shopsreturns a profile for every shop
5. Mall store surfaces
- 5.1
pages/stores/index.vue: list fromGET /api/shopsand drop the distance column and its sort; verify the directory renders every active shop and no "km" text remains - 5.2
pages/stores/[id].vue: load the shop by slug and its products from the catalog API byshop_id, drop the mock sales ranking in favour of the same shop-scoped product call; verify a store page renders its profile and products - 5.3
pages/goods/[id].vue: read the store card from the shop API instead ofstoreById, keeping the existing guards for a missing profile - 5.4
pages/checkout/pay.vueandpages/user/orders/index.vue: resolve shop names from the cached shop read, removing the generic "Shop" placeholder
6. Verification
- 6.1 Run the mall, shop-admin and admin builds, since the shared contract changed; verify all three pass and
cargo test -p vmall-apistays green - 6.2 With the backend seeded, verify in a browser that the store directory lists the demo shops, a store home renders its profile and products, the product page's store card shows a real name, and the cart/payment/order surfaces name the shop; confirm no console errors beyond deliberate failed responses
- 6.3 Verify the rollback: with every domain on fixed data and the backend stopped, the store directory and store home still render