Files
vmall/openspec/changes/archive/2026-09-23-add-content-admin-ui/tasks.md
T

4.7 KiB

1. Admin content management page

  • 1.1 Add apps/admin/pages/content.vue loading all four kinds through admin.getContent() from @vmall/shared (inactive entries included) and add a content entry to the apps/admin nav beside existing platform operations.
  • 1.2 Implement one editor section per kind — banners, promos, quick links, floor adverts — with the exact per-entry fields the API accepts: image and destination URL for banners and promos, { en, zh } label, destination URL and inline SVG glyph for quick links, and image for floor adverts, plus an active flag on every row.
  • 1.3 Support ordered row editing per kind (add, remove, move up/down — no drag and drop) and pre-validate each row with the API rules (non-empty image and destination URLs, non-empty glyph, non-empty en and zh quick-link labels), showing inline field errors before any request is sent.
  • 1.4 Save one kind at a time by submitting the whole displayed list through admin.replaceContent(kind, items) so the API replaces that kind atomically and reindexes positions, leaving the other three kinds untouched; render a per-entry storefront preview (image, destination, glyph/label) and clear success feedback on save.
  • 1.5 On a rejected save keep the edited rows and show a visible failure message, and add the page's bilingual strings through the existing admin locale sources.

2. Admin brand management page

  • 2.1 Add apps/admin/pages/brands.vue loading the registry through admin.getBrands() and add a brands entry to the apps/admin nav beside existing platform operations.
  • 2.2 Edit the whole ordered list with add, remove and move up/down rows carrying slug, non-empty { en, zh } names and an active flag; pre-validate slugs against the API pattern (ascii a-z, 0-9, -) and reject duplicate slugs and incomplete bilingual names with inline errors before any request is sent.
  • 2.3 Save the full list through admin.replaceBrands(items) so positions follow the displayed order, and render a preview row per brand as the public list serves it (slug and bilingual name) with clear success feedback on save.
  • 2.4 On a rejected save keep the edited rows and show a visible failure message, and add the page's bilingual strings through the existing admin locale sources.

3. Shop-admin profile editing

  • 3.1 Add the minimal merchant-scoped endpoint PUT /api/shop/profile in apps/api/src/modules/shop/: an authenticated write scoped with own_shop over the caller's shop, reusing the existing profile upsert and { en, zh } bilingual validation, accepting logo, banner, company, region, address, notice and after_sale, and never storing score_rating, score_agreement, score_service or score_speed; the service returns ApiResult<ShopProfileView>.
  • 3.2 Add a shop.updateMyProfile method to the @vmall/shared contract (own-profile input without score fields, returning ShopProfile) with live-client wiring; all frontend calls go through this shared contract only.
  • 3.3 Add apps/shop-admin/pages/shop-profile.vue editing the caller's own shop profile — logo and banner URLs, company, region and bilingual address, notice and after-sale copy — prefilled from shop.getMyShop() and the composed getShop(slug) read, with non-empty en and zh validation on bilingual fields and no score fields in the form.
  • 3.4 Save through shop.updateMyProfile, keep the form values and show a visible failure message when the write is refused (success feedback otherwise), and add the shop-profile nav entry to apps/shop-admin with bilingual strings through the existing shop-admin locale sources.

4. Verification

  • 4.1 Add integration coverage in apps/api/tests/ reusing the tests/common/mod.rs fixtures for the new endpoint: a merchant upsert round-trips to the public shop read, incomplete bilingual text is refused with the stored profile unchanged, submitted score values leave the stored scores unchanged, a user without a shop is refused, and another shop's profile is untouched; run the focused cargo test -p vmall-api --test shops.
  • 4.2 Build all three frontends because the shared contract changes: pnpm --filter @vmall/admin build, pnpm --filter @vmall/shop-admin build, and pnpm --filter @vmall/mall build.
  • 4.3 Run the API and browser-smoke the admin content page (edit, reorder, per-kind save reflected on the mall home with the other kinds untouched), the admin brands page (edit and save reflected in the public brand list), and the shop-admin profile page (edit, save, and the mall store page showing the new copy for that shop only).
  • 4.4 Check every OpenSpec task and run openspec change validate add-content-admin-ui --strict plus openspec validate --all --strict.