Files
color_full/docs/adr/0003-four-layer-module-architecture.md
qichi.liang c58ca26969 企业级重构:四层模块化架构 + RBAC授权 + 安全加固 + 颜色引擎/配方推演增强
架构
- 后端从 flat routes/ 重构为 modules/<domain>/ 模块化结构(8个模块)
- 四层架构:Route -> Service -> Repository -> Prisma
- 新增 shared/ 基础设施(AppError 异常体系、ALS 上下文、prom-client 指标)
- 前端 Toast/Skeleton/Alert 组件基建 + formulaService 模板

安全
- JWT 签名算法修复(HS256 用 createHmac 而非 createHash)
- 密码哈希 async scrypt + timingSafeEqual
- API Key 从 localStorage 迁移至服务端 runtime/config.json
- Helmet 安全头 + rate-limit 全局限流 100 req/min
- 全局 auth preHandler + RBAC + Ownership 中间件

颜色引擎
- 色匹配切换为 cube 粗筛 + CIEDE2000 精排
- PantoneColor 表 + 种子数据 + 搜索端点
- AI 配色 Prompt 注入成分库 colorant 列表

配方推演
- 本地优化引擎(同 category 替换 + 成本排序)
- baseFormulaId 支持 + Pareto 散点图

文档
- ADR-0003 四层架构、ADR-0004 RBAC 授权模型
- 更新 ADR-0001/0002
- api-reference.md(29端点)、project-overview.md

部署
- Dockerfile * 2 + nginx.conf + docker-compose.prod.yml
- 健康探针 + 优雅关闭 + pg_dump 备份脚本
- ESLint + Prettier + tsconfig strict
2026-05-21 17:29:52 +08:00

4.4 KiB
Raw Permalink Blame History

ADR-0003: 后端四层模块化架构

状态: 已决议
日期: 2026-05-21
父决策: ADR-0001整体技术栈
决策者: 架构评审


上下文

项目初期路由层直接操作 Prisma业务逻辑与 HTTP 适配耦合。随着模块增长8 个领域模块29 个 API 端点),缺乏分层导致:

  • 业务逻辑无法脱离 HTTP 环境做单元测试
  • Prisma 调用散落在 8 个路由文件中,查询逻辑难以复用
  • 横切关注点(日志、审计、错误处理)没有统一注入点
  • 单文件超长formulas 路由 295 行)难以维护

需对后端架构做分层设计,支持企业级扩展。


决策

选择四层模块化架构Route → Service → Repository → Prisma按领域模块聚合文件。

目录结构

src/
├── modules/
│   ├── formulas/
│   │   ├── formulas.route.ts        # Fastify 路由注册 + 参数提取
│   │   ├── formulas.service.ts      # 纯业务逻辑 + 审计埋点
│   │   ├── formulas.repository.ts   # Prisma 数据访问
│   │   ├── formulas.schema.ts       # Zod 验证 schema
│   │   └── formulas.test.ts         # 集成测试
│   ├── ingredients/                 # 同上
│   ├── projects/                    # 同上
│   ├── color/                       # 同上
│   ├── ai/                          # 同上
│   ├── auth/                        # 同上
│   ├── config/                      # 同上
│   └── health/                      # 同上
└── shared/                          # 跨模块共享
    ├── errors/                      # AppError 异常体系
    ├── logging/                     # AsyncLocalStorage 上下文
    ├── middleware/                   # RBAC / Ownership 中间件
    ├── metrics/                     # Prometheus 指标
    └── audit/                       # 审计服务

对比方案

方案 优势 劣势 结论
四层模块化(选) 按领域聚合改动一个功能不需跨目录跳转Service/Repository 可独立单元测试;横切关注点通过 shared/ 统一注入 小模块(如 health文件数多
三层Route→Service→Prisma 简单直接 Service 与持久化耦合,不含 Repository 则 Prisma mock 困难
按层分目录routes/ / services/ / repositories/ 层边界清晰 同功能文件分散在 4 个目录,开发时频繁切换
Clean/六边形 核心领域零框架依赖 过度工程化;当前仅 Web 端,无需端口-适配器抽象

层职责

职责 依赖 测试方式
Route Fastify 注册、参数提取req→纯数据、preHandler 挂载 Controller/Service + Zod app.inject() 集成测试
Service 纯业务逻辑、审计埋点、百分比验证 Repository + AuditService 单元测试mock repository
Repository Prisma 查询封装、事务管理 Prisma Testcontainers 集成测试
Schema Zod 验证定义、TypeScript 类型导出 Zod 不需要测试(声明式)

横切关注点

关注点 实现方式 注入点
认证 JWT preHandlerapp.ts 全局) onRequest
授权 requireRole() / requireFormulaOwnership() Route preHandler
错误处理 AppError 子类ValidationError/NotFoundError 等) 全局 setErrorHandler
日志 pino 结构化日志 + AsyncLocalStorage context app.log.child()
审计 AuditServicepino 输出action/resource/userId Service 层显式调用
指标 prom-clienthttp_requests_total, app_errors_total, ai_requests_total 全局 handler / AI Service
输入校验 validateOrReply() — Zod 解析,失败时 400 Route 层
API 文档 @fastify/swagger + zod-to-json-schema Route schema 定义

后果

  • 新增模块需创建 4 个文件route/service/repository/schema模板明确
  • Service 和 Repository 可脱离 HTTP 环境做纯函数测试
  • 跨模块共享逻辑必须放在 shared/ 下,不能在模块间直接 import
  • 所有错误必须使用 AppError 子类,不可裸抛 new Error()
  • 模块测试文件与源文件同目录vitest include: ['src/**/*.test.ts'] 自动发现