The merge creates the brand capability (two requirements) and extends the catalog browse requirement with the brand filter, the sales sort and a real sold count. openspec validate --all --strict stays green at 14 specs. With every box now checked, docs/TBD-migrate-wave.md is deleted, as its own instructions require. Its two durable notes move to the README instead of disappearing with it: - `nuxt build` does not typecheck, so a green build is not the type gate the verification section claimed. AGENTS.md told me to treat it as one, which is why waves 1-5 over-reported "builds pass" as evidence. - the list of what stays deliberately mock: addresses, coupons, favourites, account stats, the seckill/collective/integral pages, reviews, and the fixed-data adapter itself, which the adapter spec requires for rollback. The README's verification block also gains the real test count (29, not 16).
93 lines
4.4 KiB
Markdown
93 lines
4.4 KiB
Markdown
# VMall — B2B2C 商城 MVP
|
||
|
||
前后端分离的多商户(B2B2C)商城。一个 Rust 后端,三个 Nuxt 前端,Postgres + Redis(本地 Docker 提供),OpenSpec 驱动开发。
|
||
|
||
## 架构
|
||
|
||
```
|
||
apps/
|
||
api/ Rust 后端(axum 0.8 + sqlx + redis) http://localhost:8080/api
|
||
mall/ Nuxt 3 顾客商城 http://localhost:3000
|
||
shop-admin/ Nuxt 3 商户后台 http://localhost:3001
|
||
admin/ Nuxt 3 平台后台 http://localhost:3002
|
||
packages/
|
||
shared/ @vmall/shared:TS 类型、API client、en/zh 语言包、共享样式
|
||
openspec/ OpenSpec 规范(specs/ 为归档后的能力规范)
|
||
scripts/
|
||
seed-demo.mjs 演示数据脚本
|
||
```
|
||
|
||
技术要点:
|
||
|
||
- **金额**:整数最小单位(minor units)+ ISO 币种码存储,禁止浮点。`rate_to_base` 表示"1 基准币 = N 本币",换算四舍五入(half-up)。
|
||
- **多语言**:商品/店铺/分类/币种内容以 JSONB `{"en","zh"}` 存储;UI 文案在 `@vmall/shared` locales + 各应用 `locales-extra.ts`。
|
||
- **RBAC**:`platform_admin`、`shop_owner`、`shop_staff`(带 shop_id 作用域)、`customer`;JWT(24h)。
|
||
- **下单**:Redis 购物车 → 单事务结算,按店铺拆单,价格快照 + 扣库存;缺货整单 409 回滚;取消恢复库存。
|
||
- **发货单**:支持部分发货(校验剩余量),状态联动 fulfilling → shipped → completed。
|
||
- **发票**:每单最多一张有效发票;企业发票必填税号;商户开具生成发票号。
|
||
|
||
## 快速开始
|
||
|
||
前置:Docker 中的 Postgres(容器 `pg18`,postgres/postgres)与 Redis(容器 `rdb8`)已运行;Rust 1.98+、Node 22+、pnpm 10+。
|
||
|
||
```bash
|
||
# 1. 数据库(只需一次)
|
||
docker exec pg18 psql -U postgres -c "CREATE DATABASE vmall;" -c "CREATE DATABASE vmall_test;"
|
||
|
||
# 2. 安装依赖
|
||
pnpm install
|
||
|
||
# 3. 启动后端(自动执行 sqlx 迁移并播种平台管理员)
|
||
cargo run -p vmall-api
|
||
|
||
# 4. 播种演示数据(店铺、店主、4 个双语商品)
|
||
node scripts/seed-demo.mjs
|
||
|
||
# 5. 启动前端(另开终端)
|
||
pnpm dev:mall # :3000
|
||
pnpm dev:shop-admin # :3001
|
||
pnpm dev:admin # :3002
|
||
```
|
||
|
||
演示账号:
|
||
|
||
| 角色 | 账号 | 密码 | 应用 |
|
||
|---|---|---|---|
|
||
| 平台管理员 | admin@vmall.local | admin1234 | admin :3002 |
|
||
| 店主 | shop@vmall.local | shop12345 | shop-admin :3001 |
|
||
| 顾客 | customer@vmall.local | customer123 | mall :3000 |
|
||
|
||
## 测试与校验
|
||
|
||
```bash
|
||
cargo test -p vmall-api # 29 个集成测试(vmall_test + Redis)
|
||
pnpm --filter @vmall/mall build # 打包;注意:并不做类型校验
|
||
pnpm --filter @vmall/shop-admin build
|
||
pnpm --filter @vmall/admin build
|
||
openspec validate --all --strict # 规范校验
|
||
```
|
||
|
||
`nuxt build` 不做类型校验:`nuxt.config.ts` 未开启 `typescript.typeCheck`,也未安装 `vue-tsc`。构建通过只说明能打包。要补上这道关:加 `vue-tsc` + `typescript` 依赖、设 `typescript: { typeCheck: true }`,首次运行会暴露一批既有错误。在那之前,**能证明页面可用的是浏览器实测,而不是构建**。
|
||
|
||
## 商城的 mock 边界
|
||
|
||
`apps/mall` 通过 `apps/mall/plugins/api.ts` 的 `liveDomains` 按域选择适配器。已有 API 的域全部走真实后端:catalog、currency、content、brands、shops、auth、cart、orders、shipments、invoices。
|
||
|
||
仍来自 `~/mock/data` 的部分是**有意保留**的展示内容,不是待办:
|
||
|
||
- **收货地址**(`MOCK_ADDRESSES`):`Address` 内嵌在订单里,结算直接在请求体里携带,不需要地址表。
|
||
- **优惠券、收藏、账户统计**:纯展示,不参与交易。
|
||
- **seckill / collective / integral 营销页**:纯展示内容。
|
||
- **商品评价**:没有评价模型,所以商城不再展示任何评价——卡片上的评价数与详情页的评价页签、评分、回复都已移除,而不是继续展示虚构的评论者与评分。评价是独立功能,不是迁移的一部分。
|
||
- **fixed-data 适配器本身**:`Mock API adapter` 规范要求它仍能服务每个域,因此它是回滚路径,删除它会破坏回滚。
|
||
|
||
## 环境变量(后端)
|
||
|
||
| 变量 | 默认值 |
|
||
|---|---|
|
||
| `DATABASE_URL` | `postgres://postgres:postgres@127.0.0.1:5432/vmall` |
|
||
| `REDIS_URL` | `redis://127.0.0.1:6379/` |
|
||
| `JWT_SECRET` | `vmall-dev-secret-change-me` |
|
||
| `PORT` | `8080` |
|
||
| `JWT_TTL_SECS` | `86400` |
|