# ADR-0001: 整体技术栈选型 > **状态**: 已决议 > **日期**: 2026-05-20 > **决策者**: 架构评审 --- ## 上下文 构建 AI 驱动的化妆品配方研发智能平台(纯 Web 端),涉及四大核心模块:颜色引擎(广色域渲染)、配方可视化编辑器(拖拽交互 + 实时 AI 反馈)、配方记录管理(结构化存储 + NL 搜索)、配方推演引擎(多方案并行优化)。需对前端框架、图表库、色彩科学库、后端架构、数据库等做出技术选型。 --- ## 决策 ### 1. 前端框架 → React 18 + TypeScript 5.7 | 候选 | 优势 | 劣势 | 结论 | | :--- | :--- | :--- | :--- | | **React** | 生态最丰富;ECharts/D3/color.js 均有 React 绑定;招聘成本最低;TS 成熟 | Hooks 学习曲线 | ✅ 推荐 | | Vue 3 | 模板直观;Composition API 类型推导好 | ECharts 官方 React 绑定更成熟;D3 + Vue 组合不如 React 灵活 | ❌ | | Svelte 5 | 编译时框架,运行时极小 | 生态较小;关键库适配风险;社区资源少 | ❌ | | SolidJS | 性能优于 React;API 相似 | 社区太小(GitHub stars ~30k vs React ~230k);生产风险高 | ❌ | **决策**:React 18 + TypeScript strict mode。React 19 待生态稳定后再升级。 --- ### 2. 构建工具 → Vite 6 | 候选 | 优势 | 劣势 | 结论 | | :--- | :--- | :--- | :--- | | **Vite** | 原生 ESM 开发(毫秒级 HMR);Rollup 生产打包;零配置开箱;SSR 可选 | — | ✅ 推荐 | | Next.js 15 | 全栈能力;SSR/SSG/ISR | 内部工具无需 SSR/SEO;增加复杂度;App Router 学习曲线陡峭 | ❌ | | Remix | SSR 优先;Web 标准 | 同上;社区较 Next.js 小 | ❌ | | CRA | — | 已停止维护;Webpack 构建慢 | ❌ | **决策**:Vite 6,SPA 模式。平台为内部工具,无需 SEO/SSR。 --- ### 3. 状态管理 → Zustand 5 | 候选 | 优势 | 劣势 | 结论 | | :--- | :--- | :--- | :--- | | **Zustand** | 极简 API(无 Provider/Reducer);TS 完美;< 2KB;中间件(persist/immer/devtools) | — | ✅ 推荐 | | Redux Toolkit | 完善的 DevTools;团队规范 | 模板代码多;概念多(slice/thunk/selector);过度工程化 | ❌ | | Jotai | 原子化精细更新 | 原子拆分粒度决策成本高;对中型应用过度 | ❌ | | MobX | 响应式直观 | 装饰器语法过时;与 React 18+ 严格模式兼容性问题 | ❌ | **决策**:Zustand。服务端状态用 TanStack Query,客户端状态用 Zustand,边界清晰。 --- ### 4. 路由 → React Router v7 | 候选 | 优势 | 劣势 | 结论 | | :--- | :--- | :--- | :--- | | **React Router v7** | 最广泛使用;layout routes;v7 类型安全路由;社区资源极丰富 | — | ✅ 推荐 | | TanStack Router | 编译时类型安全最强 | 生态较小;与第三方库集成案例少 | ❌ | **决策**:React Router v7。 --- ### 5. CSS 方案 → Tailwind CSS 4 + CSS Modules | 候选 | 优势 | 劣势 | 结论 | | :--- | :--- | :--- | :--- | | **Tailwind + CSS Modules** | Tailwind 处理 80% 日常样式;CSS Modules 处理复杂定制(颜色盘);零运行时;Tailwind v4 CSS-first 配置 | 需同时掌握两套语法 | ✅ 推荐 | | styled-components | CSS-in-JS,组件级隔离 | 运行时开销(~14KB);Server Components 不兼容趋势 | ❌ | | Panda CSS | 编译时 CSS-in-JS | 较新(2024),生态不成熟 | ❌ | | Vanilla Extract | 类型安全 CSS-in-JS | 构建步骤复杂;社区小 | ❌ | **决策**:Tailwind CSS 4(原子化,处理布局/间距/响应式)+ CSS Modules(处理颜色盘 Canvas 容器、图表交互区等复杂定制场景)。 --- ### 6. UI 行为组件 → Radix UI | 候选 | 优势 | 劣势 | 结论 | | :--- | :--- | :--- | :--- | | **Radix UI** | Headless(完全控制样式);WAI-ARIA 内置;组件粒度合适;与 Tailwind 天配 | 无预置视觉风格(需要自行设计) | ✅ 推荐 | | Ant Design | 开箱即用,组件丰富 | 企业后台感强;视觉定制困难;不适合创意工具;bundle 大 | ❌ | | MUI | Material Design 完整实现 | 同上;Google 风格固化 | ❌ | | shadcn/ui | 基于 Radix + Tailwind,复制源码 | 本质是 Radix 封装;直接 Radix 更灵活 | ❌ | **决策**:Radix UI 提供 Dialog、Popover、Dropdown、Tabs、Tooltip 等行为组件。视觉层完全自定义,匹配配方研发工具的专业调性。 --- ### 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 | 候选 | 优势 | 劣势 | 结论 | | :--- | :--- | :--- | :--- | | **TanStack Query** | 缓存/重试/乐观更新/无限滚动开箱即用;与 Zustand 分工清晰 | — | ✅ 推荐 | | SWR | 类似功能 | API 不如 TanStack Query 丰富 | ❌ | | RTK Query | Redux 集成 | 绑定 Redux | ❌ | **决策**:TanStack Query v5。推荐列表、配方搜索、AI 预测等所有异步请求均通过它管理。 --- ### 11. 后端 → Fastify(BFF 单体)+ 外部 AI API ``` ┌─────────┐ 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 调用的编排和降级 | | 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 名称、比例、工艺参数 | --- ### 12. 数据库 → PostgreSQL 16 + pgvector | 候选 | 结构化 | 向量搜索 | JSONB | 全文搜索 | 运维 | 结论 | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | **PostgreSQL + pgvector** | ✅ | ✅ IVFFlat/HNSW | ✅ | ✅ | 成熟 | ✅ 推荐 | | MongoDB | ⚠️ 文档型 | ✅ Atlas Vector | ✅ | ⚠️ | 成熟 | ❌ 配方强关系 | | Elasticsearch | ❌ | ⚠️ 需插件 | ❌ | ✅ | 复杂 | ❌ 过度 | | Neo4j | ❌ 图 | ⚠️ | ❌ | ❌ | 小众 | ❌ 过度 | **决策**:PostgreSQL 16 + pgvector。 - 配方是强结构化数据(成分→相→配方→版本,经典关系模型) - pgvector 0.7+ 支持 HNSW 索引,NL 搜索和相似配方匹配性能优秀 - JSONB 处理灵活的工艺参数和元数据 - 一个数据库同时满足关系查询 + 向量搜索 + 全文搜索,运维简单 - 配方版本管理利用 PostgreSQL 的 MVCC + 时间戳快照 --- ### 13. 对象存储 → MinIO **决策**:MinIO(S3 兼容),存储参考图片、导出文件。本地部署,S3 API 可无缝迁移到云。 --- ### 14. 部署 → Docker Compose(开发)+ K8s(生产) | 服务 | 端口 | 职责 | | :--- | :--- | :--- | | Nginx | 80/443 | 静态资源、反向代理、SSL 终结 | | Fastify BFF | 3001 | API 聚合、认证、文件上传、AI API 代理 | | PostgreSQL | 5432 | 配方数据 + 向量 | | MinIO | 9000 | 对象存储 | | Redis(可选) | 6379 | 缓存、Session、AI 响应缓存 | **开发环境**:Docker Compose 一键启动所有服务(无需 AI 依赖,BFF 可 mock AI API) **生产环境**:Kubernetes,仅 4 个核心服务,显著降低运维复杂度 --- ## 后果 ### 正向 - 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