Persist the modular-monolith decision (ADR 0001 handler/service/repo, ADR 0002 keep REST) with the companion tech spec and the api-architecture OpenSpec capability. Replace the finished mock-migration tracker with docs/TBD-marketing.md listing the backend-less marketing domains still on fixtures (coupons, favorites, account stats, seckill, collective, integral, reviews). README and AGENTS.md point at the new docs.
91 lines
4.2 KiB
Markdown
91 lines
4.2 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/ 为归档后的能力规范)
|
||
docs/adr/ Architecture Decision Records(英文)
|
||
docs/tech-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、addresses。
|
||
|
||
仍来自 `~/mock/data` 的部分都是没有后端能力的营销/账户域,逐项记录在 `docs/TBD-marketing.md`(优惠券、收藏、账户统计、秒杀、拼团、积分商城、评价等)。每一项都是一次新的能力建设,不是适配层切换。
|
||
|
||
- **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` |
|