Files
lingxi/docs/评估/_调研/sucaigongfang-调研报告.md
T
Stev_Wang 6096568621 docs: 新增双项目整合评估、调研报告与技术栈架构定稿
- 新增双项目整合可行性评估 V0.1 rev.2:覆盖度矩阵、方案对比、目标架构、工作量/TCO、风险与决策清单
- 新增 dewu/sucaigongfang 两份调研报告(内部资料,平台敏感值已脱敏)
- 新增技术栈与架构定稿 V1.0:Node 24.15.0 / pnpm 11.4.0 / Prisma 7.10.1 / PostgreSQL 18 / Redis 7
- 更新 README 文档索引与仓库结构
2026-10-30 14:13:00 +08:00

741 lines
82 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# sucaigongfang 调研报告
> 调研对象:`参考项目/sucaigongfang/`(「素材工坊」图片素材自动化生产系统,v1.0.0,git `main` @ `d1b01fa`,2026-09-26)
> 调研方式:只读代码勘察 + 文档比对,**以代码为准**。未执行 `pnpm install` / 构建 / 迁移 / 长任务。
> 对照文档:`docs/PRD/平台电商素材生产平台_PRD_V0.1.md` 的 1.1(P-01~P-07)与 1.2(功能框架)。
> 口径约定:LOC/文件数均不含 `node_modules`、`dist`、`.cache`、`.npm-cache`、`uploads` 内二进制。
---
## 0. 结论速览
**一句话定位**:素材工坊是一套**面向信息流广告投放(电商唤端 + 券商)的图片素材批量生产线**——设计师上传 PSD 模板、优化师上传商品图并填写字段,系统按「模板 × 商品图」交叉批量合成图片,自动命名、打包、通知,并配套完整的账号/权限/客户/配置/任务治理体系。
**架构形态**:pnpm workspace 双包。后端 Express 5 + Sequelize 6 + PostgreSQL + Redis/BullMQ + `ag-psd`/`@napi-rs/canvas`/`sharp`/`fontkit` 渲染 + `@imgly/background-removal-node`(ONNX) 抠图 + `ws` 实时推送;前端 React 19 + Arco Design + Tailwind 4 + zustand + axios + react-router 7 + Vite 8。**API 与 BullMQ Worker 同进程**(`backend/src/app.ts:65-66`、`app.ts:402`),单容器部署,文件存储为**本地磁盘**(`backend/uploads`,854MB/775 文件在本机副本)。
**成熟度**:
| 维度 | 结论 | 证据 |
| --- | --- | --- |
| 版本/形态 | v1.0.0,可部署的生产态(容器化 + 1Panel 反代 + 回滚脚本) | `package.json:1-3`、`deploy/docker-compose.yml:1-40`、`deploy/deploy.sh:1-30` |
| 提交活跃度 | 249 commits,2026-03-23 → 2026-09-26;3 月 85 / 4 月 33 / **9 月 131**(5–8 月空档) | `git log --format='%ad' --date=format:'%Y-%m'` |
| 代码规模 | 后端 `src` 30,835 行 / 137 文件;前端 `src` 32,797 行 / 74 文件;测试 2,078 行 | 见 §6 口径命令 |
| 测试 | `node:test` 175 个用例 / 14 文件,**全部纯函数,无 DB/HTTP 集成测试、无 E2E** | `backend/tests/*.test.ts`、`package.json:24` |
| 质量门禁 | 本地 CI 6 步硬卡:prettier/eslint/单测/前端设计 token 静态校验/tsc/构建 | `deploy/ci-local.sh:24-45` |
| 部署 | 前后端双镜像 + host/bridge 网络 + Node 24-slim + nginx 反代 `/api` `/uploads` `/ws` | `backend/Dockerfile`、`frontend/Dockerfile`、`frontend/nginx.conf.template:20-40` |
| 文档 | `docs/` 33 篇 md + 4 份方舟 PDF,但 **`docs/` 整个目录被 .gitignore 忽略(110 个文件 0 入库)** | `.gitignore:122`、`git ls-files docs` = 0 |
**结论表(能力域 → 复用结论)**
| 能力域 | 复用结论 | 关键原因 | 粗估人日 |
| --- | --- | --- | --- |
| 后端工程地基(Express/Sequelize/PG/迁移/日志/健康检查) | 直接复用 | 结构规整;umzug 迁移已落地;日志/健康检查/进程兜底齐全 | 3–5 |
| 认证与账号安全(JWT/强制改密/口令策略/登录限流/口令审计) | 直接复用 | 服务端强制、令牌版本失效、一次性随机口令,安全设计超标 | 2–3 |
| RBAC 角色权限 + 客户级数据范围 | 直接复用 | 权限 key 目录 + `fail-closed` 客户范围双层 | 3–4 |
| 系统配置框架(40 项 / 10 模块 / L1-L3 / 审计 / 专用控件) | 直接复用 | 声明式注册表,是「加配置不写迁移」的成熟范式 | 3–5 |
| 模板/分类/标签/规格管理 | 改造复用 | 结构可留,需加平台维度与 Logo/促销/展示方式资产 | 8–10 |
| PSD 解析与渲染引擎 | 改造复用 | 核心资产(1773 行合成器),但**只支持单一商品图入参** | 12–18 |
| 抠图(白底判定 + ONNX + 降级告警) | 直接复用 | 失败会标 `low_quality_warning`,不静默交付 | 2–3 |
| 批量任务/队列/进度/暂停恢复取消重试/收尾 | 直接复用 | BullMQ + DB 计数 + WS 推送 + 失败口径分轮次,工程细节成熟 | 6–8 |
| 命名规则引擎(变量模板/客户级/批次快照) | 直接复用 | 变量域与 PRD「自定义字段组合」高度一致 | 3–4 |
| 导出 / ZIP 打包 / 下载 | 直接复用 | CSV 导出 + BullMQ 异步打包 + 选集下载 | 3–4 |
| 通知 / 站内信 / WebSocket | 改造复用 | 通知模板可配;缺独立通知中心页(仅文档) | 3–4 |
| 任务事件 / 失败目录 / 时间线 / 任务日志 | 直接复用 | 事件目录 + 失败目录 + 90 天保留期,是统一平台的可观测底座 | 3–4 |
| 文件存储 / 缩略图 / 清理 | 改造复用 | **纯本地磁盘、无 OSS**,需加存储适配层 | 4–6 |
| 前端设计体系 / 布局 / 守卫 / 共享组件 | 改造复用 | token 单点 + 自动校验;但菜单与权限映射硬编码 | 5–7 |
| 素材制作页(2625 行) | 服务端重写 | 需按「平台 → 选品 → 展示方式/Logo/促销」重构 | 10–15 |
| 首页 Dashboard | 服务端重写 | 指标口径(单套成本/模板占比/提审通过率)全部变化 | 3–5 |
| AI 生图 | 服务端重写 | **仅验证到 M2-0,无产品代码**;分支实现已声明作废 | 20–30 |
| 数据字典 / 枚举 | 服务端重写 | 仅文档;分支实现未合并且已停用 | 3–4 |
| 多平台 / 平台切换 | 新建 | 系统内**没有平台概念**(得物仅作示例客户名) | 5–8 |
| 选品 / 原始物料获取 | 新建(另一项目迁移) | 该能力在 `dewu-material-Downloader`(Electron),本系统无爬取代码 | 15–25 |
| 视频素材 AI 生产 | 新建 | 完全空白,无 ffmpeg/视频依赖 | 40+ |
| 提审 | 新建 | 完全空白 | 8–12 |
| 投放配置(DP/承接页) | 新建 | 完全空白 | 8–12 |
> 粗估口径:按「熟悉本仓库的 1 名全栈 + 1 名前端」并行估算,仅作量级参考,**需与研发负责人校准**。可复用/改造部分合计约 **60–85 人日**;加上制作页与首页重写(13–20 人日),**图片产线地基落地约 75–105 人日**;再叠加 AI 生图(20–30)、多平台(5–8)、数据字典(3–4)、选品抓取(15–25)、提审(8–12)、投放配置(8–12)≈ 134–196 人日,计入约 20% 的联调/迁移余量后,统一平台 MVP(不含视频深水区)总量级约 **165–235 人日**。
---
## 1. 项目定位与业务链路
### 1.1 解决什么问题、给谁用
原 PRD 写得很直白:**信息流优化师在电商 APP 唤端项目中面临素材产能不足**,需要「设计师上传 PSD 模板 → 优化师一键替换产品图生成素材 → 支持批量」(`docs/PRD.md:5-14`)。用户角色只有三类:管理员 / 设计师 / 优化师(`docs/PRD.md:16-22`、`docs/用户使用手册.md:38-44`)。
因此本系统的真实定位是:
- **面向「素材生产」而不是「素材投放」**:产出到「按命名规则落盘 + ZIP 打包下载」为止,不涉及账户搭建、DP、承接页、提审。
- **单客户 = 单个广告主/品牌方**(如「得物」「华泰证券」):`clients` 表是业务归属维度,**不是多租户**(同一套部署、同一个库,靠 `user_clients` + `created_by` 做数据范围收敛)。
- **设计师与优化师的协作边界被固化成「模板」**:模板承载图层契约,优化师只填字段和传商品图。
补充一个容易被忽略的事实:本系统同时服务**电商(得物)与券商(华泰证券等)两个行业**,AI 方向的全部验证文档都以券商素材为样本(免责声明、收益暗示、合规红线)。这与本次新 PRD 只聚焦「平台电商(得物/唯品会)」不同——**行业假设不一致,AI 侧结论不能整体平移**。
### 1.2 主链路(代码实证)
```
① 管理员:建客户 → 建用户并绑定客户/角色 →(可选)配置客户级命名规则
② 设计师:上传 PSD → 系统解析图层(ag-psd)→ 逐图层绑定「图片替换/文本替换/剪贴蒙版」
→ 预览图生成 → 归属客户/分类/标签/规格
③ 优化师:素材制作页选模板(可多选)→ 上传商品图(≤100 张)→ 按文件名识别商品ID/名称/品牌
→ 表格可编辑 → 选生产参数(抠图/尺寸限制/JPG/缩放/字号)→ 二次确认提交
④ 系统:建批次(N 模板 × M 商品图 交叉)→ 写命名快照 + 预渲染文件名 → 入 BullMQ
⑤ Worker:白底图自动抠图 → MaterialComposer 合成 → 写 materials → 更新批次统计 → WS 推送
⑥ 收尾:批次完成 → 站内信通知 → 自动/手动触发 ZIP 打包 → 下载交付
⑦ 管理:任务列表 / 任务详情抽屉 / 时间线 / 任务日志(跨用户只读)/ CSV 导出
```
主链路的关键代码:`productionBatchController.ts:646`(建批次)、`workers.ts:70-412`(素材 Worker)、`materialComposer.ts:143`(合成入口)、`workers.ts:764`(ZIP Worker)。
### 1.3 与 PRD 1.1 的问题对应关系(P-01~P-07)
| 编号 | PRD 问题 | 本系统覆盖度 | 说明 |
| --- | --- | --- | --- |
| P-01 | 原始物料:详情页图片人工下载、分散存放 | ❌ **0** | 无选品/抓取/物料库;商品图靠本地上传。该能力在**另一个参考项目** `dewu-material-Downloader`(Electron 桌面端) |
| P-02 | 图片制作:三规格 × 四层信息全靠人工排版 | 🟡 **部分覆盖** | 已覆盖「基础框架模板 + 商品展示(单图)+ 产品信息(文本层)」,**但缺 AI 模特/脚模、Logo 组合、促销信息叠加**;规格是通用 `(w,h)` 实体,非固定的三档 |
| P-03 | 视频制作依赖实拍与个人经验 | ❌ **0** | 全仓库无视频/ffmpeg 依赖与代码 |
| P-04 | 命名提审:手工改名、进度散落 | 🟡 **命名全覆盖、提审 0** | 命名引擎(变量模板 + 客户级 + 快照 + 重试同名)非常成熟;**无提审清单/状态机** |
| P-05 | 账户搭建:DP、承接页逐条复制 | ❌ **0** | 无任何 DP/承接页/链接配置能力 |
| P-06 | 多平台:资源与口径不统一 | ❌ **0** | 系统无「平台」维度;`得物` 只出现在通知模板的示例文案里(`utils/notificationTemplates.ts:97`) |
| P-07 | 资产管理:模板、脚本散落 | 🟡 **模板资产强、其余缺** | 模板/分类/标签/规格/批次模板完整;**Logo(仅标签 logo 字段,未进合成)、展示方式、脚本无** |
**覆盖率小结**:PRD 七类问题里,本系统实质回答的是 **P-02(约一半)+ P-04(一半)+ P-07(约一半)**,其余四类需要新建或从另一项目迁移。
---
## 2. 功能模块清单(全量)
> 逐项核对方式:以 `backend/src/app.ts:147-164` 的 17 个 `*Routes` 挂载 + `frontend/src/App.tsx:100-120` 的路由表为准,辅以 `routes/*.ts` 内逐条 `router.<verb>`。
> 接口规模:**约 113 个业务接口**(按 `routes/*.ts` 的 `router.get/post/put/delete` 计数)+ `/api/health` + `/api/queue-health` + `/uploads` 静态 + `/ws`。
| 模块 | 前端路由 / 页面 | 后端 API 前缀 | 核心功能点 | 实现状态 | 关键文件:行 |
| --- | --- | --- | --- | --- | --- |
| 登录与账号安全 | `/login`、`/first-login-password` | `/api/auth` | JWT 登录、IP+用户名双维限流、首次登录强制改密、口令有效期三态策略、改密后旧令牌立即失效 | 完整 | `routes/authRoutes.ts:14-28`、`middlewares/auth.ts:18-32`、`utils/passwordPolicy.ts` |
| 用户管理 | `/system/users` | `/api/users` | CRUD、重置密码(一次性随机口令仅显示一次)、角色分配、口令审计、最近登录、密码状态 | 完整 | `routes/userRoutes.ts:16-33`、`controllers/userController.ts` |
| 角色与权限 | `/system/roles` | `/api/roles` | 角色 CRUD、权限勾选、启用/禁用、`isAdmin` 超管;前端菜单+路由双守卫 | 完整 | `utils/permissions.ts:4-20`、`components/PermissionGuard.tsx:8-21`、`AdminLayout.tsx:85-98` |
| 客户与数据范围 | `/system/clients` | `/api/clients` | 客户 CRUD、用户↔客户多对多绑定、`client_scope_mode` 受限模式、客户级命名规则 Tab | 完整 | `models/Client.ts:79`、`models/UserClient.ts`、`utils/clientScopeCore.ts:12-22` |
| 模板分类 | `/templates/categories` | `/api/categories` | 树形分类(父子自关联)、客户归属、CRUD | 完整 | `routes/categoryRoutes.ts:19-24`、`models/TemplateCategory.ts:81` |
| 模板标签 | `/templates/tags` | `/api/tags` | 标签 CRUD、颜色、客户归属、**logo 上传(后端有接口,前端未接线)** | BETA | `routes/tagRoutes.ts:20-25`、`controllers/tagController.ts:21-37` |
| 规格管理 | `/templates/specifications` | `/api/specifications` | 规格 CRUD;**名称由 (w,h) 派生**(`横版 1280×720`),唯一性从名称迁到尺寸 | 完整 | `utils/specificationName.ts:46-57`、`migrations/20260924000001-specification-name-derivation.ts` |
| 模板管理 | `/templates/list`、`/upload`、`/:id/edit` | `/api/templates` | PSD 上传/解析/预览、图层绑定、按客户字段池自动匹配、复制模板、批量删除/改分类/加标签、字体列表 | 完整 | `routes/templateRoutes.ts:17-50`、`controllers/templateController.ts:178` |
| 素材制作(核心页) | `/material-maker` | `/api/materials/*`、`/api/batches/*` | 模板筛选/搜索/最近使用/批次模板、商品图批量上传与文件名识别、字段表格可编辑、生产参数、提交前二次确认、悬停预览 | 完整 | `pages/Production.tsx:207-364`、`productionBatchRoutes.ts:12-66` |
| 生产任务列表 | `/tasks` | `/api/batches` | 卡片/表格双视图、状态页签与 facet 计数、详情抽屉、暂停/恢复/取消/重试/补跑失败项/重置卡死、选集下载、批量操作 | 完整 | `pages/Tasks.tsx:467-700`、`components/BatchDetailDrawer.tsx` |
| 批次模板(组合) | 制作页内保存/选用 | `/api/batch-templates` | 把「多模板组合」存为可复用快捷模板,支持私有/共享、客户归属 | 完整 | `routes/batchTemplateRoutes.ts:12-24`、`controllers/batchTemplateController.ts:16` |
| 任务日志(管理端) | `/system/task-logs` | `/api/admin/batches` | 跨用户只读看板、事件流/时间线、失败分类、CSV 导出、执行人筛选 | 完整 | `routes/taskLogRoutes.ts:28-49`、`components/TaskLogBoard.tsx` |
| 命名规则 | 客户弹窗「命名规则」Tab、制作页识别列 | `/api/naming` | 商品图识别模板、字段/别名/必填/可编辑、素材命名模板、ZIP 命名模板、实时预览与校验 | 完整 | `utils/namingConfig.ts:240-328`、`components/NamingConfigEditor.tsx` |
| 导出 / 打包 / 下载 | `/tasks` 内按钮 | `/api/batches/export`、`/:id/tasks/download`、`/:id/package-zip` | CSV 导出(BOM 防乱码、上限 1 万条)、选中子任务 ZIP、整批 ZIP(BullMQ 异步 + 状态机) | 完整 | `productionBatchController.ts:1249`、`:2005`、`:2269`、`workers.ts:764` |
| 通知(站内信) | 顶栏铃铛下拉 | `/api/notifications` | 列表/未读数/标记已读/全读/删除;三类触发(批次完成/失败/ZIP 就绪);标题与内容模板可在系统配置里改 | 完整(**无独立页面**) | `routes/notificationRoutes.ts:8-20`、`AdminLayout.tsx:126-133`、`utils/notificationTemplates.ts:130` |
| 通知中心独立页 | — | — | 需求文档中的独立页面:筛选、批量已读/清空、下载关联 | **仅文档** | `docs/通知中心页面需求.md:1-80` |
| 首页 Dashboard | `/` | `/api/stats/dashboard` | 5 张指标卡(模板数量 / 素材生产量 / 生产任务量 / 模板使用率 / 失败率,统一「本周 vs 上周」环比)、今日任务、待我处理(失败/暂停/进行中)、最近任务、快捷入口 | 完整 | `pages/Home.tsx:60-140`、`:367-443`、`controllers/statsController.ts:52-80` |
| 系统配置 | `/system/config` | `/api/system/configs` | 10 模块 40 项配置、L1/L2/L3 生效级别、类型与范围校验、审计留痕、两个专用控件(命名规则/通知模板)、运行环境只读面板 | 完整 | `utils/systemConfigRegistry.ts:192`、`controllers/systemConfigController.ts`、`pages/SystemConfig.tsx` |
| 存储管理 / 清理 | 系统配置 → 存储 | `/api/system/storage` | 分类用量统计、**先预览后清理**、默认只删孤儿文件、保护模板资产、定时清理(默认关) | 完整 | `utils/storageCleanup.ts:18-40`、`utils/storageCleanupScheduler.ts` |
| 文件服务 | `/uploads/*` | — | JWT 鉴权(header 或 `?token=`)、按需缩略图 `?w=320/640` 落盘缓存、失败回退原图 | 完整 | `app.ts:139-144`、`middlewares/uploadAuth.ts`、`middlewares/uploadThumbnail.ts:9` |
| 实时进度 | `/ws?token=` | `WS /ws` | 批次整行快照推送、300ms 按批次节流、心跳、鉴权失败码 4401、前端降级轮询 | 完整 | `utils/realtime.ts:31-40`、`hooks/useRealtimeBatches.ts` |
| 素材历史记录 | —(`history` 路由被注释) | `/api/materials` | 分页查询、详情、重生成(复用生产链路入队) | **BETA:后端就绪,前端未接线** | `App.tsx:118-120`、`materialRoutes.ts:28-34` |
| 数据字典 / 枚举 | — | — | 「字典类型 → 字典项」两层、系统管理入口、code/label 分离、供 AI 提示词消费 | **仅文档**(分支 `backup/ai-asset-m1` 有 625 行后端 + 999 行前端实现,未合并) | `docs/数据字典与枚举管理评估.md:1-40`、分支 `controllers/dictionaryController.ts` |
| 合规词库 / 免责声明校验 | — | — | 禁用词扫描、免责声明逐字比对、AI 成品复核闸门 | **仅文档/分支**(未合并) | 分支 `controllers/complianceController.ts`、`utils/disclaimerCheck.ts` |
| AI 生图(M2 路线) | — | — | 9 要素表单 → 提示词合成 → Seedream 出图 → 程序保证免责声明/logo → VLM 文字逐字校验 → 挑图 | **仅验证(M2-0)**,无产品代码 | `tools/ai-image-validation/README.md:3`、`docs/AI生图-M2-0验证记录.md:8-11` |
| AI 素材生成(M1 路线) | —(分支) | —(分支 `/api/ai/*`) | 图片模板上传 → VLM 反推 → 人工框选绑定 → 冻结契约 → SchemaRenderer 出图 + AI 底图 | **实验/已作废**:53 commits、约 3.1 万行新代码,但最新方案明确「整体作废,不参考、不复用」 | `git log backup/ai-asset-m1`、`docs/AI生图相关功能-实现方案.md:6` |
| 视频素材 | — | — | — | **不存在** | — |
| 提审 | — | — | — | **不存在** | — |
| 投放配置(DP/承接页) | — | — | — | **不存在** | — |
| 多平台切换 | — | — | — | **不存在** | — |
| 队列/依赖健康检查 | — | `/api/health`、`/api/queue-health` | DB/Redis 真实探活(失败 503)、队列积压/Worker 状态/WS 在线数/清理状态 | 完整 | `app.ts:175-237` |
> 说明:「历史上传记录」与「生产任务列表」是两件事。**生产记录(批次)已完整实现**(`/tasks`);**素材级历史(`materials` 表)只有 API、没有页面**,`history` 路由在 `App.tsx:118-120` 被注释为「等待迁移」。
---
## 3. 技术栈与架构
### 3.1 版本清单(以 `package.json` 实际声明为准)
| 层 | 技术 | 版本 | 备注 |
| --- | --- | --- | --- |
| 后端运行时 | Node.js | 24(`.nvmrc`) | 镜像 `node:24-slim` |
| Web 框架 | Express | `^5.2.1` | 5.x,路由级中间件 |
| ORM / DB | Sequelize / pg | `^6.37.8` / `^8.20.0` | PostgreSQL 18(生产由 1Panel 管理) |
| 迁移 | umzug + SequelizeStorage | `^3.8.3` | 账本表 `SequelizeMeta`(`utils/migrator.ts:26`) |
| 队列 | BullMQ / ioredis | `^5.71.0` / `^5.10.1` | 2 个队列:`material-generation`、`zip-packaging`;项目级键前缀 `sucaigongfang` |
| PSD 解析 | ag-psd | `^30.1.0` | `initializeCanvas` 接 `@napi-rs/canvas` |
| 画布 / 图像 | @napi-rs/canvas / sharp | `^0.1.97` / **`0.32.6`(锁定)** | sharp 锁版本,PNG 量化行为依赖该版本 |
| 字体 | fontkit | `^2.0.4` | 读字体名 + `GlobalFonts` 注册 |
| 抠图 | @imgly/background-removal-node | `^1.4.5` | 内含 onnxruntime-node(medium 模型) |
| 上传 | multer | `^2.1.1` | 按请求构造实例以支持热改限制(`utils/configurableUpload.ts`) |
| 打包 | archiver | `^7.0.1` | ZIP level 9 |
| 实时 | ws | `^8.21.3` | 复用同一 `http.Server` |
| 鉴权 | jsonwebtoken / bcrypt | `^9.0.3` / `^6.0.0` | JWT 带口令版本号 `pwdv` |
| 前端框架 | React / react-router-dom | `^19.2.4` / `^7.13.1` | 路由级 lazy 分包 |
| UI | @arco-design/web-react | `^2.66.12` | 全站指定 Arco + 自定义 token 层 |
| 样式 | Tailwind CSS / tw-animate-css | `^4.2.2` / `^1.4.0` | Tailwind 4 + `styles/` token 双轨 |
| 状态 | zustand | `^5.0.12` | 只有 2 个 store(auth / appConfig) |
| HTTP | axios | `^1.13.6` | 单一 `services/api.ts`(1223 行,113 个方法) |
| 图表 | recharts | `^3.8.1` | 首页趋势 |
| 图标 | lucide-react | `^1.7.0` | 全站图标 |
| 构建 | Vite / TypeScript | `^8.0.1` / `~5.9.3` | 前端 `tsc -b && vite build` |
依赖证据:`backend/package.json:29-47`、`frontend/package.json:20-45`。
### 3.2 架构分层与请求链路
```
┌──────────────────────────── 浏览器(React 19 SPA)────────────────────────────┐
│ pages(16) ─ components(24) ─ services/api.ts(113 方法) ─ zustand(auth/appConfig) │
│ styles/tokens.ts(字号/颜色) + theme.ts(Arco ConfigProvider) + Tailwind 4 │
└───────────────┬───────────────────────────────────────────────┬─────────────────┘
│ /api/* (nginx → backend:8300) │ /ws?token= /uploads?w=
┌───────────────▼───────────────────────────────────────────────▼─────────────────┐
│ Express 5 (单进程,API + Worker 同进程) │
│ 中间件链: 请求日志 → CORS 白名单 → body → normalizeQuery → /uploads(鉴权+缩略图+static) │
│ → 17 个 Router(登录校验在 router 内;10 个涉及客户数据的再挂 attachClientScope)│
│ 兜底: multer 错误 → JSON 400;uncaughtException → exit(1) 交给容器重启 │
│ 业务: controllers(17, 9.7k 行) → utils(55, 14.2k 行) → models(20, 2.7k 行) │
│ 异步: BullMQ(material 2 并发 / zip 1 并发,可页面热调 L3) ──► workers(43.8k 行) │
│ 实时: realtime.ts 进程内 pub(批内 300ms 节流)──► ws 推送 │
│ 观测: taskEvents(事件目录) / failureCatalog(失败目录) / taskMonitor(超时卡住巡检) │
└───────┬──────────────────────┬───────────────────────┬──────────────────────────┘
│ PostgreSQL(19 表) │ Redis(2 队列 + 项目前缀) │ 本地磁盘 backend/uploads(~732MB)
```
**三个关键架构决策(都可直接继承)**:
1. **API 与 Worker 同进程**:换来「实时推送零跨进程成本 + 部署极简」,代价是**无法按 CPU/内存独立扩缩容**,且 `uncaughtException` 会同时打断 API(`app.ts:64-78` 注释明确承认)。
2. **按批次节流推整行快照**(`realtime.ts:20-40`):不做增量、不做 diff,漏收一条下一条即纠正;300ms 合并 + 发送时重读库。
3. **配置生效级别 L1/L2/L3**(`systemConfigRegistry.ts:33-45`):L1 请求级热生效、L2 新任务生效(批次快照)、L3 需重建运行时(由 `app.ts:276-299` 注册 applier)。**这是统一平台最值得整套照搬的机制之一**。
### 3.3 构建与部署
- **镜像**:后端多阶段 `node:24-slim` + `pnpm build`(`backend/Dockerfile`);前端 builder → `nginx:1.27-alpine`,构建期注入 `VITE_API_BASE_URL`,`BUILD_INFO.txt` 做制品溯源(`frontend/Dockerfile:20-66`)。
- **网络**:backend 用 `host` 网络(监听宿主 8300),frontend 用 bridge + 端口映射(3300),容器内 nginx 经 `host.docker.internal` 反代后端(`deploy/docker-compose.yml:1-40`)。
- **反代**:SPA history 回退、`/api` `/uploads` `/ws` 转发、WS 必须 `map $http_upgrade`、`client_max_body_size 200M`、安全响应头(`frontend/nginx.conf.template:20-80`)。
- **CI**:`deploy/ci-local.sh` 6 步硬卡(格式 → lint → 单测 → 前端静态校验 → tsc → 构建),构建镜像前必须全绿。
- **发布**:`build.sh`(本地构建推送,`linux/amd64` 固定)→ `deploy.sh`(服务器拉镜像,先备份 DB 再部署,健康校验)→ `rollback.sh`。DB 备份脚本 `backup-db.sh`。
- **宿主机依赖**:PostgreSQL 18 / Redis 8.6.1 / OpenResty / SSL 均由 1Panel 管理,本项目不负责(`deploy/docker-compose.yml:3-8`)。
---
## 4. 数据模型与持久化
### 4.1 模型逐表清单(19 张表)
建表顺序由 `utils/schemaFromModels.ts:30-56` 的 `MIGRATION_MODELS` 固化(必须先满足外键依赖)。所有表均 `underscore` 列名、`timestamps`。
| # | 表名 | 关键字段 | 关系 / 用途 |
| --- | --- | --- | --- |
| 1 | `roles` | name, description, status(enum enabled/disabled), permissions(JSON), isAdmin, deleted_at | 角色;`isAdmin=true` 直接映射全部权限 |
| 2 | `users` | username, password(bcrypt), role(legacy: admin/designer/optimizer), role_id, nickname, last_login_at, must_change_password, password_changed_at, password_version, client_scope_mode(all/restricted), deleted_at | 账号;口令版本 + 客户范围模式都在行上 |
| 3 | `clients` | name, remark, **naming_config(JSONB)**, deleted_at | 客户(=广告主/品牌),客户级配置的载体 |
| 4 | `user_clients` | user_id, client_id | 用户↔客户多对多,仅 `restricted` 模式生效 |
| 5 | `template_categories` | name, parent_id, customer_id | 树形分类(自关联) |
| 6 | `template_specifications` | name, width, height, orientation, description | 规格;`(width,height)` 唯一,名称派生 |
| 7 | `template_tags` | name, color, logo_path, customer_id | 标签(多值、带颜色、客户级) |
| 8 | `templates` | name, client_id, orientation, category_id, specification_id, psd_file_path, preview_image_path, **layer_config(JSON)**, created_by | 模板主表;`layer_config` 是图层契约 |
| 9 | `template_tag_relations` | template_id, tag_id | 模板↔标签中间表(另有 `tagsFilter` 别名专用于筛选,`associations.ts:67-74`) |
| 10 | `materials` | template_id, product_image_path, output_image_path, product_id, material_number, output_filename, extra_fields(JSONB), created_by, batch_id, batch_task_id, status, error_message, retry_count, low_quality_warning | 单张产出物;`low_quality_warning` 记录「抠图降级/压缩不足」 |
| 11 | `production_batches` | batch_number, task_type(single/batch), status, priority, client_id, created_by, template_ids(INT[]), total/success/failed_count, estimated/actual_duration, zip_file_path, zip_status, started_at, completed_at, **auto_cutout/size_limit/force_jpg/jpg_quality/png_colours/scale_mode/font_size**, **naming_snapshot(JSONB)** | 批次;**生产参数与命名规则在创建时快照**(L2 语义) |
| 12 | `batch_templates` | name, description, template_ids(INT[]), client_id, created_by, is_shared, deleted_at | 模板组合快捷方式 |
| 13 | `batch_tasks` | batch_id, template_id, product_image_path, product_id, product_name, brand_name, extra_fields(JSONB), **planned_filename**, status(pending/processing/completed/failed), error_code, error_message, retry_count, started_at, completed_at | 子任务;`planned_filename` 建单时预渲染(保证重试同名) |
| 14 | `notifications` | user_id, type, title, content, batch_id, is_read | 站内信 |
| 15 | `sequence_numbers` | date, current_seq | 每日批次号自增(`YYMMDD` + 3 位) |
| 16 | `system_configs` | config_key, config_value(JSONB), value_type, updated_by | 只存「用户改过的值」,默认值在注册表 |
| 17 | `system_config_audits` | config_key, old_value, new_value, operator | 配置变更审计(**完整存明文,没有脱敏**) |
| 18 | `user_audits` | action, target_username, operator_name, detail | 口令/账号审计(**刻意不建外键**,审计要比被审计者活得久) |
| 19 | `task_events` | batch_id, batch_number, batch_task_id, level(batch/task), event_type, status_from/to, failure_code/message, detail, metadata(JSONB), actor/creator/client 快照 | 任务事件流;快照冗余 + 90 天保留期 |
关系总图由 `models/associations.ts:17-236` 统一定义;删除策略:`batch_tasks` CASCADE 于批次,`notifications` CASCADE 于用户、SET NULL 于批次。
### 4.2 迁移机制
- **umzug 迁移**,不是 `sequelize.sync`:`DBSync.sync()` 启动即 `runMigrations()`(`utils/dbSync.ts:24-40`),账本 `SequelizeMeta`,迁移文件名去扩展名做身份(避免 ts/js 双执行,`migrator.ts:56-63`)。
- **11 个迁移 / 778 行**(`backend/src/migrations/`),全部幂等、带 `down`。初始迁移复用模型定义生成 DDL(`schemaFromModels.createSchemaFromModels`),避免模型与 DDL 两份漂移。
- **为什么不 alter**:实测开发库累积到「1112 个唯一约束 / 1154 个索引 / 18MB」,每次启动 ACCESS EXCLUSIVE 锁(`utils/migrator.ts:8-23`)。
- **初始化脚本**:`scripts/init-admin.ts`(管理员引导,口令来自 `ADMIN_INITIAL_PASSWORD`,无内置口令)、`scripts/migrate.ts`(migrate/status/baseline/rollback)、`scripts/backfill-password-flags.ts`、`scripts/clean-data.ts`、`scripts/clear-queue.ts`、`scripts/redis-namespace.ts`。
- **枚举/字典**:**没有独立字典表**。规格是专表;状态/类型用 TS 字面量联合类型 + 目录文件(`failureCatalog.ts`、`taskEventCatalog.ts`);字典化只做到文档层(见 §2 数据字典行)。
### 4.3 文件存储
| 目录 | 用途 | 是否受保护 | 证据 |
| --- | --- | --- | --- |
| `uploads/psd` | 模板 PSD 源文件 | ✅ 永不清理 | `storageCleanup.ts:65` |
| `uploads/preview` | PSD 解析后的预览 PNG(无损,平均 829KB,最大 2.37MB) | ✅ | `imageThumbnail.ts:22-32` |
| `uploads/product/<date>` | 商品原图 + 抠图中间产物 | ❌ 可清理 | `workers.ts:203` |
| `uploads/output/<date>` | 生成素材 | ❌ 可清理 | `workers.ts:234` |
| `uploads/zip/<date>` | ZIP 交付包 | ❌ 可清理(有保留天数) | `workers.ts:830-840` |
| `uploads/tag-logos` | 标签 logo | ✅ | `tagController.ts:24` |
| `uploads/temp` | 上传临时区 | ❌ 可清理 | `storageCleanup.ts:36-40` |
| `uploads/thumb/<w>` | 按需缩略图缓存(WebP q80) | ✅(随源删除 + 孤儿清扫) | `imageThumbnail.ts:40-60` |
- **对外 URL 规则**:`/uploads/<相对路径>`,JWT 鉴权(`Authorization` 头或 `<img>` 场景 `?token=`),追加 `?w=320|640` 返回 WebP 缩略图,失败静默回退原图(`middlewares/uploadThumbnail.ts:9-30`)。
- **容量与清理**:代码注释记录实测 732MB(psd 417M / output 146M / product 62M / zip 59M / preview 47M);本机副本 854MB / 775 文件。清理策略为「先预览、只删文件、绝不碰模板资产、默认只删孤儿」(`storageCleanup.ts:16-40`),可配保留天数 + 定时清理(默认关)。
- **路径安全**:所有客户端传入的相对路径必须过 `resolveUploadPath`(`..`/绝对路径/NUL 全拒绝),历史上曾有任意文件读取漏洞(`utils/uploadPath.ts:1-20`)。
### 4.4 Redis 用途与任务状态机
- **Redis 只做 BullMQ**:2 个队列(`material-generation` / `zip-packaging`)、项目级键前缀 `sucaigongfang`、可配 db(`REDIS_DB` 真正生效)。**限流用进程内存**(非 Redis),因此水平扩容会失效(`middlewares/rateLimit.ts:11-18` 自述待改)。
- **批次状态机**(`models/ProductionBatch.ts:12`):
`pending → processing → completed | failed`,旁支 `paused`(可 resume)与 `cancelled`(不可被收尾覆盖)。
- **结束态判定唯一来源** `utils/batchStatus.ts`:`completed|failed` 才算结束;`failed_count>0` 即 `failed`;`cancelled` 不允许被收尾改写(`batchStatus.ts:12-80`)。
- **子任务状态**:`pending → processing → completed|failed`;BullMQ `attempts=3` 时**中间轮次保持 processing**,只有最终失败才计入 `failed_count`(`workers.ts:324-401`,这是踩过「失败数按尝试次数累加 → 进度 300%」坑后的修正)。
- **ZIP 状态**:`none → generating → ready|failed`(`ProductionBatch.ts:24`)。
---
## 5. 关键机制
### 5.1 PSD 模板:上传 → 解析 → 图层约定 → 渲染合成
**① 解析**(`utils/psdParser.ts`)
- `readPsd(buffer)` + `initializeCanvas(@napi-rs/canvas)`;递归 `children` 提取图层(`psdParser.ts:104-161`)。
- 只识别 **3 类前缀**:`image_replacement_`(产品图替换)、`text_replacement_`(文本替换)、`clipping_mask_`(剪贴蒙版容器)(`psdParser.ts:123-147`)。
- 预览图:`psd.canvas → sharp().png()` 原尺寸无损落盘(`psdParser.ts:170-236`)。
**② 图层契约**(`models/Template.ts:10-34`)
```ts
LayerConfig {
imageReplacements: [{ layerName, type, description,
linkedContentLayer?, linkedClippingMask?, // 剪贴蒙版双向关联
scaleMode?: 'fill'|'contain'|'stretch' }]
textReplacements: [{ layerName, field(deprecated), textTemplate?, hideWhenEmpty?,
description, font?, fontSize? }]
}
```
**③ 文本图层 ↔ 客户字段匹配**(`utils/layerFieldMatcher.ts:1-20`,四层优先级)
1. `placeholder`:图层名直接写模板,如 `text_replacement_标题-{品牌名称}{商品名称}`(零配置,推荐给设计师);
2. `key`:去掉前缀等于字段名(`text_replacement_商品名称`);
3. `alias`:等于字段别名(`spmc`/`title`/`sku`/`pp`,不区分大小写);
4. `fuzzy`:含「标题/名称/title」等关键词兜底;
5. 未命中返回 null,**不猜测**(避免把静态文案层错绑成商品名)。
**④ 渲染合成**(`utils/materialComposer.ts`,1773 行,本仓库最核心资产)
- 入口 `compose(psdPath, layerConfig, productImagePath, outputPath, fields, forceJpg, sizeLimit, cutoutFailed, renderOptions)`(`materialComposer.ts:143`)。
- 流程:`readPsd` 全量图层 → 先渲染「非替换图层」到临时画布(用于取真实背景色)→ **以 PSD 合成 canvas 为底** → 处理替换图层(剪贴蒙版/真实背景/叠加/仅替换 四条分支)→ 输出编码。
- 支持:图层不透明度、**15 种混合模式**(multiply/screen/overlay/…/luminosity,`materialComposer.ts:427-477`)、隐藏图层跳过、剪贴蒙版 alpha 与形状蒙版、scaleMode 三档(fill/contain/stretch)。
- 文本渲染:`buildCanvasFont` 按 CSS 规则构造字体简写(**踩过引号不成对导致 `@napi-rs/canvas` Rust 层 panic → SIGABRT → 容器反复重启**的坑,`materialComposer.ts:100-125`);默认字体栈把项目内置中文字体放在最前,避免 node:24-slim 无中日韩字形时渲染成「豆腐块而任务仍报成功」。
- 输出约束:JPG 用**二分搜索质量**逼近大小上限;PNG 因 sharp 0.32.6 的 `quality` 无效,改为**调色板 colours 逐级减半**(`materialComposer.ts:258-357`);压不下去时返回 `lowQualityWarning` 而不是假报成功。
- **已知限制(对 PRD P-02 致命)**:所有 `imageReplacements` 图层共用**同一个 `productImageBuffer`**(`materialComposer.ts:222-236`、`516-620`),即「同一张商品图贴到多个位置」。**不支持**按图层注入不同资产(Logo/促销图/AI 模特/脚模),`type` 字段除 `clipping_mask` 外被忽略。
### 5.2 图片生成流水线(当前唯一真正可跑的产线)
```
上传商品图(≤100) → 按客户命名模板识别文件名(latin1→utf8 乱码修复)
→ 前端可编辑表格(商品图/商品ID/商品名称/品牌) → 校验必填(商品ID)
→ POST /api/batches(事务内建批次+子任务;命名快照;预渲染 planned_filename)
→ 事务外入队(失败不回滚,可用「重试」补救)
→ Worker:白底判定(ImageTypeDetector) → 是白底则 imgly 抠图
→ 抠图失败/产物缺失 ⇒ 回退原图 + cutoutFailed=true(写 low_quality_warning)
→ MaterialComposer.compose → 写 materials → 更新批次计数 → publishBatchUpdate(WS)
→ checkBatchCompletion → 有失败项=skipped failed / 全成功=completed
→ 站内信(成功/失败模板可配)+ 自动 ZIP 打包 → 下载
```
关键点:
- **交叉批量**:`totalTasks = templateIds.length * products.length`,双层循环(`productionBatchController.ts:839-840`、`:888-890`、`:948-950`)。
- **抠图是「条件触发 + 可降级 + 有痕迹」**:仅白底图抠(`workers.ts:193-230`),失败标记低质量而不是静默成功——这是全项目「不静默交付」原则的典型。
- **并发与内存**:素材 Worker 默认 **2 并发**(可页面 L3 热改 1–4),因为 API 与 Worker 同进程,抠图峰值可能吃掉数 GB(`workers.ts:52-66`)。
- **任务监控**:超时任务、ZIP 卡住由 `taskMonitor.ts` 巡检(默认 30 分钟 / 10 分钟,可配),恢复卡死批次。
- **重试语义**:BullMQ 自动重试 3 次 + 手动「重试失败项/继续执行」,`planned_filename` 保证重试同名不产生重复文件。
### 5.3 AI 生图:M0 / M1 / M2 三条线的真实结论
> **一句话:AI 能力目前全部停留在「验证工作台 + 文档」,`main` 分支没有任何 AI 产品代码;另有一条已声明作废的 M1 实现分支。**
**证据基线**:`grep -rniE "seedream|volc|方舟|ai.?image|aigc" backend/src frontend/src` **零命中**;`docs/AI生图相关功能-实现方案.md:4` 明确写「基线:main 分支现状(没有任何 AI 代码)+ 从零新写」。
#### M0 · VLM 反推 / 图层分离可行性(`tools/vlm-lab/`,10,469 行,已入库)
- 模型:A=`doubao-seed-2-1-pro-260915`、B=`qwen3.8-max-0902`;34 条原始记录。
- 结论(`docs/AI素材生成-M0验证记录.md:10-30`):坐标精度 IoU 几何 0.968/0.982、文字 0.819/0.833(达标);坐标格式**可被提示词控制**(11/11 遵从归一化);`json_schema` 严格模式 100% 合法;**图层分离真实跑通 96s 返回 12 图层**;免责声明可逐字锁定。
- 未达标:**换文案鲁棒性(溢出率 16.7%,未达 ≤5%)**、单张耗时(86–110s,关思考后 31.3s 达标)。对策是字段加 `maxChars`,不是放宽阈值。
- 状态:**验证完成,未产品化**。
#### M1 · 图片模板(非 PSD)契约 + 冻结 + Schema 渲染(分支 `backup/ai-asset-m1-20260923-1451`)
- 规模:**53 个提交**,相对 main 净增约 4.8 万行;其中新增文件 **后端 ~19,455 行 / 前端 ~11,928 行**(`aiTemplateController` 1341、`schemaRenderer` 2748、`layerMerge` 1200、`imageTemplateRenderer` 774、`aiProvider` 547…),分支整体约 10 万行。
- 目标(`docs/AI素材生成-M1正式开发方案与计划.md:16-25`):设计师传普通图片 → VLM 反推 → 人工框选确认 → 冻结契约 → 优化师填文案出图(≤5 分钟 + ≤3 分钟)。
- 已实现多条产品链路(合规闸门、警示语逐字比对、擦除遮罩、自由改图、品牌资产逐像素贴回等,见 `git log main..branch`)。
- **但已被最新方案整体否决**:`docs/AI生图相关功能-实现方案.md:6` 写明「M1 的文档与代码**整体作废,不参考、不复用**」,原因是需求方改口径为「生成图即成品,不套模板、不做契约/冻结/图层绑定」。
- 状态:**实验分支,不可作为交付物**(但不排除局部算法/经验可借鉴,如擦除遮罩、文字校验、合规词库)。
#### M2 · Seedream 表单式生图(`tools/ai-image-validation/`,2,122 行,已入库)
- 模型:`doubao-seedream-5-0-pro-260628` / `doubao-seedream-5-0-flash-260915`(`lib/config.mjs:27-31`);读图校验用 `doubao-seed-2-1-pro` 或 `qwen3.8-max` 交叉验证。
- 实测(34 张真实生成,34/34 成功;`docs/AI生图-M2-0验证记录.md:46-66`):
| 验证项 | 结论 |
| --- | --- |
| 中文文字逐字正确率 | ✅ 凡提示词写明文案的全部逐字正确(含中英数混排、6 卡片 9 处文案) |
| `background=transparent` | ✅ 成立(四角 alpha=0,全透明 70–78%),但输出有 20–28% 半透明像素,贴回**不能硬阈值抠图** |
| 多图参考融合(≤10 张) | ✅ 真融合(背景取风格图、主体取主体图) |
| flash vs pro | ✅ 文字/透明底打平,输出 token 相同(16428/张),**flash 快约 3 倍**(19–25s vs 55–76s)→ 建议默认 flash |
| 文字校验闸门 | ⚠️ 机制有效(5 个真错字样本全拦住、0 漏检;读图失败返回 `unchecked` 而非 `passed`),但「漏检率为 0」**不应作为上线门槛** |
| 账号级限流 | ⚠️ **真实存在**(撞过 `429 RPM limit exceeded`),产品化必须自己排队(工作台用 12s 串行节流) |
- **产品化差距**:M2-A 之后才写 `backend/` 代码(`tools/ai-image-validation/README.md:3-5`),当前**零集成**:没有 `ai` 配置模块、没有 AI 数据表、没有 AI 队列、没有前端页面。
- **成本**:**待确认**。M2-0 明确写「flash 单张价格待补,需把价格做成可配置项用于成本预估」(`docs/AI生图-M2-0验证记录.md:134-135`)。可确定的是:flash 单张 19–25s、输出 16,428 token/张;文字校验是**每张一次额外 VLM 调用**,会让耗时与费用接近翻倍(`docs/AI生图相关功能-实现方案.md:522`)。
- **密钥约束**:AI API Key **不能放系统配置**——`ConfigValueType` 没有 `secret` 类型,且 `SystemConfigAudit` 完整存 `oldValue/newValue` 不脱敏,Key 会长期明文留痕(`docs/AI素材生成-与现有系统整合方案.md:122-155`)。必须走 `.env` 或先补 secret 机制。
**AI 成熟度判定**:`M0 验证完成` → `M1 实现完成但作废` → `M2 验证完成(M2-0),产品代码未开始`。**统一平台若排 AI 生图,必须按「从零新建」估算,不能按「接入现有能力」估算。**
### 5.4 命名规范引擎(PRD P-04 的直接答案)
- **变量体系**(`backend/src/types/naming.ts:19-40`):系统变量 11 个(用户昵称/客户名称/模板名称/横竖版/任务编号/批次号/序号/素材序号/日期/时间/扩展名)+ 客户自定义字段(可映射 `productId/productName/brandName` 三个语义字段,其余落 `extra_fields` JSONB)。
- **默认模板**(`utils/namingConfig.ts:28-72`):
- 商品图识别:`['交易-sp{商品ID}-{商品名称}', '交易-sp{商品ID}']`
- 素材命名:`交易-sp{商品ID}-{横竖版}-{品牌名称}-{用户昵称}-{任务编号}-{序号}.{扩展名}`
- ZIP:`{客户名称}图片素材-{任务编号}`
- **三层兜底**:客户配置 → 客户配置不命中回落到旧 `FilenameParser` 宽松解析 → 仍失败用 `renderFallbacks`(商品ID/品牌默认 `unknown`)(`namingConfig.ts:352-403`)。
- **校验很实**:字段名不得与系统变量重名、别名不得跨字段重复、识别模板必须能编译且字段已定义、命名模板不得引用未知变量(`namingConfig.ts:240-328`)。前端 `NamingConfigEditor.tsx`(765 行)实时预览。
- **批次快照**(`types/naming.ts:104-119`):建单时固化 `materialTemplate/zipTemplate/renderFallbacks`,保证「客户事后改规则不影响在途/历史批次,重试产出同名文件」。
- **文件名安全**:非法字符清洗 `sanitizeFilename` + UTF-8 字节截断 `truncateFilename`(`namingTemplate.ts:177`、`:218`、`:277`)。**注意:main 分支没有「提交前重名门禁」**——若命名模板不含商品维度,同批次会产出同名文件;ZIP 下载路径里有注释承认「会互相覆盖」(`productionBatchController.ts:2096`),而「撞名返回 400」的重名门禁只存在于 AI 分支(`32f1a09`)。整合时需补这条校验。
### 5.5 客户级配置与数据范围
- **客户级配置范式**:`clients.naming_config` JSONB,`null` = 用系统默认(`models/Client.ts:61-65`)。AI 侧方案明确要求「新增客户级配置照这个模式,别发明新机制」(`docs/AI素材生成-与现有系统整合方案.md:19`)。
- **数据范围**:`users.client_scope_mode` + `user_clients`。语义是 **fail-closed**:`restricted + 无绑定 = 什么都看不到`,绝不放大成「全部客户」(`utils/clientScopeCore.ts:12-22`)。
- **落地很扎实**:涉及客户数据的 10 个 Router 都挂了 `attachClientScope`;模板清单、建批次、上传商品图、命名预览、批次模板都做 `checkClientReadable/Writable`;甚至专门修过「生产入口未消费客户范围 → 可用别家模板出图并套出命名规则」的安全 bug(commit `b7e2c68`、`100544e`)。
### 5.6 通知、站内信与 WebSocket
- **通知模板可配**:5 类模板(批次全部成功 / 部分失败 / 全部失败 / ZIP 就绪(自动清理)/ ZIP 就绪(保留)),支持变量占位(批次号、客户名称、数量、失败原因、过期日期),长度上限标题 60/内容 200,`uiControl: 'notification-templates'` 挂专用编辑器(`utils/notificationTemplates.ts:130-180`、`:411`)。
- **触发点**:`workers.ts` 批次完成与失败、ZIP 打包完成;开关可配(`notification.on_batch_completed` 等)。
- **前端形态**:顶栏铃铛 **hover 下拉**(最近 10 条 + 未读数 + 标记/删除/清空),**没有独立通知中心页**(`AdminLayout.tsx:126-133`、`:400-420`)。
- **WS**:`/ws?token=<jwt>`(浏览器 WS 不能带 header),推整行快照,300ms 按批合并,30s 心跳,鉴权失败 `4401` 让前端停止重连;前端 `useRealtimeBatches` 在无连接时降级轮询(`utils/realtime.ts:20-70`)。
### 5.7 系统配置框架(统一平台应整套继承)
- 40 个配置项 / 10 模块:basic(2)、production(9)、upload(3)、naming(1)、queue(8)、notification(4)、monitor(3)、security(5)、log(1)、storage(4)(`utils/systemConfigRegistry.ts:192-760`)。
- 每个配置项声明:`module/label/type/default/level/description/min/max/options/nullable/isPublic/warning/uiControl/uiControlMeta/validate`。
- **默认值只能定义在注册表**,DB 只存改过的值;`default` 支持函数形式从 env 派生(升级不重置现网调优)(`systemConfigRegistry.ts:33-100`)。
- **明确禁止**把进程级基础设施(JWT_SECRET/DB_*/REDIS_*/PORT)放进注册表——改完不生效只会制造错觉(`systemConfigRegistry.ts:1-20`)。
- 审计:`system_config_audits` 存 old/new,**不脱敏**(因此不适合放凭据)。
- 这套机制直接对应统一平台所需的「平台级参数、AI 模型/并发/上限、上传限制、队列并发、通知开关、安全策略」等集中治理。
---
## 6. 代码规模与质量
### 6.1 LOC / 文件数(口径命令)
```bash
cd 参考项目/sucaigongfang
# 后端源代码(ts/js,不含 node_modules/dist/uploads)
find backend/src -type f \( -name '*.ts' -o -name '*.js' \) -print0 | xargs -0 wc -l | tail -1
# → 30835
# 前端源代码(ts/tsx/css)
find frontend/src -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.css' \) -print0 | xargs -0 wc -l | tail -1
# → 32797
# 后端测试
find backend/tests -type f -name '*.ts' -print0 | xargs -0 wc -l | tail -1
# → 2078
# 文件数
find backend/src -type f -name '*.ts' | wc -l # 137
find frontend/src -type f \( -name '*.ts' -o -name '*.tsx' \) | wc -l # 74
```
| 模块 | 文件数 | LOC | 占比 | 说明 |
| --- | --- | --- | --- | --- |
| backend/utils | 55 | 14,169 | 46.0% | 渲染/队列/命名/配置/清理/日志,绝对核心 |
| backend/controllers | 17 | 9,746 | 31.6% | `productionBatchController` 2,404 行、`templateController` 1,500+ 行 |
| backend/models | 20 | 2,721 | 8.8% | 19 表 + associations |
| backend/scripts | 8 | 1,348 | 4.4% | 运维脚本 |
| backend/migrations | 11 | 778 | 2.5% | umzug |
| backend/middlewares | 6 | 766 | 2.5% | auth/clientScope/upload/rateLimit |
| backend/routes | 17 | 657 | 2.1% | 薄层 |
| backend/app.ts + types | 3 | 650 | 2.1% | 入口 + 类型 |
| **后端合计** | **137** | **30,835** | 100% | |
| frontend/pages | 16 | 16,705 | 50.9% | `Production` 2,625、`SystemConfig` 1,860、`TemplateList` 1,735、`Tasks` 1,610 |
| frontend/components | 24 | 8,303 | 25.3% | `BatchDetailDrawer` 1,125、`AdminLayout` 874、`TaskLogBoard` 779 |
| frontend/utils | 20 | 2,528 | 7.7% | 纯函数多,易复用 |
| frontend/types | 1 | 1,648 | 5.0% | 单文件类型字典 |
| frontend/styles | 7 | 1,561 | 4.8% | token/theme/arco-overrides |
| frontend/services | 1 | 1,223 | 3.7% | 113 个 API 方法 |
| frontend/hooks + stores + 入口 | 11 | 829 | 2.5% | 4 hooks + 2 store + App/main/index.css/App.css/arcoStyles.ts |
| **前端合计** | **74(+css)** | **32,797** | 100% | |
| **总计** | **211+** | **63,632** | — | 约 6.4 万行(与任务书「约 62k 行 TS」量级一致) |
补充:AI 验证工作台 `tools/vlm-lab` 10,469 行、`tools/ai-image-validation` 2,122 行(**非产品代码**);分支 `backup/ai-asset-m1` 整体约 10 万行。
### 6.2 TypeScript 严格度
- 后端 `tsconfig.json`:`strict: true`、`target ES6`、`skipLibCheck: true`(**无 `noUnusedLocals`/`noUncheckedIndexedAccess`**)。
- 前端 `tsconfig.app.json`:`strict` + `noUnusedLocals` + `noUnusedParameters` + `verbatimModuleSyntax` + `noFallthroughCasesInSwitch` + `erasableSyntaxOnly`(比后端更严)。
- 全量 `tsc --noEmit` 纳入 CI(前后端 + 测试独立 tsconfig),且后端生产镜像是 `tsc` 全量编译,类型错误会直接卡住镜像构建(`ci-local.sh:28-32`)。
### 6.3 测试
- `node --test`(Node 内置 test runner),**175 个用例 / 14 个文件 / 2,078 行**。
- 覆盖的都是「口径类纯函数」:通知模板(41)、统计趋势(26)、客户范围(23+4+2)、口令有效性与策略(14+11)、规格名称派生(13)、存储清理计划(10)、缩略图路径(10)、批次状态(8)、失败目录(7)、事件目录(3)、命名变量别名(3)。
- **缺口**:无 DB 集成测试、无 API 契约测试、无渲染快照测试、无 E2E(Playwright 只在另一项目里)。PSD 渲染这种最容易静默出错的模块,**没有自动化回归**。
### 6.4 Lint / CI
- 后端 `.eslintrc.js`(@typescript-eslint 8)+ prettier 3;前端 `.eslintrc.cjs` + react-hooks/react-refresh。
- `deploy/ci-local.sh` 六步:格式 → lint → 单测 → **前端设计 token 静态校验**(`scripts/verify-design-tokens.mjs`,穷举扫描 Arco CSS 变量三元组/完整色值混用)→ 失效筛选判定(`verify-invalid-filters.mjs`)→ tsc → 构建。
- 设计 token 校验被硬卡的原因写得很实在:Arco 变量格式用错**不报错、只静默失效**,2026-09 因此连续出过两次线上视觉事故(`ci-local.sh:18-24`)。
- 版本管理:commitizen(`git cz`),语义化提交(feat/fix/docs/refactor/style/chore/test/ci)。
### 6.5 技术债与已知问题(须带入整合评估)
| # | 问题 | 影响 | 证据 |
| --- | --- | --- | --- |
| 1 | **`docs/` 整体 gitignore,110 个文件 0 入库** | AI 验证结论、命名方案、部署手册都只存在本机;换人/换机即丢失上下文 | `.gitignore:122`、`tools/ai-image-validation/README.md:5-8` |
| 2 | API 与 Worker 同进程 | 无法独立扩缩容;Worker OOM/崩溃会连带 API;`uncaughtException` 直接退出 | `app.ts:64-78`、`app.ts:402` |
| 3 | 文件存储纯本地磁盘 | 多副本/多机部署不可行;无 OSS/S3 适配层 | `utils/uploadPath.ts:20`、`docs/AI多行业素材生成方案.md:87` |
| 4 | 登录限流用进程内存 | 水平扩容后限流失效(代码自述) | `middlewares/rateLimit.ts:11-18` |
| 5 | 无 `secret` 配置类型、审计不脱敏 | API Key 等凭据不能进系统配置 | `docs/AI素材生成-与现有系统整合方案.md:122-155` |
| 6 | 渲染引擎只支持单张商品图 | 无法做 Logo/促销/AI 模特多资产叠加 | `materialComposer.ts:222-236` |
| 7 | 大量 `console.log` 混在渲染器里 | 生产日志噪音大、性能损耗 | `materialComposer.ts:288-357` |
| 8 | 文档漂移:`database/README.md` 写「15 张表」实际 19;`deploy.sh:16-20` 仍写「启动 DBSync alter」实际已是 umzug | 运维按文档操作会误判 | `database/README.md:11`、`deploy/deploy.sh:16-20`、`utils/dbSync.ts:9-40` |
| 9 | `estimatedDuration` 后端从未写入,前端曾据此展示「预估剩余时间」 | 已修(前端改为不显示),但字段仍是死字段 | `pages/Home.tsx:306-310` |
| 10 | 标签 logo 上传后端有、前端未接线 | 资产能力半成品 | `tagController.ts:21-37`、`frontend/src` 无 `logoPath` 消费 |
| 11 | `history` 路由被注释 | 素材历史页缺失 | `App.tsx:118-120` |
| 12 | sharp 锁 `0.32.6` | 升级需回归 PNG 量化行为 | `backend/package.json:45`、`materialComposer.ts:317-329` |
| 13 | Windows 下抠图不可用(动态 require 降级) | 开发环境与生产行为不一致 | `utils/backgroundRemover.ts:5-30` |
| 14 | 前端菜单/路由/权限映射三处硬编码 | 加一个模块要改 4 处,易漏 | `AdminLayout.tsx:85-98`、`:763-841`、`App.tsx:100-120` |
| 15 | **权限模型只有「页面级」,没有「动作级」**;任务日志因此刻意不提供暂停/取消/重试 | 统一平台的提审、投放配置、AI 产出复核都需要动作级/数据级权限,现模型不够用 | `routes/taskLogRoutes.ts:18-24`、`utils/permissions.ts:4-20` |
| 16 | 素材历史(`materials`)与生产批次两套记录并存,前者无页面 | 后续若做「素材资产/提审」会有两套口径 | `routes/materialRoutes.ts:28-34`、`App.tsx:118-120` |
---
## 7. 逐模块复用评估(核心交付)
### 7.1 逐模块评估表
> 复用级别:**A=几乎直接复用**;**B=改造可控**;**C=需重写**;**D=废弃**。
> 人日为「改造成统一平台形态」的粗估,不含产品/测试/联调,需与研发负责人校准。
| 模块 | 现有实现 | 统一平台中的目标形态 | 复用级别 | 改造要点 | 粗估人日 | 风险 |
| --- | --- | --- | --- | --- | --- | --- |
| 工程地基(Express/Sequelize/PG/umzug/日志/健康检查) | 17 Router、19 模型、11 迁移、结构化错误兜底 | 统一后端基座 | **A** | 拆 `platform` 维度;健康检查增加 OSS/第三方 AI 探活 | 3–5 | 低 |
| 认证 / 口令安全 / 限流 / 审计 | JWT+pwdv、强制改密、三态有效期、一次性口令、IP+用户名限流 | 同一套 | **A** | 限流迁 Redis(为多副本) | 2–3 | 低 |
| RBAC + 客户数据范围 | 权限 key 目录 + `fail-closed` 范围 + 全链路校验 | 平台/客户双层范围 | **A** | 权限 key 按新模块扩充;客户范围升级为「平台×客户」 | 3–4 | 权限遗漏=静默越权,需补回归测试 |
| 系统配置框架 | 40 项/10 模块/L1-L3/审计/专用控件 | 加 `platform`、`ai`、`selection`、`video` 模块 | **A** | 加 `secret` 类型 + 审计脱敏(AI Key 前置条件) | 3–5 | 低 |
| 模板/分类/标签/规格管理 | 完整 CRUD + 批量 + 复制 + 自动匹配 | 平台级模板资产库 | **B** | 加 `platform_id`/`project`;标签 logo 接入渲染;规格扩三档 | 8–10 | 模板迁移与兼容 |
| PSD 解析与渲染引擎 | 1773 行合成器 + 字体兜底 + 质量压缩 | 多资产合成(模板/商品/AI模特/信息/Logo) | **B** | **核心改造:按图层注入不同资产**;Logo 组合与拼接字符;促销图层;三尺寸派生 | 12–18 | 改造面大、无自动化回归、字体版权 |
| 抠图 | imgly + ONNX medium + 白底判定 + 降级告警 | 同能力 | **A** | 抽成独立推理服务(可选);非白底/透明底策略 | 2–3 | 单机 ONNX 内存峰值 |
| 批量任务/队列/进度/收尾/重试 | BullMQ 2 队列 + DB 计数 + WS + 监控 + 失败口径 | 多产线统一任务中心 | **A** | 队列按产线拆分;Worker 独立进程化(可选) | 6–8 | 同进程 OOM |
| 命名规则引擎 | 变量模板 + 客户级 + 快照 + 校验 + 商品图识别 | 提审命名规范引擎 | **A** | 变量域扩 `SPUID/平台/活动/日期` 等;与提审状态联动 | 3–4 | 字段域扩展后校验规则要同步 |
| 导出 / ZIP / 下载 | CSV + 选集 ZIP + 整批 ZIP 异步 | 按路径导出/打包 | **A** | 导出字段调整;路径规则(平台/项目专用路径) | 3–4 | 低 |
| 通知 / 站内信 / WS | 可配模板 + 3 类触发 + 铃铛下拉 + WS | 通知中心(含提审/投放事件) | **B** | 补独立通知中心页;补事件类型;WS 跨进程改 Redis pub/sub | 3–4 | 低 |
| 任务事件 / 失败目录 / 时间线 / 任务日志 | 事件目录 + 失败目录 + 90 天保留 + 管理端看板 | 统一可观测中心 | **A** | 新增事件类型;权限粒度可能需细分 | 3–4 | 低 |
| 文件存储 / 缩略图 / 清理 | 本地磁盘 + 按需 WebP + 先预览后清理 | 对象存储 + CDN | **B** | 抽 `StorageAdapter`(local/OSS),URL 规则改造,清理策略按存储对象 | 4–6 | **迁移期双写/回填** |
| 前端设计体系/布局/守卫/共享组件 | token 单点 + 自动校验 + AssetThumb/StatCard/SectionCard 等 | 统一设计系统 | **B** | 菜单/路由/权限映射改为配置驱动;主题换肤 | 5–7 | 菜单硬编码三处耦合 |
| 素材制作页(2625 行) | 选模板/传图/识别/填字段/参数/二次确认 | 「平台 → 选品 → 品类 → 尺寸 → 模板 → 展示方式 → Logo/促销 → 预览 → 导出」 | **C** | 按新信息架构重写,复用其上传识别与字段表格逻辑 | 10–15 | 新交互未定稿即返工 |
| 首页 Dashboard | 5 卡环比 + 今日任务 + 待我处理 | 新 KPI(单套成本/模板占比/提审通过率) | **C** | 指标口径重定义 + 后端聚合 | 3–5 | 指标口径待业务确认 |
| AI 生图 | **无可运行产品代码**(仅 M2-0 验证) | 9 要素表单→提示词→生成→校验→挑图→入生产 | **C** | 从零:模型网关、配额排队、成本预估、文字校验闸门、素材落库、UI | 20–30 | 成本/限流/合规/一致性 |
| AI 素材生成(M1 分支) | 53 commits / ~3.1 万行新增 | — | **D** | 官方已声明作废;仅可借鉴擦除遮罩/文字校验/合规词库经验 | 0(不计) | 误用会引入大量死代码 |
| 数据字典 / 枚举 | 仅文档 + 未合并分支 | 字典类型→字典项(code/label/description) | **C** | 重写(表+API+页面+权限),供 AI 提示词与筛选消费 | 3–4 | 低 |
| 多平台 / 平台切换 | 无 | 得物/唯品会切换,资源路径按平台隔离 | **C/新建** | 平台表、平台上下文、菜单/模板/命名/ZIP 全链路带平台 | 5–8 | 与客户维度正交,需先定数据模型 |
| 选品 / 原始物料获取 | 无(在 Electron 桌面端) | 商品检索(SPUID/粗词)→ 圈选 → 详情页图片抓取归档 | **新建** | 迁移 `dewu-material-Downloader` 的抓取能力到服务端 + 物料库 | 15–25 | 平台反爬/登录态/合规 |
| 视频素材 AI 生产 | 无 | 脚本(AI/人工)→ 画面 → 组合,16:9 / 9:16 | **新建** | 完全新产线(模型选型、异步长任务、素材管理) | 40+ | 成本、时长、质量不可控 |
| 提审 | 无 | 待审清单 + 状态跟踪 + 与素材/商品关联 | **新建** | 新表+状态机+清单页+通知事件 | 8–12 | 平台提审口径未定义 |
| 投放配置(DP/承接页) | 无 | 输入点(SPUID/官网链接)→ 自动生成链接 → 一键复制/批量替换 | **新建** | 新表+生成规则+批量操作+校验 | 8–12 | 规则来源与合规未确认 |
### 7.2 能否直接作为统一 WEB 平台的技术底座?
**结论:能作为「图片素材产线 + 平台工程地基」的底座,但不能直接当作整个统一平台的底座。**
**可以成立的四个理由**
1. **工程底座是成熟的**:认证/权限/客户范围/系统配置/迁移/队列/事件/失败目录/通知/打包/部署/CI,几乎覆盖统一平台 70% 的「非业务」工作量,且质量高于平均水平(大量注释是「为什么这么写 + 踩过什么坑」,对后来者价值极高)。
2. **图片产线的主干已经跑通**:PSD 模板 → 图层契约 → 批量交叉生产 → 命名 → 打包 → 交付,正是 PRD P-02 的骨架。
3. **命名引擎就是 P-04 的一半**,且实现质量明显高于「按规范重写」的预期(客户级可配 + 快照 + 兜底 + 校验)。
4. **可观测性天然具备**:任务事件时间线 + 失败分类目录 + 管理端任务日志,统一平台最容易忽略、又最难后补的东西这里已经有了。
**必须补齐的 8 块(按优先级)**
| # | 缺口 | 现状 | 建议 |
| --- | --- | --- | --- |
| 1 | **多平台/项目抽象** | 完全无「平台」概念 | 先定数据模型:`platform`(得物/唯品会)+ 资源路径规则 + 平台上下文贯穿模板/命名/ZIP/导出 |
| 2 | **选品 / 原始物料获取** | 在另一 Electron 项目 | 服务端化抓取(登录态/反爬/限速),建物料库与 SPU 关联 |
| 3 | **四层信息中的三块**(展示方式/Logo/促销) | 只有单品图 + 文本 | 改造渲染引擎支持「按图层注入不同资产」;Logo 组合与拼接字符;促销模板叠加 |
| 4 | **视频素材产线** | 空白 | 独立产线,勿与图片产线耦合;先做脚本/画面/组合三段 MVP |
| 5 | **提审** | 空白 | 新状态机 + 清单 + 通知 + 与素材/商品稳定关联 |
| 6 | **投放配置** | 空白 | DP/承接页生成器 + 批量替换 + 一键复制 |
| 7 | **对象存储 / 队列水平扩展** | 本地磁盘 + 同进程 Worker + 内存限流 | 抽存储适配层;Worker 独立进程 + Redis 限流;否则多副本不可行 |
| 8 | **权限体系细化** | 菜单级 key + 客户范围 | 提审/投放/AI 需要更细的能力点 + 数据范围(平台×客户) |
**一个必须提前说明的取舍**:若把「AI 生图」和「视频」放进同一期,本系统的「单进程 + 本地磁盘 + 同步重 CPU 渲染」架构会先撞墙——**图片渲染(CPU/内存密集)与 AI 调用(长耗时、外部限流)应该分属不同队列与不同 Worker 进程**,这在原系统里是有意合并的(`app.ts:65-66`),整合时必须拆。
---
## 8. 可复用资产清单
### 8.1 后端(可直接搬运/改造)
| 资产 | 路径 | 价值 |
| --- | --- | --- |
| PSD 渲染合成引擎 | `backend/src/utils/materialComposer.ts`(1773 行) | 剪贴蒙版/混合模式/缩放模式/字体兜底/质量压缩,全项目最贵资产 |
| 字体管理 | `backend/src/utils/fontManager.ts` + `backend/fonts/方正兰亭中黑简体.TTF` | 字体扫描双目录 + 别名兜底(防豆腐块事故);**字体商用授权待确认** |
| PSD 解析 | `backend/src/utils/psdParser.ts` | 图层前缀识别 + 预览图生成 |
| 图层字段匹配 | `backend/src/utils/layerFieldMatcher.ts` | placeholder/key/alias/fuzzy 四级匹配,纯函数可单测 |
| 抠图 | `backend/src/utils/backgroundRemover.ts` + `imageTypeDetector.ts` | 白底判定 + ONNX 抠图 + 降级告警 |
| 命名引擎 | `backend/src/utils/namingTemplate.ts`、`namingConfig.ts`、`namingRuleResolver.ts`、`filenameParser.ts`、`types/naming.ts` | 变量模板/识别/校验/快照,纯函数多 |
| 队列与 Worker | `backend/src/utils/queue.ts`、`workers.ts`(1074 行)、`batchTasks.ts`、`batchStatus.ts`、`taskMonitor.ts` | 入队/重试/收尾/超时/卡死恢复 |
| 任务事件体系 | `taskEvents.ts`、`taskEventCatalog.ts`、`failureCatalog.ts`、`taskEventQuery.ts` | 事件目录 + 失败目录 + 保留期,可观测底座 |
| 系统配置框架 | `systemConfigRegistry.ts`(40 项)、`systemConfigService.ts`、`models/SystemConfig(Audit).ts` | 声明式配置 + L1/L2/L3 + 审计 |
| 权限与范围 | `utils/permissions.ts`、`clientScope.ts`、`clientScopeCore.ts`、`middlewares/auth.ts`、`middlewares/clientScope.ts` | RBAC + fail-closed 数据范围 |
| 账号安全 | `utils/passwordPolicy.ts`、`passwordExpiry*.ts`、`middlewares/rateLimit.ts`、`utils/jwt.ts` | 口令策略/有效期/令牌失效/限流 |
| 文件服务 | `utils/uploadPath.ts`、`imageThumbnail.ts`、`thumbnailPath.ts`、`storageCleanup.ts`、`storageCleanupScheduler.ts`、`middlewares/upload(Thumbnail|Auth).ts` | 路径安全 + 按需缩略图 + 预览式清理 |
| 通知模板 | `utils/notificationTemplates.ts` | 变量化模板 + 校验 + 渲染 |
| 实时推送 | `utils/realtime.ts` | 整行快照 + 节流 + 心跳 + 401 停止重连 |
| 迁移机制 | `utils/migrator.ts`、`dbSync.ts`、`schemaFromModels.ts`、`backend/src/migrations/*`(11 个) | 模型即 DDL 来源 + 幂等迁移 |
| 运维脚本 | `backend/src/scripts/*`(init-admin/migrate/backfill/clean/clear-queue) | 部署与数据治理 |
| 数据模型 | `backend/src/models/*`(19 表)+ `associations.ts` | 用户/客户/模板/批次/任务/事件/配置全量 |
| API 契约 | `backend/src/routes/*`(113 接口)+ `frontend/src/services/api.ts`(113 方法) | 前后端一一对应的契约样板 |
| 测试 | `backend/tests/*`(175 用例) | 纯函数测试范式,可直接扩展 |
### 8.2 前端(可直接复用)
| 资产 | 路径 | 价值 |
| --- | --- | --- |
| 设计 token / 主题 | `frontend/src/styles/tokens.ts`、`theme.ts`、`arco-overrides.css` | 字号 7 档/颜色/圆角/控件描边,全站唯一来源 |
| 设计规范 + 自动校验 | `frontend/前端设计规范.md`、`frontend/scripts/verify-design-tokens.mjs` | 规范落到可执行脚本(CI 硬卡) |
| 布局与守卫 | `components/AdminLayout.tsx`、`AuthGuard.tsx`、`PermissionGuard.tsx` | 侧栏/面包屑/通知/用户菜单/双守卫 |
| 复用组件 | `AssetThumb`(统一缩略图)、`StatCard`、`SectionCard`、`HelpTip`、`BatchEventTimeline`、`TaskLogTimeline`、`TemplateHoverPreview`、`useHoverPreview` | 直接可用 |
| 业务重组件 | `BatchDetailDrawer`(1125 行)、`TaskLogBoard`、`LayerBindingEditor`、`NamingConfigEditor`、`NotificationTemplatesEditor`、`ImageLayerTable`、`TemplateChecklist` | 改造后价值高 |
| 工具函数 | `utils/naming.ts`、`assetUrl.ts`、`download.ts`、`clipboard.ts`、`batchDisplay.ts`、`taskEvents.ts`、`specification.ts`、`realtime.ts` | 纯函数,易搬 |
| 页面参考 | `pages/Production.tsx`、`Tasks.tsx`、`TemplateList.tsx`、`SystemConfig.tsx`、`UploadTemplate.tsx`/`EditTemplate.tsx` | 作为重构蓝本而非直接复制 |
| 发布说明(12 篇) | `frontend/发布说明-*.md` | 记录每次改动与踩坑,交接价值高 |
### 8.3 文档(**注意:全部未入库**)
| 文档 | 价值 |
| --- | --- |
| `docs/AI素材生成-M0验证记录.md`(924 行) | VLM 反推/图层分离的实测数据与 Go/No-Go 判定 |
| `docs/AI生图-M2-0验证记录.md`(335 行) | Seedream 五项门槛实测、flash/pro 对比、限流与成本注意点 |
| `docs/AI生图相关功能-实现方案.md`(757 行) | 最新 AI 口径(表单化/不套模板)+ 9 要素表单 + 官方参数硬边界 |
| `docs/AI素材生成-与现有系统整合方案.md`(459 行) | 代码勘察结论、API Key 不能进配置、整合顺序 |
| `docs/AI多行业素材生成方案.md`(959 行) | 契约化方案(已部分作废,但行业分析/现有能力边界表仍有效) |
| `docs/命名规范梳理与客户级配置方案.md`(874 行) | 命名现状/硬编码落点/改造影响面 |
| `docs/数据字典与枚举管理评估.md`(478 行) | 字典建模结论(code/label 分离、单值/多值取舍) |
| `docs/系统配置页面规划文档-v2.md`(799 行) | L1/L2/L3 分级的来源与「不要放进页面」清单 |
| `docs/通知中心页面需求.md`(92 行) | 通知中心独立页的交互稿(未实现) |
| `docs/用户使用手册.md`(543 行) | 三个角色的真实操作路径 |
| `deploy/部署上线手册.md` | 容器化部署/迁移/回滚的标准流程 |
| `tools/vlm-lab/`、`tools/ai-image-validation/` | 可复跑的 AI 验证工作台(**注意 config.json 含真实 Key,永不入库**) |
---
## 9. 风险与待确认问题
### 9.1 六个最大风险
| # | 风险 | 说明 | 影响 | 缓解建议 |
| --- | --- | --- | --- | --- |
| R1 | **单机架构撞上「多产线 + AI」** | API 与 Worker 同进程、抠图 ONNX 单机内存峰值、本地磁盘存储、内存限流(`app.ts:65-66`、`rateLimit.ts:11-18`) | 无法水平扩容;AI 长任务会拖垮图片产线的 API 响应;OOM 导致整站不可用 | 整合前先拆三层:API / 图片渲染 Worker / AI 任务 Worker;存储抽象层 + 对象存储;限流迁 Redis |
| R2 | **AI 生图从零开始,成本与合规双未知** | 无产品代码;flash 单张 19–25s、16,428 token;文字校验接近翻倍;账号级 IPM 限流真实存在;单张单价未获取(`docs/AI生图-M2-0验证记录.md:62-65`、`:134-135`) | 排期与成本预估都会失真;上线后易被限流/账单打爆 | 先做 1 人日连通性与配额压测;把单价与日调用上限做成配置;默认 flash;强制人工复核闸门 |
| R3 | **PSD 渲染引擎改造的正确性风险** | 1773 行、无自动化回归、只支持单商品图;字体/混合模式/剪贴蒙版细节多(`materialComposer.ts`) | 一次改造就可能让存量模板产出错图,且**错误是静默的**(图能出、内容错) | 建立「存量模板黄金样本 + 像素级回归」再动引擎;灰度客户;保留旧渲染器开关 |
| R4 | **PRD 的四层信息与现引擎不匹配** | Logo 组合/拼接字符、促销模板、AI 模特/脚模都要「按图层注入不同资产」,现引擎共用一个 `productImageBuffer`(`materialComposer.ts:222-236`) | P-02 的验收标准(四层信息)达不到 | 把「多资产图层」列为引擎改造第一优先级;先与产品确认四层的技术边界 |
| R5 | **文档与知识全部未入库** | `docs/` 110 文件 0 入库;AI 验证结论只在本机(`.gitignore:122`) | 人员变动/机器损坏即丢失决策上下文;「为什么这么设计」无法追溯 | 整合启动第一件事:文档入库(或迁到统一知识库),先抢救 AI 验证结论与配置分级结论 |
| R6 | **平台/客户维度正交 + 存量数据迁移** | 现在只有「客户」,PRD 要「平台(得物/唯品会)」;模板/命名/ZIP/导出都要带平台;现有 854MB 文件与 19 表数据要迁 | 模型改错代价最大(迁移难回滚);历史产出可能无法归属到平台 | 先出「平台 × 客户 × 项目」数据模型评审;迁移脚本先 dry-run + 备份;不动 19 表而是加列/加表 |
**其余风险(次级)**:中文/字体版权(`方正兰亭中黑简体.TTF` 商用授权待确认);PSD 兼容性(`ag-psd` 对智能对象/文字特效/图层样式的支持边界未系统测试);许可证(依赖多为 MIT/Apache,但 `sharp 0.32.6`/`onnxruntime` 需过安全扫描);AI 输出内容合规(券商场景已证明需要人工复核,电商场景的商标/肖像/功效宣称同样有风险)。
### 9.2 待确认清单
| 编号 | 问题 | 为什么影响整合 | 建议向谁确认 |
| --- | --- | --- | --- |
| Q-01 | 统一平台的「平台」是数据维度还是独立部署?(得物/唯品会是否共享同一套模板与命名规则) | 决定是否需要给 19 张表加 `platform_id`,以及资源路径规则 | 产品负责人 + 运营 |
| Q-02 | 图片产线是否必须保留「PSD 模板」为唯一模板载体?是否允许图片模板(非 PSD)并存? | 决定是否复活 M1 分支的 SchemaRenderer,还是只改造 MaterialComposer | 产品 + 设计负责人 |
| Q-03 | AI 生图的定位:替代 PSD 产线,还是「无模板场景」的补充产线? | 决定 AI 是 P0 还是 P2,以及是否与模板体系解耦 | 产品负责人 |
| Q-04 | 三规格(800×800 / 1280×720 / 1080×1920)是固定枚举还是可扩展规格? | 现有规格是通用 `(w,h)` 实体;固定则逻辑更简单 | 产品 + 设计 |
| Q-05 | Logo 的「拼接方式与拼接字符」具体是什么交互?字符是否需要上传字体/图形? | 决定渲染引擎是否需要「图形组合器」,工作量差异大 | 设计负责人 + 唯品会对接人 |
| Q-06 | 促销信息(折扣/活动标识)是模板叠加还是独立图层组? | 决定促销图层的模型与编辑器 | 设计 + 运营 |
| Q-07 | 选品主键:得物用 SPUID、唯品会用什么?是否统一? | 决定物料库与模板变量域 | 运营 + 平台对接人 |
| Q-08 | 详情页图片抓取是否有合规/授权依据?是否需要登录态? | 决定选品模块可行性与架构(是否要浏览器自动化) | 法务 + 运营 |
| Q-09 | 提审是「平台后台人工提审」还是「系统内审批流」?需要跟踪到哪一级状态? | 决定提审模块是轻量清单还是完整工作流 | 运营 + 产品 |
| Q-10 | DP / 承接页的生成规则由谁提供?是否有稳定模板与校验规则? | 决定投放配置模块是「规则引擎」还是「固定拼接」 | 运营 + 平台对接人 |
| Q-11 | AI 生图的单张成本上限与日预算?可接受的单张耗时? | 决定模型档位(flash/pro)、是否做文字校验、是否批量 | 财务 + 产品 |
| Q-12 | AI 生图是否需要「文字逐字校验 + 人工复核」双闸门? | 决定额外 VLM 调用成本(接近翻倍)与流程设计 | 合规 + 产品 |
| Q-13 | 视频素材的模型选型、时长上限、单条预算? | 视频是最大不确定性,需前置验证(M0 式) | 产品 + 财务 |
| Q-14 | 视频/图片产出是否需要对象存储与 CDN?部署形态是单机还是多副本? | 决定是否必须先做存储适配层与 Worker 拆分 | 运维 + 技术负责人 |
| Q-15 | 字体商用授权:`方正兰亭中黑简体` 是否已购买商用授权?新增字体如何管理? | 字体是合规红线,且换字体会改变渲染结果 | 法务 + 设计 |
| Q-16 | 存量数据(19 表 + 854MB 文件)是否需要迁移?迁移到哪个平台维度? | 决定迁移工作量与回滚方案 | 产品 + 运维 |
| Q-17 | 「历史选品」「历史脚本」「模板复用次数」等 P1 指标是否需要埋点体系? | 现有统计只有批次/素材维度,无选品/脚本 | 产品 + 数据 |
| Q-18 | 统一平台是否需要多租户(不同客户数据硬隔离)?还是继续「单部署 + 客户范围」? | 决定权限与存储架构(这是最大的架构分叉) | 技术负责人 + 业务负责人 |
---
## 10. 证据索引
> 格式:结论 → `文件:行`。均为本次只读勘察直接可见。
| # | 结论 | 证据 |
| --- | --- | --- |
| 1 | 17 个业务 Router 挂载 + 静态文件 + 健康检查 | `backend/src/app.ts:147-164`、`:139-144`、`:175-201` |
| 2 | API 与 BullMQ Worker 同进程 | `backend/src/app.ts:65-66`、`:402` |
| 3 | WebSocket 复用同一 http.Server | `backend/src/app.ts:429-432` |
| 4 | 17 个控制器 / 113 个接口 | `backend/src/routes/*.ts`(逐文件 `router.<verb>` 计数) |
| 5 | 19 张表与建表顺序 | `backend/src/utils/schemaFromModels.ts:30-56`、`models/*.ts` 的 `tableName` |
| 6 | umzug 迁移取代 `alter:true` 及原因 | `backend/src/utils/migrator.ts:8-30`、`utils/dbSync.ts:9-40` |
| 7 | 批次/子任务/结束态状态机与失败口径 | `models/ProductionBatch.ts:12-51`、`models/BatchTask.ts:19-34`、`utils/batchStatus.ts:12-80` |
| 8 | 生产参数与命名规则在建批次时快照(L2) | `models/ProductionBatch.ts:37-48`、`productionBatchController.ts:680-712`、`:797-806`、`:873-877` |
| 9 | 交叉批量 N×M 与命名预渲染 | `productionBatchController.ts:839-840`、`:888-908`、`:948-950` |
| 10 | 素材 Worker 主流程(抠图→合成→落库→计数→WS) | `utils/workers.ts:70-412`、`:193-230`、`:271-312` |
| 11 | 自动重试与「最终失败才计数」的语义 | `utils/workers.ts:324-401` |
| 12 | ZIP 打包 Worker | `utils/workers.ts:764-860` |
| 13 | PSD 只识别 3 类图层前缀 | `utils/psdParser.ts:123-147` |
| 14 | 图层契约结构(图片/文本/剪贴蒙版/缩放模式) | `models/Template.ts:10-34` |
| 15 | 文本图层↔字段四级匹配(placeholder/key/alias/fuzzy) | `utils/layerFieldMatcher.ts:1-20` |
| 16 | 合成器入口与签名 | `utils/materialComposer.ts:143-154` |
| 17 | 以 PSD 合成画布为底 + 替换图层四分支 | `utils/materialComposer.ts:212-236`、`:516-620` |
| 18 | 15 种混合模式支持 | `utils/materialComposer.ts:427-477` |
| 19 | 字体简写引号不成对导致 SIGABRT 的坑 | `utils/materialComposer.ts:100-125` |
| 20 | 中文字体兜底栈(防豆腐块静默交付) | `utils/materialComposer.ts:27-38`、`utils/fontManager.ts:1-40` |
| 21 | JPG 二分质量 / PNG 调色板减半压缩 | `utils/materialComposer.ts:258-357` |
| 22 | **所有图片替换图层共用同一张商品图** | `utils/materialComposer.ts:222-236`、`:585-620`、`:750-752` |
| 23 | 默认命名模板与字段定义 | `utils/namingConfig.ts:28-72` |
| 24 | 系统变量清单(11 个) | `backend/src/types/naming.ts:19-40` |
| 25 | 命名配置校验(重名/别名/未知变量) | `utils/namingConfig.ts:240-328` |
| 26 | 批次级命名快照结构 | `backend/src/types/naming.ts:104-119` |
| 27 | 商品图识别三层兜底(客户→legacy→fallback) | `utils/namingConfig.ts:352-403` |
| 28 | 系统配置注册表与 L1/L2/L3 | `utils/systemConfigRegistry.ts:1-100`、`:192-760`(40 个 key) |
| 29 | 权限 key 目录(11 个)与历史角色兜底 | `utils/permissions.ts:4-45` |
| 30 | 客户范围 fail-closed 语义 | `utils/clientScopeCore.ts:12-22`、`:40-60` |
| 31 | 登录限流为进程内存(扩容失效) | `middlewares/rateLimit.ts:11-30` |
| 32 | 口令策略/强制改密/令牌版本 | `docs/PRD.md:46-56`、`middlewares/auth.ts:1-80`、`models/User.ts:1-60` |
| 33 | 存储目录保护清单与清理原则 | `utils/storageCleanup.ts:16-65` |
| 34 | 缩略图按需生成 + 失败回退原图 | `utils/imageThumbnail.ts:22-60`、`middlewares/uploadThumbnail.ts:9-30` |
| 35 | 上传路径越界漏洞与修复 | `utils/uploadPath.ts:1-40` |
| 36 | 通知模板可配 + 变量 | `utils/notificationTemplates.ts:38-180`、`:411-455` |
| 37 | WS 整行快照 + 300ms 节流 + 心跳 | `utils/realtime.ts:20-70` |
| 38 | 任务事件目录与 90 天保留 | `utils/taskEventCatalog.ts:1-40`、`utils/taskEvents.ts:15-45` |
| 39 | 失败原因目录(code/audience/rawDetail) | `utils/failureCatalog.ts:1-50` |
| 40 | 任务监控(超时/卡死/巡检可配) | `utils/taskMonitor.ts:9-40` |
| 41 | 规格名称由尺寸派生、唯一性迁到尺寸 | `utils/specificationName.ts:46-57`、`migrations/20260924000001-specification-name-derivation.ts:1-40` |
| 42 | CI 六步硬卡与设计 token 校验动机 | `deploy/ci-local.sh:24-45`、`frontend/前端设计规范.md:1-12` |
| 43 | 容器化部署与网络模型 | `deploy/docker-compose.yml:1-40`、`frontend/Dockerfile:1-66`、`frontend/nginx.conf.template:20-80` |
| 44 | 健康检查真实探活 DB/Redis | `backend/src/app.ts:175-201` |
| 45 | `docs/` 全目录被 gitignore(110 文件 0 入库) | `.gitignore:122`、`git ls-files docs` = 0、`find docs -type f` = 110 |
| 46 | AI 生图「main 无任何 AI 代码 + 从零新写」 | `docs/AI生图相关功能-实现方案.md:4-11`、`grep -rniE "seedream|volc|aigc" backend/src frontend/src` = 0 |
| 47 | M1 分支被整体作废 | `docs/AI生图相关功能-实现方案.md:6`、`git log main..backup/ai-asset-m1`(53 commits) |
| 48 | M2-0 五项验证结论(34 张全成功、flash 快 3 倍、透明底成立) | `docs/AI生图-M2-0验证记录.md:8-11`、`:46-66`、`:120-135` |
| 49 | AI 账号级 IPM 限流真实存在 | `docs/AI生图-M2-0验证记录.md:62-65`、`tools/ai-image-validation/lib/config.mjs:59` |
| 50 | AI API Key 不能进系统配置(无 secret 类型 + 审计不脱敏) | `docs/AI素材生成-与现有系统整合方案.md:122-155` |
| 51 | AI 验证工作台不是产品代码 | `tools/ai-image-validation/README.md:3-8`、`tools/ai-image-validation/lib/config.mjs:1-12` |
| 52 | M0 反推/图层分离结论与未达标项 | `docs/AI素材生成-M0验证记录.md:10-35` |
| 53 | M1 验收定义与量化门槛 | `docs/AI素材生成-M1正式开发方案与计划.md:16-25`、`:1275-1298` |
| 54 | 现系统无视频/提审/投放/平台/抓取/OSS | 以下 grep 均 **0 命中**:`grep -rniE "ffmpeg\|\bvideo\b" backend/src frontend/src`、`grep -rniE "\boss\b\|s3\|minio\|对象存储" backend/src`、`grep -rniE "crawl\|scrape\|puppeteer\|playwright" backend/src frontend/src`、`grep -rniE "提审\|审核" backend/src frontend/src`、`grep -rniE "平台切换" backend/src frontend/src`(「得物」仅在通知模板示例中) |
| 55 | 文档漂移:database README 写 15 表、deploy 注释写 alter | `database/README.md:11`、`deploy/deploy.sh:16-20` |
| 56 | `estimatedDuration` 从未写入 | `frontend/src/pages/Home.tsx:306-310` |
| 57 | 素材历史页被注释、历史 API 仍在 | `frontend/src/App.tsx:118-120`、`backend/src/routes/materialRoutes.ts:28-34` |
| 58 | 标签 logo 后端有、前端未消费 | `controllers/tagController.ts:21-37`、`grep -rn "logoPath" frontend/src` 仅 `types/index.ts` |
| 59 | 端口/部署实测环境 | `deploy/docker-compose.yml:1-30`、`生产环境部署/PRODUCTION.md:1-8`(旧文档已自标失效) |
| 60 | 提交活跃度与时间分布 | `git log --format='%ad' --date=format:'%Y-%m' \| sort \| uniq -c`(3 月 85 / 4 月 33 / 9 月 131) |
---
### 附:本报告未展开的部分
- `dewu-material-Downloader`(另一参考项目,Electron 桌面端)只做了边界确认:它承担「得物素材下载」能力,**未做深读**,选品/抓取的服务端化评估需以其专项报告为准。
- `docs/API文档/` 下 4 份火山方舟 PDF(约 4.9–7MB/份)为二进制,未解析;模型参数边界以 `docs/AI生图相关功能-实现方案.md:15-70` 的摘录为准。
- `frontend/发布说明-*.md`(12 篇)仅做存在性登记,未逐篇展开。
- 未运行任何测试/构建,所有质量结论均来自静态代码与脚本内容;「实际能否一次跑通」属**待确认**。