# 配方研发智能平台 — 项目全貌 > 最后更新 2026-05-21 | 版本 v0.1.0 | 企业级重构后 --- ## 1. 项目是什么 AI 驱动的化妆品配方研发智能平台(纯 Web 端)。面向化妆品研发工程师,提供四大核心能力: | 能力 | 说明 | |------|------| | 颜色管理 | CIELAB 色空间 + Display P3 广色域渲染 + AI 配色推荐 | | 可视化配方调整 | 拖拽交互 + 实时 AI 预测反馈 + ECharts 图表 | | 配方记录管理 | 结构化存储 + 版本管理 + 自然语言搜索 | | 配方推演 | 多方案并行优化 + Pareto 前沿 + 成本/功效约束 | --- ## 2. 目录全貌 ``` color_full/ │ ├── CONTEXT.md # 领域词汇表(纯业务术语) ├── README.md ├── AGENTS.md # Agent 配置 │ ├── docs/ │ ├── adr/ │ │ ├── 0001-architecture-stack.md # 技术栈选型(React/Fastify/Prisma/...) │ │ ├── 0002-ai-api-strategy.md # AI 外部 API 调用策略 │ │ ├── 0003-four-layer-module-architecture.md # 后端四层模块化架构 │ │ └── 0004-rbac-ownership-authorization.md # RBAC + 资源级 Ownership │ ├── api-reference.md # API 接口文档(29 端点) │ ├── project-overview.md # 本文件 │ └── agents/ # Agent skills 配置 │ ├── backend/ # 后端(Fastify + TypeScript) │ ├── Dockerfile │ ├── package.json │ ├── tsconfig.json # strict + noUncheckedIndexedAccess │ ├── vitest.config.ts │ ├── eslint.config.js │ ├── .prettierrc │ ├── .env.example # 环境变量模板 │ ├── runtime/ │ │ └── config.json # 运行时 AI Key 持久化 │ ├── scripts/ │ │ └── generate-openapi.ts # OpenAPI spec 生成 │ ├── prisma/ │ │ ├── schema.prisma # 数据模型定义(10 个模型) │ │ ├── seed.ts │ │ └── migrations/ │ └── src/ │ ├── app.ts # ★ 应用入口:插件注册 + 全局中间件 │ ├── server.ts # ★ 启动 + 优雅关闭 │ ├── lib/ # 工具库 │ │ ├── prisma.ts # Prisma 客户端 │ │ ├── configStore.ts # 服务器端配置持久化 │ │ ├── validate.ts # Zod → Fastify 校验桥接 │ │ └── swagger.ts # Zod → JSON Schema 转换 │ ├── shared/ # ★ 跨模块共享基础设施 │ │ ├── errors/ │ │ │ ├── app-error.ts # AppError 6 子类体系 │ │ │ └── codes.ts # 30+ 错误码常量 │ │ ├── logging/ │ │ │ └── context.ts # AsyncLocalStorage 请求上下文 │ │ ├── middleware/ │ │ │ ├── rbac.ts # requireRole('admin') │ │ │ └── ownership.ts # requireFormulaOwnership() │ │ ├── metrics/ │ │ │ └── metrics.ts # prom-client 5 指标 │ │ └── audit/ │ │ └── audit.service.ts # 结构化审计日志 │ ├── services/ # 核心服务 │ │ └── ai/ │ │ ├── index.ts # ★ AIService(Provider 抽象 + 缓存 + 限流 + 回退) │ │ ├── cache.ts # LRUCache │ │ ├── rate-limiter.ts # Token Bucket │ │ ├── audit.ts # AI 调用审计记录 │ │ ├── providers/ │ │ │ ├── types.ts # AIProvider 接口 │ │ │ ├── openai.ts # OpenAI (GPT-4o) │ │ │ └── deepseek.ts # DeepSeek (deepseek-chat) │ │ └── templates/ │ │ └── index.ts # 5 个 Prompt 模板 │ ├── modules/ # ★ 业务模块(四层架构) │ │ ├── auth/ # 认证(注册/登录/JWT) │ │ ├── ingredients/ # 成分目录(route + service + repository + test) │ │ ├── formulas/ # 配方记录(route + service + repository + test) │ │ ├── color/ # 颜色引擎(推荐/匹配/保存) │ │ ├── ai/ # AI 推演(预测/探索/提取/搜索, SSE 流) │ │ ├── projects/ # 项目管理 │ │ ├── config/ # 配置管理(AI Key/admin only) │ │ └── health/ # 健康检查(live/ready + /metrics) │ └── generated/ # Prisma 自动生成 │ ├── frontend/ # 前端(React 19 + Vite 8 + TypeScript) │ ├── Dockerfile │ ├── package.json │ ├── vite.config.ts │ ├── vitest.config.ts │ ├── eslint.config.js │ ├── tsconfig.json / tsconfig.app.json / tsconfig.node.json │ ├── index.html │ ├── nginx.conf # 生产 Nginx 配置 │ ├── scripts/ │ │ └── generate-types.ts # OpenAPI → TypeScript 类型生成 │ └── src/ │ ├── main.tsx # ★ 入口:ToastProvider + QueryClient + Router │ ├── App.tsx │ ├── router.tsx # React Router v7 配置 │ ├── index.css # Tailwind CSS 4 入口 │ ├── lib/ │ │ ├── api.ts # apiFetch 封装 + Auth header │ │ ├── queryClient.ts # TanStack Query 配置 │ │ └── color/ # 色彩科学工具 │ │ ├── convert.ts # 色空间转换(Lab/Hex/RGB/LCH/P3) │ │ ├── deltaE.ts # ΔE 2000/CMC/76 计算 │ │ ├── types.ts # 颜色类型定义 │ │ └── color.test.ts # 颜色工具测试 │ ├── shared/ # ★ 共享 UI 基建 │ │ ├── components/ │ │ │ ├── Toast.tsx # Toast 通知系统(Provider + Hook) │ │ │ ├── Skeleton.tsx # 骨架屏(单行/多行/页面级) │ │ │ └── Alert.tsx # 警告提示(4 种变体) │ │ └── services/ │ │ └── api.ts # 统一 API 客户端(带 Auth Token) │ ├── modules/ # 前端模块 │ │ └── formulas/ │ │ └── formulas.service.ts # 配方 Service 层(TanStack Query 就绪) │ ├── pages/ # 页面组件(14 个) │ │ ├── DashboardPage.tsx # 仪表盘 │ │ ├── FormulaListPage.tsx # 配方列表 │ │ ├── FormulaDetailPage.tsx # 配方详情(含可视化编辑器) │ │ ├── FormulaEditorPage.tsx # 配方编辑器 │ │ ├── FormulaExplorerPage.tsx # 配方推演 │ │ ├── VersionHistoryPage.tsx # 版本历史 │ │ ├── VersionComparePage.tsx # 版本对比 │ │ ├── ColorLabPage.tsx # 颜色实验室 │ │ ├── IngredientsPage.tsx # 成分目录 │ │ ├── ProjectsPage.tsx # 项目管理 │ │ ├── SettingsPage.tsx # 设置(外观 + AI 配置) │ │ ├── SearchPage.tsx # AI 搜索 │ │ ├── LoginPage.tsx # 登录 │ │ └── RegisterPage.tsx # 注册 │ ├── components/ # 共享组件 │ │ ├── AuthGuard.tsx # 路由守卫 │ │ ├── ErrorBoundary.tsx # 错误边界 │ │ ├── ColorWheel.tsx # 色轮 Canvas │ │ ├── EyedropperPanel.tsx # 取色棒 │ │ ├── ColorRecommendPanel.tsx # AI 配色推荐弹窗 │ │ └── FormulaVisualEditor.tsx # 配方可视化编辑器 │ ├── layouts/ │ │ └── AppLayout.tsx # 主布局(侧栏 + 顶栏) │ ├── hooks/ │ │ └── useAIPredict.ts # AI 预测 Hook │ └── stores/ │ ├── authStore.ts # 认证状态(Zustand) │ └── themeStore.ts # 主题状态(Zustand) │ ├── docker/ │ └── Dockerfile.pgvector # PostgreSQL + pgvector 镜像 ├── docker-compose.yml # 开发环境(PostgreSQL + MinIO[可选]) ├── docker-compose.prod.yml # 生产环境(Traefik + PostgreSQL + Backend + Frontend) └── scripts/ ├── backup-db.sh # pg_dump 备份脚本(7 天留存) └── init-db.sh # 数据库初始化 ``` --- ## 3. 架构全景 ### 3.1 后端:四层模块化 ``` HTTP Request │ ▼ ┌──────────────────────────────────────────────┐ │ app.ts (Fastify) │ │ ├── Helmet + CORS + RateLimit │ │ ├── global preHandler: JWT verify │ │ ├── global setErrorHandler: AppError → HTTP │ │ └── /docs (Swagger UI) + /api/* routes │ └────────────┬─────────────────────────────────┘ │ ┌────────▼────────┐ │ Route Layer │ ← 参数提取 (req → 纯数据) + Zod 校验 │ *.route.ts │ preHandler: requireRole() / requireFormulaOwnership() └────────┬────────┘ │ ┌────────▼────────┐ │ Service Layer │ ← 纯业务逻辑 + 审计埋点 + 百分比验证 │ *.service.ts │ 依赖 Repository + AuditService └────────┬────────┘ │ ┌────────▼────────┐ │ Repository │ ← Prisma 查询封装 + 事务管理 │ Layer │ 每个模块独立 Repository │ *.repository.ts│ └────────┬────────┘ │ ┌────────▼────────┐ │ Prisma ORM │ │ PostgreSQL │ │ + pgvector │ └─────────────────┘ ``` ### 3.2 横切关注点注入矩阵 | 关注点 | 注入方式 | 注入位置 | |--------|----------|----------| | 请求 ID | `genReqId: () => randomUUID()` | app.ts 构造 | | 认证 | `addHook('preHandler')` → verifyToken → set userId | app.ts 全局 | | 授权 | `{ preHandler: [requireRole(), requireFormulaOwnership()] }` | Route 注册 | | 输入校验 | `validateOrReply(zodSchema, data, reply)` | Route handler | | 错误处理 | `setErrorHandler(error, request, reply)` → AppError 子类匹配 | app.ts 全局 | | 结构化日志 | `request.log.child({ requestId })` | app.ts onRequest | | 审计日志 | `auditService.log({ action, resource, userId })` | Service 层显式调 | | API 文档 | `@fastify/swagger` + `routeSchema()` | Route 注册 | | Prometheus | `app_errors_total.inc()` / `/api/metrics` 端点 | 全局 handler + health 模块 | | HTTP 安全 | `@fastify/helmet` + `@fastify/rate-limit` | app.ts 插件注册 | ### 3.3 前端:渐进式分层 ``` React Router │ ▼ ┌──────────────────────────┐ │ Page 组件 │ ← UI 渲染 + 调用 Hooks │ (pages/) │ └────────────┬─────────────┘ │ ┌────────▼────────────┐ │ Hooks │ ← useQuery / useMutation (TanStack Query) │ + 页面级 State │ useReducer / useState └────────┬────────────┘ │ ┌────────▼────────────┐ │ Service 层 │ ← API 调用封装 (apiFetch) │ (modules/*.service) │ 类型安全的请求/响应 └────────┬────────────┘ │ ┌────────▼────────────┐ │ 共享 UI 基建 │ │ - ToastProvider │ │ - Skeleton │ │ - Alert │ │ - ErrorBoundary │ └──────────────────────┘ ``` "当前状态:后端四层已全部落地,前端仅 formulaService 完成模板,其余 page 仍使用 `apiFetch` 直调。这是待完成的迁移动脉。" --- ## 4. 数据模型 ``` User ────1:N──→ Formula ────1:N──→ FormulaVersion ────1:N──→ Phase │ │ │ │ │ │ │ 1:N │ │ │ │ FormulaIngredient ────N:1──→ Ingredient │ │ │ │ 1:N │ 1:N │ ├─────→ ColorFormula Phase (via formulaId on Phase) │ └─────→ Project ────1:N──→ Formula ``` | 表 | 核心字段 | 说明 | |----|----------|------| | users | username(unique), passwordHash(scrypt), role(engineer/admin) | 用户 | | projects | name, description, createdBy | 项目 | | formulas | name, description, currentVersion, projectId, embedding(vector) | 配方 | | formula_versions | formulaId, versionNumber(unique pair), snapshotData(JSON), createdBy | 版本快照 | | phases | name, formulaId(→FormulaVersion), sortOrder | 工艺阶段 | | formula_ingredients | formulaVersionId, phaseId, ingredientId, percentage, processNotes | 成分关联 | | ingredients | inciName, chineseName, functionCategory(12枚举), supplier, unitPrice | 原料 | | color_formulas | name, targetLab(JSON), actualLab(JSON), deltaE, colorantComposition(JSON) | 颜色配方 | | ai_audit_logs | capability, modelName, promptHash, tokensUsed, durationMs | AI 调用审计 | --- ## 5. 安全架构 ### 5.1 认证流程 ``` POST /api/auth/register 用户名 + 密码 → scrypt 异步哈希 → 存入 users.passwordHash 返回 JWT Token (HS256, 24h) POST /api/auth/login 用户名 + 密码 → scrypt 异步比对 (timingSafeEqual) 返回 JWT Token 每个业务请求: Authorization: Bearer → preHandler: 解码验证 → 查 DB 确认用户存在 → set request.userId ``` ### 5.2 授权矩阵 | 操作 | admin | engineer | |------|:-----:|:--------:| | 管理 AI 配置 | ✓ | ✗ | | 增删改成份目录 | ✓ | ✓ | | 创建配方 | ✓ | ✓ | | 编辑/删除**自己**的配方 | ✓ | ✓ | | 编辑/删除**他人**的配方 | ✓ | ✗ | | 颜色引擎 / AI 推演 | ✓ | ✓ | | 管理项目 | ✓ | ✓ | ### 5.3 安全层 | 层 | 工具 | 作用 | |----|------|------| | HTTP 头 | `@fastify/helmet` | CSP/HSTS/X-Frame 等安全头 | | CORS | `@fastify/cors` | 仅允许 localhost:5173 | | 速率限制 | `@fastify/rate-limit` | 全局 100 req/min | | 密码 | scrypt(salt=16, output=64) + timingSafeEqual | 抗彩虹表 + 防时序攻击 | | Token | JWT HMAC-SHA256 (HS256) | 正确实现,非 SHA256 裸哈希 | | API Key | `runtime/config.json` 服务器端存储 | 不从 localStorage 传输 | --- ## 6. 可观测性 ### 6.1 健康探针 | 端点 | 用途 | 实现 | |------|------|------| | `/api/health` | 基础存活 | 返回 timestamp | | `/api/health/live` | K8s liveness | `SELECT 1` 检测 DB 连接,失败 503 | | `/api/health/ready` | K8s readiness | SIGTERM 后返回 503 | | `/api/metrics` | Prometheus scrape | 5 个指标 | ### 6.2 Prometheus 指标 | 指标 | 类型 | 标签 | |------|------|------| | `http_requests_total` | Counter | method, path, status | | `http_request_duration_ms` | Histogram | method, path | | `app_errors_total` | Counter | category, module, code | | `ai_requests_total` | Counter | capability, provider, status | | `ai_request_duration_ms` | Histogram | capability | ### 6.3 日志 - **框架**: pino(结构化 JSON) - **上下文**: 每个请求自动注入 `requestId` - **审计**: `auditService.log()` → `{ audit: true, action, resource, resourceId, userId }` - **格式**: 开发 `pino-pretty`,生产纯 JSON → Loki/ELK --- ## 7. 部署架构 ### 7.1 开发环境 ```bash docker compose up # PostgreSQL (pgvector) pnpm dev # backend (3001) + frontend (5173) ``` MinIO 可选:`docker compose --profile full up` ### 7.2 生产环境 ``` ┌────────────────────────────────────────────┐ │ Traefik (80/443) │ │ ├── /api/* → backend:3001 │ │ └── /* → frontend:80 │ ├────────────────────────────────────────────┤ │ Backend (Fastify, port 3001) │ │ ├── /api/* 业务路由 │ │ ├── /docs Swagger UI │ │ ├── /api/health/live liveness probe │ │ ├── /api/health/ready readiness probe │ │ └── /api/metrics Prometheus scrape │ ├────────────────────────────────────────────┤ │ Frontend (Nginx, port 80) │ │ ├── SPA static files │ │ └── /api/* → backend proxy │ ├────────────────────────────────────────────┤ │ PostgreSQL (pgvector) │ └────────────────────────────────────────────┘ ``` ```bash docker compose -f docker-compose.prod.yml up -d ``` ### 7.3 备份 ```bash # 手动备份 ./scripts/backup-db.sh # crontab 每日备份 0 2 * * * /opt/colorfull/scripts/backup-db.sh >> /var/log/colorfull-backup.log 2>&1 ``` --- ## 8. 质量保障 ### 8.1 TypeScript 严格度 | 开关 | 后端 | 前端 | |------|:----:|:----:| | `strict: true` | ✓ | ✓ | | `noUncheckedIndexedAccess` | ✓ | ✓ | | `noUnusedLocals` | ✓ | ✓ | | `noUnusedParameters` | ✓ | ✓ | | `skipLibCheck` | ✓ | ✓ | ### 8.2 代码规范 | 工具 | 后端 | 前端 | |------|:----:|:----:| | ESLint | ✓ (`typescript-eslint`) | ✓ | | Prettier | ✓ (semi=false, singleQuote, trailingComma=all) | ✓ | | 状态 | **lint 零错误** | — | ### 8.3 测试 | 层 | 后端 | 前端 | |----|------|------| | 单元测试 | —(待补:Service 层) | `lib/color/color.test.ts`(色空间转换) | | 集成测试 | `ingredients.test.ts` + `formulas.test.ts`(26 用例) | —(待补:React Testing Library) | | E2E | —(待补:Playwright) | — | | 运行 | `pnpm test` (vitest) | `pnpm test` (vitest) | ### 8.4 命令速查 ```bash # 后端 cd backend pnpm dev # 启动开发服务器 (tsx watch) pnpm build # TypeScript 编译 pnpm test # 运行 26 个集成测试 pnpm lint # ESLint 检查 pnpm format # Prettier 格式化 pnpm db:migrate # 数据库迁移 pnpm db:seed # 种子数据 pnpm api:gen # 生成 OpenAPI spec # 前端 cd frontend pnpm dev # 启动 Vite 开发服务器 pnpm build # 生产构建 pnpm lint # ESLint pnpm api:gen # 从 OpenAPI spec 生成 TypeScript 类型 ``` --- ## 9. API 速览 | 模块 | 端点 | 方法 | 认证 | 说明 | |------|------|------|:----:|------| | health | `/api/health` | GET | ✗ | 基础存活 | | health | `/api/health/live` | GET | ✗ | DB 检查 | | health | `/api/health/ready` | GET | ✗ | 就绪检查 | | health | `/api/metrics` | GET | ✗ | Prometheus | | auth | `/api/auth/register` | POST | ✗ | 注册 | | auth | `/api/auth/login` | POST | ✗ | 登录 | | auth | `/api/auth/me` | GET | ✓ | 当前用户 | | ingredients | `/api/ingredients` | GET/POST | ✓ | 列表/创建 | | ingredients | `/api/ingredients/:id` | GET/PUT/DEL | ✓ | 详情/更新/删除 | | formulas | `/api/formulas` | GET/POST | ✓ | 列表/创建 | | formulas | `/api/formulas/:id` | GET/PUT/DEL | ✓ | 详情/更新/删除 | | formulas | `/api/formulas/:id/composition` | PUT | ✓ | 更新成分(新版本) | | color | `/api/color/recommend` | POST | ✓ | AI 配色推荐 | | color | `/api/color/formulas/match` | GET | ✓ | 颜色配方匹配 | | color | `/api/color/formulas` | POST | ✓ | 保存颜色配方 | | ai | `/api/ai/predict-formula` | POST | ✓ | 预测指标(SSE) | | ai | `/api/ai/explore-formula` | POST | ✓ | 配方推演(SSE) | | ai | `/api/ai/extract-formula` | POST | ✓ | 提取配方文本 | | ai | `/api/ai/search` | GET | ✓ | NL 搜索 | | projects | `/api/projects` | GET/POST | ✓ | 列表/创建 | | projects | `/api/projects/:id` | PUT/DEL | ✓ | 更新/删除 | | config | `/api/config` | GET/PUT | ✓ | 查看/更新配置(admin) | | config | `/api/config/test` | POST | ✓ | 测试 AI 连接(admin) | --- ## 10. 待完成清单 | 优先级 | 项目 | 状态 | |--------|------|:----:| | P1 | 前端页面逐批迁移到 Service 层 + TanStack Query | 仅 formulaService 完成 | | P1 | 前端集成 shadcn/ui 组件(替换手动创建的 Toast/Skeleton/Alert) | Tailwind 4 兼容性问题待解决 | | P2 | 后端 Service 层单元测试(mock Repository) | 待开始 | | P2 | 后端 Testcontainers 集成测试框架 | 待开始 | | P2 | Playwright E2E 关键流程测试 | 待开始 | | P2 | Husky pre-commit hooks(后端 + 前端) | 待配置 | | P3 | CI/CD 流水线(GitHub Actions / GitLab CI) | 待配置 | | P3 | 前端 OpenAPI 类型生成流水线验证 | 脚本已就绪,待端到端跑通 | | P3 | Admin 用户管理 UI | 直接操作 DB | --- ## 11. 相关文档索引 | 文档 | 路径 | 内容 | |------|------|------| | 领域词汇 | `CONTEXT.md` | 纯业务术语定义 | | 技术栈 ADR | `docs/adr/0001-architecture-stack.md` | 为什么选 React/Fastify/Prisma 等 | | AI 策略 ADR | `docs/adr/0002-ai-api-strategy.md` | 为什么用外部 LLM API | | 架构 ADR | `docs/adr/0003-four-layer-module-architecture.md` | 为什么四层模块化 | | 授权 ADR | `docs/adr/0004-rbac-ownership-authorization.md` | 为什么 RBAC + Ownership | | API 文档 | `docs/api-reference.md` | 29 个接口完整说明 | | PRD | `.scratch/formula-rd-platform/PRD.md` | 产品需求 |