89 lines
4.5 KiB
Markdown
89 lines
4.5 KiB
Markdown
# 备考中枢 · 架构交付说明(垂直切片最终形态)
|
||
|
||
> 汇编:项目总监 大湾区靓仔 · 2026-08-26
|
||
> 产出:首席架构师 高见远
|
||
> 版本:v2.0(垂直切片最终形态)· 已通过门禁核验
|
||
> 门禁结论:无 emoji / 无 any 类型声明 / 无"原来→改为"对照措辞 / 目录为最终形态
|
||
|
||
---
|
||
|
||
## 一、这套架构长什么样
|
||
|
||
采用**垂直切片(Vertical Slice)**组织方式,而非按层堆放大目录。一个资源被"纵向切透"——从 HTTP 入口到数据落盘端到端归属一个切片,切片内按职责分 **3 层**,层与层之间依赖只向下。
|
||
|
||
### 3 层结构
|
||
|
||
| 层 | 职责 | 落地位置 |
|
||
|----|------|----------|
|
||
| **Handler 层** | 路由注册 + zod 请求校验 + 调 service + 组装 `ApiResponse<T>` | `routes/*.routes.ts`(校验/编排/响应全在一个文件) |
|
||
| **Service 层** | 跨实体业务:抽题 / 判定 / 错题入本 / 增量聚合 / 备份还原 | `services/*.service.ts`(不碰 req/res) |
|
||
| **数据访问 + 领域类型层** | 读 JSON(zod 校验) + 原子写 + 写队列 + 领域类型 | `data/store.ts` + `packages/shared/schemas` |
|
||
|
||
> 领域类型不手写 interface,由 `packages/shared/src/schemas/*.schema.ts` 的 zod schema 经 `z.infer` 产出,前后端共用。
|
||
|
||
---
|
||
|
||
## 二、为什么改一个接口不再"跳来跳去"
|
||
|
||
一个资源 = **一个 route 文件(内含 handler)+ 一个 service 文件**。跨切片的实体业务(如答错同时写 answer-record、wrong-question 并增量更新统计)统一交给 service 层承载——这正是 service 层在该架构中不可替代的价值。
|
||
|
||
**改一个典型接口的落点**:
|
||
|
||
| 改动 | 落点 | 数量 |
|
||
|------|------|:---:|
|
||
| 改某个字段 / 新增字段 | 改 `shared/schemas/*.schema.ts` 的 zod schema + 对应 `route` handler | **~2 处** |
|
||
| 改一段业务逻辑 | 对应 `service` 文件 | **1 处** |
|
||
| 类型 / OpenAPI 契约 / 请求校验 | 由 zod schema 自动跟随(`z.infer` 产类型、`zod-openapi` 反推契约) | **0 处(自动)** |
|
||
|
||
**单一契约源**是这套架构的灵魂:同一份 zod schema 同时驱动三处——请求运行时校验、TS 类型(`z.infer`)、OpenAPI 契约(`zod-openapi` 自动反推),三者永不失同步,杜绝手写契约导致的漂移。
|
||
|
||
---
|
||
|
||
## 三、关键工程化要点
|
||
|
||
| 项 | 说明 |
|
||
|----|------|
|
||
| **单一契约源** | zod schema 唯一来源 → `z.infer` 产类型 + `zod-openapi` 自动反推 OpenAPI 契约 + 同一 schema 做请求校验,三者同步 |
|
||
| **无 any** | tsconfig strict 全家桶(noImplicitAny / strictNullChecks / exactOptionalPropertyTypes / noUncheckedIndexedAccess / useUnknownInCatchVariables)+ `ApiResponse<T>` 泛型 + catch 用 unknown 窄化 + zod 收窄 |
|
||
| **JSON 数据层三重防护** | zod 运行时校验(文件是不可信输入)+ 临时文件 rename 原子替换 + 写队列串行,保证数据资产永不损坏 |
|
||
| **数据资产** | `APP_DATA_DIR` 可配置 + Docker volume 挂载 + 导出 JSON/CSV / 备份 / 还原接口(还原前自动备份,坏备份不覆盖好数据) |
|
||
| **AI 扩展位** | 二期 P1 前置但本期零实现:`services/ai/` 占位 + `providers/` 接口 + `aiEnabled` 恒 false |
|
||
|
||
---
|
||
|
||
## 四、8 个领域实体
|
||
|
||
`Question / AnswerRecord / WrongQuestion / MockExam / ShenLunEssay / StudyTask / StatsSnapshot / AppSettings`,全部由 `packages/shared/src/schemas/*.schema.ts` 的 zod schema 经 `z.infer` 产出具名类型。
|
||
|
||
---
|
||
|
||
## 五、版本锚定
|
||
|
||
| 技术 | 版本锚定 |
|
||
|------|----------|
|
||
| Node.js | 24.x(LTS) |
|
||
| Express | 5.2.x |
|
||
| Vue | 3.5.x / Vite 6.x |
|
||
| TypeScript | 5.8.x |
|
||
| zod | 4.x(若落 3.x,zod-to-openapi 须降级 v7.3.4) |
|
||
| @asteasolutions/zod-to-openapi | 8.x |
|
||
|
||
> Phase 2 安装后需把 `package.json`/`pnpm-lock.yaml` 精确版本回写锚定表,使规格与实现同步。
|
||
|
||
---
|
||
|
||
## 六、交付物清单(全部在 `deliverables/architecture/`)
|
||
|
||
| 文件 | 说明 |
|
||
|------|------|
|
||
| `architecture.md` | 核心架构文档(v2.0,垂直切片最终形态) |
|
||
| `openapi.yaml` | OpenAPI 契约(标注由 zod-openapi 自动反推生成,勿手改) |
|
||
| `params.md` | 技术约束清单 + 8 实体 scha + 枚举 + 错误码 |
|
||
| `decisions/ADR-001~006` | 6 份架构决策记录(新增 ADR-006 垂直切片 + 单一契约源) |
|
||
|
||
---
|
||
|
||
## 七、下一步
|
||
|
||
架构已确定为垂直切片最终形态,随时可进入 **Phase 1.5 Spec 生成** 或直接进入 **Phase 2 设计细化 + 开发**。确认后我将推进。
|