企业级重构:四层模块化架构 + 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
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
# ADR-0001: 整体技术栈选型
|
||||
|
||||
> **状态**: 已决议
|
||||
> **日期**: 2026-05-20
|
||||
> **状态**: 已决议(2026-05-21 修订)
|
||||
> **日期**: 2026-05-20
|
||||
> **修订**: 2026-05-21
|
||||
> **决策者**: 架构评审
|
||||
|
||||
---
|
||||
@@ -14,7 +15,7 @@
|
||||
|
||||
## 决策
|
||||
|
||||
### 1. 前端框架 → React 18 + TypeScript 5.7
|
||||
### 1. 前端框架 → React 19 + TypeScript 5.7
|
||||
|
||||
| 候选 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
@@ -23,11 +24,13 @@
|
||||
| Svelte 5 | 编译时框架,运行时极小 | 生态较小;关键库适配风险;社区资源少 | ❌ |
|
||||
| SolidJS | 性能优于 React;API 相似 | 社区太小(GitHub stars ~30k vs React ~230k);生产风险高 | ❌ |
|
||||
|
||||
**决策**:React 18 + TypeScript strict mode。React 19 待生态稳定后再升级。
|
||||
**决策**:React 19 + TypeScript strict mode。
|
||||
|
||||
> **修订(2026-05-21)**:从 React 18 升级到 React 19。生态已稳定,React Compiler 带来额外性能收益。
|
||||
|
||||
---
|
||||
|
||||
### 2. 构建工具 → Vite 6
|
||||
### 2. 构建工具 → Vite 8
|
||||
|
||||
| 候选 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
@@ -36,11 +39,13 @@
|
||||
| Remix | SSR 优先;Web 标准 | 同上;社区较 Next.js 小 | ❌ |
|
||||
| CRA | — | 已停止维护;Webpack 构建慢 | ❌ |
|
||||
|
||||
**决策**:Vite 6,SPA 模式。平台为内部工具,无需 SEO/SSR。
|
||||
**决策**:Vite 8,SPA 模式。平台为内部工具,无需 SEO/SSR。
|
||||
|
||||
> **修订(2026-05-21)**:从 Vite 6 升级到 Vite 8。
|
||||
|
||||
---
|
||||
|
||||
### 3. 状态管理 → Zustand 5
|
||||
### 3. 状态管理 → Zustand
|
||||
|
||||
| 候选 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
@@ -84,128 +89,83 @@
|
||||
| **Radix UI** | Headless(完全控制样式);WAI-ARIA 内置;组件粒度合适;与 Tailwind 天配 | 无预置视觉风格(需要自行设计) | ✅ 推荐 |
|
||||
| Ant Design | 开箱即用,组件丰富 | 企业后台感强;视觉定制困难;不适合创意工具;bundle 大 | ❌ |
|
||||
| MUI | Material Design 完整实现 | 同上;Google 风格固化 | ❌ |
|
||||
| shadcn/ui | 基于 Radix + Tailwind,复制源码 | 本质是 Radix 封装;直接 Radix 更灵活 | ❌ |
|
||||
| shadcn/ui | 基于 Radix + Tailwind 预封装 | 封装度低,仍需二次开发 | — |
|
||||
|
||||
**决策**:Radix UI 提供 Dialog、Popover、Dropdown、Tabs、Tooltip 等行为组件。视觉层完全自定义,匹配配方研发工具的专业调性。
|
||||
**决策**:Radix UI。平台 UI 需要与化妆品实验室品牌调性一致,Radix 的 Headless 模式允许完全定制视觉。
|
||||
|
||||
---
|
||||
|
||||
### 7. 图表可视化 → ECharts 5(主力) + D3.js 7(定制)
|
||||
|
||||
| 候选 | 雷达图 | 拖拽饼图 | 仪表盘 | 散点图 | 自定义度 | Bundle | 结论 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| **ECharts** | ✅ 内置 | ✅ resize 事件 | ✅ 内置 | ✅ 内置 | 中 | ~300KB(按需~150KB) | ✅ 主力 |
|
||||
| **D3.js** | 需自建 | 需自建 | 需自建 | 需自建 | ✅ 最高 | ~150KB | ✅ 定制场景 |
|
||||
| Recharts | ✅ | ⚠️ 有限 | ✅ | ✅ | 低 | ~100KB | ❌ 拖拽不足 |
|
||||
| Nivo | ✅ | ⚠️ 有限 | ❌ | ✅ | 中 | ~200KB | ❌ 缺仪表盘 |
|
||||
| Plotly.js | ✅ | ⚠️ | ✅ | ✅ | 中 | ~3MB | ❌ 体积过大 |
|
||||
| Visx | 需自建 | 需自建 | 需自建 | 需自建 | 高 | 按需 | ❌ 开发量大 |
|
||||
|
||||
**决策**:
|
||||
- **ECharts** 处理标准化图表:雷达图(肤感指标)、饼图(成分比例,监听 resize 实现拖拽联动)、仪表盘(稳定性/成本)、散点图(成本-功效 Pareto 前沿)
|
||||
- **D3.js** 处理高度定制场景:色相环/颜色盘、配方路径示意图、配方结构树图
|
||||
- React 绑定使用 `echarts-for-react`
|
||||
|
||||
---
|
||||
|
||||
### 8. 色彩科学 → color.js
|
||||
|
||||
| 候选 | 色空间 | ΔE | Display P3 | 色域映射 | TS 类型 | 维护者 | 结论 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| **color.js** | Lab/LCH/OKLab/Display P3 + 20+ | CIEDE2000/CMC/... | ✅ | ✅ | ✅ 完备 | Lea Verou (W3C CSS WG) | ✅ 推荐 |
|
||||
| chroma.js | Lab/LCH/RGB | CIEDE2000 | ❌ | ❌ | ⚠️ 部分 | Gregor Aisch | ❌ 缺 P3 |
|
||||
| culori | Lab/LCH/OKLab | CIEDE2000 | ⚠️ 有限 | ⚠️ 有限 | ✅ | Dan Burzo | ❌ 社区小 |
|
||||
| d3-color | Lab/RGB | ❌ 无 | ❌ | ❌ | ✅ | Mike Bostock | ❌ 功能太基础 |
|
||||
|
||||
**决策**:color.js。唯一同时支持 Display P3 色空间、CIEDE2000 ΔE、色域映射的开源 JS 库。由 CSS Color Level 4 规范编者维护,与浏览器标准对齐。
|
||||
|
||||
---
|
||||
|
||||
### 9. 拖拽交互 → DnD Kit
|
||||
|
||||
| 候选 | 状态 | 鼠标/触摸/键盘 | 碰撞检测 | TS | 维护 | 结论 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| **@dnd-kit** | 活跃 | ✅ 全部 | 可定制 | ✅ | 活跃 | ✅ 推荐 |
|
||||
| react-beautiful-dnd | 停止维护 | 鼠标/触摸 | 内置 | ⚠️ | Atlassian 停止维护(2023) | ❌ |
|
||||
| Pragmatic drag and drop | 活跃 | ✅ 全部 | 可定制 | ✅ | Atlassian 新项目 | ⚠️ 太新 |
|
||||
|
||||
**决策**:@dnd-kit/core + @dnd-kit/sortable。饼图段的拖拽调整比例场景完美匹配,支持自定义碰撞检测算法。
|
||||
|
||||
---
|
||||
|
||||
### 10. 数据请求 → TanStack Query 5
|
||||
### 7. 图表 → ECharts
|
||||
|
||||
| 候选 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **TanStack Query** | 缓存/重试/乐观更新/无限滚动开箱即用;与 Zustand 分工清晰 | — | ✅ 推荐 |
|
||||
| SWR | 类似功能 | API 不如 TanStack Query 丰富 | ❌ |
|
||||
| RTK Query | Redux 集成 | 绑定 Redux | ❌ |
|
||||
| **ECharts** | 可视化类型最丰富(雷达图/桑基图/热力图等);React 绑定成熟(echarts-for-react);大数据集高性能 | 包体积较大(~1MB) | ✅ 推荐 |
|
||||
| D3.js | 自由度最高;定制性极强 | 命令式 API;React 集成需大量封装;开发效率低 | ❌ |
|
||||
| Recharts | React 声明式;组件化 | 图表类型有限;大数据集性能差 | ❌ |
|
||||
|
||||
**决策**:TanStack Query v5。推荐列表、配方搜索、AI 预测等所有异步请求均通过它管理。
|
||||
**决策**:ECharts 作为主图表库,D3.js 作为辅助(颜色空间可视化等高度定制场景)。
|
||||
|
||||
---
|
||||
|
||||
### 11. 后端 → Fastify(BFF 单体)+ 外部 AI API
|
||||
### 8. 色彩科学 → colorjs.io
|
||||
|
||||
```
|
||||
┌─────────┐ HTTP/SSE ┌──────────┐ HTTP ┌──────────┐
|
||||
│ React │ ◄─────────────► │ Fastify │ ◄────────────► │ AI API │
|
||||
│ 前端 │ │ BFF 层 │ │ (外部) │
|
||||
└─────────┘ └────┬─────┘ └──────────┘
|
||||
│
|
||||
┌────▼─────┐
|
||||
│PostgreSQL │
|
||||
│ + pgvector│
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
| 层 | 技术 | 职责 | 理由 |
|
||||
| 候选 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **BFF** | Fastify 5 | API 聚合、认证鉴权、文件上传、配方 CRUD、AI API 调用代理、SSE 推送 | TS 全栈一致性;Schema 验证内置;性能优于 Express |
|
||||
| **AI** | 外部 API | 配方预测、配方生成、NL 解析、颜色匹配推荐 | 无需自建 ML infra;按需调用;模型持续更新 |
|
||||
| **通信** | REST + SSE | 前端 ↔ BFF REST;AI 预测 SSE 实时推送;BFF ↔ AI API HTTP | SSE 适合单向实时数据流;BFF 统一处理 AI 调用的编排和降级 |
|
||||
| **colorjs.io** | 支持所有颜色空间(CIELAB/Display P3/LCH 等);ΔE 2000/CMC 计算;积极维护 | 社区较 chroma.js 小 | ✅ 推荐 |
|
||||
| chroma.js | 轻量 API;流行度高 | 不支持 ΔE 2000;不支持 Display P3 | ❌ |
|
||||
| d3-color | 与 D3 生态集成 | 颜色空间有限;无 ΔE | ❌ |
|
||||
|
||||
| BFF 框架对比 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Fastify** | 高性能(~60k req/s);插件体系;内置 Schema 验证(AJV);TS 支持;日志(pino) | 社区较 Express 小 | ✅ 推荐 |
|
||||
| Express | 生态最大;中间件极多 | 性能较低;无内置验证;回调风格 | ❌ |
|
||||
| Hono | 极快;边缘部署 | 主要用于 Cloudflare/边缘场景 | ❌ |
|
||||
|
||||
**AI API 调用设计**(详见 ADR-0002):
|
||||
|
||||
BFF 作为 AI API 的统一网关,负责:
|
||||
- **编排**:组合多次 API 调用(如"先解析 NL 查询 → 再向量搜索 → 组合 prompt → 生成推荐")
|
||||
- **降级**:API 超时或失败时返回缓存结果或降级提示
|
||||
- **限流**:保护 API 额度,控制并发
|
||||
- **缓存**:相似查询复用结果,减少 API 调用
|
||||
- **SSE 流式**:配方推演等长耗时场景,BFF 转发 AI API 的 streaming 响应
|
||||
|
||||
| AI 能力 | 调用方式 | 说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| 配方指标预测 | Prompt + 历史数据(few-shot) | 将成分列表和比例作为 context,LLM 预测肤感/稳定性/成本 |
|
||||
| NL 搜索解析 | LLM → 结构化查询 → pgvector | LLM 将自然语言转为过滤条件 + 向量搜索 |
|
||||
| 配方生成/推演 | LLM with constraints | 给定约束条件,LLM 生成候选配方方案 |
|
||||
| 颜色推荐 | LLM + 色彩库 | 结合色差计算和 LLM 推理推荐色浆组合 |
|
||||
| 成分标签提取 | LLM 结构化提取 | 从配方文本中提取 INCI 名称、比例、工艺参数 |
|
||||
**决策**:colorjs.io。
|
||||
|
||||
---
|
||||
|
||||
### 12. 数据库 → PostgreSQL 16 + pgvector
|
||||
### 9. 后端框架 → Fastify
|
||||
|
||||
| 候选 | 结构化 | 向量搜索 | JSONB | 全文搜索 | 运维 | 结论 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| **PostgreSQL + pgvector** | ✅ | ✅ IVFFlat/HNSW | ✅ | ✅ | 成熟 | ✅ 推荐 |
|
||||
| MongoDB | ⚠️ 文档型 | ✅ Atlas Vector | ✅ | ⚠️ | 成熟 | ❌ 配方强关系 |
|
||||
| Elasticsearch | ❌ | ⚠️ 需插件 | ❌ | ✅ | 复杂 | ❌ 过度 |
|
||||
| Neo4j | ❌ 图 | ⚠️ | ❌ | ❌ | 小众 | ❌ 过度 |
|
||||
| 候选 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Fastify** | 性能最高(~60k req/s);插件生态完善(CORS/Swagger/Helmet);TypeScript 原生支持;schema 验证 | 社区较 Express 小 | ✅ 推荐 |
|
||||
| Express | 最广泛使用;中间件生态极丰富 | 性能较差(~15k req/s);TS 支持需额外配置;回调风格 | ❌ |
|
||||
| Hono | 极轻量(< 10KB);运行时无关(Node/Deno/Bun/Edge) | 生态较小;企业级插件不成熟 | ❌ |
|
||||
| NestJS | 开箱即用架构(Module/Controller/Service);DI 容器 | 过度工程化;装饰器侵入性强;学习曲线陡峭;冷启动慢 | ❌ |
|
||||
|
||||
**决策**:PostgreSQL 16 + pgvector。
|
||||
**决策**:Fastify 5 + TypeScript。插件体系完整且性能优异,适合 API 密集型场景。
|
||||
|
||||
- 配方是强结构化数据(成分→相→配方→版本,经典关系模型)
|
||||
- pgvector 0.7+ 支持 HNSW 索引,NL 搜索和相似配方匹配性能优秀
|
||||
- JSONB 处理灵活的工艺参数和元数据
|
||||
- 一个数据库同时满足关系查询 + 向量搜索 + 全文搜索,运维简单
|
||||
- 配方版本管理利用 PostgreSQL 的 MVCC + 时间戳快照
|
||||
---
|
||||
|
||||
### 10. 数据库 → PostgreSQL + pgvector
|
||||
|
||||
| 候选 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **PostgreSQL + pgvector** | 成熟稳定;pgvector 扩展支持向量搜索(HNSW 索引);ACID 事务 | 向量搜索性能不如专用向量 DB | ✅ 推荐 |
|
||||
| MongoDB | 文档模型灵活;内置 Atlas Search | 缺乏 ACID;向量搜索需 Atlas | ❌ |
|
||||
| Elasticsearch | 全文搜索最强 | 运维成本高;需额外同步数据 | ❌ |
|
||||
|
||||
**决策**:PostgreSQL + pgvector。配方数据是典型的关系型结构(配方→相→成分),PostgreSQL 的关系模型天然适配;向量搜索用于语义配方查找,pgvector 性能足够。
|
||||
|
||||
---
|
||||
|
||||
### 11. ORM → Prisma
|
||||
|
||||
| 候选 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Prisma** | 类型安全;Schema-first;迁移工具成熟;Client 自动生成;关系模型直观 | 复杂查询性能不如原生 SQL | ✅ 推荐 |
|
||||
| Drizzle ORM | 轻量零依赖;SQL-like API;性能接近原生 | 生态较新;迁移工具不如 Prisma 成熟 | ❌ |
|
||||
| Knex.js | SQL 构建器;灵活 | 无类型安全;手写迁移 | ❌ |
|
||||
| Sequelize | 历史悠久;生态大 | 类型支持弱;API 设计过时 | ❌ |
|
||||
|
||||
**决策**:Prisma 7 + pg adapter。项目中配方的关系嵌套深度大(Formula→Version→Phase→FormulaIngredient→Ingredient),Prisma 的关联查询和事务支持良好。
|
||||
|
||||
---
|
||||
|
||||
### 12. 包管理 → pnpm workspace
|
||||
|
||||
| 候选 | 优势 | 劣势 | 结论 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **pnpm** | 硬盘高效(硬链接);严格依赖;monorepo workspace 支持;速度快 | lockfile 格式与 npm 不兼容 | ✅ 推荐 |
|
||||
| npm | 默认工具 | 依赖扁平化导致幽灵依赖;磁盘占用大;慢 | ❌ |
|
||||
| Yarn | Plug'n'Play 模式 | PnP 兼容性问题多;社区分裂 | ❌ |
|
||||
|
||||
**决策**:pnpm。前后端独立 package,共享 workspace 协议。
|
||||
|
||||
---
|
||||
|
||||
@@ -213,56 +173,31 @@ BFF 作为 AI API 的统一网关,负责:
|
||||
|
||||
**决策**:MinIO(S3 兼容),存储参考图片、导出文件。本地部署,S3 API 可无缝迁移到云。
|
||||
|
||||
> **修订(2026-05-21)**:MinIO 设为 docker compose `profiles: ["full"]`,默认不启动。当前无实际代码使用。
|
||||
|
||||
---
|
||||
|
||||
### 14. 部署 → Docker Compose(开发)+ K8s(生产)
|
||||
### 14. 部署 → Docker Compose + Traefik
|
||||
|
||||
| 服务 | 端口 | 职责 |
|
||||
| :--- | :--- | :--- |
|
||||
| Nginx | 80/443 | 静态资源、反向代理、SSL 终结 |
|
||||
| Fastify BFF | 3001 | API 聚合、认证、文件上传、AI API 代理 |
|
||||
| PostgreSQL | 5432 | 配方数据 + 向量 |
|
||||
| MinIO | 9000 | 对象存储 |
|
||||
| Redis(可选) | 6379 | 缓存、Session、AI 响应缓存 |
|
||||
**决策**:开发环境 `docker compose up`(PostgreSQL + MinIO(可选)),生产环境 `docker compose -f docker-compose.prod.yml up`(Traefik + PostgreSQL + Backend + Frontend)。
|
||||
|
||||
**开发环境**:Docker Compose 一键启动所有服务(无需 AI 依赖,BFF 可 mock AI API)
|
||||
**生产环境**:Kubernetes,仅 4 个核心服务,显著降低运维复杂度
|
||||
> **修订(2026-05-21)**:新增生产环境部署方案。Traefik 负责反向代理和自动负载均衡,Backend/Frontend 均已容器化。
|
||||
|
||||
---
|
||||
|
||||
### 15. 安全加固
|
||||
|
||||
| 组件 | 用途 | 添加日期 |
|
||||
|------|------|----------|
|
||||
| `@fastify/helmet` | 安全 HTTP 头(HSTS/X-Frame/X-Content-Type 等) | 2026-05-21 |
|
||||
| `@fastify/rate-limit` | 全局速率限制(100 req/min) | 2026-05-21 |
|
||||
| `@fastify/swagger` + `@fastify/swagger-ui` | OpenAPI 文档生成 + `/docs` 交互式浏览 | 2026-05-21 |
|
||||
|
||||
---
|
||||
|
||||
## 后果
|
||||
|
||||
### 正向
|
||||
|
||||
- React + Vite + Zustand + TanStack Query 形成轻量高效的现代前端栈
|
||||
- ECharts + D3.js 组合覆盖标准化图表和定制可视化全场景
|
||||
- color.js 唯一满足 Display P3 + CIEDE2000 需求的色彩库
|
||||
- AI 通过外部 API 调用,无需自建 ML 基础设施,运维简单
|
||||
- 仅 4 个核心服务(Nginx + BFF + PostgreSQL + MinIO),部署轻量
|
||||
- PostgreSQL + pgvector 单一数据库减少运维复杂度
|
||||
|
||||
### 风险和缓解
|
||||
|
||||
| 风险 | 缓解 |
|
||||
| :--- | :--- |
|
||||
| color.js 仍为 Beta(v0.x) | 锁定版本;Delta E 逻辑简单,必要时可自实现 CIEDE2000 |
|
||||
| DnD Kit 维护节奏慢 | API 稳定,核心功能完备;锁定版本 |
|
||||
| AI API 延迟 / 不可用 | BFF 层缓存 + 降级策略;关键路径设置超时(详见 ADR-0002) |
|
||||
| AI API 调用成本 | 缓存相似查询;Prompt 压缩优化;使用 cheaper 模型做预处理 |
|
||||
| pgvector HNSW 索引构建耗时 | 配方数据量级可控(万级),索引构建秒级 |
|
||||
|
||||
### 需要关注但未在本次决议的
|
||||
|
||||
- CI/CD 流水线(GitHub Actions / GitLab CI)
|
||||
- 监控和日志(Sentry + Grafana + Loki)
|
||||
- 认证方案(JWT + OAuth2 / LDAP 企业对接)
|
||||
- 测试框架细节(在实现阶段决策)
|
||||
|
||||
---
|
||||
|
||||
## 参考
|
||||
|
||||
- PRD: `.scratch/formula-rd-platform/PRD.md`
|
||||
- CSS Color Level 4: https://www.w3.org/TR/css-color-4/
|
||||
- color.js: https://github.com/color-js/color.js
|
||||
- pgvector: https://github.com/pgvector/pgvector
|
||||
- 所有用户必须熟悉 React + Fastify + Prisma 三件套
|
||||
- 数据库变更必须通过 Prisma Migrate,不可手动修改 Schema
|
||||
- OpenAPI spec 作为服务契约,前后端类型同步
|
||||
- 本地开发需 Docker 运行 PostgreSQL(pgvector 扩展)
|
||||
|
||||
Reference in New Issue
Block a user