docs: architecture, guidelines, domain designs, progressive code index

This commit is contained in:
Chengdong Zhang
2026-09-24 16:59:32 +08:00
parent c532f87b03
commit a968327b12
19 changed files with 728 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
# Index: Catalog
Domain design: `docs/domains/catalog.md`. Specs: `openspec/specs/product/`,
`category/`, `brand/`.
## Backend (`apps/api`)
| File | Holds |
|---|---|
| `src/modules/product/service.rs` | public list/detail, merchant CRUD, publish/unpublish, SKU upsert, template link validation |
| `src/modules/product/repo.rs` | SKU attach + sold_count aggregation |
| `src/modules/category/` | public category tree |
| `src/modules/brand/` | public list; admin whole-list replacement |
| `migrations/0003_catalog.sql`, `0005_seed_category_tree.sql`, `0008_brands.sql` | schema + seeds |
## Shared contract
`types.ts`: `Product`, `Sku`, `Category`, `Brand`, `ProductStatus`.
`api.ts`: `listProducts`, `getProduct`, `listCategories`, `listBrands`,
`shop.*` product/SKU methods, `admin.replaceBrands`.
## Frontends
- Mall: `pages/index.vue` (floors), `pages/search.vue`, `pages/goods/[id].vue`,
`components/ui/ProductCard.vue`
- Shop-admin: `pages/products/{index,new,[id]}.vue`,
`components/ProductForm.vue`
- Admin: `pages/brands.vue`
+32
View File
@@ -0,0 +1,32 @@
# Index: Console apps (shop-admin, admin)
Both are live-only (no mock adapter), Tailwind-token layouts, auth middleware
per page. Navigation is a static list in each `app.vue`.
## apps/shop-admin (merchant console, :3001)
| Page | Domain |
|---|---|
| `pages/index.vue` | dashboard counters |
| `pages/products/{index,new,[id]}.vue` + `components/ProductForm.vue` | product/SKU CRUD, freight template link, SKU weight |
| `pages/orders/` | order list/detail + shipment creation (company selector) |
| `pages/shipments.vue` | shipment list, mark shipped |
| `pages/aftersales/` | after-sale processing workspace |
| `pages/reviews.vue` | review list + one-time reply |
| `pages/coupons.vue`, `flash-sales.vue`, `group-buying.vue` | merchant marketing |
| `pages/invoices.vue` | invoice issuing |
| `pages/freight-templates.vue` | freight templates + region rules |
| `pages/shop-profile.vue` | own shop profile self-edit |
## apps/admin (platform console, :3002)
| Page | Domain |
|---|---|
| `pages/index.vue` | platform overview |
| `pages/users.vue`, `pages/shops.vue` | users/roles, shop lifecycle |
| `pages/orders.vue` | read-only orders |
| `pages/aftersales.vue` | monitoring + dispute arbitration |
| `pages/reviews.vue` | moderation (hide/delete) |
| `pages/content.vue`, `pages/brands.vue` | storefront content, brand registry |
| `pages/currencies.vue` | currency registry + rates |
| `pages/points-products.vue`, `pages/points-orders.vue` | points mall ops |
+20
View File
@@ -0,0 +1,20 @@
# Code Index
Progressive disclosure: pick the domain, open its file, get the concrete
paths. **Update the affected domain file whenever you add/remove/rename
files it lists.**
| Domain | Covers | Index |
|---|---|---|
| Order & freight | checkout, orders, shipments, freight templates, shipping companies | [code_index/order.md](order.md) |
| Post-order | aftersales/refunds, reviews | [code_index/post-order.md](post-order.md) |
| Catalog | products, SKUs, categories, brands | [code_index/catalog.md](catalog.md) |
| Marketing | coupons, flash sales, group buying, points | [code_index/marketing.md](marketing.md) |
| Platform | identity, accounts/ledger, shops, storefront content, currencies, addresses | [code_index/platform.md](platform.md) |
| Shared contract | types, API client, locales, UI components | [code_index/shared.md](shared.md) |
| Storefront app | mall pages, mock adapter, live-domain wiring | [code_index/mall.md](mall.md) |
| Console apps | shop-admin, admin pages | [code_index/consoles.md](consoles.md) |
Cross-cutting references: `docs/architecture.md` (system),
`docs/backend-guidelines.md`, `docs/frontend-guidelines.md`,
`docs/development.md` (run/test), `openspec/specs/` (normative behavior).
+21
View File
@@ -0,0 +1,21 @@
# Index: Mall storefront app (`apps/mall`)
Guidelines: `docs/frontend-guidelines.md`.
| Path | Holds |
|---|---|
| `plugins/api.ts` | `$api` composition: mock base + per-domain live picks (`LiveDomain`, `LIVE_PICKS`, `DEFAULT_LIVE_DOMAINS`) |
| `mock/api.ts` | deterministic fixed-data adapter; versioned persisted state (`STORAGE_KEY`) |
| `mock/data.ts` | seed fixtures for the mock adapter |
| `nuxt.config.ts` | `liveDomains` runtime default (JSON array env `NUXT_PUBLIC_LIVE_DOMAINS` overrides) |
| `pages/index.vue` | home: banners/promos/quick links/category floors |
| `pages/search.vue`, `pages/goods/[id].vue` | catalog browsing; goods detail has reviews tab |
| `pages/cart.vue`, `pages/checkout/*` | cart and checkout (address → quote → submit → pay → success) |
| `pages/stores/*` | store directory + store detail |
| `pages/user/*` | buyer center: orders, aftersales, reviews, coupons, addresses, invoices, favorites |
| `pages/seckill.vue`, `collective.vue`, `integral.vue` | flash sale, group buying, points mall |
| `app.vue` + `components/shell/*` | header/footer shell |
| `composables/` | session/cart stores, `usePrice` (currency conversion display) |
Remember: mall is the only app with a mock adapter; every new live domain
needs mock parity so `NUXT_PUBLIC_LIVE_DOMAINS` rollback keeps working.
+25
View File
@@ -0,0 +1,25 @@
# Index: Marketing (coupons, flash sales, group buying, points)
Domain design: `docs/domains/marketing.md`. Specs: `openspec/specs/shop-coupons/`,
`flash-sales/`, `group-buying/`, `points-mall/`.
## Backend (`apps/api`)
| Module | Holds |
|---|---|
| `modules/coupon/` | template CRUD, claim, checkout discount + redemption |
| `modules/flash_sale/` | sessions/items CRUD, activity price resolution, reserved stock |
| `modules/group_buying/` | activities, groups, seat claim at payment |
| `modules/points/` | points catalog, redemption, fulfillment |
Migrations: `0011_shop_coupons.sql`, `0012_points_mall.sql`,
`0013_flash_sales.sql`, `0014_group_buying.sql`.
Tests: `tests/coupons.rs`, `tests/flash_sales.rs`, `tests/group_buying.rs`,
`tests/points.rs`.
## Frontends
- Mall: `pages/seckill.vue`, `pages/collective.vue`, `pages/integral.vue`,
`pages/user/coupons.vue`; checkout coupon selection in `pages/checkout/index.vue`
- Shop-admin: `pages/coupons.vue`, `pages/flash-sales.vue`, `pages/group-buying.vue`
- Admin: `pages/points-products.vue`, `pages/points-orders.vue`
+34
View File
@@ -0,0 +1,34 @@
# Index: Order & Freight
Domain design: `docs/domains/orders.md`. Specs: `openspec/specs/order/`,
`shipment/`, `shipping/`.
## Backend (`apps/api`)
| File | Holds |
|---|---|
| `src/modules/order/service.rs` | checkout transaction, pay/cancel, shipping quote |
| `src/modules/order/repo.rs` | `ORDER_COLS`/`ORDER_ITEM_COLS`, insert_order/insert_item, locks, status transitions |
| `src/modules/order/handlers.rs` | `/orders*` customer routes, `/shop/orders*`, `/admin/orders` |
| `src/modules/order/dto.rs` | OrderView, AddressBody, ShippingQuoteView |
| `src/modules/fulfillment/` | shipments: create (company-validated), ship, confirm-delivered |
| `src/modules/freight/service.rs` | template CRUD, region rules, `shop_fee()` calculation, company dictionary |
| `src/modules/freight/handlers.rs` | `/shop/freight-templates*`, `/shipping/companies` |
| `migrations/0004_orders.sql` | orders/order_items/shipments base schema |
| `migrations/0017_freight_templates.sql` | freight tables, `orders.shipping_fee_minor`, item snapshots, `skus.weight_grams` |
| `tests/orders.rs`, `tests/freight.rs` | integration coverage |
## Shared contract (`packages/shared/src`)
`types.ts`: `Order`, `OrderItem`, `Shipment`, `FreightTemplate*`,
`ShippingCompany`, `ShippingQuote`. `api.ts`: `checkout`, `quoteShipping`,
`listShippingCompanies`, shop freight CRUD, `createShipment`.
## Frontends
- Mall: `pages/checkout/{index,pay,success}.vue`, `pages/user/orders/`,
`pages/user/addresses.vue`
- Shop-admin: `pages/orders/`, `pages/shipments.vue`,
`pages/freight-templates.vue`, `components/ProductForm.vue`
(freight template + SKU weight)
- Admin: `pages/orders.vue` (read-only)
+30
View File
@@ -0,0 +1,30 @@
# Index: Platform (identity, accounts, shops, content, currency, addresses)
Domain design: `docs/domains/platform.md`. Specs: `openspec/specs/auth/`,
`customer-accounts/`, `store-directory/`, `storefront-content/`, `currency/`,
`address-book/`, `rbac/`.
## Backend (`apps/api`)
| Module | Holds |
|---|---|
| `modules/identity/` | register/login/me; admin user role assignment |
| `modules/account/` | customer_accounts ledger; credit/debit/freeze/release, `ensure_monetary_account` |
| `modules/shop/` | shop CRUD/status, profiles, `PUT /shop/profile` merchant self-write |
| `modules/content/` | four home-content kinds, whole-list replacement |
| `modules/currency/` | currency registry, rates, `convert` endpoint |
| `modules/address/` | customer address book |
| `src/auth.rs` | `AuthUser`, `require`, `own_shop`, `require_shop` |
| `src/error.rs` | `ApiError` envelope, `unique_conflict` |
| `src/money.rs` | `convert_minor` |
Tests: `tests/auth.rs`, `tests/accounts.rs`, `tests/shops.rs`,
`tests/content.rs`, `tests/addresses.rs`, `tests/catalog.rs` (currency too).
## Frontends
- Mall: `pages/login.vue`, `pages/register.vue`, header/footer shell in
`layouts/`/`app.vue`, `pages/user/addresses.vue`
- Shop-admin: `pages/shop-profile.vue`
- Admin: `pages/users.vue`, `pages/shops.vue`, `pages/content.vue`,
`pages/brands.vue`, `pages/currencies.vue`
+30
View File
@@ -0,0 +1,30 @@
# Index: Post-order (aftersales, reviews)
Domain design: `docs/domains/aftersales-reviews.md`. Specs:
`openspec/specs/aftersale/`, `reviews/`.
## Backend (`apps/api`)
| File | Holds |
|---|---|
| `src/modules/aftersale/service.rs` | state machine, refund completion (ledger-backed), arbitration, messages |
| `src/modules/aftersale/handlers.rs` | `/aftersales*`, `/shop/aftersales*`, `/admin/aftersales*` |
| `src/modules/review/service.rs` | create/reply/moderate, listing, rating summary, reviewable lines |
| `src/modules/review/handlers.rs` | `/products/{id}/reviews*`, `/me/reviewable`, `/reviews`, shop/admin routes |
| `migrations/0016_aftersales.sql` | aftersales + messages, `orders.refund_total_minor` |
| `migrations/0018_product_reviews.sql` | product_reviews |
| `tests/aftersales.rs`, `tests/reviews.rs` | integration coverage |
## Shared contract
`types.ts`: `Aftersale*`, `Review*`, `ReviewableItem`. `api.ts`: customer
aftersale/review methods, `shop.*` processing, `admin.*` arbitration/moderation.
## Frontends
- Mall: `pages/user/aftersales/{index,[id],apply}.vue`,
`pages/user/reviews.vue`, `pages/user/orders/[id].vue` (apply entry),
`pages/goods/[id].vue` (reviews tab); mock fixtures in `mock/api.ts`
(persisted `v6` state)
- Shop-admin: `pages/aftersales/{index,[id]}.vue`, `pages/reviews.vue`
- Admin: `pages/aftersales.vue`, `pages/reviews.vue`
+28
View File
@@ -0,0 +1,28 @@
# Index: Shared contract & UI
The single API contract. Every frontend change starts here when an endpoint
is added or a payload shape changes.
## packages/shared
| File | Holds |
|---|---|
| `src/types.ts` | every DTO shared across API and frontends (money as `number` minor units, `{en, zh}` as `LocalizedText`) |
| `src/api.ts` | `ApiClient` interface + `createApi()` live client; input-body types (`ProductUpsertBody`, `SkuUpsertBody`, …) |
| `src/locales/en.ts`, `zh.ts` | shared copy; app-specific keys go to the app's `locales-extra.ts`, never here from app work |
| `src/theme.css` | Tailwind v4 `@theme` tokens + `html[data-accent]` presets |
| `src/money.ts` | `formatMoney(minor, code, exponent, locale)` |
## packages/ui
`src/components/`: `VBtn`, `VBadge`, `VCard`, `VField`, `VInput`, `VPage`,
`VPanel`, `VTable`, `VAccentSwatch`; `useAccent()`. Auto-registered as a Nuxt
module in all three apps.
## Rules of engagement
- Adding an API method: declare in the interface, implement in `createApi`,
implement the mock in `apps/mall/mock/api.ts` (mall-facing) or
`unsupported()` (console-only), and add exact picks to
`apps/mall/plugins/api.ts` `LIVE_PICKS` when mall-facing.
- Build all three apps after any change here.