From 6096568621ded686c706664c93b60418b49b890e Mon Sep 17 00:00:00 2001 From: Stev_Wang <304865932@qq.com> Date: Fri, 30 Oct 2026 14:13:00 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=E5=8F=8C=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E6=95=B4=E5=90=88=E8=AF=84=E4=BC=B0=E3=80=81=E8=B0=83?= =?UTF-8?q?=E7=A0=94=E6=8A=A5=E5=91=8A=E4=B8=8E=E6=8A=80=E6=9C=AF=E6=A0=88?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E5=AE=9A=E7=A8=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增双项目整合可行性评估 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 文档索引与仓库结构 --- README.md | 9 +- docs/技术架构/技术栈架构_定稿_V1.0.md | 1014 ++++++++++++++ docs/评估/_调研/dewu-调研报告.md | 726 ++++++++++ docs/评估/_调研/sucaigongfang-调研报告.md | 740 +++++++++++ ...台电商素材生产平台_整合可行性评估_V0.1.md | 1173 +++++++++++++++++ 5 files changed, 3660 insertions(+), 2 deletions(-) create mode 100644 docs/技术架构/技术栈架构_定稿_V1.0.md create mode 100644 docs/评估/_调研/dewu-调研报告.md create mode 100644 docs/评估/_调研/sucaigongfang-调研报告.md create mode 100644 docs/评估/平台电商素材生产平台_整合可行性评估_V0.1.md diff --git a/README.md b/README.md index 0aa919c..c3c6f0a 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,11 @@ | 文档 | 版本 | 状态 | 位置 | | --- | --- | --- | --- | | 平台电商素材生产平台 PRD(产品需求文档) | V0.1 | 草稿 | [docs/PRD/平台电商素材生产平台_PRD_V0.1.md](docs/PRD/平台电商素材生产平台_PRD_V0.1.md) | +| 双项目整合可行性评估(评审稿) | V0.1 rev.2 | 待评审 | [docs/评估/平台电商素材生产平台_整合可行性评估_V0.1.md](docs/评估/平台电商素材生产平台_整合可行性评估_V0.1.md) | +| **技术栈与架构定稿** | **V1.0** | **已定稿** | [docs/技术架构/技术栈架构_定稿_V1.0.md](docs/技术架构/技术栈架构_定稿_V1.0.md) | +| 参考项目调研报告(内部,已脱敏) | — | 调研底稿 | [docs/评估/_调研/](docs/评估/_调研/) | -PRD V0.1 已完成「1.1 背景与问题」「1.2 产品目标」及整体章节框架,其余章节待补充。 +PRD V0.1 已完成「1.1 背景与问题」「1.2 产品目标」及整体章节框架,其余章节待补充。整合评估基于两个参考项目的代码与文档通读,结论为「有条件 Go」,前置条件见评估文档 §10/§11。 ## 仓库结构 @@ -25,7 +28,9 @@ PRD V0.1 已完成「1.1 背景与问题」「1.2 产品目标」及整体章节 . ├── README.md └── docs/ - └── PRD/ 产品需求文档(Markdown) + ├── PRD/ 产品需求文档(Markdown) + ├── 评估/ 整合可行性评估 + 参考项目调研底稿 + └── 技术架构/ 技术栈与架构定稿 ``` ## 协作说明 diff --git a/docs/技术架构/技术栈架构_定稿_V1.0.md b/docs/技术架构/技术栈架构_定稿_V1.0.md new file mode 100644 index 0000000..7f7f9ea --- /dev/null +++ b/docs/技术架构/技术栈架构_定稿_V1.0.md @@ -0,0 +1,1014 @@ +# 平台电商素材生产平台 · 技术栈与架构定稿 + +> **文档类型**:技术栈与架构设计(定稿) +> **版本**:V1.0 | **状态**:已定稿(评审通过后进入 M0) | **日期**:2026-10-30 +> **适用范围**:统一 WEB 平台(选品 → 原始物料 → 图片/视频生产 → 命名 → 提审 → 投放配置) +> **输入依据**:`docs/PRD/平台电商素材生产平台_PRD_V0.1.md`、两份参考项目调研报告、`docs/评估/平台电商素材生产平台_整合可行性评估_V0.1.md` +> **环境基线(已在本机核实)**:macOS arm64、Node **v24.15.0**、pnpm **11.4.0**、PostgreSQL **18.4**(Docker,5432)、Redis **7.4.9**(Docker,6379) +> **密级**:内部;本文不含平台签名盐、账号、密钥等敏感值。 + +--- + +## 目录 + +0. 定稿结论(一页纸) +1. 决策依据与约束 +2. 技术栈总表(版本锁定) +3. 架构总览 +4. Monorepo 结构与包职责 +5. 前端架构 +6. 后端架构 +7. 数据层(PostgreSQL 18 + Prisma 7) +8. Redis、队列与实时 +9. 文件与对象存储 +10. 平台适配与 Playwright +11. 图片产线 +12. AI 网关 +13. 认证、权限、凭据与安全 +14. 工程规范与质量门禁 +15. 开发环境与命令 +16. 构建与部署 +17. 版本治理 +18. 与评估文档的差异 +19. M0 必须验证的风险 +20. 明确不采用的技术与理由 +21. 附录 A:`.npmrc` 与根配置 +22. 附录 B:依赖清单 +23. 附录 C:待确认项 + +--- + +## 0 定稿结论(一页纸) + +| 决策 | 定稿 | 关键理由 | +|---|---|---| +| 运行时 | **Node.js 24.15.0(精确版本)** | 与开发机一致;Prisma 7 引擎要求 `^24.11`;Vite 8 要求 `>=22.12` | +| 包管理 | **pnpm 11.4.0(唯一)** | 与开发机一致;workspace 严格依赖;**不使用 npm** | +| 语言 | TypeScript **5.9.3**(strict) | typescript-eslint 8.72 要求 `<6.1`,暂不上 TS 7 | +| 前端 | React **19.3.1** + **Semi Design 2.104.0** + **Tailwind CSS 4.3.3** + Vite **8.3.5** | Semi 支持 React 19(dewu 已验证);Tailwind 4 由 scgf 验证;Vite 8 满足 Tailwind/Semi 插件 | +| 后端 | **Express 5.3.0** + **Prisma 7.10.1** + **PostgreSQL 18** + **Redis 7** + **BullMQ 6.5.0** | Express 5 可迁移 scgf 中间件;Prisma 7 是当前稳定线(8 仍为 RC);PG/Redis 已在本机运行 | +| 数据访问 | **Prisma 7.10.1 + `@prisma/adapter-pg`**(ESM) | 类型安全、迁移一体化;19 表模型需重写(+8~12 人日,见 §18) | +| 队列/实时 | BullMQ 5 类队列 + **SSE**(不用 WebSocket) | 任务进度是单向流;SSE 对 nginx/公网更友好 | +| 图像 | sharp **0.32.6(锁定)** + ag-psd **30.1.0** + @napi-rs/canvas **0.1.97** + fontkit **2.0.4** + ONNX 抠图 | 与 scgf 图像引擎行为一致,降低存量模板回归风险 | +| 平台自动化 | **Playwright 1.64.1**(独立 platform-worker) | 送审必须页面自动化;独立进程隔离;账号级串行锁 | +| 部署 | **单机 Docker Compose**(api + 4 worker + web/nginx) | 首期够用;代码保持无本地状态,后续可平滑扩副本 | +| 对象存储 | **开发本地磁盘 / 生产 OSS(S3 适配层)** | 开发机不新增容器;生产支持多副本与签名 URL | +| 数据库/缓存部署 | **复用开发机已有 Docker(PG 18 / Redis 7),平台不负责安装** | 用户明确要求;`.env` 直连 localhost | + +> **与评估文档的差异**(详见 §18):ORM 由评估时的 Sequelize 改为 **Prisma**,工作量 **+8~12 人日**(全量 383~569 → **391~581 人日**);UI 由评估的 Tailwind 3 改为 **Tailwind 4**(+1~3 人日验证,在不确定性内);其余方案不变。 + +--- + +## 1 决策依据与约束 + +### 1.1 硬约束(用户已确认) + +| 约束 | 值 | 来源 | +|---|---|---| +| Node.js | **24.15.0** | 与开发机一致 | +| 包管理 | **pnpm**,非必要不用 npm | 用户明确要求 | +| PostgreSQL | **18**(开发机 Docker `postgres:18-alpine`,实际 18.4,5432) | 用户明确要求 | +| Redis | **7**(开发机 Docker `redis:7-alpine`,实际 7.4.9,6379) | 用户明确要求 | +| 部署 | 内部平台,但**公网可访问 + 登录鉴权** | 用户确认 | +| 对象存储 | 开发本地磁盘,生产 OSS | 用户确认 | +| 数据库/缓存 | 开发前直接开启已有容器,平台不做安装/编排 | 用户明确要求 | +| 形态 | 统一 WEB 平台,桌面端停止演进 | 用户确认 | +| 工程 | 新建统一工程 + 迁移两个参考项目资产 | 用户确认 | +| UI | Semi Design 最新版(支持 React 19)+ Tailwind CSS 4 | 用户确认 | +| ORM | Prisma | 用户确认 | + +### 1.2 参考项目继承关系 + +| 资产 | 来源 | 在本工程中的处理 | +|---|---|---| +| 认证/口令安全/RBAC/客户范围/系统配置/任务事件/通知/导出 | scgf `backend/src` | 迁移业务逻辑;**数据访问层改为 Prisma**,模型重写 | +| PSD 解析/合成/抠图/字体/命名引擎 | scgf `utils/*` | 代码级迁移;渲染行为锁定(sharp/ag-psd/canvas 版本不变) | +| 星光签名/字段映射/送审命名/混剪规则/DPLink/审核 CSV | dewu `scripts/lib/*`、`electron/platform/*` | 抽为 `packages/domain` / `packages/platform-dewu`;纯逻辑几乎原样迁移 | +| 送审批次策略(串行/幂等/回查/审计) | dewu `electron/submit/*` | 迁移逻辑,存储改 DB + Redis | +| 只读接口层、商品详情 SSR 直取 | dewu `electron/platform/*`、`shop/detail.ts` | 服务端化,去掉 Electron | +| Electron 外壳/更新/签名/窗口/本地文件 | dewu `electron/*` | 废弃 | +| 页面信息架构(选品/物料/审核/送审/投放) | dewu `src/pages/*` | 交互参考;组件按 Semi 2.104 重写 | +| 页面信息架构(模板/生产/任务/配置) | scgf `frontend/src/pages/*` | 交互参考;按新 IA 重写 | + +### 1.3 本机实测结论(定稿依据) + +| 项 | 实测 | 结论 | +|---|---|---| +| Node | `v24.15.0` | 与要求一致;Prisma 7 要求 `^24.11`,满足 | +| pnpm | `11.4.0` | 锁定;`packageManager` 写 11.4.0 | +| PG | `PostgreSQL 18.4`(alpine,5432) | 直连;使用 PG18 原生 `uuidv7()` | +| Redis | `redis_version:7.4.9`(6379) | BullMQ 6 支持 Redis 7 | +| 图像原生依赖 | sharp 0.32.6、ag-psd 30.1.0、@napi-rs/canvas 0.1.97、fontkit 2.0.4、@imgly/background-removal-node 1.4.5 均可在 Node 24.15 arm64 加载(libvips 8.14.5) | 锁定该组合作为图像基线 | +| pnpm registry 最新版本 | Semi 2.104.0、Tailwind 4.3.3、Vite 8.3.5、Prisma 7.10.1、Express 5.3.0、BullMQ 6.5.0、Playwright 1.64.1 | 见 §2 版本总表 | + +--- + +## 2 技术栈总表(版本锁定) + +> 标记 **🔒** 的为精确锁定(升级需回归/评审);其余使用 caret 范围 + 提交 lockfile。 +> 版本以 2026-10-30 查询/实测为准;`pnpm-lock.yaml` 是唯一事实来源。 + +### 2.1 运行时与工具链 + +| 类别 | 技术 | 版本 | 说明 | +|---|---|---|---| +| 运行时 | Node.js | **24.15.0 🔒** | `.nvmrc`、`engines`、Docker 镜像三处一致 | +| 包管理 | pnpm | **11.4.0 🔒** | `packageManager`;corepack;禁止 npm | +| 语言 | TypeScript | **5.9.3 🔒** | strict;typescript-eslint 8.72 要求 `<6.1` | +| 开发执行 | tsx | 4.23.15 | 后端/脚本热执行 | +| 构建 | Vite | **8.3.5 🔒** | 前端;Node `>=22.12` | +| Lint | ESLint | **10.13.0 🔒** | flat config | +| Lint | typescript-eslint | **8.72.1 🔒** | 支持 ESLint 8/9/10、TS `<6.1` | +| 格式 | Prettier | 3.9.10 | 与 ESLint 分离 | +| 单测 | Vitest | **5.0.5 🔒** | 支持 Vite 8 | +| 覆盖率 | @vitest/coverage-v8 | 5.0.5 | — | +| E2E | Playwright | **1.64.1 🔒** | 同时用于平台自动化;浏览器版本随包锁定 | + +### 2.2 前端 + +| 类别 | 技术 | 版本 | 说明 | +|---|---|---|---| +| 框架 | React / react-dom | **19.3.1 🔒** | Semi 2.104 支持 React 19 | +| 路由 | react-router-dom | 7.18.5 | Data Router;路由级 lazy | +| 组件库 | @douyinfe/semi-ui | **2.104.0 🔒** | 最新稳定;zh_CN、暗色、Table/Form/Upload/Tree | +| 组件库构建 | @douyinfe/semi-vite-plugin | **2.104.0 🔒** | 主题/CSS Layer;peer vite `>=3` | +| 图标 | @remixicon/react | 4.9.0 | 与 Semi 搭配 | +| CSS | Tailwind CSS | **4.3.3 🔒** | `@tailwindcss/vite` 4.3.3;`@theme` token | +| 构建插件 | @vitejs/plugin-react | **6.1.2 🔒** | peer Vite `^8`;React 19 | +| 状态 | zustand | 5.0.16 | 会话/UI 状态 | +| 服务端状态 | @tanstack/react-query | 5.105.0 | 列表/轮询/缓存 | +| HTTP | axios | 1.21.0 | 拦截器、刷新令牌、上传进度 | +| 表单 | react-hook-form | 7.91.0 | 复杂表单 | +| 校验 | @hookform/resolvers + zod | 6.0.2 / 4.6.7 | 与后端共享 schema | +| 图表 | recharts | 3.10.1 | Dashboard | +| 日期 | dayjs | 1.11.23 | zh-cn | +| Markdown | marked | 18.1.2 | 发版说明/富文本白名单渲染 | +| 测试 | @testing-library/react | 16.3.3 | React 19;配合 jsdom 30.1.3 | + +### 2.3 后端 + +| 类别 | 技术 | 版本 | 说明 | +|---|---|---|---| +| Web 框架 | Express | **5.3.0 🔒** | 迁移 scgf 中间件;不选 Nest/Fastify | +| ORM | Prisma | **7.10.1 🔒** | 稳定线;8 仍为 RC,不采用 | +| ORM 客户端 | @prisma/client | **7.10.1 🔒** | ESM;`prisma-client` 生成器 | +| PG 驱动适配 | @prisma/adapter-pg | **7.10.1 🔒** | 连接 PG18 | +| PG 驱动 | pg | 8.23.1 | 适配器/运维脚本/健康检查 | +| 数据库 | PostgreSQL | **18(18.4)🔒** | 已有 Docker;PG18 `uuidv7()` | +| 缓存/队列 | Redis | **7(7.4.9)🔒** | 已有 Docker | +| Redis 客户端 | ioredis | **6.0.0 🔒** | BullMQ 6 推荐 | +| 队列 | BullMQ | **6.5.0 🔒** | 5 类队列;Redis 7 兼容 | +| 鉴权 | jsonwebtoken | 9.0.3 | access/refresh + pwdv | +| 密码 | bcrypt | 6.0.0 | 复用 scgf 策略 | +| 上传 | multer | 2.5.0 | 内存/临时盘;大文件直传 OSS | +| 校验 | zod | 4.6.7 | DTO/环境变量/表单共享 | +| 日志 | pino + pino-http | 10.4.0 / 11.0.0 | 结构化 JSON | +| 安全头 | helmet | 8.3.0 | 公网暴露必配 | +| CORS | cors | 2.8.6 | 白名单 | +| 压缩 | compression | 1.8.2 | 静态/JSON | +| 限流 | express-rate-limit + rate-limit-redis | 8.7.2 / 6.0.2 | Redis 共享限流 | +| 打包 | archiver | 8.0.0 | ZIP level 9 | +| 表格 | exceljs | 4.4.0 | CSV/XLSX 导入导出 | +| ID | uuid | 14.0.3 | 仅应用侧特殊场景;主键用 PG `uuidv7()` | +| 环境变量 | dotenv | 18.0.9 | dev 加载;prod 由编排注入 | +| 指标 | prom-client | 15.1.3 | `/metrics` | +| 对象存储 | @aws-sdk/client-s3 + presigner | 3.1160.0 | S3/MinIO | +| 阿里云 OSS | ali-oss | 6.23.0 | 生产 OSS 驱动 | +| MFA(管理员) | otplib | 13.5.0 | TOTP;公网暴露必配 | + +### 2.4 图像 / PSD / 平台 / AI + +| 类别 | 技术 | 版本 | 说明 | +|---|---|---|---| +| 图像处理 | sharp | **0.32.6 🔒** | 与 scgf 引擎行为一致;不可随意升级 | +| PSD 解析 | ag-psd | **30.1.0 🔒** | 图层读取 | +| Canvas | @napi-rs/canvas | **0.1.97 🔒** | 合成画布 | +| 字体 | fontkit | **2.0.4 🔒** | 字体名/排版 | +| 抠图 | @imgly/background-removal-node | **1.4.5 🔒** | ONNX medium;独立 Worker | +| 浏览器自动化 | Playwright | **1.64.1 🔒** | platform-worker;Chromium 版本随包 | +| AI Provider | 火山方舟 Seedream(图片)/ 视频模型待选 | 通过 REST 适配 | 不绑定 SDK;密钥只走环境变量 | +| AI 校验 | VLM(文字逐字/合规) | 通过 REST 适配 | 可插拔 provider | + +### 2.5 为什么是这些版本(关键兼容性证据) + +| 组合 | 证据 | +|---|---| +| Node 24.15 + Prisma 7.10.1 | Prisma engines:`^22.18 \|\| ^24.11 \|\| >=26`;`@prisma/client`:`^20.19 \|\| ^22.12 \|\| >=24.0` | +| Vite 8.3.5 + Node 24.15 | Vite engines:`^20.19.0 \|\| >=22.12.0` | +| Vite 8 + Tailwind 4 | `@tailwindcss/vite` peer:`^5.2 \|\| ^6 \|\| ^7 \|\| ^8` | +| Vite 8 + Semi 插件 | `semi-vite-plugin` peer:`vite >=3` | +| Vite 8 + plugin-react 6.1.2 | peer `vite ^8`;其 oxc/babel peer 均为 optional | +| React 19.3 + Semi 2.104 | Semi peer `react >=16`;dewu 已在 React 19.3 + Semi 2.103 生产验证 | +| TS 5.9.3 + typescript-eslint 8.72 | typescript-eslint peer `typescript >=4.8.4 <6.1.0`(故不选 TS 7.0.2) | +| ESLint 10 + typescript-eslint 8.72 | peer 支持 `^10.0.0` | +| BullMQ 6.5 + Redis 7.4 | BullMQ peer `ioredis >=5`、Node `>=14.18`;Redis 7 兼容 | +| 图像栈 + Node 24 arm64 | 本机实测 5 个原生包全部加载成功(libvips 8.14.5) | + +--- + +## 3 架构总览 + +### 3.1 运行拓扑(开发环境) + +> 开发机不新增 PG/Redis 容器:平台进程直接连已有 Docker;文件落本地目录。 + +``` +┌───────────────────────────── macOS 开发机 ─────────────────────────────┐ +│ │ +│ 浏览器 ──http://localhost:5173──▶ Vite dev server(apps/web) │ +│ │ /api 代理 │ +│ ▼ │ +│ apps/api(Express 5,:8300) │ +│ │ │ │ +│ │ ├──▶ PostgreSQL 18.4 :5432 │ +│ │ │ (Docker 已有) │ +│ │ ├──▶ Redis 7.4.9 :6379 │ +│ │ │ (Docker 已有) │ +│ │ └──▶ 本地磁盘 ./var/uploads │ +│ │ │ +│ 独立进程(pnpm dev:workers): ▼ │ +│ worker-image(PSD/合成/抠图) worker-platform(Playwright 有头/无头) │ +│ worker-ai(生图/视频) worker-export(ZIP/CSV/打包) │ +│ │ │ +│ └──▶ BullMQ 队列(Redis) │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +### 3.2 运行拓扑(生产) + +``` + 公网(HTTPS) + │ + ┌────────▼────────┐ + │ WAF / 云防护 │ (可选但建议) + └────────┬────────┘ + ┌────────▼────────┐ + │ nginx(web 镜像)│ SPA + /api 反代 + SSE + /files + └────────┬────────┘ + │ + ┌────────────────────┼────────────────────┬────────────────────┐ + ▼ ▼ ▼ ▼ + api ×1~N worker-image ×1~N worker-platform ×1 worker-export/ai + │ │ │ │ + └──────────┬─────────┴──────────┬─────────┴──────────┬─────────┘ + ▼ ▼ ▼ + PostgreSQL 18 Redis 7 对象存储(OSS/S3) + (托管/独立容器) (队列/锁/限流) (物料/成片/导出包) +``` + +**关键设计**: +- API 无状态(会话在 JWT/Redis;文件在对象存储)→ 可水平扩副本。 +- Worker 按负载类型拆进程:图像/抠图吃 CPU+内存,Playwright 吃内存+浏览器,AI 吃网络等待,导出吃 IO。 +- 平台账号写操作在 `worker-platform` 内**按账号串行**,API 不直接开浏览器。 + +### 3.3 请求与任务链路 + +``` +同步请求:浏览器 → nginx → api → Prisma(PG) → 返回 +异步任务:api 建任务行(PG)→ 入 BullMQ(jobId = taskId)→ worker 执行 + → 更新任务行 + 写 task_event → Redis Pub/Sub → api SSE → 浏览器 +文件:上传 → api 签发上传凭证(或本地直存)→ 对象存储/本地盘 → 记录 storage_key + 下载 → api 校验权限 → 302 签名 URL / 流式代理 +``` + +--- + +## 4 Monorepo 结构与包职责 + +### 4.1 目录 + +``` +lingxi/ +├── package.json # 根:scripts、engines、packageManager +├── pnpm-workspace.yaml +├── pnpm-lock.yaml # 唯一事实来源 +├── .nvmrc # 24.15.0 +├── .npmrc # engine-strict=true 等 +├── tsconfig.base.json +├── prisma/ +│ ├── schema.prisma # 唯一 schema +│ ├── migrations/ # prisma migrate 生成 +│ └── seed.ts +├── apps/ +│ ├── web/ # React 19 + Semi + Tailwind 4(Vite 8) +│ ├── api/ # Express 5(BFF + 业务 API) +│ ├── worker-image/ # sharp/ag-psd/canvas/抠图 +│ ├── worker-platform/ # Playwright:登录/送审/审核/投放 +│ ├── worker-ai/ # 生图/视频 +│ └── worker-export/ # ZIP/CSV/XLSX +├── packages/ +│ ├── shared/ # zod schema、DTO、错误码、枚举、类型 +│ ├── domain/ # 命名引擎、送审规则、DPLink、审核映射(纯逻辑) +│ ├── platform-dewu/ # 星光签名/只读接口/页面自动化 +│ ├── platform-vipshop/ # 唯品会适配(M3 起) +│ ├── db/ # Prisma client 单例、事务工具、Repository +│ ├── storage/ # StorageAdapter(local / s3 / oss) +│ ├── ai/ # Provider 接口 + Ark 实现 + 成本核算 +│ └── ui/ # 设计 token + Semi 封装 + 通用组件 +├── infra/ +│ ├── docker/ # 各镜像 Dockerfile +│ ├── nginx/ # SPA + API + SSE + /files +│ ├── compose/ # dev/prod compose +│ └── scripts/ # db-create、备份、健康检查 +├── test/ +│ ├── integration/ # PG/Redis 集成测试 +│ ├── golden/ # PSD 黄金样本 + 像素 diff +│ └── e2e/ # Playwright +└── docs/ +``` + +### 4.1.1 模块规范 + +- 全仓库 **ESM**:各包 `package.json` 设 `"type": "module"`,`tsconfig` 用 `module: NodeNext` + `verbatimModuleSyntax`。 +- Prisma 7 使用 `prisma-client` 生成器产出 ESM client,统一从 `@lingxi/db` 导入。 +- 后端构建用 `tsc`(ESM 输出),开发用 `tsx`;不使用 CommonJS `require`。 +- 禁止跨包相对路径引用;统一 `@lingxi/*` workspace 协议。 + +### 4.2 包依赖规则 + +| 规则 | 说明 | +|---|---| +| `apps/*` 不得被其他包依赖 | 应用是组合根 | +| `packages/domain` 只依赖 `shared` | 纯逻辑、可单测、不碰 DB/HTTP | +| `packages/platform-*` 依赖 `domain` + `shared` | 平台协议/页面自动化;不反向依赖 API | +| `packages/db` 只暴露 Prisma client 与 Repository | 禁止业务直接 import Prisma client 到处用 | +| `packages/ui` 只依赖 React/Semi/Tailwind | 不含业务请求 | +| 跨包引用走 `@lingxi/*` workspace 协议 | `pnpm` 严格链接,禁止相对路径穿透 | + +### 4.3 根 scripts(只用 pnpm) + +```json +{ + "packageManager": "pnpm@11.4.0", + "engines": { "node": "24.15.0", "pnpm": "11.4.0" }, + "scripts": { + "dev": "pnpm --parallel -r --filter @lingxi/web --filter @lingxi/api run dev", + "dev:workers": "pnpm --parallel -r --filter './apps/worker-*' run dev", + "build": "pnpm -r build", + "lint": "eslint .", + "format": "prettier --write .", + "typecheck": "pnpm -r typecheck", + "test": "vitest run", + "test:integration": "vitest run -c vitest.integration.config.ts", + "test:e2e": "playwright test", + "db:create": "tsx infra/scripts/db-create.ts", + "db:migrate": "prisma migrate dev", + "db:deploy": "prisma migrate deploy", + "db:seed": "prisma db seed", + "db:studio": "prisma studio", + "playwright:install": "playwright install chromium" + } +} +``` + +--- + +## 5 前端架构(React 19 + Semi 2.104 + Tailwind 4) + +### 5.1 应用结构 + +``` +apps/web/src/ +├── app/ # 入口、路由、Provider、错误边界 +├── layouts/ # 侧边栏/顶栏/权限布局 +├── features/ +│ ├── platform/ # 平台切换 +│ ├── selection/ # 选品/圈选/历史 +│ ├── materials/ # 原始物料 +│ ├── image/ # 模板/制作/批量/预览 +│ ├── video/ # 脚本/画面/成片 +│ ├── review/ # 提审/审核 +│ ├── delivery/ # 投放配置/DPLink +│ ├── assets/ # 模板/Logo/展示/促销/脚本资产 +│ └── system/ # 用户/角色/客户/配置/任务日志 +├── shared/ # api client、hooks、utils、权限、i18n +└── styles/ # tailwind.css、semi-theme.css、tokens.css +``` + +- 路由:`react-router-dom` 7 Data Router;按 `features` 懒加载;路由守卫统一在 `app/routes.tsx`。 +- 权限:后端 `/auth/me` 返回 `permissions[]`;菜单/按钮用 ``;**前端不作为安全边界**,后端每个接口独立校验。 +- 状态:服务端状态全部走 TanStack Query;仅会话/主题/布局用 zustand。禁止把列表数据塞 zustand。 +- 请求:单一 `shared/api/client.ts`(axios);自动附加 access token;401 触发一次 refresh;失败统一 toast + 错误码映射。 +- 表单:react-hook-form + zod(schema 来自 `@lingxi/shared`),Semi Form 作为展示层。 + +### 5.2 Semi 2.104 + Tailwind 4 集成(必须按此顺序,否则静默失效) + +```css +/* apps/web/src/styles/index.css —— 顺序 = 层叠优先级(M0 Spike 最终确认) */ +@layer theme, base, semi, components, utilities; + +@import "tailwindcss"; +@import "@douyinfe/semi-ui/dist/css/semi.min.css" layer(semi); +@import "./semi-theme.css" layer(semi); /* Semi CSS 变量覆盖 */ +@import "./tokens.css"; /* 品牌 token(@theme) */ +``` + +**硬性约定**: +1. `@import` 顺序即层叠顺序:Tailwind base → Semi → 主题 token → 页面样式;页面级样式不得写未分层的 `* { margin:0 }`。 +2. 品牌色/圆角/字号只允许在 `tokens.css` 的 `@theme` 与 `semi-theme.css` 的 `--semi-color-*` 定义,页面禁止硬编码色值(CI 用脚本校验)。 +3. 不使用 `.semi-*` 内部类做覆盖;只通过 Semi 语义 token 与 `ConfigProvider`。 +4. 组件统一从 `@lingxi/ui` 导出(薄封装 Semi),页面不直接 import Semi 的内部组件,便于后续换肤/升级。 +5. **M0 必须先做构建 Spike**:Semi 2.104 + Tailwind 4.3 + Vite 8 同时引入,验证 modal/drawer/table 样式与 `@layer` 顺序;失败则回退方案见 §19 R1。 + +### 5.3 页面与路由(首期) + +| 路由 | 页面 | 首期 | +|---|---|---| +| `/` | 工作台/Dashboard | 是 | +| `/selection` | 选品(检索/圈选/历史) | 是 | +| `/materials` | 原始物料 | 是 | +| `/image/templates` | 模板资产 | 是 | +| `/image/produce` | 图片制作(三规格/四层合成/批量) | 是 | +| `/review` | 提审与审核 | 是(MVP-2) | +| `/delivery` | 投放配置/DPLink | 是(MVP-2) | +| `/assets` | 资产中心 | M4 | +| `/system/*` | 用户/角色/客户/配置/任务日志 | 是 | +| `/video/*` | 视频产线 | M5 | + +### 5.4 构建与性能 + +- Vite 8:`build.target = es2022`;路由级 code-split;Semi 按需(插件已处理)。 +- 图片列表用缩略图 URL(`?w=320`);大图预览走原图/签名 URL。 +- 表格默认分页 20/50;超过 200 行启用虚拟滚动(Semi Table 支持)。 +- 首屏预算:JS ≤ 350KB gzip(不含图片);超过则拆包。 + +--- + +## 6 后端架构(Express 5) + +### 6.1 分层 + +``` +apps/api/src/ +├── server.ts # 启动、优雅退出 +├── app.ts # Express 装配(middleware 顺序) +├── routes/ # 路由声明(薄) +├── controllers/ # 参数校验 + 调 service +├── services/ # 业务编排(事务边界) +├── repositories/ # Prisma 查询封装(可测试) +├── middlewares/ # auth、scope、rateLimit、error、requestId +├── events/ # SSE、任务事件发布 +└── jobs/ # 入队(只投递,不执行) +``` + +- **Controller 不写 SQL/Prisma**;Service 不直接读 `req`。 +- 事务:Service 层用 `prisma.$transaction`;跨任务/文件操作先落库再入队。 +- 错误:统一 `AppError(code, message, httpStatus, details)`;错误码在 `packages/shared/errors.ts`;响应不泄露堆栈。 +- 请求 ID:`x-request-id` 透传 pino;审计与日志可关联。 + +### 6.2 API 规范 + +| 项 | 约定 | +|---|---| +| 前缀 | `/api/v1` | +| 成功 | `{ "data": ..., "requestId": "..." }` | +| 失败 | `{ "error": { "code": "AUTH_401", "message": "...", "details": ... }, "requestId": "..." }` | +| 分页 | `?page=1&pageSize=20`;返回 `{ items, total, page, pageSize }`;大列表用 cursor | +| 幂等 | 写操作支持 `Idempotency-Key`;任务创建以 `(batchId, templateId, productId)` 唯一约束兜底 | +| 时间 | ISO 8601 UTC;DB `timestamptz` | +| 文件 | 上传走 `POST /files/presign`(生产)或 `POST /files/upload`(开发本地) | +| 实时 | `GET /api/v1/events?topics=batch:{id}`(SSE) | +| 文档 | zod → OpenAPI(dev 环境 `/api/docs`);不维护手写文档 | + +### 6.3 中间件顺序(固定) + +``` +requestId → pino-http → helmet → cors 白名单 → compression(跳过 SSE) +→ body parser(json 2mb / urlencoded)→ cookie parser +→ 全局限流(Redis)→ 路由 +→ 404 → error handler(统一信封) +``` + +- `helmet` 在公网必须开启;`cors` 只允许 `WEB_ORIGIN`。 +- SSE 路由放在 `compression` 之后但显式跳过压缩,并设置 `Cache-Control: no-cache`、`X-Accel-Buffering: no`。 +- 上传路由使用 multer 单独限制大小与 MIME,不适用全局 body 限制。 + +### 6.4 健康检查与可观测 + +| 端点 | 用途 | +|---|---| +| `GET /health/live` | 进程存活(不查依赖) | +| `GET /health/ready` | DB/Redis/对象存储探活;失败 503 | +| `GET /metrics` | Prometheus(内部网段/鉴权) | + +- 日志:pino JSON;字段 `requestId/userId/platformId/taskId`;**禁止打印 token/密码/签名盐**。 +- 指标:HTTP P95、队列积压、任务成功率/时长、图像处理耗时、AI 调用成本。 + +--- + +## 7 数据层(PostgreSQL 18 + Prisma 7.10.1) + +### 7.1 Prisma 约定 + +- 生成器:Prisma 7 的 `prisma-client`(ESM),输出到 `packages/db/src/generated/prisma`;应用统一从 `@lingxi/db` 导入。 +- 连接:`@prisma/adapter-pg`(driver adapter)+ `pg`;连接池 `max=10`(API)/`max=3`(Worker),按实例数核算 PG `max_connections`。 +- 迁移:本地 `prisma migrate dev`;CI/生产 `prisma migrate deploy`;**禁止 `db push` 到生产**。 +- 命名:`@@map("snake_case")`、`@map("snake_case")`;Prisma 字段 camelCase,DB 列 snake_case。 +- 主键:`String @id @default(dbgenerated("uuidv7()")) @db.Uuid`(PG18 原生 `uuidv7()`,时间有序、索引友好)。 +- 时间:`DateTime @db.Timestamptz(6)`;统一 UTC。 +- JSON:`Json`(映射 JSONB);仅用于配置/快照/扩展字段,不用于高频过滤。 +- 软删除:`deletedAt DateTime?`;查询统一走 Repository 的 `notDeleted`。 +- 枚举:稳定集合用 Prisma enum;运营可维护的字典用表(如失败原因、类目)。 +- 索引:`platform_id/client_id/status/created_at` 组合;任务表 `(status, created_at)`;事件表 `(task_id, created_at)`。 + +### 7.2 初始 schema 范围(与评估 §5.6 对齐) + +| 域 | 表(Prisma model) | +|---|---| +| 组织 | `Platform`、`Project`、`Client`、`User`、`Role`、`UserClient` | +| 凭据 | `PlatformAccount`(能力:soft/hard/review;密文;归属) | +| 商品/选品 | `ProductSnapshot`、`SelectionBatch`、`SelectionItem` | +| 物料 | `RawAsset` | +| 模板/资产 | `Template`、`TemplateCategory`、`TemplateTag`、`TemplateTagRelation`、`TemplateSpec`、`Asset` | +| 生产 | `ProductionBatch`、`ProductionTask`、`Material`、`NamingRule` | +| 提审 | `ReviewTicket`、`ReviewItem`、`SubmitLedger` | +| 投放 | `DeliveryConfig`、`DeliveryLink` | +| 任务/通知 | `TaskEvent`、`FailureCatalog`、`Notification`、`NotificationTemplate` | +| 配置/审计 | `SystemConfig`、`SystemConfigAudit`、`UserAudit`、`OperationAudit` | + +> 共约 33 张表;与评估文档的数据模型一致,仅访问层从 Sequelize 改为 Prisma。 + +### 7.3 迁移与种子 + +- 初始化:`pnpm db:create`(Node 脚本连 `postgres` 库,`CREATE DATABASE lingxi`,不存在才建)→ `pnpm db:migrate` → `pnpm db:seed`。 +- 种子:管理员账号(口令随机、仅显示一次)、基础角色/权限、得物平台、默认规格(800×800 / 1280×720 / 1080×1920)、字典。根 `package.json` 需声明 `"prisma": { "seed": "tsx prisma/seed.ts" }`。 +- 回滚:Prisma 迁移是前向的;破坏性变更采用 expand/contract(先加列/双写,再切读,最后删列),保留 down 说明在迁移目录 README。 +- 备份:生产每日 `pg_dump` + WAL;迁移前强制快照。 + +### 7.4 数据隔离 + +- 单租户(内部平台);数据范围:`platformId` + `clientId`。 +- 所有列表查询必须带范围条件(Repository 强制参数);`fail-closed`:无范围 = 查不到,而不是全量。 +- 审计表不做外键级联,保留历史。 + +--- + +## 8 Redis、队列与实时 + +### 8.1 Redis 使用边界 + +| 用途 | Key 前缀 | 说明 | +|---|---|---| +| BullMQ | `lingxi:bull:*` | 5 类队列 | +| 缓存 | `lingxi:cache:*` | 平台枚举/标签树/配置;TTL | +| 限流 | `lingxi:rl:*` | 登录、API、AI 调用 | +| 锁 | `lingxi:lock:account:{id}` 等 | `SET NX PX` + Lua 释放 | +| Pub/Sub | `lingxi:events` | SSE 广播 | +| 会话(可选) | `lingxi:sess:*` | 刷新令牌黑名单/设备 | + +- Redis 7 已有;**不执行 `FLUSHALL`**;统一前缀,避免与其他项目冲突。 +- 禁用 `KEYS`;批量用 `SCAN`。 +- 本地开发使用 db 0;测试用 db 15(`REDIS_URL=.../15`)。 + +### 8.2 队列拓扑 + +| 队列 | 生产者 | 消费者 | 并发建议 | 说明 | +|---|---|---|---|---| +| `image-render` | api | worker-image | 2~4 | PSD/合成/抠图;吃内存 | +| `platform-task` | api | worker-platform | 每账号 1 | 登录/送审/审核/投放;串行 | +| `ai-image` | api | worker-ai | 2~4 | 外部 API;限流/配额 | +| `ai-video` | api | worker-ai | 1~2 | 长任务;M5 | +| `export` | api | worker-export | 2 | ZIP/CSV;IO 密集 | + +约定:`jobId = DB task id`;`attempts=3`(平台写操作只 1 次 + 回查);指数退避;`removeOnComplete` 保留 1000/1 天;失败进 DLQ(`*-failed`)。DB 是事实来源;每 60s reconciler 扫描 `processing` 超时任务重新入队或标记失败。 + +### 8.3 SSE(任务进度) + +- 端点:`GET /api/v1/events?topics=batch:{id},platform:{code}`;`text/event-stream`。 +- 鉴权:登录 cookie/JWT(EventSource 不能带 header → 用短时 ticket:`POST /events/ticket` 换 60s ticket)。 +- 服务端:worker 更新任务 → `publish(lingxi:events, {topic, seq, payload})` → 每个 api 实例订阅并 fan-out 给本实例 SSE 连接。 +- 事件:`{ type: 'batch.progress' | 'task.status' | 'notification', topic, seq, ts, data }`。 +- 心跳 15s;断线重连用 `Last-Event-ID`(seq 游标,保留最近 5 分钟环形缓冲)。 +- nginx:单独 location,`proxy_buffering off; proxy_read_timeout 3600s;`。 + +### 8.4 分布式锁与幂等 + +- 账号锁:`SET lock:account:{id} NX PX 900000`;释放用 Lua 比对 token;超时自动释放并告警。 +- 任务幂等:DB 唯一约束 + `jobId`;重复投递由 BullMQ 去重。 +- 提交幂等:`SubmitLedger`(md5)先查后提;平台返回重复码时按已提交处理。 +- 限流:登录 5 次/分钟/IP+用户名;普通 API 300 次/分钟/用户;AI 按日配额。 + +--- + +## 9 文件与对象存储 + +### 9.1 StorageAdapter + +```ts +export interface StorageAdapter { + put(key: string, body: Buffer | Readable, opts: { contentType: string; cacheControl?: string }): Promise<{ key: string; size: number; md5: string }>; + get(key: string): Promise; + delete(key: string): Promise; + exists(key: string): Promise; + signDownload(key: string, ttlSeconds: number): Promise; + copy(srcKey: string, dstKey: string): Promise; +} +``` + +| 驱动 | 使用场景 | 实现 | +|---|---|---| +| `local` | 开发/单机 | `./var/uploads`;`/files/:key` 鉴权后流式返回;禁止路径穿越 | +| `s3` | MinIO/兼容 S3 | `@aws-sdk/client-s3` + presigner | +| `oss` | 阿里云 OSS 生产 | `ali-oss`(STS/签名 URL) | + +- 配置:`STORAGE_DRIVER=local|s3|oss`;启动时 zod 校验必填项。 +- Key 规则:`{platformCode}/{clientId}/{domain}/{yyyy}/{mm}/{uuid}.{ext}`;禁止使用客户端文件名作为 key。 +- 缩略图:图片上传后由 `worker-image` 生成 `_thumb.webp`(`?w=320/640`);清理任务按引用计数/保留期。 +- 大文件(视频 140–190MB):生产走浏览器/客户端直传 OSS(STS 临时凭证),API 只登记元数据;Playwright 送审时 worker 从对象存储下载到本地临时目录再 `setInputFiles`。 +- 生命周期:原始物料默认长期保留;导出包 7~30 天;临时文件 24 小时。 + +--- + +## 10 平台适配与 Playwright(worker-platform) + +### 10.1 适配器接口 + +```ts +export interface PlatformAdapter { + code: 'dewu' | 'vipshop'; + capabilities: { read: boolean; write: boolean; submit: boolean; dplink: boolean }; + login(ctx: AccountContext): Promise; + searchProducts(q: SearchQuery): Promise; + getProduct(spuId: string): Promise; + listRawAssets(spuId: string): Promise; + listMaterials(q: MaterialQuery): Promise; + submitReview(input: SubmitInput): Promise; + queryReview(input: ReviewQuery): Promise; + buildDeliveryLink(input: DeliveryLinkInput): Promise; +} +``` + +- 得物:读链路走签名 HTTP(`packages/platform-dewu/http.ts`);写链路默认页面自动化(`page.ts`),直连写接口作为 POC 备选。 +- 唯品会:M3 开始,先摸登录/接口/提审流程,再实现同一接口。 +- **不另开浏览器 context**:同一账号复用持久化 context;token 由凭据服务单写(API 只读,禁止自行重登)。 + +### 10.2 Worker 运行约束 + +| 项 | 约定 | +|---|---| +| 浏览器 | Chromium 版本随 Playwright 1.64.1 锁定;`pnpm playwright:install` 安装 | +| 账号并发 | 同一 `platformAccountId` 同时只允许 1 个写任务(Redis 锁) | +| 只读并发 | 全局上限 4;按平台限速 | +| 失败证据 | 截图 + DOM 快照 + reasonCode 存对象存储,DB 记录 key | +| 选择器 | 全部走配置(`selectors.dewu.json`),禁止散落硬编码;关键元素缺失触发健康告警 | +| 上传 | 大文件先落本地临时目录,`setInputFiles` 后清理;超时 15 分钟 | +| 重试 | 网络/5xx 重试 1 次;提交超时**只回查不重试** | + +--- + +## 11 图片产线(worker-image) + +- 输入:模板(PSD)+ 商品图 + 展示方式资产 + Logo + 促销模板 + 字段;输出:三规格图片 + 命名 + 元数据。 +- 流程:`readPsd` → 资产快照 → 图层合成(保持 PSD z 序,按 `assetType` 取资产)→ 抠图(仅白底)→ 压缩(JPG 二分质量 / PNG 调色板)→ 写对象存储 → `Material` 落库。 +- 版本:sharp 0.32.6 / ag-psd 30.1.0 / canvas 0.1.97 / fontkit 2.0.4 **锁定**;升级必须过黄金样本。 +- 回归:`test/golden/` 存 ≥5 个真实模板 + 期望图;像素 diff 阈值(默认 mean diff < 0.5%,单像素阈值 8/255);CI 跑 `pnpm test:golden`。 +- 字体:内置字体清单与授权登记;换字体必须跑回归;缺字形时显式失败(不许"豆腐块但任务成功")。 +- 并发:worker-image 独立进程,默认 2 并发;内存上限监控,OOM 重启由容器策略兜底。 + +--- + +## 12 AI 网关(worker-ai) + +### 12.1 接口 + +```ts +export interface AiImageProvider { + generate(input: ImageGenInput): Promise; // 返回 storageKey/成本/耗时 + checkText(input: TextCheckInput): Promise; // VLM 逐字校验 +} +``` + +- Provider:`ark`(火山方舟 Seedream,默认);可插拔其他厂商。 +- 模型分层:成品默认 `pro`,草稿/批量初筛用 `flash`;模型名/单价/限额全部配置化。 +- 队列:`ai-image` / `ai-video`;按账号级并发与 RPM 限流;429 退避。 +- 成本:每次调用写 `AiUsage`(provider/model/tokens/单价/金额/任务);日/月预算告警;超限降级或拒绝。 +- 合规:文字逐字校验 + 人工复核闸门 + 品牌 Logo 程序贴回;生成内容留痕(prompt/输出/审核人)。 +- 密钥:只读环境变量/KMS;**禁止进 DB/系统配置/日志**。 + +--- + +## 13 认证、权限、凭据与安全 + +### 13.1 认证 + +| 项 | 约定 | +|---|---| +| Access Token | JWT,15 分钟,前端仅内存保存(不写 localStorage) | +| Refresh Token | httpOnly + Secure + SameSite=Strict Cookie,7 天,旋转 + 复用检测 | +| 口令 | bcrypt 12;策略复用 scgf(8–20 位、字母+数字、弱口令库、不得含用户名) | +| 强制改密 | 首次登录/管理员重置;服务端 403 `PASSWORD_CHANGE_REQUIRED` | +| 失效 | JWT 携带 `pwdv`;改密/重置递增,旧令牌立即失效 | +| MFA | 管理员与高权限角色强制 TOTP;公网暴露的前置 | +| 限流 | 登录 5 次/分钟/IP+用户名;失败锁定 15 分钟 | + +### 13.2 权限 + +- RBAC:`admin / designer / optimizer / operator`;权限 key(如 `template.write`、`review.submit`、`delivery.manage`)。 +- 数据范围:`platformId` × `clientId`;Repository 强制注入;越权返回 404(不泄露存在性)。 +- 平台账号:`PlatformAccount.capabilities`(soft/hard/review);使用账号需授权;敏感操作二次确认 + 审计。 + +### 13.3 凭据加密 + +- 算法:AES-256-GCM;密钥 `PLATFORM_CRED_KEY`(32 字节 base64,环境变量/KMS 注入);AAD 绑定 `accountId`。 +- 存储:`PlatformAccount.credentialCipher`(密文)+ `keyVersion`;轮换时后台重加密。 +- 禁止:写入日志、审计 old/new 明文、系统配置表、前端响应。 + +### 13.4 公网暴露面 + +| 控制 | 要求 | +|---|---| +| HTTPS | TLS 1.2+;HSTS | +| WAF | 云 WAF/高防(建议);至少 nginx + 限流 | +| 安全头 | helmet:CSP、X-Frame-Options、nosniff、Referrer-Policy | +| CORS | 仅 `WEB_ORIGIN` | +| MFA | 管理员强制;运营可配置 | +| 依赖/镜像 | CI `pnpm audit --prod`;镜像扫描 | +| 渗透测试 | 上线前 1 次;每年 1 次 | +| 备份 | PG 每日 + WAL;对象存储版本化 | +| 审计 | 登录、权限变更、凭据使用、提审/投放、导出 | + +--- + +## 14 工程规范与质量门禁 + +### 14.1 TypeScript / Lint + +- `strict: true`、`noUncheckedIndexedAccess`、`exactOptionalPropertyTypes`(新代码);禁止 `any`(`unknown` + 收窄)。 +- ESLint 10 flat config:`@typescript-eslint`、`react-hooks`、`import` 排序;`pnpm lint` 零 warning。 +- Prettier 3.9:单引号、无分号、printWidth 100;`pnpm format:check` 入 CI。 +- commitlint + cz-git(沿用 scgf 规范):`feat/fix/docs/refactor/test/chore`。 + +### 14.2 测试分层 + +| 层 | 工具 | 范围 | 门禁 | +|---|---|---|---| +| 单元 | Vitest 5 | domain/命名/校验/成本 | 覆盖率 ≥ 70%(domain ≥ 85%) | +| 集成 | Vitest + PG/Redis 测试库 | Repository/事务/队列/SSE | 每次 PR | +| 契约 | Vitest + 抓包 fixture | 星光只读接口/字段映射 | 每次 PR | +| 黄金图 | Vitest + pixelmatch | PSD 合成/压缩 | 每次改图像代码 | +| E2E | Playwright 1.64 | 登录→选品→出图→提审 | 每日/M1 后 | + +- 测试库:`lingxi_test`(PG)+ Redis db 15;每个测试文件事务回滚或 truncate。 +- 不 mock 数据库(集成层);外部平台用 fixture/mock server。 + +### 14.3 CI(pnpm only) + +``` +pnpm install --frozen-lockfile +pnpm lint +pnpm typecheck +pnpm test +pnpm db:deploy(测试库) +pnpm test:integration +pnpm test:golden +pnpm build +pnpm test:e2e(可选,需浏览器) +``` + +- 服务:`postgres:18-alpine`、`redis:7-alpine`(GitHub Actions services 或 GitLab services)。 +- 缓存:pnpm store;Node 24.15.0 由 `.nvmrc`/action 指定。 +- **任何步骤禁止 `npm install`**;如遇工具要求 npm,用 `pnpm dlx` 替代 `npx`。 + +--- + +## 15 开发环境与命令(本机) + +### 15.1 前置(已具备) + +| 项 | 本机 | 说明 | +|---|---|---| +| Node | 24.15.0 | `.nvmrc` 固定 | +| pnpm | 11.4.0 | `corepack enable` 后由 `packageManager` 锁定 | +| PG | 18.4 @ 127.0.0.1:5432 | Docker 已有;**平台不启动/不安装** | +| Redis | 7.4.9 @ 127.0.0.1:6379 | Docker 已有;**平台不启动/不安装** | + +### 15.2 首次启动 + +```bash +corepack enable +pnpm install +cp .env.example .env # 填 PG 密码/JWT 密钥/凭据密钥 +pnpm db:create # 连接 postgres 库,创建 lingxi(不存在才建) +pnpm db:migrate # prisma migrate dev +pnpm db:seed # 管理员/角色/平台/规格 +pnpm playwright:install # 安装 Chromium(平台 Worker 需要) +pnpm dev # web:5173 + api:8300 +# 另开终端: +pnpm dev:workers # 4 类 Worker +``` + +### 15.3 `.env.example` + +```dotenv +NODE_ENV=development +PORT=8300 +WEB_ORIGIN=http://localhost:5173 + +DATABASE_URL=postgresql://postgres:CHANGE_ME@127.0.0.1:5432/lingxi?schema=public +REDIS_URL=redis://127.0.0.1:6379/0 +REDIS_PREFIX=lingxi + +JWT_ACCESS_SECRET=CHANGE_ME_32+_CHARS +JWT_REFRESH_SECRET=CHANGE_ME_32+_CHARS +PLATFORM_CRED_KEY=base64:CHANGE_ME_32_BYTES + +STORAGE_DRIVER=local +STORAGE_LOCAL_ROOT=./var/uploads +# STORAGE_DRIVER=s3 +# S3_ENDPOINT=http://127.0.0.1:9000 +# S3_REGION=us-east-1 +# S3_BUCKET=lingxi +# S3_ACCESS_KEY_ID= +# S3_SECRET_ACCESS_KEY= +# STORAGE_DRIVER=oss +# OSS_REGION=oss-cn-shanghai +# OSS_BUCKET= +# OSS_ACCESS_KEY_ID= +# OSS_ACCESS_KEY_SECRET= + +PLAYWRIGHT_BROWSERS_PATH=./.cache/ms-playwright +AI_PROVIDER=ark +ARK_BASE_URL=https://ark.cn-beijing.volces.com/api/v3 +ARK_API_KEY= +LOG_LEVEL=info +``` + +### 15.4 端口与目录 + +| 服务 | 端口 | 说明 | +|---|---|---| +| web | 5173 | Vite dev;`/api` 代理到 8300 | +| api | 8300 | 避开常见 3000,降低冲突 | +| PG | 5432 | 已有容器 | +| Redis | 6379 | 已有容器 | +| 本地文件 | `./var/uploads` | 已 gitignore | +| Playwright | `./.cache/ms-playwright` | 已 gitignore | + +### 15.5 pnpm 构建脚本白名单 + +pnpm 11 默认拦截依赖的安装脚本;以下必须放行(与 scgf `pnpm-workspace.yaml` 一致): + +```yaml +# pnpm-workspace.yaml +packages: + - apps/* + - packages/* +allowBuilds: + bcrypt: true + sharp: true + onnxruntime-node: true + msgpackr-extract: true +``` + +> 若 pnpm 11 提示 `allowBuilds` 未知字段,改用 `onlyBuiltDependencies`(同上清单)。CI 以 `pnpm install --frozen-lockfile` 成功为准。 + +--- + +## 16 构建与部署 + +### 16.1 镜像 + +| 镜像 | 基础 | 内容 | +|---|---|---| +| `lingxi/web` | `nginx:1.29-alpine` | 构建后的 SPA + nginx 配置 | +| `lingxi/api` | `node:24.15.0-bookworm-slim` | api 构建产物 + prisma 运行时 | +| `lingxi/worker-*` | 同上 | 各自 worker 产物 | + +- 构建阶段:`corepack enable` → `pnpm install --frozen-lockfile` → `pnpm --filter build`;运行阶段只拷贝 `dist` + `node_modules`(pnpm deploy/`--prod`)。 +- 非 root 用户运行;`NODE_ENV=production`。 +- Node 镜像若暂无 `24.15.0-bookworm-slim` tag:锁定 `node:24-bookworm-slim` 的 digest,并在构建阶段执行 `node -v` 断言 `v24.15.0`,不通过则失败。 + +### 16.2 Compose(生产/联调) + +```yaml +services: + web: { image: lingxi/web, ports: ["80:80", "443:443"] } + api: { image: lingxi/api, env_file: .env } + worker-image: { image: lingxi/worker-image, env_file: .env } + worker-platform: { image: lingxi/worker-platform, env_file: .env } + worker-ai: { image: lingxi/worker-ai, env_file: .env } + worker-export: { image: lingxi/worker-export, env_file: .env } +# PG/Redis 使用外部实例(已有/托管),不写入 compose +``` + +- 发布顺序:备份 → `prisma migrate deploy`(一次性 job)→ api → workers → web → 健康检查。 +- 迁移采用 expand/contract,保证旧版本可回滚;镜像保留上一版。 +- 备份:每日 `pg_dump` + WAL 归档;对象存储版本化;恢复演练每季度。 + +### 16.3 nginx 关键配置 + +| 路径 | 配置 | +|---|---| +| `/` | SPA,`try_files $uri $uri/ /index.html` | +| `/api/` | 反代 api:8300;`client_max_body_size 300m`;超时 300s | +| `/api/v1/events` | `proxy_buffering off; proxy_read_timeout 3600s;` | +| `/files/` | 反代 api(本地驱动)或直连对象存储(生产用签名 URL 跳过) | + +--- + +## 17 版本治理 + +| 类别 | 策略 | +|---|---| +| Node/pnpm | 精确锁定;`.nvmrc` + `engines` + 镜像三处一致 | +| Playwright | 精确锁定;浏览器 revision 随包;升级需回归送审选择器 | +| 图像栈 | 精确锁定;升级需黄金样本 + 像素 diff 通过 | +| Prisma | 精确锁定 minor;升级需跑迁移与集成测试 | +| UI 库 | caret + lockfile;每月升级窗口 | +| 依赖 | `pnpm-lock.yaml` 提交;`pnpm audit --prod` 入 CI | +| 废弃 | 不保留 Electron/桌面端构建链 | + +--- + +## 18 与评估文档的差异(需同步) + +| 项 | 评估(ORM/UI 定稿前) | 本定稿 | 影响 | +|---|---|---|---| +| ORM | Sequelize 6(复用 scgf) | **Prisma 7.10.1**(模型/迁移重写) | **+8~12 人日**;总量 383~569 → **391~581**;首期 280~414 → **288~426** | +| UI CSS | Tailwind 3.4(dewu 验证) | **Tailwind 4.3.3 + Semi 2.104** | +1~3 人日集成验证(在 ±25% 内) | +| 运行时 | Node 24 LTS | **Node 24.15.0 精确** | 无 | +| 数据/缓存 | PG/Redis 由部署提供 | **复用开发机已有 Docker,不负责安装** | 省去部署工作 | +| 部署 | 单机 Compose | 同 | 公网安全加固 4~8 人日已列 | +| 对象存储 | S3 适配 | **local(dev)/OSS(prod)** | 同 | + +> 评估文档已同步更新为 **391~581 人日 / 首期 288~426 人日**(rev.2);本定稿以 Prisma + Tailwind 4 为准。 + +--- + +## 19 M0 必须验证的风险(Go/No-Go) + +| 编号 | 风险 | 验证方式 | 通过标准 | 回退方案 | +|---|---|---|---|---| +| R1 | Semi 2.104 + Tailwind 4.3 + Vite 8 样式层叠冲突 | 建一个含 Table/Modal/Drawer/Form 的 Spike 页 | 组件样式正确、暗色/中文正常、`@layer` 顺序可控 | 回退 Tailwind 3.4.19 + Semi 2.104(dewu 已验证) | +| R2 | Prisma 7.10.1 + PG18 + Node 24.15 | 建 5 张表、迁移、seed、事务、uuidv7 默认值、adapter-pg 连接 | 迁移/回滚/连接池/类型生成全通过;`select uuidv7()` 返回 v7(本机已验证 PG18 支持) | 回退 Prisma 7.9.x 或评估 Drizzle(需重新评审) | +| R3 | sharp 0.32.6 / ag-psd 30.1 / canvas 0.1.97 在 Node 24 arm64 + Linux 镜像 | 本机 + Docker 各跑一次合成 | 输出一致、无崩溃 | 逐项升级并重跑黄金样本 | +| R4 | Playwright 1.64 在 macOS/Linux 行为差异 | 本机跑登录/送审空跑 | 选择器/上传可用 | 锁定 1.60(dewu 已验证) | +| R5 | Node 24.15.0 官方镜像 tag | `docker build` 构建 API 镜像 | `node -v` = 24.15.0 | 用 `node:24-bookworm-slim` + digest + 版本断言 | +| R6 | OSS SDK 选择(ali-oss vs S3 兼容) | 用测试 bucket 跑 put/sign/get | 签名 URL 可下载、分片上传可用 | 统一改用 S3 兼容网关 | +| R7 | Prisma 迁移 19 表的一次性搬迁 | 从 scgf 导出数据导入新库 | 行数/文件/命名对账通过 | 分批迁移 + 只读并行 | + +--- + +## 20 明确不采用的技术与理由(ADR) + +| 不采用 | 理由 | +|---|---| +| Sequelize 6 | 用户选择 Prisma;类型/迁移体验更好;代价是模型重写 +8~12 人日 | +| Tailwind 3 | 用户选择 Tailwind 4;需 M0 验证 Semi 共存 | +| Arco Design / shadcn/ui | 用户选择 Semi;Arco 与 scgf 页面绑定,shadcn 需自建后台组件层 | +| WebSocket | 任务进度单向,SSE 足够;少一套鉴权/心跳/广播实现 | +| Next.js | 内部 SPA,不需要 SSR/SEO;Vite SPA 更简单 | +| NestJS / Fastify | Express 5 可迁移 scgf 中间件;换框架收益低于成本 | +| MongoDB | 主数据强关系 + 事务 + 报表;PG 合适 | +| Redis 8 / PG 17 | 用户环境已固定 Redis 7 / PG 18 | +| K8s(首期) | 单机 Compose 足够;代码保持无状态,后续可迁移 | +| MinIO(开发必选) | 用户未提供;开发用 local 驱动,生产用 OSS | +| npm | 用户要求统一 pnpm | +| Electron | 桌面端停止演进 | + +--- + +## 21 附录 A:`.npmrc` 与根配置 + +```ini +engine-strict=true +auto-install-peers=true +strict-peer-dependencies=false +resolution-mode=highest +``` + +> `auto-install-peers=true` 用于兼容 Semi/Tailwind 生态的 peer 依赖;锁定 lockfile 后再收紧。 + +## 22 附录 B:依赖清单(按包) + +> 完整版本以 `pnpm-lock.yaml` 为准;下表为定稿基线。 + +| 包 | dependencies 摘要 | +|---|---| +| `apps/web` | react 19.3.1、react-dom 19.3.1、react-router-dom 7.18.5、@douyinfe/semi-ui 2.104.0、@remixicon/react 4.9.0、zustand 5.0.16、@tanstack/react-query 5.105.0、axios 1.21.0、react-hook-form 7.91.0、@hookform/resolvers 6.0.2、zod 4.6.7、recharts 3.10.1、dayjs 1.11.23、marked 18.1.2 | +| `apps/api` | express 5.3.0、@lingxi/db、@lingxi/shared、@lingxi/domain、@lingxi/storage、@lingxi/ai、bullmq 6.5.0、ioredis 6.0.0、jsonwebtoken 9.0.3、bcrypt 6.0.0、multer 2.5.0、zod 4.6.7、pino 10.4.0、pino-http 11.0.0、helmet 8.3.0、cors 2.8.6、compression 1.8.2、express-rate-limit 8.7.2、rate-limit-redis 6.0.2、archiver 8.0.0、exceljs 4.4.0、uuid 14.0.3、dotenv 18.0.9、prom-client 15.1.3、otplib 13.5.0 | +| `packages/db` | @prisma/client 7.10.1、@prisma/adapter-pg 7.10.1、pg 8.23.1 | +| `packages/domain` | zod 4.6.7、dayjs 1.11.23(纯逻辑,不依赖 DB/HTTP) | +| `packages/platform-dewu` | 原生 fetch(Node 24 内置)、playwright 1.64.1、zod 4.6.7 | +| `packages/storage` | @aws-sdk/client-s3 3.1160.0、@aws-sdk/s3-request-presigner 3.1160.0、ali-oss 6.23.0 | +| `packages/ai` | 原生 fetch、zod 4.6.7 | +| `apps/worker-image` | sharp 0.32.6、ag-psd 30.1.0、@napi-rs/canvas 0.1.97、fontkit 2.0.4、@imgly/background-removal-node 1.4.5、@lingxi/domain、@lingxi/storage | +| `apps/worker-platform` | playwright 1.64.1、@lingxi/platform-dewu、@lingxi/platform-vipshop、@lingxi/db | +| `apps/worker-ai` | @lingxi/ai、@lingxi/storage | +| `apps/worker-export` | archiver 8.0.0、exceljs 4.4.0、@lingxi/storage | +| 根 devDependencies | typescript 5.9.3、tsx 4.23.15、vite 8.3.5、@vitejs/plugin-react 6.1.2、tailwindcss 4.3.3、@tailwindcss/vite 4.3.3、@douyinfe/semi-vite-plugin 2.104.0、eslint 10.13.0、typescript-eslint 8.72.1、prettier 3.9.10、vitest 5.0.5、@vitest/coverage-v8 5.0.5、@testing-library/react 16.3.3、jsdom 30.1.3、playwright 1.64.1、pino-pretty 13.2.0、prisma 7.10.1 | + +## 23 附录 C:待确认项 + +| 编号 | 问题 | 影响 | 建议 | +|---|---|---|---| +| C-01 | 生产 OSS 的 region/bucket/账号是否已就绪? | 决定 `oss` 驱动配置与直传凭证 | M0 前确认 | +| C-02 | 是否有云 WAF/高防?还是仅 nginx 限流? | 公网安全方案 | M0 前确认 | +| C-03 | CI 平台是 GitHub Actions 还是内网 GitLab? | CI 配置模板 | M0 前确认 | +| C-04 | 生产是否为单台 Linux + Docker? | Compose/备份/监控方案 | M0 前确认 | +| C-05 | 管理员 MFA 是否首期强制? | 登录流程与 `otplib` 依赖 | 建议首期强制 | +| C-06 | Tailwind 4 + Semi 的 Spike 谁负责/何时完成? | 前端开工前置 | M0 第 1 周 | + +--- + +*定稿基于 2026-10-30 的开发机实测、pnpm registry 版本与两个参考项目源码;任何版本调整必须更新本文档与 lockfile。* diff --git a/docs/评估/_调研/dewu-调研报告.md b/docs/评估/_调研/dewu-调研报告.md new file mode 100644 index 0000000..86003b4 --- /dev/null +++ b/docs/评估/_调研/dewu-调研报告.md @@ -0,0 +1,726 @@ +# dewu-material-Downloader 调研报告 + +> **调研对象**:`参考项目/dewu-material-Downloader/`(应用名「得物素材助手」,v2.7.0,git HEAD `fe7646b`)。 +> **密级**:内部;文中平台接口/签名等敏感信息已脱敏,原文见受控知识库。 +> **调研方式**:只读通读源码与文档,交叉核对 git 历史、CI 配置与构建脚本;**未安装依赖、未运行构建、未修改参考项目**。凡文档与代码冲突处,以代码为准,并在文中注明文档已过时的位置。 +> **路径简写**:下文 `dw/` = `参考项目/dewu-material-Downloader/`;`dw:line` 均指该仓库内文件行号。 +> **数字口径**:LOC 用 `find -name '*.ts' -o -name '*.tsx'`(scripts 为 `*.mjs`/`*.cjs`)+ `wc -l`,口径在 §7.1 写明;文件数不含 `node_modules/`、`dist/`、`dist-electron/`、`release/`、`.cache/`、`.probe-material-page/`、`review/` 等产物或本地取证目录。 +> **调研时间**:2026-10-30。 + +--- + +## 0. 结论速览 + +- **一句话定位**:这不是一个简单的「下载器」,而是得物「星光平台」软广素材的**桌面端运营工作台**——已从 v1 的「登录→抓素材→下视频」演进为「素材下载 + 商品查询 + 素材审核查询 + 批量送审/混剪送审 + DPLink 一键复制」五段闭环。 +- **端形态**:Electron 44 单窗口桌面应用(Windows 为主力历史平台、macOS 为当前开发/验证机;Linux 有配置但未验证);`contextIsolation: true` + preload 白名单;React 19 + Semi Design 2 + Tailwind 3 + Playwright(`dw/package.json:3`、`dw/electron/main.ts:1`)。 +- **成熟度**:v2.7.0;git 记录 **228 个提交 / 21 个 tag / 2026-05-23 → 2026-10-22**(约 5 个月;最后 tag 为 v2.4.0,2.5.0–2.7.0 未打 tag,仅有 release 提交);功能覆盖深、但**真机验证不均**(送审非混剪已端到端成功,混剪「是」分支未真机;素材审核页仍挂 BETA)。 +- **质量基线**:TypeScript `strict` 全开、`tsc --noEmit` 是 CI 第一道门禁;**无单一测框架**(无 vitest/jest),但有 **32 个验证脚本、15,411 行、CI 三个 job**(`verify:ui` v2.7.0 记录 480 条通过、`verify:platform` 260 条通过;脚本内 `ok()` 断言点分别为 472/255);无 ESLint/Prettier 配置。 +- **体量**:`src/` 19,120 行(67 个 ts/tsx)、`electron/` 17,345 行(45 个 ts)、`scripts/` 27,828 行(73 个 mjs/cjs)、`release-scripts/` 875 行(mjs/cjs,不含 .sh/README 的 622 行),合计 **65,168 行**;另有 CSS 3,675 行、docs 30 篇 Markdown 14,633 行。 +- **最大的整合事实**:它只覆盖 **得物/星光一个平台**(全仓检索不到唯品会/vipshop 代码),且只覆盖 PRD 的 **P-01/P-04 与 P-05 的一部分**;**P-02 图片模板、P-03 视频 AI、P-06 多平台、P-07 资产管理完全不含**。新平台这两条产线必须另起,不能指望从本项目迁移。 +- **Web 化的核心结论**:**「读」链路可以做到无浏览器**(签名 + 只读接口已验证,纯 Node 可复现);**「写」链路(送审)必须保留服务端浏览器自动化**(平台上传走页面第一方 SDK + `duToken` 网关,重放成本高且易踩风控);**Electron 外壳能力(内嵌 webview、本地文件路径、FTP Cookie 同步、safeStorage、自动更新、代码签名)全部重写或废弃**。 + +### 0.1 结论表(能力域 → Web 化结论) + +| 能力域 | Web 化结论 | 关键原因 | 粗估人日 | +|---|---|---|---| +| 登录态(接口验证码登录 / 浏览器兜底 / Cookie 同步) | **服务端重写** | 单账号单会话;凭据是本机 `safeStorage` 加密文件 + FTP 静态共享;服务端需多用户账号归属与 KMS 加密 | 8–12 | +| 素材读取(软广素材库列表/详情、审核列表、枚举) | **改造复用** | 只读接口 + MD5 签名 + 信封解析已跑通,纯 Node 可复现;去掉 Electron 直接作为服务端模块 | 5–8 | +| 原始物料下载(含任务工作台 UI + 视频 CDN 直连 + 商品图/主视频) | **服务端重写** | 浏览器只用于「登录/兜底」;下载、MD5 去重、分批冷却可保留策略,但文件落盘改为对象存储/下载中心;UI 需按新设计系统重做 | 25–38 | +| 商品查询(SPU 解析 + 商品详情 + 素材 9 项) | **改造复用** | 商品详情是 SSR HTML 直取,不需要浏览器;链接短链解析可服务端做 | 12–18(含 UI) | +| 内嵌商品 H5 画布 + 净化模式 | **废弃** | 依赖 Electron `` + 移动端 UA + 持久分区;Web 端受 iframe/X-Frame-Options 限制,且价值低于「数据直取」 | 0(可选 3–5) | +| 素材审核页(列表/筛选/驳回原因/上传记录/CSV) | **改造复用** | 纯只读接口 + 平台枚举,无 Electron 依赖;UI 需按新设计系统重做 | 8–12 | +| 送审判定 / 命名解析 / 预检规则 | **直接复用** | 已是应用与门禁共用的纯逻辑(`scripts/lib/submit-naming.mjs` 等),零 Electron 依赖 | 3–5 | +| 批量送审(页面自动化 + 上传 + 幂等 + 回查 + 账本/审计) | **服务端重写** | 浏览器填表 + `setInputFiles` + 观察响应;服务端需浏览器池、大文件上传通道、会话串行;策略层可复用 | 26–37 | +| 混剪送审(双栏配对 + 源检索 + N 组提交) | **服务端重写(UI 改造复用)** | 纯逻辑已抽到 `scripts/lib/mix-submit.mjs`;「混剪=是」写链路尚未真机验证 | 14–22 | +| DPLink 一键复制 | **改造复用** | 纯算法 4/4 样本逐字符复现;仅两个只读接口 + 硬广凭据 | 5–8 | +| 应用设置 / 远端配置 / 日志 | **改造复用** | 配置分层、档位预设、白名单和签名机制可迁移;用户配置改服务端 DB | 7–10 | +| 自动更新 / 关于页 / 旧版本清理 / 窗口状态 | **废弃** | 桌面应用专属(Squirrel/ShipIt、`legacy-bundle`、BrowserWindow maximize) | 0–1 | +| 验证门禁与纯逻辑资产 | **改造复用** | 21 个 `scripts/lib/*.mjs` + fixtures + 32 个 verify 脚本,可直接转服务端单测/契约测试 | 6–10 | + +> 人日为「分析员粗估、供排期参考」,含联调与验收、不含图片/视频 AI 产线;合计约 **115–190 人日**(逐项见 §8)。 + +--- + +## 1. 项目定位与业务链路 + +### 1.1 解决什么问题、给谁用 + +**业务背景**:得物「星光平台」是软广/KOL 投放的素材后台,素材库、审核、送审都在内网/H5 体系里,**没有面向内部的开放 API**,也没有批量下载能力。运营与剪辑的日常是: + +1. 在软广视频库里逐条点「预览」,复制视频地址,手工记录 `媒体任务ID / 视频ID / SPUID / 投放类目 / 授权时间`; +2. 手工改名落盘,反复登录网页版导致桌面工具掉线; +3. 剪辑后回到素材池「KOL原生二创素材上传」抽屉,逐条填投放渠道、媒体任务ID、视频ID、SPUID、挂 140–190MB 成片、点提交; +4. 被拒后去审核列表逐条看驳回原因; +5. 投放前再去星光「商品生成链接」页手工选落地页、商品,复制 iOS/Android 唤端链接。 + +**目标用户**:得物软广素材运营、剪辑、投放优化师(小团队、共享少数星光账号)。产品一直是**内部效率工具**,不是多租户 SaaS——这决定了它大量假设「一台机器、一个人、一个账号」。 + +### 1.2 主链路(端到端) + +``` +① 登录星光(接口验证码登录 / 浏览器登录兜底 / 云端 Cookie 同步) + ↓ +② 选品 + A. 素材下载页:输入 SPUID(可多个)→ 软广视频库筛选 → 提取素材 + B. 商品查询页:输入 SPUID / 商品链接 / App 分享文本 → 商品详情 + 9 项原始素材 + ↓ +③ 原始物料获取 + A. 视频:按「媒体任务ID-视频ID-SPUID-类目-授权起-授权止.mp4」命名 → CDN 直连下载 → MD5 去重 + B. 商品图/主视频:按「<下载目录>/商品素材/-<货号>-<标题前40字>/」落盘 + ↓ +④ 本地剪辑 / 混剪(应用外,本仓库不覆盖) + ↓ +⑤ 提审:命名解析 → md5 本地查重 → 预检弹窗 → 页面自动化逐条提交 → 超时只回查不重试 + → 已送审 md5 账本 + JSONL 审计 + ↓ +⑥ 审核查询:审核中/通过/不通过/全部 → 驳回原因、审核人、视频直链、上传记录 xlsx、CSV 导出 + ↓ +⑦ 投放配置:商品查询页复制 iOS UniversalLink / 安卓 DeepLink(DPLink) +``` + +**与旧版下载器的关键差异**(git 历史可证):v1.x 只有 ①③(登录 + 下载)以及更新/设置;v2.0 加商品查询页;v2.1 收敛设置/远端配置/更新验签;v2.2 升 Electron 44 并落地 mac 签名公证;v2.3 把「读」接口化(P1);v2.4 加素材审核(P2);v2.5 加素材送审(P4)+ 改名 + mac 原生更新;v2.6 加 DPLink;v2.7 改为任务工作台、加混剪送审/素材预览/过滤开关。**它已经是一个流程闭环产品,而不是单点脚本**。 + +### 1.3 与 PRD 1.1 问题的对应关系 + +| PRD 编号 | PRD 问题 | 本项目覆盖度 | 证据 / 说明 | +|---|---|---|---| +| P-01 | 原始物料:详情页图片逐张人工下载、分散存放 | **部分覆盖** | 商品查询页支持主图/详情图/主视频一键下载并按商品目录归档(`dw/electron/shop/materials.ts:24-26`);视频素材库支持按 SPUID 批量下载(`dw/electron/platform/materials.ts`)。**只覆盖得物单平台**,且无「本次选品物料库」概念 | +| P-02 | 图片:三规格 × 四层信息人工排版 | **不覆盖** | 全仓无 PSD 解析、无模板合成、无 800×800/1280×720/1080×1920 产出代码 | +| P-03 | 视频:依赖实拍与个人脚本经验 | **不覆盖** | 无脚本生成、无 AI 视频、无 TTS/画面组合 | +| P-04 | 命名提审:手工改名与登记,进度散落 | **覆盖** | 命名规范 + 末三段解析 + 预检弹窗 + 批量送审 + 审核状态跟踪 + md5 幂等 + 审计(`dw/electron/submit/*`、`dw/docs/送审命名规范与预检规则.md`) | +| P-05 | 账户搭建:DP、承接页逐条复制 | **部分覆盖(仅 DPLink)** | 只做「商品 → 投放唤端链接」拼接与复制,**不做 DP 编写、不做承接页字段批量替换**(PRD 中 DP 的具体口径也待业务确认) | +| P-06 | 多平台:资源与口径不统一 | **不覆盖** | 全仓检索 `唯品会/vipshop/vip.com` 无命中;平台地址只有星光 + 得物商品站 | +| P-07 | 资产管理:模板/脚本散落 | **不覆盖** | 无模板/脚本/Logo 资产库;仅有「落地页列表」与「商品库」两个只读数据源 | + +> **结论**:本项目是**新平台「选品→原始物料→提审→投放链接」段的现成参考实现**,但不是「图片/视频产线」的参考实现;新平台需要「得物作业端(迁移+增强) + 图片/视频产线(新建) + 多平台抽象(新建)」三块并行。 + +--- + +## 2. 功能模块清单(全量) + +> 以 `dw/src/App.tsx:240-306` 的侧边栏 6 个入口 + 代码内实际存在的能力为准;「实现状态」按代码与文档的真实完成度标注(完整 / BETA / Phase 1 待真机 / 仅配置 / 未实现)。 + +| 模块 | 页面/入口 | 核心功能点 | 实现状态 | 关键文件:行 | 依赖 Electron 能力 | +|---|---|---|---|---|---| +| **素材下载** | 侧边栏「素材下载」`/` | SPUID 筛选(多值、中文分隔归一化、填写后显示各 SPUID 素材数);按页数/按数量两种范围;提取「拦截→接口→DOM 兜底」三级路径并显示读取方式;两个下载前过滤开关(30 天内到期 / 未授权快手);素材预览;分批+并发+随机延迟+指数退避+冷却;MD5 去重;任务详情/重试历史;打开下载目录/系统通知/日志导出;新建任务(保留前置条件) | **完整**(v2.7.0 真机可用) | `dw/src/pages/DownloadPage/index.tsx:250`、`dw/electron/browser/manager.ts`、`dw/electron/downloader/manager.ts`、`dw/electron/platform/materials.ts` | 是:Playwright、文件系统、dialog、通知、剪贴板、`shell.openPath` | +| **商品查询** | 侧边栏「商品查询」`/shop` | 输入 SPUID / 商品链接 / App 分享文本;左栏内嵌得物 H5 商品页(移动 UA + 独立持久分区 + 净化模式 + 导航白名单 + 右键菜单);右栏 SSR 直取商品卡片(标题/价格/货号/SKU/主图/详情图/主视频/来源链接);9 项素材格;下载范围「主图+视频 / 全部」;逐文件进度与取消;DPLink 两个复制按钮 | **完整**(2026-10-22 摘除 BETA) | `dw/src/pages/ShopPage/index.tsx:426`、`dw/src/components/SpuCanvas.tsx`、`dw/electron/shop/session.ts:32-66`、`dw/electron/shop/detail.ts:11-27` | 是:``、partition、dialog、文件系统 | +| **素材审核** | 侧边栏「素材审核」`/review` | 审核中/通过/不通过/全部 4 Tab + 总数;按素材ID、审核时间、上传时间筛选;列表(32 条/页,与网页版一致);详情弹窗(视频、字段、审核人);驳回原因富文本(白名单 AST,不 `dangerouslySetInnerHTML`);上传/送审记录(含 xlsx 预签名下载);勾选行导出 CSV;权限前置「建议而非硬拦」 | **BETA**(数据来自平台接口,界面仍按反馈调整) | `dw/src/pages/ReviewPage/index.tsx:627`、`dw/src/pages/ReviewPage/ReviewTable.tsx`、`dw/electron/platform/reviews.ts:43-48`、`dw/scripts/lib/review-csv.mjs` | 否(只读 HTTP);CSV 落盘用 dialog | +| **批量送审** | 素材审核页「批量送审 / 选文件夹」→ 预检弹窗 → 进度浮层 | 命名两模式解析(文件夹名恰好三段 / 文件名末三段);SPUID 回显;md5 流式查重 + 已送审账本;批内去重;就地改 ID / 批量补 SPUID / 冲突二选一;逐条开抽屉→选混剪=否→投放渠道→填 3 字段→`setInputFiles`→等上传→提交→观察响应;超时只回查;掉线停批;审计 JSONL | **完整**(非混剪链路 2026-10-16 端到端成功 1 条;离线门禁全绿) | `dw/src/pages/ReviewPage/SubmitPrecheckModal.tsx`、`dw/electron/submit/page.ts:47-110`、`dw/electron/submit/batch.ts:1-40`、`dw/electron/submit/verify.ts` | 是:Playwright、dialog | +| **混剪送审** | 素材审核页「混剪送审」→ 双栏配对弹窗 | 成品文件名只取末段 SPUID;右栏按 SPUID 自动检索平台素材/本机下载库;授权状态(有效/≤30天/已过期/未生效/长期/未知);N 组 `{xtTaskId, videoId}` 配对;提交前校验配对/渠道/SPUID 一致性/组数;页面自动化选「混剪=是」并回读组数 | **Phase 1 已落地,待真机**(「混剪=是」写链路未验证) | `dw/src/pages/ReviewPage/MixSubmitModal.tsx`、`dw/electron/submit/mix.ts`、`dw/electron/platform/source-search.ts`、`dw/scripts/lib/mix-submit.mjs` | 是:Playwright、dialog | +| **送审进度** | 全局浮层 + 页面卡片 | 逐条阶段(填表/上传/提交/回查)、成功/跳过/失败/未知、可中断(当前条跑完即停)、切页不中断、可按 md5 看审计尾部 | **完整** | `dw/src/pages/ReviewPage/SubmitProgressPopover.tsx`、`dw/src/hooks/useSubmitProgress.ts` | 是(经 IPC) | +| **DPLink 一键复制** | 商品查询页「复制 iOS DPLink / 复制安卓 DPLink」+ 设置「投放落地页」 | 拉落地页列表(含 `flag/_gsign/navControl`)、按 SPU 反查商品库 `cSpuId`、拼两层链接(内层整段 encode)、复制到剪贴板;硬广账号独立凭据、云端 `accounts.dplink` 分区、错误分类(未配置/无权限/未选落地页/不在商品库/网络) | **完整**(2.6.0;4 条样本 4/4 逐字符复现;依赖客户共享硬广账号) | `dw/src/pages/ShopPage/index.tsx:695-703`、`dw/electron/dplink/link.ts:39-41`、`dw/electron/dplink/account.ts:1-40` | 剪贴板(主进程 `clipboard`);凭据 safeStorage | +| **登录态** | 侧边栏底部状态、登录弹窗、设置「账号与同步」 | 软广账号:接口发码/登录(不启浏览器)、浏览器登录兜底、无头/有头切换、登录预检(启动检测)、退出(只清本机+忽略云端);硬广账号:独立加密槽 + 独立登录;云端 Cookie 同步 v2(soft/dplink 分区、HTTP 拉、FTP 推、写后回读) | **完整**(接口登录 `verify:login` 9/9 实测;云端同步为遗留架构) | `dw/src/components/SidebarLoginStatus.tsx:32-74`、`dw/src/components/LoginDialog.tsx`、`dw/electron/platform/auth.ts:1-70`、`dw/electron/browser/cookieSync.ts:1-40` | 是:Playwright、safeStorage、FTP、文件系统 | +| **配置管理** | 侧边栏「应用设置」`/config` | 分区清单:账号与同步 / 下载(路径、完成后自动打开、三档速度)/ 外观与启动(主题、启动最大化)/ 更新(启动检查、自动下载、退出安装)/ 投放落地页 / 诊断与日志(版本、日志、远端配置来源、忽略远端配置);未保存改动导航守卫;恢复默认 | **完整** | `dw/src/pages/ConfigPage/index.tsx:716-1180`、`dw/electron/config/default.ts:52-72`、`dw/electron/config/presets.ts:59-102` | 是:dialog、safeStorage、BrowserWindow | +| **远端配置** | 设置「诊断与日志 → 远端配置」 | Ed25519 验签、JSONC 解析、白名单+区间校验、revision 单调、三级回退(远端→缓存→内置)、紧急 `disabled`、送审总开关 `enableSubmitReview` | **完整**(线上 revision 2) | `dw/electron/config/remote.ts:1-40`、`dw/scripts/lib/remote-config-schema.mjs:32-80`、`dw/remote-config/app-config.json:26,72` | 否(HTTP GET) | +| **运行日志** | 设置「诊断与日志」、下载/送审页 | 内存缓冲 + 按日文件(保留 7 个)+ 导出 + 打开目录 + 跨天切换 | **完整** | `dw/electron/logger.ts:41-101` | 是:文件系统、shell | +| **自动更新** | 侧边栏「软件更新」`/update` | 检查/下载/安装/跳过此版本/恢复提醒;更新元数据 `.sig` Ed25519 验签;强制更新、最低版本、更新说明 Markdown 渲染;mac 走 Squirrel 原生替换 `.app` | **完整**(CI 签名+公证+装订;本机 ad-hoc 包点更新会失败属预期) | `dw/src/pages/UpdatePage/index.tsx`、`dw/electron/updater/manager.ts:56-90,185,274-301` | 是:electron-updater、shell、app 生命周期 | +| **关于页** | 侧边栏「关于应用」`/about` | 版本徽标、复制版本信息、日志入口、第三方许可清单/完整文本、企微反馈;**无更新逻辑**(跳更新页) | **完整** | `dw/src/pages/AboutPage/index.tsx:23-59` | 是:clipboard、shell、许可文件路径 | +| **应用外壳** | `App.tsx` | HashRouter 6 页、侧边栏、主题(亮/暗/跟随系统)、4 页骨架屏、错误边界、退出二次确认、崩溃兜底、单实例锁、窗口最小尺寸/启动最大化、`Cmd/Ctrl+,` 打开设置 | **完整** | `dw/src/App.tsx:240-306,437-442`、`dw/src/contexts/*`、`dw/electron/window/state.ts` | 是:BrowserWindow、Menu、app 事件 | +| **浏览器组件分发** | 首次启动/设置提示 | 三级检测:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` → 系统 Chrome → 自建服务器 manifest 下载;manifest Ed25519 验签 + sha256 + revision 精确匹配;无 CDN 回退(防无校验下载) | **完整**(曾有版本错配事故,已修并加门禁) | `dw/electron/browser/playwrightInstaller.ts:1-125,436`、`dw/scripts/lib/browser-manifest-trust.mjs` | 是:Chromium 下载/解压、文件系统 | +| **旧版本应用清理** | macOS 启动弹窗 | 改名后新旧 `.app` 并存,检测旧包→移入废纸篓/访达显示/7 天稍后提醒;路径二次校验防后门 | **完整**(仅 macOS) | `dw/electron/legacy/bundle.ts:33-64,60` | 是:shell、应用枚举 | +| **素材预览 / 过滤偏好** | 素材下载页 | 素材卡片首帧预览、已过滤卡片隐藏与计数、两个开关记 localStorage、DOM 兜底路径同一规则 | **完整**(门禁 43 条;真实数据过滤比例待真机) | `dw/src/components/MaterialPreview.tsx`、`dw/scripts/lib/material-filter.mjs`、`dw/docs/素材下载过滤开关-实现说明.md` | 否(渲染层) | +| **SPUID 素材数量即时查询** | 素材下载页筛选区 | 填完 SPUID 后显示各 SPUID 达人素材条数;最多 20 个、超出显式截断;单条失败不拖垮整批 | **完整** | `dw/src/components/SpuMaterialCounts.tsx`、`dw/electron/platform/materials.ts:112-140` | 否(只读接口) | +| **混剪 Excel/CSV 导入(Phase 2)** | 方案文档 | 批量导入清单 | **未实现(仅文档 + 模板 xlsx)** | `dw/docs/混剪素材批量上传-开发方案.md`、`dw/docs/混剪素材批量上传模板.xlsx` | — | + +> **核对说明**:侧边栏只有 6 个一级入口,但「素材审核」页内聚合了 4 个写/读子能力(批量送审、混剪送审、上传明细、CSV 导出),菜单文字易让人低估其分量;「素材下载」页也不只是下载,而是任务工作台(提取、预览、过滤、结果分级)。另:PRD 语境里的「混剪素材」在本项目中不是下载分类,而是**审核页的混剪送审**(源素材检索 + N 组配对提交);下载侧只有「软广视频库素材」与「商品原始素材」两条链路。 + +--- + +## 3. 技术栈与架构 + +### 3.1 栈与关键版本 + +| 层 | 选型 | 版本(声明 → 实测) | 说明 | +|---|---|---|---| +| 渲染层 | React / react-dom | `^19.3.0` → 19.3.0 | 无全局状态库;Theme/LoginStatus/UnsavedChanges 三个 Context | +| 路由 | react-router-dom | `^6.20.0` → 6.30.3 | `HashRouter`(Windows 打包后 BrowserRouter 失效的历史修复) | +| UI | @douyinfe/semi-ui | `^2.103.0` → 2.103.0 | 2026-10 全量从 Ant Design 迁到 Semi(commit `bf350ae`);`@douyinfe/semi-vite-plugin` | +| 样式 | Tailwind CSS / PostCSS | `^3.4.0` → 3.4.19 | 大量页面级 CSS + Semi token 变量(`--semi-color-*`) | +| 图标 | @remixicon/react | `^4.9.0` → 4.9.0 | 统一图标库(`src/icons.tsx` 173 行) | +| Markdown | marked | `^18.1.0` → 18.1.0 | 发版说明渲染(`Changelog.tsx`) | +| 桌面 | Electron | `^44.7.0` | contextIsolation + preload;主进程 ESM 打包为 `dist-electron/main.js` | +| 浏览器自动化 | playwright | **`^1.40.0` → 1.60.0(⚠️ 漂移)** | 核心能力:登录、DOM 兜底、送审抽屉自动化、上传 | +| 构建 | Vite + vite-plugin-electron | 5.4.21 / 0.28 | 三份构建配置(frontend 配置为死文件) | +| 打包 | electron-builder | `^26.15.3` | Win NSIS / mac dmg+zip / Linux;`extraResources` 分发许可文本 | +| 更新 | electron-updater | `^6.8.9` | generic provider + 自建签名元数据 | +| 其他 | basic-ftp、adm-zip、fs-extra | 6.2.3 / 0.6.1 / 11.3.5 | Cookie FTP 同步、Chromium zip 解压 | +| 类型 | TypeScript | `^5.3.0` → 5.9.3 | `strict` / `noUnusedLocals` / `noUnusedParameters` / `noFallthroughCasesInSwitch` 全开(`dw/tsconfig.json`) | + +### 3.2 进程模型与数据流 + +``` +Renderer(React,HashRouter,6 页) + └─ window.electronAPI(preload.ts contextBridge,唯一通道) + ├─ invoke/handle:87 条(请求-响应) + └─ on/send:14 条单向事件(进度/登录态/更新) +Main(Electron) + ├─ ipc/handlers.ts(1822 行,模块级单例协调层,唯一组装点) + │ ├─ BrowserManager(Playwright 会话、登录、提取、送审编排,1962 行) + │ ├─ DownloadManager(下载、MD5、分批/并发/重试,516 行) + │ ├─ PlaywrightInstaller(浏览器分发,864 行) + │ ├─ configManager(三层配置:用户/档位/开发者 + 远端覆盖) + │ ├─ platform/*(只读接口层:client/http/sign/auth/materials/reviews/cache/authorization) + │ ├─ submit/*(写链路:page 自动化 / batch 执行器 / plan 会话 / verify 回查 / idempotency 账本 / audit) + │ ├─ shop/*(商品查询:webview 承载 / SSR 直取 / 素材下载) + │ ├─ dplink/*(硬广凭据 + 只读商品库/落地页 + 拼链) + │ └─ updater / logger / legacy / task-state / window-state +``` + +**文件落盘**:主进程是唯一写文件的地方——`userData/config.json`、`cookies.json`、`dplink-*.json`、`platform-cache/*`、`submit-audit.jsonl`、`submit-payloads.jsonl`、`remote-config.cache.json`、`logs/`、下载目录(默认 `~/Downloads/得物素材` 或用户指定)。渲染层无文件系统权限,所有落盘必须经 IPC(CSV 导出、日志导出、下载目录选择)。 + +**关键约束(详见 `dw/docs/新功能开发计划.md:455-475`)**: + +1. **业务写只走页面自动化**,绝不直接调用写接口;唯一豁免是登录(`electron/platform/auth.ts` 只含两条硬编码路径且不重试); +2. **不另开浏览器 context**(平台单账号单会话,另开会被判新会话并踢掉自己); +3. **提交超时只回查、不重试**; +4. **筛选/取数失败显式失败**,不静默降级为「下载全部」; +5. 选择器不绑哈希类名(`previewBtn___*` 集中到 `legacySelectors.ts`,仅 DOM 兜底可用)。 + +### 3.3 IPC 契约(按域汇总,不逐条贴参数) + +| 域 | 通道数 | 主要用途 | 事件 | 定义位置 | +|---|---|---|---|---| +| `browser:*` | 24 | 启停、登录预检/登录/退出、发码/验证码登录、切换无头、导航/分页/提取、保存 Cookie、浏览器组件安装 | `browser:loginStateChanged`、`browser:download:progress` | `dw/electron/ipc/channels.ts`、`dw/electron/preload.ts:5-100` | +| `submit:*` | 16 | 可用性、选文件/解析、md5 计算、起批、混剪选成品/检索/计算/起批、中断、状态快照、审计尾部、忘记已送审 | `submit:md5Progress`、`submit:batchProgress` | `dw/electron/preload.ts:190-240` | +| `update:*` | 11 | 检查/下载/安装/跳过/恢复/状态 + 5 个事件 | 进度/可用/无更新/已下载/错误 | `dw/electron/preload.ts:300-380` | +| `platform:*` | 10 | 签名自检、取素材页/详情、SPUID 数量、预览、审核列表、上传记录、枚举、标签树、账号详情 | — | `dw/electron/platform/*` | +| `dplink:*` | 9 | 硬广账号状态/发码/登录/复核/退出、落地页列表/读取/保存、按 SPU 拼链 | — | `dw/electron/dplink/*` | +| `download:*` | 8 | 开始/停止/统计/打开目录 + 4 个事件 | 进度/完成/汇总/状态 | `dw/electron/downloader/*` | +| `shop:*` | 6 | 承载配置、链接解析、商品详情、素材下载、取消 + 进度事件 | `shop:downloadProgress` | `dw/electron/shop/*` | +| `config:*` | 4 | 读取/保存/恢复默认/刷新远端配置 | — | `dw/electron/config/*` | +| `legacy:*` | 4 | 检测/移入废纸篓/访达显示/7 天稍后 | — | `dw/electron/legacy/bundle.ts` | +| `log:*` | 3 | 日志目录/导出/打开 | — | `dw/electron/logger.ts` | +| 其他 | 6 | 通知、剪贴板、许可、dialog、shell.openExternal、review 导出 CSV | — | `dw/electron/ipc/channels.ts` | +| **合计** | **101** | 87 invoke + 14 event | — | `dw/scripts/verify-channels.mjs` 断言唯一来源 | + +> 通道名收口到 `IpcChannel` 常量表(`dw/electron/ipc/channels.ts:1`),`verify:channels` 静态守「handlers/preload 不得出现字符串字面量」——这是 2026-10 修掉的历史债(旧版 channels.ts 曾是死代码且含拼写错误)。 + +### 3.4 构建与发布链路 + +- **开发**:`npm run dev`(Vite + vite-plugin-electron 热重载);`postinstall` 是 `playwright install chromium --dry-run`,**装依赖不会装浏览器**。 +- **构建**:`build:web`(licenses + `tsc` + `vite build`)与 `build[:win|:mac|:linux]`(再跑 electron-builder)。 +- **CI**:三个 workflow——`ci.yml`(每次 push/PR:gates 20+ 步、ui-verify 480 条通过、package-size)、`build-release.yml`(仅 `workflow_dispatch`,Win 构建 + mac 签名/公证 + 产物断言 + 更新元数据签名 + GitHub Release + FTP)、`build-chromium.yml`(手动构建 Chromium 包 + manifest)。 +- **发版唯一入口**:`npm run release`(`scripts/release.mjs`,改版本号 + 预检 + 门禁 + 推送 + `gh workflow run`),已移除 tag 触发后门。 +- **签名/信任根**:远端配置 Ed25519、更新元数据 Ed25519、浏览器 manifest Ed25519 三把独立密钥;macOS Developer ID + 公证 + 装订(`verify:mac-sign` 断言产物本身)。 + +--- + +## 4. 数据模型与持久化 + +### 4.1 存储位置与形态(`app.getPath('userData')`) + +| 数据 | 路径 | 形态 | 加密 | 说明 | +|---|---|---|---|---| +| 用户配置 | `config.json` | JSON | 字段级 safeStorage(`ftpPassword`/`cookieSyncKey` 加 `encrypted:` 前缀) | 明文可读;解析失败**静默回退默认**,不备份坏文件(排查坑) | +| 软广 Cookie | `cookies.json` | safeStorage 整文件加密 | 是 | 跨机器复制**解不开且静默解析失败**(双刃剑) | +| 硬广账号 | `dplink-account.json` | safeStorage 整文件 | 是 | 与软广凭据**完全隔离**,绝不注入浏览器上下文 | +| 硬广落地页设置 | `dplink-settings.json` | safeStorage 整文件 | 是 | 只在本机、不同步云端;旧明文首次读取自动迁移 | +| 平台枚举/标签树缓存 | `platform-cache/enums.json`、`label-tree.json` | JSON + `fetchedAt` | 否 | TTL 24 小时;过期仍返回并标 `stale`(离线可用) | +| 已送审 md5 账本 | `platform-cache/submitted-md5.json` | JSON `{version, md5s[], updatedAt}` | 否 | 无 TTL(100 年);原子写;审核列表回灌自愈 | +| 送审审计 | `submit-audit.jsonl` | JSONL 追加 | 否 | 每条结果/阶段/md5/groups;写失败不阻断送审 | +| 送审请求体快照 | `submit-payloads.jsonl` | JSONL 追加 | 脱敏后否 | 与同事「人工提交」做字段级对账 | +| 远端配置缓存 | `remote-config.cache.json` | JSON + `.sig` 校验后缓存 | 否 | 读缓存**重新验签**,防本地投毒 | +| 旧版本清理状态 | `legacy-bundle.json` | JSON | 否 | 已处理/稍后提醒(7 天) | +| 云 Cookie 上传临时文件 | `_cloud_cookies_upload.json` | JSON 明文 | 否 | 遗留 P1 风险:上传临时文件明文落盘 | +| 日志 | `logs/YYYY-MM-DD.log` | 文本,保留 7 个 | 否 | 内存缓冲 + 按日 + 跨天切换 | +| 本地操作偏好 | `localStorage` | `download.skipExpiring`、`download.skipUnauthorizedChannel`、`submit.lastSpuId`、最近 SPU 等 | 否 | 渲染层,生产 `file://` 下可能不可用,读写全 try/catch | + +> **无 sqlite、无数据库**:全部 JSON/JSONL;缓存写入一律「临时文件 + rename」原子写(`dw/electron/platform/cache.ts:11-24`)。 + +### 4.2 配置项全表 + +**A. 用户项(`PersistedUserConfig`,`dw/electron/config/default.ts:16-72`)** + +| 键 | 默认 | 含义 | 远端可覆盖 | +|---|---|---|---| +| `theme` | `light` | 亮/暗/跟随系统 | 否 | +| `downloadPath` | `''` → `~/Downloads/得物素材` | 素材保存目录 | 否 | +| `downloadPreset` | `balanced` | 下载速度档位(保守/均衡/快速) | 档位数值可覆盖 | +| `autoOpenDownloadDir` | `true` | 完成后打开下载目录 | 否 | +| `cookieCloudSync` | `true` | 登录态云同步开关 | 否 | +| `checkUpdateOnStart` | `true` | 启动检查更新 | 否 | +| `autoDownloadUpdate` | `false` | 自动后台下载新版本 | 否 | +| `installOnQuit` | `true` | 退出时安装已下载更新 | 否 | +| `ignoreRemoteConfig` | `false` | 忽略远端配置(逃生口) | 否 | +| `maximizeOnStart` | `true` | 启动最大化(≠全屏) | 否 | + +**B. 档位参数(`downloadPresets`,`dw/electron/config/presets.ts:59-102`)** + +| 参数 | 保守 | 均衡(默认) | 快速 | 远端允许区间 | +|---|---|---|---|---| +| `maxConcurrent` | 2 | 3 | 5 | 1–10 | +| `retryTimes` | 5 | 3 | 3 | 0–10 | +| `downloadTimeout`(秒) | 180 | 120 | 90 | 30–600 | +| `downloadDelayMin/Max`(秒) | 3/8 | 1/3 | 0/1 | 0–30 / 0–60 | +| `batchSize` | 3 | 5 | 10 | 1–50 | +| `batchCooldownMin/Max`(秒) | 20/45 | 10/20 | 3/8 | 0–300 / 0–600 | +| `retryBaseDelay/MaxDelay`(秒) | 5/120 | 3/60 | 2/30 | 1–60 / 10–300 | + +**C. 远端可下发字段(`dw/scripts/lib/remote-config-schema.mjs:32-53`)** + +| 字段 | 类型 | 说明 | +|---|---|---| +| `platform.baseUrl` | URL | 星光主站 | +| `platform.videoLibraryUrl` | URL | 软广视频库页面 | +| `platform.updateCheckUrl` | URL | 更新 feed | +| `platform.cookieCloudUrl` | URL | 云端 Cookie 读地址 | +| `platform.enableSubmitReview` | boolean(独立白名单) | **送审总开关**,内置默认 `true`,远端 `false` 一键止血 | +| `presets.{gentle,balanced,fast}.*` | number | 档位数值覆盖,超区间整份拒收 | + +**D. 开发者项(`dw/electron/config/developer.ts:65-160`,不出现在 UI)** + +| 键 | 值/默认 | 说明 | +|---|---|---| +| `baseUrl` / `videoLibraryUrl` / `spuDetailUrlTemplate` | 星光 + `fast.dewu.com/page/productDetail` | `spuDetailUrlTemplate` **不在远端白名单**(要改需同时改白名单并重签) | +| `updateCheckUrl` / `cookieCloudUrl` | `http://dw_update.xinsenidea.com/...` | **明文 HTTP**(历史债) | +| `cookieSyncKey` / `ftpHost` / `ftpPort` / `ftpUser` / `ftpPassword` / `ftpRemotePath` | **仓库内明文默认值**(`developer.ts:130,135`) | 🔴 严重:凭据仍在源码与 git 历史中,Web 化前必须轮换并改为服务端密钥管理 | +| `timeout` / `headless` | 30 秒 / `true` | 浏览器自动化内部参数,无 UI 开关 | +| `remoteConfigBootstrap.url/publicKey` | 远端配置地址 + Ed25519 公钥 | 信任根,**不可远端下发** | +| `updateMetadataPublicKey` | Ed25519 公钥 | 与远端配置是两把独立密钥 | + +### 4.3 下载文件命名与路径规则 + +**视频素材(星光软广素材库)**: + +``` +{媒体任务ID}-{视频ID}-{SPUID}-{投放类目}-{授权开始日期}-{授权结束日期}.mp4 +``` + +- 空值哨兵:SPUID → `无商品ID`;类目 → `未知类目`;开始 → `无开始日期`;结束 → `无限用日期`; +- `-`/`unknown`/空 均视为无值;长期授权 → `长期-长期`; +- 非法字符 `< > : " / \ | ? *` 替换为 `_`; +- 落盘:先写 `{name}.downloading{ext}` 临时文件 → 校验 MD5 → `rename` 原子转正。 +- 证据:`dw/electron/downloader/utils.ts:11-20,24-37`、`dw/electron/downloader/manager.ts:430`(`-internal.aliyuncs.com` → `.aliyuncs.com` 内网转公网改写)。 + +**商品原始物料(商品查询页)**: + +``` +<下载目录>/商品素材/-<货号>-<标题前40字>/ + 主图-01.jpg … 主图-06.jpg + 详情图-<段落名>-01.jpg … + 主视频.mp4 +``` + +- 取的是 SSR 载荷里的**原图**(`cdn.poizon.com/pro-img/origin-img/...`),不是页面 `webimg.dewucdn.com` 的压缩衍生图;详情图在 `imageAndTextMap` 下; +- 证据:`dw/electron/shop/materials.ts:24-26`、`dw/electron/shop/detail.ts:11-27,242-280`。 + +**提审文件命名(与下载命名刻意不同)**: + +- 模式 A(文件夹批量):文件夹名**恰好** `{媒体任务ID}-{视频ID}-{SPUID}`; +- 模式 B(单文件批量):文件名**末三段** = `{媒体任务ID}-{视频ID}-{SPUID}`,前缀(日期/版本/商品名/授权期/剪辑师)只展示不校验; +- **不兼容**应用自己下载的 `ID 在开头` 的命名 → 明确判识别失败并标红,不会误提交; +- 证据:`dw/docs/送审命名规范与预检规则.md:20-75`、`dw/scripts/lib/submit-naming.mjs`。 + +### 4.4 状态机 + +| 状态机 | 取值 | 说明/证据 | +|---|---|---| +| 登录态(渲染层) | `checking` / `logging_in` / `logged_in` / `not_logged_in` / `error` / `not_ready` | `dw/electron/browser/manager.ts:46-55` | +| 提取/下载任务 | `idle → extracting → downloading → done/stopped/failed`(渲染层 `currentStep 0..3`) | `dw/src/pages/DownloadPage/index.tsx:289,1562-1573` | +| 下载单文件结果 | `success / skipped / failed` + `retryHistory` | `dw/electron/downloader/manager.ts:288-339` | +| 送审行状态 | `pending / warning / conflict / invalid / duplicate / already_submitted / submitted / failed / unknown` | `dw/src/types/index.ts:511-520` | +| 送审批次结果 | `submitted / skipped / failed / unknown` | `dw/electron/submit/batch.ts:1-30`、`dw/src/types/index.ts:792-802` | +| 混剪授权状态 | `valid / soon / expired / not_started / longterm / unknown` | `dw/src/types/index.ts:629`、`dw/scripts/lib/mix-submit.mjs` | +| 审核状态(平台) | 数字:待审核=1 / 通过=2 / 拒绝=3;字符串 `toBeReviewed/reviewPassed/reviewFailed`;Tab 另加「全部=null」 | `dw/scripts/lib/platform-material-mapping.mjs:424-506`、`dw/docs/星光平台API接口文档.md:551` | + +### 4.5 去重与校验 + +- **下载去重**:按内容 MD5(不是文件名)。下载前一次性扫描目录建 `md5 → path` 映射;命中则跳过并写明「经md5校验,本地已存在相同的文件」。已知性能债:**同步全量扫描 + 整文件读内存**(`dw/electron/downloader/manager.ts:174`、`dw/electron/downloader/utils.ts:78-100`;评估文档 §5.1 标 P0)。 +- **送审去重**:只按 `md5`,双向同步——提交成功后立即记账;每次打开审核页/回查把平台审核行的 md5 并进账本(换机/清 userData 后能自愈)。平台侧同样按 md5 在「提交」步查重(`code:900` + msg 含 `md5/重复/已送审`),本地只是提前拦一次流量。 +- **签名/完整性**:远端配置、更新元数据、浏览器 manifest 三处 Ed25519;安装包 sha512 由 electron-updater 校验;浏览器包 sha256 + revision 精确匹配。 +- **上传预检**:原视频授权渠道(`authedMediaIds` 与投放渠道 `deliveryMediaIds` 求交集)、videoId↔xtTaskId 成对性、SPUID 回显、批内同名/同 md5、组数为 0 等。 + +--- + +## 5. 外部平台集成(重点) + +### 5.1 星光平台(唯一外部平台) + +**域名与鉴权** + +| 项 | 值 | 证据 | +|---|---|---| +| 主站 | `https://material-manage.shizhuang-inc.com` | `dw/electron/config/developer.ts:119`(可由远端配置覆盖) | +| 商品站 | `https://fast.dewu.com/page/productDetail?spuId=…` | `dw/electron/config/developer.ts:124` | +| CDN | `h5cdn.dewu.com`、`delivery-platform.dewucdn.com`、`delivery-platform.oss-cn-shanghai.aliyuncs.com` | `dw/docs/星光平台API接口文档.md:19-24` | +| 凭据 | Cookie `materialAccessToken`(非 HttpOnly,会话 Cookie)→ 请求头 `authorization: ` | `dw/docs/星光平台API接口文档.md:54-62` | +| 未登录 | HTTP 401 + `{"code":700,"msg":"请先登录"}`;`hacking-kol` 族则是 HTTP 200 + `code:401` | 同上 §1.4 | +| 会话特性 | **单账号单会话**:网页版登录会顶掉应用 token;应用内所有操作复用同一个 Playwright context | `dw/docs/星光平台送审与审核查询-可行性评估.md:1-120` | + +**登录方式(三条通道)** + +1. **接口登录(主力,P1/P2 已上线)**:`POST /platform/user/send-code` → `POST /platform/user/login` → 响应体 `data.token`(实测长度 168);裸 Node 可完成,不启浏览器;`GET /platform/user/detail` 复核并取账号信息/权限菜单。实测 9/9(`dw/electron/platform/auth.ts:1-70`、`dw/docs/接口登录通道-实现说明.md:146-169`)。 +2. **浏览器登录(兜底)**:有头 Chromium 打开登录页,轮询 120 秒 + 登录后 `detectLoginState()` 再确认;成功后切无头;换账号时先清本地 Cookie。 +3. **云端 Cookie 同步(历史架构)**:HTTP GET `cookies.json`(带 `X-Sync-Key`)+ FTP 上传;v2 分区 `accounts.soft` / `accounts.dplink`,写时只替换自己的分区并回读校验;本地 `safeStorage` 加密。**明文 HTTP + FTP 无 TLS,且是「全体共享一个账号」的传输方式**(`dw/electron/browser/cookieSync.ts:1-40`)。 + +**Cookie 保活**:没有定时刷新/心跳。保活依赖三个检查点——① 启动时 `probeLoginState()` 无头校验;② 业务导航落到登录页时广播 `not_logged_in` 并抛错;③ 用户点侧边栏「重新登录」(清旧 Cookie 或以新 token 覆盖)。云端同步只发生在启动/登录/退出等节点,**不是持续保活机制**;平台无刷新 token 接口,token 失效只能重登。 + +**接口清单(实测/代码在用;完整 106 条静态枚举见 API 文档 §9.3)** + +| 用途 | 方法 | 路径 | 证据 | +|---|---|---|---| +| 软广素材列表(含下载直链) | POST | `/api/v1/h5/delivery-platform/v1/platform/soft-material/material-library/list` | `dw/electron/platform/materials.ts:91`、API 文档 §2.1 | +| 素材全字段详情 | POST | `…/soft-material/material-library/detail` | `dw/electron/platform/materials.ts:177`、API 文档 §2.2 | +| 审核列表(状态/驳回原因/md5) | POST | `…/platform/self-material/list` | `dw/electron/platform/reviews.ts:43`、API 文档 §3.1 | +| 上传/送审记录(含明细 xlsx 预签名) | POST | `…/platform/self-material/publishRecord` | `dw/electron/platform/reviews.ts:44`、API 文档 §3.2 | +| 万能枚举(35 键:驳回原因/品牌/角色…) | GET | `…/platform/common/config-list` | `dw/electron/platform/reviews.ts:45`、API 文档 §5.1 | +| 标签树 | POST | `…/platform/material-label/label-tree` | `dw/electron/platform/reviews.ts:46`、API 文档 §3.3 | +| 账号信息 + 权限菜单 | GET | `…/platform/user/detail` | `dw/electron/platform/reviews.ts:48`、API 文档 §6 | +| 发短信验证码 | POST | `…/platform/user/send-code` | `dw/electron/platform/auth.ts:66` | +| 验证码登录 | POST | `…/platform/user/login` | `dw/electron/platform/auth.ts:68` | +| 媒体多清晰度详情 | POST | `/api/v1/h5/media-data-center/v1/media/query` | API 文档 §3.4(代码未接入) | +| SPUID 预检(标题/品牌/货号) | POST | `…/soft-material/kol-native/spuid-check` | API 文档 §4.1(送审预检数据源) | +| OSS 直传凭证 | POST | `/api/v2/h5/oss-platform/token/customize/stsToken/v2` | API 文档 §4.2(由页面 SDK 调用,应用不实现) | +| 登记 mediaId | POST | `/api/v1/h5/media-center/v1/media/create` | API 文档 §4.4(由页面 SDK 调用) | +| **提交审核(写)** | POST | `…/soft-material/kol-native/upload-derivative-material` | `dw/electron/submit/page.ts:47`、API 文档 §4.5 | +| DPLink 落地页列表 | GET | `…/platform/material-library/list-landing` | `dw/electron/dplink/link.ts:39`、DPLink 文档 §4.4 | +| DPLink 商品库反查 `cSpuId` | POST | `…/platform/material-library/list-commodities` | `dw/electron/dplink/link.ts:41`、DPLink 文档 §4.4 | + +**签名/加密/remote-config** + +- 每个请求带 `?sign=<32位hex>`:`md5(按 key 升序拼接的 "key" + serialize(value) + SALT)`,`SALT = <已脱敏;原值见受控文档>`;GET 覆盖 query、POST 覆盖 JSON body(`dw/scripts/lib/platform-sign.mjs:37,106`、`dw/electron/platform/sign.ts:18-36`)。 +- **启动自校验**:`sign({})` 必须等于平台未登录时实际发出的签名(`fe26befc…`);盐变化时日志直接报「签名盐已变化」,避免把所有 401 误判成登录失效。 +- 平台前端常量(`userId=1000000`、`bizSourceId=500041536`、上传 `appId=Jem7c…`、OSS bucket/prefix)来自前端硬编码,应用侧应配置化而非再硬编码(API 文档 §1.6)。 +- 送审写链路**不重放接口**:用 `page.setInputFiles` 把文件交给平台自己的上传 SDK(含 md5/分片/OSS token/`duToken` 网关),应用只填表 + 点提交 + 观察响应。 +- `remote-config` 是**应用自身**的运维配置(非星光),见 §4.2;三把 Ed25519 密钥分别守护远端配置、更新元数据、浏览器 manifest。 + +**CDN 直连下载与防限速** + +- 下载不走浏览器:Node `http/https.get` 直连素材 `url`;把 `-internal.aliyuncs.com` 改写成 `.aliyuncs.com`(内网地址转公网);`downloadWithRetry` 指数退避 `min(base*2^n, max)`;随机延迟、分批、批间冷却、并发信号量;文件名/目录规则见 §4.3(`dw/electron/downloader/manager.ts:181-227,374-430`)。 +- 商品图/视频下载同样直连 CDN,但只允许 `poizon.com / dewu.com / dewucdn.com` 三个域(IPC 入参防越权),带 `User-Agent` 与 Referer(`dw/electron/shop/materials.ts:82-95,212`)。 +- 已识别的限速/风控线索:平台按账号会话统计;应用刻意把详情并发限制为 4、SPUID 数量查询串行、不并发轰炸(`dw/electron/platform/materials.ts:1-32,121-140`)。 + +**其他平台** + +- **唯品会:无任何代码**(全仓检索 `唯品会/vipshop/vip.com` 零命中)。PRD 的 P-06 多平台能力在本项目完全没有参考实现;`sucaigongfang` 项目是否覆盖唯品会需由另一份调研确认(本报告不越界)。 + +### 5.2 服务端(无 Electron、多用户并发)复现评估 + +| 集成点 | 服务端复现可行性 | 改造点 | 结论 | +|---|---|---|---| +| 只读接口(素材/审核/枚举/标签) | **高**:纯 HTTPS + 签名 + 信封,Node 即可 | 把 `electron/platform/*` 抽成服务端 SDK;token 从「本机加密文件」改为「用户/账号凭据服务」;加缓存与限流 | **直接迁移(工作量小)** | +| 登录(发码/验证码) | **高**:不需要浏览器 | 服务端接收用户手机号/验证码;token 加密落库(KMS/信封加密);处理短信频控与失败码未知问题 | **可迁移,但账号归属需重设计** | +| 会话模型(单账号单会话) | **中**:技术可行,业务冲突 | 必须按「账号」串行化(同一账号同一时刻只允许一个任务),或为不同用户分配不同账号;Web 多用户共享一个 token 会互相顶号 | **最大架构约束之一** | +| 素材下载(CDN 直连) | **高** | 服务端可直接下载并转存对象存储;或下发签名 URL 让浏览器直下(省带宽);保留 MD5 去重与冷却策略,去重索引改 DB/Redis | **可迁移** | +| 商品详情 SSR 直取 | **高** | 服务端 HTTP GET + 解析 `__remixContext`,无需 UA/浏览器;短链解析放服务端(域名白名单) | **可迁移且更稳** | +| 内嵌商品 H5 / 净化 | **低** | Web 端 iframe 受 `X-Frame-Options/CSP` 限制;Electron `` 无对应物。替代:只保留数据卡片 / 服务端截图(成本高、收益低) | **建议废弃** | +| 送审写链路(页面自动化) | **中**:必须服务端浏览器 | 浏览器池 + 每账号一个 context + 上传通道(浏览器→服务端 140–190MB 或服务端代传 OSS)+ 队列/断点/回查/审计;风控暴露面从「单机」变成「机房 IP」 | **可做,但成本最高、风险最高** | +| DPLink | **高**:纯算法 + 两个只读接口 | 硬广账号凭据独立密钥槽;落地页配置存用户/项目级;错误分类保留 | **最划算的迁移项** | +| Cookie 云同步(HTTP+FTP) | **低**:架构应废弃 | 改为服务端凭据库(加密、审计、按用户/账号授权);FTP 与明文 HTTP 不应保留 | **废弃并重写** | +| 自动更新/浏览器分发/代码签名 | **不适用** | Web 无客户端分发;服务端浏览器镜像由部署流水线维护 | **废弃** | +| 本机文件/账本/审计 | **中** | 本地 JSON/JSONL → 数据库表;文件下载 → 对象存储 + 下载中心;路径语义(下载目录)改为「云端素材库/导出任务」 | **需数据模型重设计** | + +**建议的 Web 目标形态(供后续架构评审)**: + +1. **BFF + Worker 两层**:BFF 走只读接口与元数据;Worker 承担 Playwright 浏览器任务(送审、登录兜底),按账号加分布式锁,任务状态落 Redis/DB,前端用 SSE/WebSocket 订阅进度(替代 IPC 事件)。 +2. **上传走「浏览器/客户端 → OSS 直传」**:服务端只发 STS 临时凭证并登记 mediaId,避免 140MB 文件绕行应用服务器;必要时再让服务端浏览器 `setInputFiles` 指向挂载的临时对象。 +3. **凭据服务**:平台 token 与硬广 token 分别加密存储(KMS + 信封),按「用户/项目/账号」授权;禁止再出现仓库内硬编码密钥。 +4. **账号串行化**:以 `accountId` 为粒度排队;同一账号的下载/送审/审核查询并发需互斥(沿用现在 `runExclusive` 的思路,但改为分布式锁)。 +5. **只读优先**:把「读」全部走接口(无浏览器),仅「写」用浏览器,显著降低风控暴露面与资源成本。 + +--- + +## 6. 关键机制与难点 + +### 6.1 Playwright 浏览器自动化 + +- **登录/会话**:`smartStart` 状态机——有会话且有效→复用;云端/本地 Cookie→无头启动注入→校验→写回;失败则有头手动登录(120 秒轮询)→切无头。所有会动会话的操作走 `runExclusive` 串行队列(`dw/electron/browser/manager.ts:223,617-812`)。 +- **读路径**:先挂 `page.on('response')` 拦截页面自身列表响应(第 1 页),后续页/详情走接口;失败整体降级 DOM(点预览弹窗 + 解析字段)。DOM 兜底只保留一期,哈希类名集中在 `legacySelectors.ts` 并加门禁。 +- **写路径**:开送审抽屉 → 定位 `#deliveryMediaIds`/`#xtTaskId`/`#videoId`/`#spuIds`/`#url input[type=file]` → `setInputFiles` → 等上传完成(最长 15 分钟)→ 点提交 → `waitForResponse(SUBMIT_API_PATH)`(60 秒)。选择器必须「限定抽屉内 + 按 `label[title]` 精确匹配」,否则会命中页面上的「KOL投放渠道」筛选框(真机踩坑记录 `dw/electron/submit/page.ts:209-222`、`dw/docs/星光平台API接口文档.md:800-830`)。 +- **难点**:平台改版即失效(最高频维护工作);上传完成没有可靠事件,只能轮询百分比/表单回显;抽屉复用必须显式清空上一条残值;「提交超时」不能重试。 + +### 6.2 登录态托管 + +- 本地 `safeStorage` 加密 + 云端 v2 分区共享;`loginInteractive(force)` 换账号;`logout` 只清本机并置 `ignoreCloudCookies`;启动预检 `probeLoginState` 用无头浏览器只校验、不弹窗。 +- **已知边界**:单账号单会话(网页版登录会顶掉);接口登录失败码未实测;应用侧凭据落地(落盘/注入/云同步)仍需真人点一次才能验证;`verify:login` 刻意不进 CI(会发真短信、会让跑的人生效掉线)。 + +### 6.3 批量上传:并发/重试/断点 + +- **串行**而非并发(同一个浏览器会话,且上传本身占满上行);整批圈进 `runExclusive`,下载/送审互斥。 +- **可中断**:中断请求在当前条跑完才停(避免半截抽屉 + 账本未落盘)。 +- **可续跑**:账本按 md5 拦住已成功项;失败项不记账;「结果未知」只回查(3 次退避)不重试。 +- **重试**:只有网络错误/5xx 才重试 1 次;提交响应超时绝不重试。 +- **失败显式**:抽屉打不开、字段找不到、上传未完成 → 带 `reasonCode` 的 failed,并 dump 页面实况(抽屉数量、入口是否被遮、`elementFromPoint`)。 + +### 6.4 命名字段组合与预检规则 + +- 命名只承载三要素(媒体任务ID/视频ID/SPUID),前缀不校验;末三段解析 + 文件夹名恰好三段双候选,冲突不自动挑、要求人工确认;`无spuid` 五种写法大小写不敏感;位数 ≠ 19 只警告不阻断。 +- 预检两段式:① 文件名解析(毫秒级,不读盘)先出结果;② md5 查重 + SPUID 商品标题回显(秒~几十秒,异步可取消)。只有 `pending/warning` 可勾选;失败可「就地修好」。 +- 送审前额外预检:原视频授权渠道、videoId↔xtTaskId 配对、SPUID 一致性、组数;「unknown 不阻断」是刻意保守策略(宁可白传一次,不可误拦)。 + +### 6.5 混剪任务 + +- 成品只解析最后一个 SPUID;每条成品带 N 组 `{xtTaskId, videoId}`;右栏从平台素材库或本机下载目录检索源,授权状态六档;已过期/未生效/明确未授权默认不勾;平台检索目前只取第一页(最多 30 条)、无「加载更多」;Phase 2 Excel/CSV 导入未实现。 +- **风险点**:「混剪=是」的写链路(选「是」、增删行、无 id 的视频ID输入框、组数回读)**尚未真机验证**,只做了离线门禁。 + +### 6.6 错误码与重试 + +| 平台回答 | 应用行为 | 说明 | +|---|---|---| +| `code:200` | 成功,记 md5 | 成功必须看 `code`,不能只看 HTTP 状态 | +| HTTP 401 + `code:700` | 未登录:停止批次、侧边栏变红、指向重登 | 与平台故障区分 | +| HTTP 200 + `code:401` | 平台族故障(`hacking-kol`),不当作未登录 | 平台自身页面也报错 | +| HTTP 200 + `code:900` | 业务校验失败:**必须看 msg**;只有含 `md5/重复/已送审` 才当重复记账,否则按 failed 显式展示 | 曾因「只看 900」把业务拒绝误记成已送审 | +| 提交超时/无响应 | unknown → 回查审核列表(3 次);命中记 submitted,未命中提示稍后刷新 | 绝不重试 | +| 网络错误/5xx | 只读请求重试 1 次;下载按档位指数退避;发短信不重试 | — | + +### 6.7 更新与代码签名(Web 化后大概率废弃,但资产有价值) + +- 桌面更新链路:electron-updater + 自建 feed;更新元数据 `.sig` Ed25519 验签 → 强制/最低版本/跳过版本;mac 走 Squirrel/ShipIt 原生替换 `.app` 并支持改名迁移;Win NSIS 静默安装。 +- 代码签名:mac Developer ID 签名 + 公证 + 装订 + 产物门禁;Win 目前无签名(历史状态)。 +- **Web 化后这些全部消失**,但可复用其**设计模式**:信任根不可远端下发、原始字节签名、灰度放行策略表、revision 单调、双密钥隔离。这些模式可直接用于新平台的「配置中心/发布系统」安全设计。 + +--- + +## 7. 代码规模与质量 + +### 7.1 规模(口径见页首) + +| 目录 | 文件数 | 行数 | 主要内容 | +|---|---|---|---| +| `src/` | 67(ts/tsx) | **19,120** | 6 页 + 19 组件 + 3 Context + 1 Hook + 15 个 `.d.ts` + 1 个 `types/index.ts` | +| `electron/` | 45(ts) | **17,345** | IPC/浏览器/平台接口/送审/商品查询/DPLink/配置/更新/日志 | +| `scripts/` | 73(mjs/cjs) | **27,828** | 32 个 verify 脚本 + 21 个共享纯逻辑 + 探针/截图/发版/签名 | +| `release-scripts/` | 5 | **875**(mjs/cjs;含 .sh/README 共 1,497) | 本机发版、mac 签名/公证、Windows 构建 | +| **合计** | **190** | **65,168** | 不含 CSS(3,675 行)与 docs(30 篇、14,633 行) | + +**单文件 Top(复杂度集中点)**:`DownloadPage/index.tsx` 2,241 行;`browser/manager.ts` 1,962;`ipc/handlers.ts` 1,822;`submit/page.ts` 1,824;`ConfigPage/index.tsx` 1,241;`SubmitPrecheckModal.tsx` 1,035;`ReviewPage/index.tsx` 1,004;`UpdatePage/index.tsx` 896;`playwrightInstaller.ts` 864;`ShopPage/index.tsx` 841。 + +### 7.2 类型与规范 + +- `tsconfig.json`:`strict: true`、`noUnusedLocals`、`noUnusedParameters`、`noFallthroughCasesInSwitch`;`include: ["src","electron"]`;无 `allowJs`,因此 `scripts/lib/*.mjs` 靠**手写 `.d.ts` 副本**+ `verify:type-declarations` 门禁保证一致。 +- **无 ESLint / Prettier 配置**(仓库根目录无相关文件);格式靠约定与 review。 +- `any` 仍有:`preload.ts` 51 处、`handlers.ts` 15 处、`src` 16 处(跨进程类型未共享,历史评估标 P1)。 +- 无全局状态管理库:Context + 页面内 state;下载/送审状态主进程持有,渲染层用事件订阅。 + +### 7.3 测试与质量门禁 + +| 层 | 现状 | +|---|---| +| 单元测试框架 | **无**(无 vitest/jest,`src/App.test.tsx` 名不副实,是组件不是测试) | +| 离线验证 | **32 个 `verify:*` 脚本**,合计 15,411 行;`verify:ui` 5,283 行 / 472 个 `ok()` 断言点(v2.7.0 记录 480 通过;真实 Chromium 加载真实 `dist/`);`verify:platform` 2,352 行 / 255 个 `ok()` 断言点(v2.7.0 记录 260 通过;真实抓包 fixture + 静态边界);`verify:channels` 101 条通道唯一来源;`verify:type-declarations` 33 个导出;`verify:mix` 24;`verify:filter` 43 | +| 实机对比脚本 | `compare:extraction-paths`、`compare:review-list`、`compare:submit-payload`(人工登录后跑,结果落盘对账) | +| CI | `ci.yml` 三 job(gates / ui-verify / package-size);发版走 `release.mjs` + `build-release.yml`;历史教训「验证资产 10 个只有 1 个进 CI」已修 | +| 依赖审计 | `audit:prod` 强制官方 registry(防 npmmirror 不支持 audit 导致「无漏洞」假象);critical/high 失败 | +| 已知质量债 | 大文件上帝模块;`preload` 大量 `any`;`CSP` 宽松(允许 http/https/ws/`unsafe-eval` 已移除但范围仍宽);`scanDirectoryMd5` 同步读内存;日志/控制台噪音;无前端虚拟列表;无端到端自动化(写链路靠人工真机) | + +### 7.4 文档与已知风险 + +- `docs/` 现有 **121 个文件、30 篇 Markdown(14,633 行)**,包括:星光 API 接口文档(807 行,含签名盐与 106 条接口)、送审/审核可行性评估(928 行)、P1/P2/P4 实现说明、送审命名规范、混剪方案、DPLink 评估、远端配置运维手册、签名/公证清单、项目评估 2.1.0(1,063 行)等。 +- `DEVELOPMENT.md` 2,380 行,是**以代码为准**的交接文档,但其 §1-§14 基线停在 v1.0.6,**已明显滞后于 v2.7.0**;§17-§19 是后续补的登录态/商品查询/接口登录章节。**新平台调研应优先信任代码与 2.x 的实现说明文档**。 +- **已知问题与风险(代码/文档交叉确认)**: + 1. 🔴 **仓库内仍硬编码运维凭据**(`cookieSyncKey`、FTP 密码,`dw/electron/config/developer.ts:130,135`),且在 git 历史中;Web 化前必须轮换、改服务端密钥管理,不可沿用。 + 2. 🟠 **单账号单会话**是平台行为(网页版登录顶掉应用 token);多用户 Web 化必须按账号串行/分账号。 + 3. 🟠 **明文 HTTP + FTP 无 TLS** 用于更新/远端配置/Cookie 同步;新平台应拒绝此模式。 + 4. 🟠 平台接口/页面结构随时可能变更:签名盐、字段、选择器、权限菜单;维护成本高(`docs/` 多篇文档都在记录平台变更)。 + 5. 🟡 Playwright 依赖声明 `^1.40.0` 与实际 1.60.0 漂移(已有 `verify:playwright-version` 守版本→revision 映射,但锁文件仍应 pin)。 + 6. 🟡 浏览器分发/更新/签名/旧包清理的复杂度对 Web 化无意义,但占主进程相当比例代码与文档。 +- `DEVELOPMENT.md §12` 列出「文档与实现的偏差」,`docs/项目评估与优化建议-2.1.0.md` 给健康度加权 **3.0/5**(产品完成度 4.5、安全信任链 2.0、测试质量 2.0、性能 3.0);其中 P0 缺陷多数已在 2.1.x-2.7.0 修复(重试退避、可重入、浏览器版本、验签),**硬编码凭据与 MD5 扫描仍是历史遗留**。 + +--- + +## 8. 逐模块 Web 化复用评估(核心交付) + +**复用级别**:A=前端页面/组件几乎直接复用;B=改造成本可控;C=需服务端重写;D=废弃。人日为粗估(含联调,不含需求/设计评审)。 + +| 模块 | 现有实现 | 目标端形态 | 复用级别 | 改造要点 | 粗估人日 | 风险 | +|---|---|---|---|---|---|---| +| 应用外壳/导航/主题/骨架屏/错误边界 | React + Semi + Tailwind;`App.tsx` 558 行 | 新平台 Shell | **A(结构)/B(视觉)** | 保留信息架构(侧边栏、页头、分区、骨架屏、未保存守卫);重写导航与主题 token;Semi 组件替换(见 §8.1) | 3–5 | 低 | +| 素材下载 · 任务工作台 UI | `DownloadPage` 2,241 行;阶段化布局、双重过滤、素材预览、结果分级、重试历史 | 新平台「原始物料获取」页 | **B** | 保留交互模型与状态机;Semi→新 UI;`localStorage` 偏好改用户配置;「打开目录/通知」改「导出到素材库/下载中心」 | 8–12 | 中(页面巨大、需重排信息层级) | +| 素材提取(只读接口路径) | `platform/materials.ts`、`browser/manager.ts` 拦截路径 | 服务端取数服务 | **B** | 直接用签名客户端;去掉浏览器与 DOM 兜底;保留「读取方式/降级」可观测语义 | 5–8 | 中(签名盐/接口变更) | +| 下载引擎(CDN/MD5/限速/重试) | `downloader/manager.ts` + `utils.ts` | 服务端下载 Worker + 对象存储 | **C** | 文件系统→对象存储;MD5 扫描→DB/Redis 索引+流式 MD5;并发/冷却策略保留;临时文件/原子改名改为分片上传完成标记 | 12–18 | 中高(带宽/存储成本、平台限速) | +| 商品查询 · 工作台 UI | `ShopPage` 841 行 + `ActionBar`/`MaterialGrid`/`useShopDownload` | 新平台「选品」页 | **B** | 保留「命令条+画布+面板+底栏」布局与 9 项素材格;去掉 webview 画布或改为可选;Semi→新 UI | 8–12 | 中 | +| 商品详情 SSR 直取/短链解析 | `shop/detail.ts` 359 行 | 服务端选品服务 | **B** | 服务端 HTTP + `__remixContext` 解析;短链解析+域名白名单;图片原图 URL 规则保留 | 4–6 | 低中(站点结构变更) | +| 内嵌商品 H5 + 净化模式 | `SpuCanvas.tsx`、`shop/session.ts` | — | **D** | Web 端无法等价复现;最多保留「查看原页」外链或服务端截图 | 0(可选 3–5) | 中(做了也价值低) | +| 素材审核页 | `ReviewPage` 1,004 行 + 6 子组件 + `review-csv.mjs` | 新平台「提审/审核」页 | **B** | 只读接口直接迁移;表格/筛选/驳回富文本/CSV 逻辑保留;Semi→新 UI;权限提示保留「建议不硬拦」 | 8–12 | 中(平台字段/权限变化) | +| 只读接口层(签名/客户端/缓存/授权预检) | `electron/platform/*` 2,526 行 | 服务端 SDK | **B** | 抽包;凭据来源改注入;缓存改 Redis/DB;错误分类保留;`authorization.ts` 的「unknown 不阻断」策略保留 | 5–8 | 中(签名/接口契约) | +| 命名解析/预检/CSV/过滤/进度模型等纯逻辑 | 21 个 `scripts/lib/*.mjs` + `.d.ts` | 服务端/前端共用包 | **A** | 直接抽成 npm 包(保持「应用与门禁同一份实现」);补真单测 | 3–5 | 低 | +| 批量送审判定与编排 | `submit/plan.ts`、`idempotency.ts`、`audit.ts`、`verify.ts`、`batch.ts` | 服务端送审服务 | **B–C** | 策略层可复用(串行/中断/回查/记账/审计);存储改 DB;队列改任务系统;进度改 SSE | 8–12 | 中高(写操作) | +| 送审页面自动化(Playwright) | `submit/page.ts` 1,824 行 | 服务端浏览器 Worker | **C** | 浏览器池 + 账号锁;选择器集中配置化;上传改「客户端→OSS→服务端挂载」;日志/证据链保留 | 18–25 | **高(平台风控/改版/大文件)** | +| 混剪配对 UI | `MixSubmitModal.tsx` 683 行 | 新平台混剪送审页 | **B** | 双栏交互与授权状态保留;Semi→新 UI;补「加载更多」与 Excel Phase 2 | 8–12 | 中 | +| 混剪服务端编排 | `submit/mix.ts`、`source-search.ts`、`mix-submit.mjs` | 服务端 | **C** | 源检索(平台+本地下载库)改「平台素材库+云端素材库」;N 组配对校验保留;「混剪=是」需真机验证 | 6–10 | 高(未真机) | +| DPLink 拼装/复制 | `dplink/link.ts` 420 行 + `account.ts` + `dplink-link.mjs` | 服务端投放配置服务 | **B** | 纯算法与错误分类直接迁移;硬广凭据改 KMS;落地页配置改项目级;复制按钮保留(前端) | 5–8 | 中(硬广账号权限/共用凭据) | +| 登录态与账号体系 | `auth.ts`、`cookieSync.ts`、`SidebarLoginStatus`、`LoginDialog` | 平台账号中心 | **C** | 接口登录可迁移;浏览器兜底需 Worker;云端 FTP 同步废弃→凭据库;多用户账号归属/授权/审计重设计 | 8–12 | **高(单会话/账号归属/合规)** | +| 配置管理/远端配置 | `config/*`(1,261 行)+ `remote-config-schema.mjs` | 平台配置中心 | **B** | 用户项→用户级 DB;档位预设与白名单保留;远端配置改服务端配置中心(不必 Ed25519,除非仍需离线下发);`enableSubmitReview` 保留为运维开关 | 4–6 | 低中 | +| 日志/审计/诊断 | `logger.ts`、`submit/audit.ts` | 服务端日志/审计 | **B** | 本地文件→结构化日志/审计表;保留「审计只追加、写失败不阻断」的语义 | 3–4 | 低 | +| IPC 通道层 | 101 条通道 / preload | HTTP API + SSE/WebSocket | **C** | 契约可参考(通道名/入参/进度事件),实现全部重写;长任务改异步任务 + 订阅 | 5–8 | 中 | +| 自动更新/关于页/旧版清理/窗口状态 | updater 438 行 + legacy + window state | — | **D** | Web 无客户端;关于页可保留为「帮助/版本信息」薄页 | 0–1 | 低 | +| 验证门禁资产 | 32 个 verify 脚本 + fixtures | 新平台测试套件 | **B** | `.mjs` 纯逻辑断言可直接用;真实抓包 fixture 可做契约测试;UI 断言(472 条)大部分随新 UI 失效,需重写 | 6–10 | 低中 | + +**合计粗估:约 115–190 人日**(低值=理想路径、无返工;高值=含平台改版适配/联调/真机验证)。其中「送审页面自动化 + 账号体系 + 下载引擎」三项占 **50% 以上**,是 Web 化成败关键。 + +### 8.1 Semi Design 2 与新平台 UI 选型的冲突处理 + +**冲突事实**:当前 UI 是 2026-10 从 Ant Design 全量迁到 **Semi Design 2.103**(React 19),组件 API/主题/图标/表单校验/表格/弹窗都深度绑定 Semi;页面级 CSS 3,675 行大量使用 `--semi-color-*` token、`@layer tailwind-utils` 与 `.semi-*` 类名。如果新平台 UI 选型是 Ant Design/Arco/自研,**组件层不能直接复用**。 + +**建议策略(按投入产出排序)**: + +1. **分层复用,不整体搬迁**:把「纯逻辑 + 类型 + 接口封装 + 页面状态机」与「视觉组件」切开。前者(约 30–40% 代码量)跨 UI 库可复用;后者重写。 +2. **先定设计 token,再谈组件**:把 Semi 的语义色/圆角/间距收敛成新平台 token(现在代码里已有集中化迹象:`icons.tsx`、`PageHeader`、`ProgressRow`、`SettingsRow`),避免把 `--semi-*` 变量原样搬进新平台。 +3. **只对高价值组件做适配层**:表格(审核列表)、弹窗/抽屉(送审判定)、进度行、Toast 提示可写薄适配层;不要为每个组件做 Semi↔新库 shim(维护成本会超过重写)。 +4. **样式资产可复用的部分**:布局类(`.shop-*`/`.dl-*`/`.review-*`)本质是 CSS Grid/Flex,可提取为设计系统布局原语;**依赖 `.semi-*` 内部 DOM 的样式必须丢弃**(`verify:css-layers` 也说明层叠顺序是精心维护的)。 +5. **如果新平台也选 Semi**:可复用度显著提高(页面组件可近乎直搬),但仍需处理 React 版本、主题、路由与 Electron API 替换。**建议在 UI 选型评审时把「是否 Semi」作为明确决策项**,因为它直接决定 8–12 人日的差异。 + +--- + +## 9. 可复用资产清单 + +### 9.1 纯逻辑 / 协议层(最高价值,A 级) + +| 资产 | 路径 | 价值 | +|---|---|---| +| 星光请求签名 + 序列化规则 + 自校验 | `dw/scripts/lib/platform-sign.mjs`(含 SALT,敏感值已脱敏)、`dw/electron/platform/sign.ts` | 服务端直连星光的关键;自校验能第一时间发现盐变更 | +| 平台字段映射 / 授权时间解析 / 审核状态映射 / 权限判定 | `dw/scripts/lib/platform-material-mapping.mjs`(719 行) | 与真实抓包逐字段对齐;P1/P2 的地基 | +| 送审命名解析 + 预检/载荷/审计记录形状 | `dw/scripts/lib/submit-naming.mjs`(1,013 行) | 新平台「命名规则 + 提审预检」可直接复用;有大量真实样本 | +| 混剪成品/源组/授权状态/结构校验 | `dw/scripts/lib/mix-submit.mjs`(约 500 行) | 混剪业务规则唯一实现 | +| 审核 CSV 构建 + 公式注入防护 | `dw/scripts/lib/review-csv.mjs` | 导出与界面列同源;安全细节可复用 | +| 驳回原因 HTML 白名单 AST | `dw/scripts/lib/reason-html.mjs`(1,028 行) | 平台自由文本渲染的安全方案(非 `dangerouslySetInnerHTML`) | +| 素材过滤规则(30 天/渠道) | `dw/scripts/lib/material-filter.mjs` | 与 PRD「授权/到期」相关的业务规则 | +| DPLink 拼装(双层/encode/常量) | `dw/scripts/lib/dplink-link.mjs` | 4 条样本 4/4 逐字符复现,可直接迁移 | +| 进度模型 / 送审进度模型 | `dw/scripts/lib/progress-model.mjs`、`submit-progress.mjs` | 统一进度语义与界面断言 | +| 远端配置 schema/白名单/区间 | `dw/scripts/lib/remote-config-schema.mjs` | 若新平台需要「运维不发版改配置」,可直接复用设计 | +| Cookie 分区 bundle(v1/v2 兼容) | `dw/scripts/lib/cookie-bundle.mjs` | 多账号凭据分区与迁移思路;**传输方式需重写** | +| Ed25519 原始字节签名/验签 | `dw/scripts/lib/ed25519-signature.mjs`、`update-metadata.mjs`、`browser-manifest-trust.mjs` | 信任链设计可迁移到配置中心/发布系统 | + +### 9.2 服务端候选代码(B 级,抽包后可用) + +| 资产 | 路径 | 说明 | +|---|---|---| +| 只读 HTTP 客户端 + 信封解析 + 失败分类 | `dw/electron/platform/http.ts`、`client.ts`、`types.ts` | 超时/重试/响应上限/`code` 分类;与登录层共用一份 | +| 素材列表/详情取数(并发 4、降级可见) | `dw/electron/platform/materials.ts` | 直接改造成服务端模块 | +| 审核列表/记录/枚举/标签树 + TTL 缓存 | `dw/electron/platform/reviews.ts`、`cache.ts` | 缓存/TTL/stale 语义清晰 | +| 授权渠道预检(unknown 不阻断) | `dw/electron/platform/authorization.ts` | 送审前风控策略可直接用 | +| 商品详情 SSR 解析 + 短链解析 | `dw/electron/shop/detail.ts` | 无浏览器取数的高价值实现 | +| 商品素材下载/命名/URL 白名单 | `dw/electron/shop/materials.ts` | 原始物料落盘结构参考 | +| 送审批次策略机(串行/中断/回查/记账/审计) | `dw/electron/submit/{batch,plan,verify,idempotency,audit}.ts` | 写链路业务策略层,独立于 Playwright | +| DPLink 拼装编排/错误分类 | `dw/electron/dplink/link.ts`、`account.ts` | 依赖硬广账号;接口参数已在文档中核实到「两个只读接口」 | + +### 9.3 前端页面/组件(B 级,需去 Semi 化) + +- 页面:`DownloadPage`(任务工作台与三阶段布局)、`ShopPage`+`ActionBar`+`MaterialGrid`(工作台布局)、`ReviewPage`+`ReviewTable`+`ReviewFilters`+`ReviewDetailModal`+`PublishRecordsModal`(审核表格与筛选)、`SubmitPrecheckModal`(预检/就地编辑/批量补字段)、`MixSubmitModal`(双栏配对)、`SubmitProgressPopover`/`SubmitProgressBody`(进度浮层)、`ConfigPage`(分区清单设置页)、`UpdatePage`/`AboutPage`(可参考信息架构)。 +- 通用组件:`PageHeader`、`ProgressRow`、`SettingsRow`、`SettingsSection`、`MaterialPreview`、`SpuCanvas`(仅参考承载思路)、`CopyButton`(页面内)、`ErrorBoundary`、4 个骨架屏、`LoginDialog`、`SidebarLoginStatus`、`DplinkAccountDialog`、`DplinkLandingDialog`。 +- 状态/工具:`src/contexts/{Theme,LoginStatus,UnsavedChanges}.tsx`(未保存守卫可直接复用思路)、`src/utils/spu.ts`(SPU 解析/价格/最近查询)、`spuIdList.ts`(多 SPUID 归一化/校验)、`updateLabels.ts`、`remote-config-label.ts`。 +- 类型契约:`src/types/index.ts`(1,000+ 行,含 ElectronAPI、IPC 载荷、审核/送审/混剪/下载/更新类型)、13 个 `.d.ts` 纯逻辑类型声明——可作为**新平台 API DTO 草案**,但需与后端共同评审。 + +### 9.4 文档(可直接迁移,价值排序) + +| 文档 | 行数 | 迁移价值 | +|---|---|---| +| `docs/星光平台API接口文档.md` | 807 | ⭐⭐⭐⭐⭐ 接口/签名/枚举/选择器/错误码全量,是服务端复现的**唯一权威**(注意含盐值,不可外发) | +| `docs/送审命名规范与预检规则.md` | 235 | ⭐⭐⭐⭐⭐ 命名/解析/预检/批量语义,直接对应 PRD P-04 | +| `docs/星光平台送审与审核查询-可行性评估.md` | 928 | ⭐⭐⭐⭐ 读写分离、页面自动化理由、单会话约束 | +| `docs/DPLink组成与一键复制-可行性评估.md` | 545 | ⭐⭐⭐⭐ 双层链接算法/字段/实测样本,对应 PRD P-05 | +| `docs/P1读数据接口化-实现说明.md` / `P2素材审核查询-实现说明.md` / `P4素材送审-实现说明.md` | 540/516/1,068 | ⭐⭐⭐⭐ 实现取舍、真机踩坑、门禁清单(P4 含 19 轮真机记录) | +| `docs/混剪素材批量上传-开发方案.md` / `混剪素材批量送审-实现说明.md` | 496/151 | ⭐⭐⭐ 混剪业务规则与 Phase 2 方向 | +| `docs/接口登录通道-实现说明.md` | 273 | ⭐⭐⭐ 登录接口化实测与红线 | +| `docs/远端配置运维手册.md` | 190 | ⭐⭐⭐ 白名单/签名/revision/应急停用;可迁移为配置中心 SOP | +| `docs/项目评估与优化建议-2.1.0.md` | 1,063 | ⭐⭐⭐ 架构/性能/安全/测试的系统性评估(部分已修,需按现状核对) | +| `DEVELOPMENT.md` | 2,380 | ⭐⭐⭐ 目录/主进程/IPC/配置/踩坑全量,但基线 v1.0.6,**只读 §3-§8 与 §17-§19,其余核对代码** | +| `docs/签名与公证落地清单.md`、`构建发布与版本更新指南.md` | 227/859 | ⭐⭐ 桌面端专用,Web 化后仅作历史参考 | + +--- + +## 10. 风险与待确认问题 + +### 10.1 风险 + +**R1 平台合规/封禁(高)** +- 本项目是**未授权的页面自动化 + 接口逆向**:签名盐从平台前端产物取得,账号是客户共享账号;平台条款是否允许此类工具、是否会把团队账号风控,**没有任何书面确认**。 +- Web 化后从「个人电脑 IP」变为「机房 IP + 多用户高频」,平台侧流量特征更显眼,封号/限流风险上升。 +- 建议:法务/客户成功提前确认;保留「只读优先、写操作人工确认、可一键停用」的设计(现有 `enableSubmitReview` 就是范式)。 + +**R2 登录态与账号归属(高)** +- 平台**单账号单会话**:网页版登录会顶掉应用 token;多用户 Web 化若共享一个 token 会互踢。现有云端 Cookie 同步(HTTP+FTP 明文)是「团队共享一个账号」的临时方案,不适合作为平台级账号体系。 +- 硬广账号是客户给团队的**共用账号**,DPLink 依赖它;多人同时使用/退出语义(退出只清本机)需要产品化定义。 +- 账号归属、权限(platform 的 `user/detail` 权限菜单表)、数据可见范围(谁看谁的送审/审核)都需要新平台的权限模型。 + +**R3 接口/页面稳定性(高)** +- 签名盐、字段、枚举、选择器、权限菜单都可能随平台发版变化;本项目用 32 个验证脚本 + 真机对比脚本 + 抓包 fixture 对抗,但**没有 SLA/版本协商**。 +- 混剪「混剪=是」写链路、登录失败码、素材审核部分字段尚未真机覆盖(文档已标注)。 +- 新平台应把「平台适配层」隔离为可独立发版的服务,并提供「平台变更检测/健康检查」机制(签名自校验已有雏形)。 + +**R4 Electron 能力缺口(中)** +- 内嵌 webview、本地文件路径/对话框、剪贴板、系统通知、打开目录、safeStorage、FTP、自动更新、代码签名、窗口状态——Web 端均无等价物,需要替代方案(对象存储、浏览器下载、通知中心、KMS、部署流水线)。 +- 特别是**送审大文件**(140–190MB)从「本地路径 `setInputFiles`」变为「浏览器→服务端→平台」,带宽与上传成功率是新增风险;建议优先设计「客户端→OSS 直传 + 服务端只发凭证」。 + +**R5 数据迁移(中)** +- 本地 `config.json`/`cookies.json`/`dplink-*`/`submitted-md5.json`/`submit-audit.jsonl`/下载目录命名规则都是「单机事实」;迁移到多用户平台需要: + - 账号与凭据迁移(safeStorage 加密跨机器不可解,必须重新登录); + - 已送审账本(避免重复送审)与审计日志的历史价值; + - 下载文件/命名规则兼容(历史文件如何进新素材库); + - 本地路径偏好(下载目录)在新平台无意义。 +- 建议迁移策略:**不做客户端数据自动迁移**,只提供「md5 账本 + 审计日志导入」与「重新登录」;历史素材通过新平台重新拉取/上传。 + +**R6 凭据泄露(高,且为既成事实)** +- 星光/FTP 凭据曾在源码与 git 历史中;即使轮换,旧仓库/文档/随包产物仍可能流出。新平台**不得复用**这些凭据;上线前必须轮换并审计。 + +### 10.2 待确认清单 + +| 编号 | 问题 | 为什么影响整合 | 建议向谁确认 | +|---|---|---|---| +| Q-01 | 星光平台是否允许内部工具/服务端自动化?客户/平台方对此的书面态度? | 决定「服务端重写送审」是否合规,可能直接否决整个写链路 | 业务方 + 客户成功 + 法务 | +| Q-02 | 新平台的账号体系:一人一星光账号,还是团队共享账号池? | 决定会话串行化、权限、审计与凭据设计;现有单账号假设不成立 | 产品负责人 + 客户 | +| Q-03 | 新平台是否也要服务唯品会?其后台是否有可复用的接口/登录方式? | 决定 P-06 是否另起一套适配层;本项目零参考 | 产品 + 另一项目调研(sucaigongfang) | +| Q-04 | DP / 承接页的准确业务口径是什么?DPLink 是否就是 PRD 所指的「自动配置」? | 决定 P-05 的范围;本项目只做了得物 DPLink(iOS/安卓唤端链接),不含 DP 字段 | 业务方(PRD 1.1.3) | +| Q-05 | 新平台的 UI 选型是否包含 Semi?还是 Ant Design/Arco/自研? | 直接决定前端 8–12 人日差异与组件复用边界(§8.1) | 设计负责人 + 前端负责人 | +| Q-06 | 平台原始素材(图片/视频)在新平台的存储形态:对象存储?CDN?保留多久? | 决定下载引擎改造与成本;现有「本地目录 + 文件名」语义要替换 | 架构 + 运维 | +| Q-07 | 「图片/视频 AI 产线」是否已有供应商/模型选型? | 与 dewu 项目无关,但影响整体排期与数据流(原始物料→产线→提审) | 产品 + AI 负责人 | +| Q-08 | 混剪送审是否仍由人工配对,还是需要 Excel/CSV 导入(Phase 2)? | 决定 8–12 人日 UI 的范围;当前 Phase 2 未实现 | 业务方 | +| Q-09 | 历史数据(已送审 md5、审计日志、下载文件)是否需要迁移? | 决定迁移成本与「重复送审」风险 | 业务方 + 产品 | +| Q-10 | 写链路是否保留「人工确认 + 可中断 + 远端一键停用」的安全设计? | 若要求无人值守批量提交,风险与实现复杂度都会显著上升 | 业务方 + 风控 | +| Q-11 | 平台接口的 SLA/变更通知机制是否存在?谁负责平台改版后的适配? | 决定长期维护成本归属(≈1 人持续投入) | 客户/平台方 + 研发负责人 | +| Q-12 | 账号权限菜单(`user/detail.list`)是否可作为新平台的功能门禁依据? | 现有实现只做「建议不硬拦」;若要做硬权限需确认菜单稳定性 | 平台方 + 产品 | + +--- + +## 11. 证据索引 + +> 路径前缀 `dw/` = `参考项目/dewu-material-Downloader/`。以下为关键结论的最小证据集(≥25 条)。 + +| # | 结论 | 证据 | +|---|---|---| +| 1 | 版本 2.7.0、应用标识 | `dw/package.json:3`、`dw/electron-builder.yml:1-2` | +| 2 | 技术栈(Electron 44 / React 19 / Semi 2 / Playwright) | `dw/package.json:70-96` | +| 3 | 6 个一级入口与 BETA 标记 | `dw/src/App.tsx:240-306` | +| 4 | 6 条路由 | `dw/src/App.tsx:437-442` | +| 5 | 101 条 IPC 通道、87 invoke + 14 event | `dw/electron/ipc/channels.ts:1`、`dw/electron/preload.ts:15,87,124,190,230,300` | +| 6 | 写链路红线(不直接调写接口) | `dw/electron/submit/page.ts:2-30` | +| 7 | 提交接口路径与上传超时 15 分钟 | `dw/electron/submit/page.ts:47,68` | +| 8 | 送审抽屉选择器(按 label 精确匹配、限定抽屉) | `dw/electron/submit/page.ts:77-110,209-222` | +| 9 | 批量送审策略表(成功/重复/失败/超时/掉线) | `dw/electron/submit/batch.ts:1-30` | +| 10 | 只按 md5 幂等 + 双向同步 | `dw/electron/submit/idempotency.ts:1-36` | +| 11 | 审计/请求体 JSONL 路径 | `dw/electron/submit/audit.ts:29-40,151` | +| 12 | 命名规范(模式 A/B、末三段、无 spuid) | `dw/docs/送审命名规范与预检规则.md:20-93` | +| 13 | 下载命名规则 | `dw/electron/downloader/utils.ts:11-20` | +| 14 | 下载分批/并发/冷却/重试 | `dw/electron/downloader/manager.ts:181-227,374-430` | +| 15 | MD5 全量同步扫描(性能债) | `dw/electron/downloader/manager.ts:174`、`dw/electron/downloader/utils.ts:78-100` | +| 16 | 星光签名盐与算法 | `dw/scripts/lib/platform-sign.mjs:20-37,73-106` | +| 17 | 素材列表/详情接口路径 | `dw/electron/platform/materials.ts:91,177` | +| 18 | 审核/记录/枚举/账号接口路径 | `dw/electron/platform/reviews.ts:43-48` | +| 19 | 登录接口路径与 token 事实 | `dw/electron/platform/auth.ts:1-70` | +| 20 | 接口登录实测 9/9 | `dw/docs/接口登录通道-实现说明.md:146-169` | +| 21 | 平台 API 全量文档(含签名/枚举/送审) | `dw/docs/星光平台API接口文档.md:130,197,229,277,326,342,366,379,522,594` | +| 22 | 读写分离与单会话红线 | `dw/docs/星光平台送审与审核查询-可行性评估.md:1-120`、`dw/docs/新功能开发计划.md:455-475` | +| 23 | 送审四步链路与 SPU 误报教训 | `dw/docs/星光平台API接口文档.md:340-520` | +| 24 | 远端配置三道防线/白名单 | `dw/electron/config/remote.ts:1-40`、`dw/scripts/lib/remote-config-schema.mjs:32-53` | +| 25 | 送审总开关/线上配置 revision 2 | `dw/remote-config/app-config.json:26,72` | +| 26 | 硬编码凭据仍在源码 | `dw/electron/config/developer.ts:130,135` | +| 27 | 三档下载参数与远端区间 | `dw/electron/config/presets.ts:59-102`、`dw/scripts/lib/remote-config-schema.mjs:60-80` | +| 28 | 商品详情 SSR 直取(无浏览器) | `dw/electron/shop/detail.ts:11-27,182-280` | +| 29 | 商品素材落盘结构/URL 白名单 | `dw/electron/shop/materials.ts:24-26,82-95` | +| 30 | 内嵌页 UA/分区/净化(Electron 依赖) | `dw/electron/shop/session.ts:32-66,198-200` | +| 31 | DPLink 双层算法与接口 | `dw/docs/DPLink组成与一键复制-可行性评估.md:12-35`、`dw/electron/dplink/link.ts:39-41` | +| 32 | DPLink 硬广凭据隔离 | `dw/electron/dplink/account.ts:1-40` | +| 33 | Cookie 同步 v2 分区(soft/dplink) | `dw/electron/browser/cookieSync.ts:1-40` | +| 34 | 登录态状态机与串行队列 | `dw/electron/browser/manager.ts:46-55,223` | +| 35 | 浏览器组件三级检测/验签 | `dw/electron/browser/playwrightInstaller.ts:1-125,436` | +| 36 | 更新元数据验签/强制/最低版本 | `dw/electron/updater/manager.ts:185,231,274-301` | +| 37 | CI 三 job 与门禁清单 | `dw/.github/workflows/ci.yml:53-217,257` | +| 38 | 验证脚本规模(verify:ui 480 通过 / verify:platform 260 通过) | `dw/scripts/verify-ui-behavior.mjs`(5,283 行)、`dw/scripts/verify-platform.mjs`(2,352 行) | +| 39 | TypeScript strict | `dw/tsconfig.json` | +| 40 | 项目评估健康度 3.0/5 与 P0 清单 | `dw/docs/项目评估与优化建议-2.1.0.md:27-43,314,455,705` | +| 41 | 素材过滤规则(30 天/未授权快手) | `dw/scripts/lib/material-filter.mjs`、`dw/docs/素材下载过滤开关-实现说明.md:1-40` | +| 42 | 混剪 Phase 1 未真机 | `dw/docs/混剪素材批量送审-实现说明.md:1-65` | +| 43 | 审核状态映射与 CSV 列 | `dw/scripts/lib/platform-material-mapping.mjs:424-506`、`dw/scripts/lib/review-csv.mjs:34-45` | +| 44 | DEVELOPMENT.md 基线过时(v1.0.6 vs 2.7.0) | `dw/DEVELOPMENT.md:1-13,1715-1830` | +| 45 | 无唯品会代码 | 全仓检索 `唯品会\|vipshop\|vip.com` 零命中 | diff --git a/docs/评估/_调研/sucaigongfang-调研报告.md b/docs/评估/_调研/sucaigongfang-调研报告.md new file mode 100644 index 0000000..8e1f4f8 --- /dev/null +++ b/docs/评估/_调研/sucaigongfang-调研报告.md @@ -0,0 +1,740 @@ +# 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.`。 +> 接口规模:**约 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/` | 商品原图 + 抠图中间产物 | ❌ 可清理 | `workers.ts:203` | +| `uploads/output/` | 生成素材 | ❌ 可清理 | `workers.ts:234` | +| `uploads/zip/` | ZIP 交付包 | ❌ 可清理(有保留天数) | `workers.ts:830-840` | +| `uploads/tag-logos` | 标签 logo | ✅ | `tagController.ts:24` | +| `uploads/temp` | 上传临时区 | ❌ 可清理 | `storageCleanup.ts:36-40` | +| `uploads/thumb/` | 按需缩略图缓存(WebP q80) | ✅(随源删除 + 孤儿清扫) | `imageThumbnail.ts:40-60` | + +- **对外 URL 规则**:`/uploads/<相对路径>`,JWT 鉴权(`Authorization` 头或 `` 场景 `?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=`(浏览器 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.` 计数) | +| 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 篇)仅做存在性登记,未逐篇展开。 +- 未运行任何测试/构建,所有质量结论均来自静态代码与脚本内容;「实际能否一次跑通」属**待确认**。 diff --git a/docs/评估/平台电商素材生产平台_整合可行性评估_V0.1.md b/docs/评估/平台电商素材生产平台_整合可行性评估_V0.1.md new file mode 100644 index 0000000..2388ce8 --- /dev/null +++ b/docs/评估/平台电商素材生产平台_整合可行性评估_V0.1.md @@ -0,0 +1,1173 @@ +# 平台电商素材生产平台 · 双项目整合可行性评估 + +> **文档类型**:技术 + 产品可行性评估(评审稿) +> **版本**:V0.1 rev.2 | **状态**:待评审 | **日期**:2026-10-30 +> **评估对象**:`参考项目/dewu-material-Downloader/`(得物素材助手 v2.7.0)、`参考项目/sucaigongfang/`(素材工坊 v1.0.0) +> **依据文档**:`docs/PRD/平台电商素材生产平台_PRD_V0.1.md` +> **密级**:内部 | **注意**:本文及两份调研报告引用了得物星光平台的接口路径、签名机制与登录方式,**属平台敏感信息,不可外发客户或平台方** +> **配套调研**:`docs/评估/_调研/dewu-调研报告.md`(726 行)、`docs/评估/_调研/sucaigongfang-调研报告.md`(740 行) +> +> **评审输入更新(2026-10-30,rev.2)**: +> ① 项目定位为**内部平台**(仅内部人员使用),但部署方式为**公网可访问 + 登录鉴权**; +> ② **设计资产(PSD 模板 / 展示方式 / 促销模板)由设计师角色提供,M1 前可给 ≥5 个真实模板 + 规范**; +> ③ **客户已授权我们使用其平台账号**(待补书面授权文件与范围),平台侧封禁风险由客户承担。 +> 注意:① 只解决"我方平台合规",不等于平台方允许服务端自动化;③ 降低但不消除平台条款残余风险(见 §5.7 / §10.1 D-09)。 +> +> **技术栈定稿(2026-10-30)**:见 `docs/技术架构/技术栈架构_定稿_V1.0.md`。相对本评估,**ORM 由 Sequelize 改为 Prisma 7.10.1**(+8~12 人日),UI 改为 **Semi 2.104 + Tailwind 4**;本评估 WBS 已同步为 **391~581 人日**、首期闭环 **288~426 人日**。 + +--- + +## 阅读指引 + +- 只想看结论:读 **第 0 章**与**第 11 章**。 +- 要判断做不做、先做什么:读 **第 3、4、5、8 章**。 +- 要判断投多少人力/多少钱:读 **第 7 章**。 +- 要拍板:读 **第 10 章**(决策项 + 待确认问题)。 +- 本文所有数字都有口径;证据等级标注为 **【代码】**(直接读源码确认)、**【文档】**(项目文档记载)、**【实测】**(历史项目真机/抓包验证记录)、**【推断】**(基于结构的判断,需 POC 确认)。 + +--- + +## 0 执行摘要 + +### 0.1 一句话结论 + +**两个项目整合为一个统一 WEB 平台在技术与产品上都成立,且互补性远大于重叠性;但这不是"合并两个仓库",而是"以新建统一工程为骨架,把两个项目分别作为「生产产线」与「投放作业端」的资产源迁入",其中图片产线代码级复用约 60%~70%,得物投放作业端约 50%~60% 需服务端重写,视频 AI 产线是 100% 新建。** + +**结论:有条件 Go(建议立项),前置条件是 4 个必需 POC(POC-1~4)+ 3 个支线 POC(POC-5~7)+ 1 份**客户书面授权文件**(客户已同意我们使用其平台账号,待补文件与授权范围)。安全侧需按"公网可访问"加固。设计资产供给已确认由设计师角色提供(M1 前 ≥5 个真实模板 + 规范)。** + +### 0.2 三个关键判断 + +| # | 判断 | 依据 | 影响 | +|---|---|---|---| +| 1 | **形态成立**:统一 WEB 端可行,Electron 桌面端可以停止演进 | 得物侧「读」链路已在裸 Node 实测可复现(签名 + 只读接口),「写」链路(送审)可服务端化:项目当前选择页面自动化(技术上也可重放写接口,但成本与风控更高,需 POC 择一);项目负责人已确认「彻底 Web 化」 | 桌面端专属能力(自动更新/签名/窗口/Cookie 同步等)全部废弃,Electron 主进程约 1.7 万行需重写或废弃(纯逻辑抽包保留) | +| 2 | **互补成立**:两项目拼起来正好是 PRD 主链路的两端,工程层重叠估计约 15%~20% | dewu 覆盖「选品 → 原始物料 → 提审 → 投放链接」;scgf 覆盖「模板 → 批量图片生产 → 命名 → 导出」;重叠集中在登录/权限/配置/队列/通知等工程层 | 整合的主要工作量在"接缝"(物料库、命名/提审、平台抽象),而不是"去重" | +| 3 | **差距成立**:PRD 是目标态,现状距目标仍有明显缺口 | 按 PRD 表 1-3 的 27 项功能框架逐条比对:**完全满足 1 项、部分满足 12 项、完全空白 14 项**(§4.1);P-02 四层信息、P-03 视频、P-06 多平台、P-07 资产中心是主要缺口 | 首期不能承诺"PRD 全量 P0",必须做范围裁剪(§4.4 / §8) | + +**本次评审输入带来的变化(rev.2)**: + +| 输入 | 结论 | 对方案的影响 | +|---|---|---| +| 内部平台、不对外部用户开放 | 单租户、内部账号体系;但**部署为公网可访问(带登录鉴权)** | 省去多租户约 2~3 人日,但新增公网安全加固 4~8 人日(已单列 §7.2 第 28 项);平台侧自动化风险仍按 R-01 管理 | +| 设计资产由设计师角色提供,M1 前可给 ≥5 个真实模板 + 规范 | A-01 成立,设计资产不属于研发交付物 | P-02 具备闭环前提;M1 可直接用真实模板做 POC-4 与回归;规范不到位仍会阻塞出图 | +| **客户已授权我们使用其平台账号** | 账号使用权与封禁风险由客户承担(**待补书面文件与授权范围**) | D-09 从"Go/No-Go 未知"降为"已确认、待文件";仍需保留半自动降级与一键停用 | + +### 0.3 推荐方案(评审主选项) + +**方案 C:新建统一工程 + 双项目资产迁移**(与您已确认的技术底座选择一致) + +``` + ┌──────────────────────────────────────────────────────┐ + │ 统一 WEB 端(React 19 + Semi Design + Tailwind) │ + └───────────────┬──────────────────────────────────────┘ + │ HTTPS / SSE + ┌───────────────────────┼───────────────────────────┐ + │ │ │ +┌─────▼─────┐ ┌──────▼──────┐ ┌──────▼──────┐ +│ API/BFF │ │ 图片渲染 │ │ 平台作业 │ +│ Express5 │ │ Worker │ │ Worker │ +│ PG/Redis │ │ (sharp/PSD/ │ │ (Playwright: │ +│ BullMQ │ │ 抠图) │ │ 登录/送审/ │ +└─────┬─────┘ └──────────────┘ │ 审核/投放) │ + │ └──────────────┘ + │ ┌──────────────┐ + └────────────────────┤ AI Worker │ + │ 生图/视频 │ + └──────────────┘ +``` + +- **复用 scgf**:后端工程地基(认证/权限/客户范围/系统配置/迁移/队列/事件/失败目录/通知/打包)、PSD 解析与合成引擎、抠图、命名引擎、任务与可观测体系(约 80~115 人日迁移改造)。 +- **复用 dewu**:21 个纯逻辑库(星光签名、命名解析、混剪规则、审核 CSV、DPLink 拼装、远端配置 schema)、只读接口层、商品详情 SSR 直取、送审批次策略、页面交互信息架构(约 60~85 人日迁移改造 + 服务端化)。 +- **新建**:多平台抽象、平台账号/凭据中心、选品与物料库、图片多资产渲染(Logo/促销/AI 模特/脚模)、提审工作流、投放配置、AI 生图产品化、视频 AI 产线、对象存储、Worker 拆分(约 215~330 人日)。三类口径有交叉,**不作为严格加总**;**合计 391~581 人日**(严格以 §7.2 逐项加总为准;含 ±25% 不确定性,不含人力成本)。 + +### 0.4 首期范围建议(图片先行) + +**建议首期(MVP,得物单平台)闭环**: +`平台切换(仅得物) → SPUID 检索/圈选 → 原始物料(主图/详情图/主视频)入库 → 模板 + 三规格 + 商品图 + Logo/促销四层合成 → 批量预览/导出(按路径/命名) → 提审清单与状态 → DPLink 一键复制` + +**M3 多平台**:唯品会适配、平台切换、新增平台机制。 +**M4 AI 增强**:AI 生图产品化、资产中心、投放配置(DP/承接页)扩展、混剪送审。 +**M5 视频产线**:脚本 → 画面 → 组合;数据看板随后。 + +### 0.5 关键数字速览 + +| 指标 | 数值 | 口径 | +|---|---|---| +| 两项目代码总量 | 约 **12.9 万行代码**(dewu 65,253 含 MJS/CJS 脚本 / scgf 63,632 含 CSS) | 口径见两份调研报告 §7.1 / §6.1 | +| 两项目数据模型 | dewu 无数据库(本地 JSON/JSONL);scgf **19 张表 / 11 个迁移** | scgf 方案可直接作为统一库起点 | +| 两项目接口/通道 | dewu **101 条 IPC**(87 invoke + 14 event);scgf **约 113 个 HTTP 接口 / 17 个 Router** | 统一后全部收敛为 HTTP/SSE | +| 两项目测试 | dewu 32 个 verify 脚本、15,411 行(无单测框架);scgf `node:test` 175 用例,无 DB/E2E | 统一后需补契约测试与渲染回归 | +| 功能框架覆盖 | PRD 表 1-3 共 27 项:**完全 1 / 部分 12 / 空白 14** | §4.1 逐条 | +| 首期闭环工作量(M0 + MVP-1 + MVP-2) | 约 **288~426 人日**(AI 辅助),传统估算约 **411~609 人日** | §7.2 | +| 全量平台工作量 | 约 **391~581 人日**(AI 辅助),传统估算约 **559~830 人日** | §7.2 | +| 建议人力/周期 | 3 人 + AI:首期闭环约 **5.5~8.5 个月**、全量约 **8~11.5 个月**;2 人:**8.5~12.5 / 11.5~17.5 个月**;1 人:**17~25.5 / 23~34.5 个月** | §7.3/§8.1 | + +> 人日为"一名熟悉本仓库的工程师全职投入"的量级估算,非承诺值;AI 辅助系数按 0.65~0.8 折算,M0 结束后必须用真实任务校准(§7.4)。 + +--- + +## 1 评估范围与方法 + +### 1.1 评估对象 + +| 项目 | 形态 | 定位 | 版本/基线 | 代码量 | 成熟度 | +|---|---|---|---|---|---| +| **dewu-material-Downloader** | Electron 44 桌面双端(Win 主力 / mac 开发验证) | 得物星光平台软广素材的**桌面运营工作台**:素材下载 + 商品查询 + 素材审核 + 批量/混剪送审 + DPLink | v2.7.0,HEAD `fe7646b`,228 commits,2026-05→10 | 65,253 行代码(src 19,120 / electron 17,345 / scripts 27,828 / release 875 + 根目录构建配置 85) | 功能闭环,真机覆盖不均;无单测框架,靠 32 个 verify 脚本 + CI 门禁 | +| **sucaigongfang** | Web 全栈(pnpm workspace,前后端双包) | 图片素材自动化生产系统:PSD 模板 → 商品图 → 批量合成 → 命名 → 打包交付 | v1.0.0,HEAD `d1b01fa`,249 commits,2026-03→09 | 63,632 行 TS/TSX/CSS(后端 30,835 / 前端 32,797) | 可部署生产态(容器化 + 反代 + 回滚);175 个纯函数单测;AI 能力仅验证未产品化 | + +### 1.2 评估依据与方法 + +| 依据 | 说明 | +|---|---| +| 源码通读 | 两份调研报告基于逐目录、逐模块只读通读;关键结论附 `文件:行` 证据(合计 105 条) | +| 项目文档 | dewu 30 篇 14.6k 行、scgf 33 篇(但 **`docs/` 被 .gitignore 忽略、0 入库**);文档与代码冲突处以代码为准 | +| git 历史 | 提交数、tag、活跃度、分支(scgf 的 `backup/ai-asset-m1` 分支约 10 万行、已声明作废) | +| 历史实测记录 | 星光接口登录通道实测 9/9;签名自校验 + 抓包 fixture 门禁;送审非混剪真机 1 条端到端;DPLink 4/4 逐字符复现;AI 生图 34/34 成功等 | +| PRD | 仅 1.1/1.2 有实质内容,2~10 章为空模板;本文只按 1.1 问题表(P-01~P-07)与 1.2 功能框架(表 1-3)做覆盖度比对 | +| **未做** | 未安装依赖、未运行构建/测试、未做真机验证、未向平台方求证、未取得 AI 供应商报价。所有"可行性"判断为**代码级判断**,需以 §6 的 POC 结论替代 | + +### 1.3 术语对齐 + +统一使用 PRD 术语:平台 / 选品 / 原始物料 / 模板 / 展示方式 / 脚本 / 提审 / DP / 承接页 / 配置信息;"产线"指图片产线、视频产线;"作业端"指平台侧操作(登录、下载、送审、审核、投放链接)。 + +--- + +## 2 两个项目的现状画像 + +### 2.1 dewu-material-Downloader(Electron 桌面端) + +#### 2.1.1 它实际是什么 + +名称是"下载器",但 v2.x 已演进为**得物星光平台的桌面运营工作台**,五段闭环: + +``` +① 登录(接口验证码登录 / 浏览器兜底 / 云端 Cookie 同步) +② 选品(素材下载页按 SPUID 筛选;商品查询页支持 SPUID/链接/App 分享文本) +③ 原始物料(视频:媒体任务ID-视频ID-SPUID-类目-授权期.mp4;商品图/主视频:按商品目录归档) +④ 提审(命名解析 → md5 查重 → 预检 → 批量/混剪送审 → 审核状态查询 → 审计) +⑤ 投放(DPLink:iOS UniversalLink / 安卓 DeepLink 一键复制) +``` + +#### 2.1.2 技术架构 + +| 层 | 选型 | 说明 | +|---|---|---| +| 渲染层 | React 19.3 + Semi Design 2.103 + Tailwind 3.4 + react-router 6(HashRouter) | 6 个一级页面;无全局状态库,3 个 Context | +| 主进程 | Electron 44 + TypeScript strict | 101 条 IPC;`contextIsolation` + preload 白名单 | +| 关键能力 | Playwright 1.60(声明 ^1.40,已漂移)+ 直连 CDN + safeStorage + basic-ftp | 浏览器会话、上传、加密凭据、Cookie 云同步 | +| 数据 | **无数据库**:`config.json` / `cookies.json` / `dplink-*.json` / `platform-cache/*.json` / `submit-audit.jsonl` / `logs/` | 全部本机 `userData`,原子写;多处 safeStorage 加密 | +| 发布 | electron-builder + electron-updater + Ed25519 三把密钥(远端配置 / 更新元数据 / 浏览器 manifest) | Windows NSIS / macOS dmg + 签名公证 | + +#### 2.1.3 与 PRD 的覆盖关系(重要) + +| PRD 问题 | 覆盖度 | 说明 | +|---|---|---| +| P-01 原始物料 | **部分(仅得物)** | 商品图/主视频/视频素材库均可抓取并归档;**无"本次选品物料库"概念** | +| P-02 图片制作 | **0** | 全仓无 PSD、无模板合成、无三规格产出 | +| P-03 视频制作 | **0** | 无脚本、无 AI 视频;只有"下载已有视频" | +| P-04 命名提审 | **部分(提审强、命名固定三字段)** | 提审链路完整(预检 + 批量送审 + md5 幂等 + 审核查询 + 审计);命名固定为 `{媒体任务ID}-{视频ID}-{SPUID}` 末三段解析,**不支持 PRD 要求的自定义字段组合** | +| P-05 投放配置 | **部分(仅 DPLink)** | 只做商品 → 唤端链接拼接与复制;**不含 DP 编写、承接页字段批量替换** | +| P-06 多平台 | **0** | 全仓检索 `唯品会 / vipshop / vip.com` **零命中** | +| P-07 资产管理 | **0** | 无模板/Logo/脚本资产库 | + +#### 2.1.4 最有价值的可迁移资产 + +| 资产 | 位置 | 价值 | +|---|---|---| +| 星光请求签名(含 salt)+ 启动自校验 | `scripts/lib/platform-sign.mjs`、`electron/platform/sign.ts` | 服务端直连星光的关键;盐变更可第一时间发现 | +| 平台字段映射 / 授权时间解析 / 审核状态映射 | `scripts/lib/platform-material-mapping.mjs`(719 行) | 与真实抓包逐字段对齐 | +| 送审命名解析 + 预检/载荷/审计形状 | `scripts/lib/submit-naming.mjs`(1,013 行) | 直接对应 PRD P-04,含大量真实样本 | +| 混剪业务规则 | `scripts/lib/mix-submit.mjs` | 混剪配对/授权状态/结构校验唯一实现 | +| DPLink 双层拼装 | `scripts/lib/dplink-link.mjs` | 4/4 样本逐字符复现;**依赖独立的星光硬广账号**(软广账号调 `list-landing` 会 401) | +| 只读接口层(签名/信封/缓存/授权预检) | `electron/platform/*`(2,526 行) | 改造成服务端 SDK 成本低 | +| 商品详情 SSR 直取 | `electron/shop/detail.ts` | 无需浏览器,服务端可直接复现 | +| 送审批次策略层(串行/中断/回查/幂等/审计) | `electron/submit/{batch,plan,verify,idempotency,audit}.ts` | 写链路业务策略,独立于 Playwright | +| API 文档(含 106 条接口枚举、选择器、错误码) | `docs/星光平台API接口文档.md`(807 行)等 | 服务端复现的唯一权威资料 | + +#### 2.1.5 必须重写 / 废弃的部分 + +- **Electron 外壳**:内嵌 `` 商品 H5 + 净化模式(Web 端受 `X-Frame-Options/CSP` 限制,无等价物)、本地文件路径/dialog、系统通知/剪贴板/打开目录、safeStorage、自动更新/代码签名/窗口状态、旧版本清理、HTTP GET 拉取 + FTP 上传的 Cookie 云同步(v2 双分区)。 +- **IPC 层**:101 条通道 → HTTP + SSE/WebSocket;契约可参考,实现重写。 +- **本地 JSON 基础设施**:config/cookies/cache/账本/审计/下载目录 → 数据库 + 对象存储 + 凭据服务。 +- **服务端浏览器**:Playwright 会话管理、送审页面自动化(`submit/page.ts` 1,824 行)必须重写为服务端浏览器池 + 账号分布式锁 + 大文件上传通道。 +- **UI**:Semi 组件与 `.semi-*` 样式深度绑定,新平台若换 UI 库则组件层需重写(§5.5)。 + +#### 2.1.6 成熟度与质量 + +- 优点:TypeScript strict 全开;32 个验证脚本 + 3 个 CI job;真实抓包 fixture;大量"为什么这么写 + 踩过什么坑"的注释;读写分离、超时只回查、幂等账本等业务红线清晰。 +- 问题:无 vitest/jest,无 ESLint/Prettier;非混剪送审已真机成功 1 条、混剪「是」写链路未真机;大文件上帝模块(DownloadPage 2,241 行、browser/manager 1,962 行);**`electron/config/developer.ts:130,135` 仍硬编码 Cookie 同步密钥与 FTP 密码(且在 git 历史中)**;本地 MD5 全量同步扫描是性能债。 +- 官方自评(`docs/项目评估与优化建议-2.1.0.md`)健康度 3.0/5(产品完成度 4.5、安全信任链 2.0、测试质量 2.0、性能 3.0)。 + +### 2.2 sucaigongfang(Web 全栈) + +#### 2.2.1 它实际是什么 + +面向信息流广告投放(电商唤端 + 券商)的**图片素材批量生产线**: + +``` +① 管理员:建客户 → 建用户并绑定客户/角色 →(可选)客户级命名规则 +② 设计师:上传 PSD → ag-psd 解析 → 逐图层绑定「图片替换/文本替换/剪贴蒙版」→ 预览图 → 归客户/分类/标签/规格 +③ 优化师:选模板(可多选)→ 上传商品图(≤100)→ 文件名识别商品ID/名称/品牌 → 表格可编辑 + → 生产参数(抠图/尺寸/JPG/缩放/字号)→ 二次确认提交 +④ 系统:建批次(N 模板 × M 商品图 交叉)→ 命名快照 + 预渲染文件名 → BullMQ +⑤ Worker:白底判定 → imgly/ONNX 抠图 → MaterialComposer 合成 → materials 落库 → WS 推送 +⑥ 收尾:站内信 → ZIP 打包 → 下载;任务列表/详情/时间线/失败目录/CSV +``` + +#### 2.2.2 技术架构 + +| 层 | 选型 | 说明 | +|---|---|---| +| 前端 | React 19.2 + Arco Design 2.66 + Tailwind 4 + zustand + axios + router 7 + Vite 8 | 16 个页面;113 个 API 方法;设计 token 单点 + CI 静态校验 | +| 后端 | Node 24 + Express 5 + Sequelize 6 + PostgreSQL 18 + Redis/BullMQ + ws | API 与 Worker **同进程**;19 表 / 17 Router / 约 113 接口 | +| 图像 | ag-psd 30 + @napi-rs/canvas + sharp 0.32.6(锁版)+ fontkit + imgly/ONNX | PSD 解析/合成/字体兜底/抠图 | +| 导出 | archiver(ZIP level 9)+ CSV + 按需 WebP 缩略图 | 异步打包 + 选集下载 | +| 部署 | 双镜像(Node 24-slim / nginx 1.27)+ 1Panel PG/Redis/OpenResty + 备份/回滚脚本 | 单机、本地磁盘 `uploads` | + +#### 2.2.3 与 PRD 的覆盖关系 + +| PRD 问题 | 覆盖度 | 说明 | +|---|---|---| +| P-01 原始物料 | **0** | 无抓取;商品图靠本地手工上传 | +| P-02 图片制作 | **约一半** | 有"模板 + 商品图 + 文本层",**缺 AI 模特/脚模、Logo 组合、促销图层、三档规格固定语义**;规格是通用 `(w,h)` | +| P-03 视频 | **0** | 全仓无视频/ffmpeg | +| P-04 命名提审 | **命名全覆盖、提审 0** | 命名引擎成熟;无提审清单/状态机 | +| P-05 投放配置 | **0** | 无 DP/承接页/链接 | +| P-06 多平台 | **0** | 系统无"平台"维度("得物"仅出现在通知模板示例文案) | +| P-07 资产管理 | **部分** | 模板/分类/标签/规格/批次模板强;Logo/展示方式/脚本无 | + +#### 2.2.4 最有价值的可迁移资产 + +| 资产 | 位置 | 价值 | +|---|---|---| +| 工程地基 | 17 Router / 19 模型 / 11 迁移 / 健康检查 / 进程兜底 | 统一平台后端约 70% 非业务工作量 | +| 认证与账号安全 | JWT + `pwdv` 口令版本、强制改密、三态口令有效期、一次性随机口令、IP+用户名限流、审计 | 安全设计高于平均水平,直接复用 | +| RBAC + 客户范围 | 权限 key 目录 + `fail-closed` 客户范围 + 全链路校验 | 升级为"平台 × 客户"双层范围即可 | +| 系统配置框架 | 40 项 / 10 模块 / L1-L3 生效级别 / 审计 / 专用控件 | **最值得整套继承**的机制;加 `platform/ai/video` 模块即可 | +| PSD 合成引擎 | `utils/materialComposer.ts`(1,773 行):15 种混合模式、剪贴蒙版、三档缩放、字体兜底、JPG 二分质量 / PNG 调色板压缩 | 全项目最贵资产;**但只支持单一商品图入参**(§6.1 第 3 项) | +| 抠图 | imgly/ONNX + 白底判定 + 降级告警 | 失败会标 `low_quality_warning`,不静默交付 | +| 任务与可观测 | BullMQ 2 队列 + DB 计数 + WS 节流 + 失败口径分轮次 + 事件目录 + 失败目录 + 90 天保留 + 卡死巡检 | 统一任务中心底座 | +| 命名引擎 | 变量模板 + 客户级 + 批次快照 + 校验 + 商品图识别三层兜底 | PRD P-04 的一半 | +| 导出/打包 | CSV(BOM 防乱码、1 万条上限)+ 选集 ZIP + 整批异步 ZIP | 按路径导出可直接改造 | +| 通知 | 5 类可配模板 + 站内信 + WS 触发 | 需补独立通知中心页与提审/投放事件 | +| 前端设计体系 | token 单点 + `verify-design-tokens.mjs` CI 硬卡 + AdminLayout/守卫/共享组件 | 迁移为统一设计系统 | + +#### 2.2.5 必须重写 / 废弃的部分 + +- **AI 能力全部不算数**:`main` 分支**没有任何 AI 产品代码**;M0(VLM 反推/图层分离)验证完成、M1 分支 53 commits 约 3.1 万行**已被官方声明整体作废**、M2-0(Seedream 表单式生图)验证完成但**产品代码从零开始**(§6.1 第 4 项)。 +- **素材制作页(2,625 行)与首页 Dashboard**:信息架构按新 PRD 完全变化,需重写;可复用"上传识别 + 字段表格 + 参数 + 二次确认"的逻辑。 +- **单进程架构**:API 与 Worker 同进程、本地磁盘、内存限流,无法支撑"多产线 + AI"(§6.1 第 7 项)。 +- **菜单/路由/权限三处硬编码**:加一个模块要改 4 处,新平台应配置驱动。 +- **文件存储**:纯本地磁盘、无 OSS 适配层。 + +#### 2.2.6 成熟度与质量 + +- 优点:容器化 + 备份/回滚 + 6 步 CI 硬卡;175 个纯函数单测;fail-closed 数据范围;系统配置/任务事件/失败目录等治理机制成熟;大量注释记录"踩过的坑"。 +- 问题:**`docs/` 整体 gitignore(110 个文件 0 入库)**,AI 验证结论与部署手册只在本机;无 DB/HTTP 集成测试、无 E2E、PSD 渲染无回归;渲染引擎与抠图单机内存峰值;API/Worker 同进程;`SystemConfigAudit` 不脱敏导致 AI Key 不能进配置;字体 `方正兰亭中黑简体` 商用授权待确认。 + +### 2.3 横向对比 + +| 维度 | dewu-material-Downloader | sucaigongfang | 对整合的含义 | +|---|---|---|---| +| 端形态 | Electron 桌面双端 | Web 全栈 | 统一为 Web,桌面能力重写/废弃 | +| 业务段 | 选品 / 物料 / 提审 / 投放 | 模板 / 生产 / 命名 / 导出 | **互补,接缝在物料与命名/提审** | +| 平台覆盖 | 得物(星光)单平台 | 无平台概念(客户维度) | 多平台抽象是新建 | +| 数据层 | 无 DB(JSON/JSONL) | PostgreSQL 19 表 + Redis | 以 scgf 数据层为起点 | +| 任务层 | Electron 主进程内串行 | BullMQ + DB 计数 + WS | 统一任务中心,Worker 拆分 | +| 认证/权限 | 无用户体系(单机单账号 + 平台凭据) | JWT/RBAC/客户范围/审计 | 以 scgf 为起点,加平台账号维度 | +| UI | Semi Design 2 + Tailwind 3 | Arco Design 2 + Tailwind 4 | 需统一(§5.5) | +| 测试 | 32 个 verify 脚本(无单测框架) | 175 个 node:test(无集成/E2E) | 互补:纯逻辑 + 契约测试 | +| 文档 | 30 篇、14.6k 行,已入库 | 33 篇,**未入库** | 整合第一件事是文档抢救入库 | +| 主要风险 | 平台合规/账号单会话/接口稳定性 | 单机架构/渲染引擎/字体版权 | 两类风险叠加,需分别治理 | + +--- + +## 3 能力重叠、互补与空白分析 + +### 3.1 功能域对照矩阵 + +> 图例:✅ 完整 🟡 部分 ❌ 无 — 不适用。仅列能力域,不含页面级细节(页面清单见两份调研报告 §2)。 + +| 能力域 | dewu | scgf | PRD 是否要求 | 统一平台建议 | +|---|---|---|---|---| +| 登录 / 用户 / 角色 / 权限 | ❌(单机无用户体系,只有平台登录态) | ✅ JWT + RBAC + 客户范围 + 口令安全 | 隐含(多角色:设计/优化/运营/管理) | **以 scgf 为起点**,补平台账号授权 | +| 客户 / 品牌归属 | ❌ | ✅ 客户 + 用户绑定 + fail-closed 范围 | 隐含(多品牌 Logo、唯品会) | 升级为"平台 × 客户 × 项目" | +| 平台切换 / 多平台 | ❌ 仅得物 | ❌ 无平台概念 | ✅ P0 | **新建** | +| 选品检索(SPUID / 粗词) | 🟡 得物 SPUID / 链接 / 分享文本 | ❌ | ✅ P0 | 迁移 dewu 商品查询并扩粗词 | +| 选品圈选 / 历史选品 | 🟡 多 SPUID 列表,无"选品批次" | ❌ | ✅ P0/P1 | **新建选品批次/圈选模型** | +| 原始物料抓取 / 归档 | 🟡 抓取完整(得物)、归档仅本地目录 | ❌ 靠手工上传 | ✅ P0 | 迁移并接入物料库 + 对象存储 | +| 物料库 / 商品快照 | ❌ 落本地目录 | ❌ | 隐含 | **新建**(统一主数据) | +| PSD 模板管理 / 图层契约 | ❌ | ✅ | ✅ P0 | 迁移 scgf,加平台/客户归属 | +| 模板渲染合成 | ❌ | ✅ 单商品图(1,773 行) | ✅ P0 | **改造为多资产图层**(核心工作) | +| 展示方式(AI 模特 / 脚模 / 设计导入) | ❌ | ❌(只有单商品图) | ✅ P0 | **新建资产类型 + 渲染分支** | +| 商品位置(固定 / AI 调优) | ❌ | 🟡 固定位置已支持(由替换图层 bbox 决定);AI 调优 ❌ | ✅ P0 | 补 AI 调优,列 P1 | +| Logo 主/副 + 拼接字符 | ❌ | 🟡 标签 logo 字段存在但未接入合成 | ✅ P0 | **新建组合式 Logo 资产 + 渲染** | +| 促销信息(折扣/活动标识) | ❌ | 🟡 文本层可放文案,无促销模板 | ✅ P0 | **新建促销图层/模板** | +| 三规格(800² / 1280×720 / 1080×1920) | ❌ | 🟡 通用 (w,h) 规格 | ✅ P0 | 固定枚举 + 可扩展规格 | +| 批量出图 / 预览 | ❌ | ✅ N 模板 × M 商品交叉批量 | ✅ P0/P1 | 迁移生产页与批量逻辑 | +| 命名规则引擎 | 🟡 送审命名固定三字段(末三段解析) | ✅ 变量模板 + 客户级 + 快照 | ✅ P0 | 合并为统一命名引擎(两套变量域,补自定义字段组合) | +| 导出 / 打包 / 下载 | 🟡 按路径落本地 | ✅ ZIP/CSV/选集下载 | ✅ P0 | 对象存储 + 导出中心 | +| 提审(内部待审清单/状态) | 🟡 只有平台侧审核查询 | ❌ | ✅ P0 | **新建内部提审工作流** | +| 批量送审(平台写操作) | 🟡 非混剪真机 1 条;混剪「是」未真机 | ❌ | 隐含(PRD 提审) | **服务端重写 Playwright** | +| 审核结果查询 / 驳回原因 | ✅ | ❌ | 隐含 | 迁移只读接口层 | +| 投放配置 / DP / 承接页 | 🟡 仅 DPLink | ❌ | ✅ P0 | 迁移 DPLink + **新建 DP/承接页配置** | +| 视频脚本(AI/人工) | ❌ | ❌ | ✅ P0 | **新建** | +| 视频生成(画面/组合) | ❌ | ❌ | ✅ P0 | **新建** | +| 脚本/动作模板资产 | ❌ | ❌ | ✅ P0 | **新建** | +| AI 生图 | ❌ | ❌ 仅 M2-0 验证资产,无产品代码 | 间接(替代实拍) | **从零产品化** | +| 资产中心(模板/Logo/展示/促销/脚本) | ❌ | 🟡 模板/分类/标签/规格 | ✅ P0 | **扩建** | +| 系统配置中心 | 🟡 本机配置 + 远端配置 | ✅ 40 项/L1-L3/审计 | 隐含 | 迁移 scgf | +| 任务队列 / 实时进度 | 🟡 Electron 主进程串行 | ✅ BullMQ + WS | 隐含 | 迁移并拆 Worker | +| 通知 / 站内信 | ❌(只有系统通知) | ✅ 铃铛下拉 + 模板 | 隐含 | 迁移 + 扩展事件 | +| 日志 / 审计 / 可观测 | 🟡 本地日志 + JSONL 审计 | ✅ 事件目录/失败目录/时间线 | 隐含 | 合并为统一可观测 | +| 文件存储 / CDN | 🟡 本地目录 | 🟡 本地磁盘 | 隐含 | **对象存储适配层(新建)** | +| 多租户 / 数据隔离 | ❌ | 🟡 客户范围(非多租户) | 隐含 | 首期单部署 + 范围隔离 | + +### 3.2 重叠项:整合时要防止"重复建设" + +两项目在**工程层**有约 15%~20% 的功能重叠,但实现质量与语义不同,不能简单保留两份: + +| 重叠域 | dewu 实现 | scgf 实现 | 统一建议 | +|---|---|---|---| +| 任务队列 / 进度 | Electron 主进程内存队列 + IPC 事件 | BullMQ + DB 计数 + WS 推送 | 采用 scgf 模型,补 dewu 的"串行/中断/超时只回查/幂等账本"语义 | +| 命名 | 送审命名(媒体任务ID-视频ID-SPUID) | 生产命名(变量模板/客户级/快照) | 合并为一个引擎,两套变量域 + 两套校验规则 | +| 配置管理 | 本机 JSON + 远端签名配置 | DB 配置中心 + L1-L3 + 审计 | 采用 scgf,补"远端配置/运维开关"能力 | +| 日志 / 审计 | 本地日志文件 + JSONL 审计 | 控制台文本日志 + 事件目录 + 任务日志(结构化日志是新工程要补的) | 采用 scgf 事件模型,保留 dewu 的"只追加审计"语义 | +| 通知 | 系统通知(下载完成) | 站内信 + 模板 | 采用 scgf,扩展提审/投放/失败事件 | +| 素材/文件管理 | 本地目录 + 文件名规则 | uploads 目录 + 缩略图 + 清理 | 统一对象存储 + 资产表 + 生命周期策略 | +| 登录态 | 平台 Cookie/token(safeStorage) | 系统 JWT | 两个不同概念,都要:系统账号 + 平台账号(凭据中心) | + +> **重复建设的典型陷阱**:如果按"两个项目各自保留"的方式合并,会出现两套任务表、两套命名、两套审计、两套权限,半年后无法维护。新工程必须"一套任务中心 + 一套资产表 + 一套权限"。 + +### 3.3 互补项:整合真正的价值在"接缝" + +| 接缝 | 上游(dewu) | 下游(scgf) | 统一后的数据流 | +|---|---|---|---| +| **商品主数据** | 商品查询:SPUID/链接/分享文本 → 标题/价格/货号/SKU/主图/详情图/主视频 | 制作页手工上传商品图 + 填字段 | 选品时落 `product_snapshot`,生产直接引用 | +| **原始物料** | 商品图/详情图/主视频/视频素材库 → 本地目录 | 商品图上传 → 生产 | `raw_asset` + 对象存储,选品即归档 | +| **命名规则** | 送审命名(末三段 = 媒体任务ID-视频ID-SPUID) | 生产命名(变量模板 + 客户级) | 统一引擎:生产命名 + 提审命名两个 profile,共享校验 | +| **素材产出 → 提审** | 送审需要本地成品文件(mp4,140–190MB) | 产出图片素材(ZIP/文件) | `material` 表统一承载,提审单引用 material,文件在对象存储 | +| **投放配置** | DPLink(商品 → 唤端链接) | 无 | 投放配置中心:SPUID/官网链接 → DP/承接页/唤端链接 | + +**结论**:整合不是"选一个项目继续做",而是把 dewu 的"投放作业端"与 scgf 的"生产端"用统一的商品/物料/素材主数据连接起来。**接缝的数据模型设计质量,决定整合成败**(§5.6)。 + +### 3.4 空白项:必须新建的 8 块 + +| # | 空白 | 影响 PRD 条目 | 难度 | 备注 | +|---|---|---|---|---| +| 1 | 多平台抽象 + 唯品会适配 | 平台切换、新增平台、多平台管理 | 高(唯品会零参考) | 唯品会的登录/接口/提审需从 0 摸底 | +| 2 | 选品批次 / 圈选 / 历史选品 | 选品模块 P0/P1 | 中 | 现有只有"多 SPUID 输入",无批次概念 | +| 3 | 图片多资产渲染 | 四层信息(展示方式/Logo/促销) | 高 | 现引擎所有替换图层共用一张商品图 | +| 4 | 提审工作流(内部清单 + 状态) | 素材提审 P0 | 中 | dewu 只有平台侧审核查询 | +| 5 | 投放配置(DP/承接页) | 投放信息 P0 | 中 | PRD 对 DP 的定义本身待确认 | +| 6 | AI 生图产品化 | 产品目标 1/2 | 高 | 仅 M2-0 验证,无产品代码 | +| 7 | 视频 AI 产线 | 视频素材 P0 | 极高 | 两项目均为 0,模型/成本/质量均未知 | +| 8 | 对象存储 / Worker 拆分 / 分布式锁 | 非功能(容量/并发/可靠性) | 中高 | 现架构单机同进程,无法水平扩展 | + +--- + +## 4 PRD 覆盖度差距分析 + +### 4.1 PRD 表 1-3 功能框架逐条覆盖 + +> 口径:以 PRD 表 1-3 的 27 项功能点为基线;"现有能力"取两项目代码实证(不是文档声称)。 + +| # | PRD 功能点 | 优先级 | dewu | scgf | 现状结论 | 差距与建议 | +|---|---|---|---|---|---|---| +| 1 | 平台切换:得物 / 唯品会 | P0 | ❌ 仅得物 | ❌ 无平台概念 | **完全空白** | 新建平台上下文;唯品会需从 0 摸底(§6.1 第 6 项) | +| 2 | 新增平台 / 新增项目 | P0 | ❌ | ❌ | **完全空白** | 平台适配器注册机制 + 资源路径规则 | +| 3 | 商品 ID / SPUID 检索 | P0 | 🟡 得物 SPUID/链接/分享文本 | ❌ | **部分(单平台)** | 迁移商品查询,抽象 PlatformAdapter | +| 4 | 商品名称(粗词)检索 | P1 | ❌ | ❌ | **空白** | 依赖平台搜索接口,需抓包验证 | +| 5 | 添加本次选品 | P0 | 🟡 多 SPUID 输入 | ❌ | **部分** | 新建选品批次/圈选模型 | +| 6 | 下载原始图片 | P0 | 🟡 得物商品图/主视频 | ❌ 手工上传 | **部分(单平台)** | 迁移 + 对象存储 + 物料库 | +| 7 | 历史选品 | P1 | ❌ | ❌ | **空白** | 选品批次查询/复用 | +| 8 | 品类 / 尺寸 / 模板 | P0 | ❌ | 🟡 模板 + 通用规格 | **部分** | 三规格固定枚举 + 品类维度 | +| 9 | 商品类别:鞋子 / 衣服 | P0 | ❌ | ❌ | **空白** | 品类字典 + 展示方式子菜单 | +| 10 | 展示方式:设计导入 / AI 模特 / AI 脚模 | P0 | ❌ | ❌(单商品图) | **空白** | 新建资产类型 + 渲染分支;AI 模特依赖生成能力 | +| 11 | 商品位置:固定 / AI 调优 | P0 | ❌ | 🟡 固定位置由图层 bbox 决定;AI 调优缺 | **部分** | 补 AI 调优,列 P1 | +| 12 | Logo:主 Logo + 副 Logo(拼接方式/字符) | P0 | ❌ | 🟡 logo 字段未接入合成 | **空白(半成品)** | 组合式 Logo 资产模型 + 渲染器 | +| 13 | 促销信息:折扣 / 活动标识 | P0 | ❌ | 🟡 文本层可放文案 | **部分** | 促销模板/图层 + 资产库 | +| 14 | 按路径导出 | P0 | 🟡 本地目录落盘 | ✅ 命名 + ZIP + 选集下载 | **部分(两端各有半套)** | 对象存储 + 导出中心 + 路径规则 | +| 15 | 批量多图制作与预览 | P1 | ❌ | ✅ 交叉批量 + 悬停预览 | **已覆盖(scgf)** | 迁移 + 接入选品物料 | +| 16 | 历史脚本 | P0 | ❌ | ❌ | **空白** | 脚本表 + 模板 + 版本 | +| 17 | 脚本模板管理 | P0 | ❌ | ❌ | **空白** | 新建 | +| 18 | 脚本 AI 分析 | P0 | ❌ | ❌ | **空白** | 新建(LLM 调用 + 结构校验) | +| 19 | 脚本生成(选品+模板+数量) | P0 | ❌ | ❌ | **空白** | 新建 | +| 20 | 动作模板:AI 分析视频方向 | P0 | ❌ | ❌ | **空白** | 新建(视频理解/动作提取) | +| 21 | 视频生成(脚本+模板+数量) | P0 | ❌ | ❌ | **空白** | 新建(视频模型 + 组合) | +| 22 | 提审标签页:待审清单与状态 | P0 | 🟡 平台审核查询 | ❌ | **部分(语义不同)** | 新建内部提审状态机,并保留平台审核同步 | +| 23 | 配置管理:加号新增 / 自定义命名 | P0 | 🟡 落地页配置 | ❌ | **部分** | 新建配置项模型(平台/项目级) | +| 24 | 一键复制单条配置 | P0 | 🟡 仅 DPLink 场景复制 | ❌ | **部分(仅 DPLink)** | 通用复制 + 权限/审计 | +| 25 | 自动配置:拉取配置 / 自动生成链接 | P0 | 🟡 DPLink | ❌ | **部分(仅 DPLink)** | 扩展 DP/承接页生成规则 | +| 26 | 批量修改固定字段 | P1 | ❌ | ❌ | **空白** | 配置批量替换 + 预览/回滚 | +| 27 | 资产统一管理(模板/Logo/展示/促销/脚本) | P0 | ❌ | 🟡 模板/分类/标签/规格 | **部分** | 资产中心扩建(Logo/展示/促销/脚本) | + +**统计**:完全满足 **1 项**(批量多图,来自 scgf);部分满足 **12 项**;完全空白 **14 项**。 + +> 这个结果不意外:PRD 是"目标态",dewu 与 scgf 是两条历史产线的局部最优。**如果按 PRD 表 1-3 全量 P0 承诺首期交付,周期与风险都不可控**(§4.4)。 + +### 4.2 P-01~P-07 问题覆盖度汇总 + +| 编号 | PRD 问题 | dewu | scgf | 合并覆盖 | 判断 | +|---|---|---|---|---|---| +| P-01 | 原始物料获取 | 部分(得物) | 0 | 约 40% | 需扩多平台 + 物料库 | +| P-02 | 图片素材制作(三规格 × 四层) | 0 | 约 50% | 约 50% | 引擎需支持多资产 | +| P-03 | 视频素材制作 | 0 | 0 | 0% | 完全新建 | +| P-04 | 命名与提审 | 提审强、命名固定三字段 | 命名强、提审 0 | 约 55% | 合并命名 + 新建提审流 + 命名支持自定义字段组合 | +| P-05 | 账户搭建与投放配置 | 部分(DPLink) | 0 | 约 25% | DP/承接页待定义 | +| P-06 | 多平台管理 | 0 | 0 | 0% | 完全新建(唯品会零参考) | +| P-07 | 素材与模板资产管理 | 0 | 部分 | 约 35% | 扩建资产中心 | + +### 4.3 PRD 自身需要补齐/澄清的地方(给产品评审的输入) + +PRD V0.1 目前只有 1.1/1.2 有实质内容,2~10 章为空模板。从研发视角,以下 12 项会在开发中直接变成阻塞: + +| # | 问题 | 为什么阻塞 | 建议补充到 PRD | +|---|---|---|---| +| 1 | 目标用户与角色未定义(2.1 空白) | 决定权限模型、菜单、数据范围 | 补设计/优化/运营/管理员四类角色与权限矩阵 | +| 2 | 用户故事/场景未填(2.2) | 无法做验收标准 | 与 1.1 的 P-01~P-07 一一对应 | +| 3 | 成功指标无现状值/目标值(表 1-4 全空) | 上线后无法判断成功 | 先补"现状值"(哪怕估算),目标值可分期 | +| 4 | 本期范围/非范围未写(3.1/3.2) | 范围蔓延风险最高 | 明确"唯品会、视频、AI 生图是否首期" | +| 5 | 功能详情模板未填(4.2) | 无验收标准 | 优先补 15 条 P0 的主流程/异常/规则 | +| 6 | 非功能需求未量化(5.1 全空) | 压测/容量/可用性无法验收 | 给出并发、P95、存储、RTO/RPO 量级 | +| 7 | DP 的准确口径未定义 | 投放配置模块无法设计 | 明确 DP 是什么、字段、生成规则、样例 | +| 8 | 提审是"平台后台提审"还是"系统内审批流" | 决定提审状态机复杂度 | 明确是否需要内部审核角色/多级审批 | +| 9 | 唯品会零参考 | 无法评估工作量 | 提供唯品会后台账号/流程/接口样例 | +| 10 | 视频质量与验收标准未定义 | AI 视频无法验收 | 定义时长、分辨率、口播/字幕、过审标准、样片 | +| 11 | AI 生成内容的合规要求未写 | 电商广告合规红线 | 明确商标/肖像/功效宣称/免责声明要求 | +| 12 | 多租户/数据隔离未定义 | 决定架构分叉(最大) | 明确单部署共享 vs 客户硬隔离 | + +### 4.4 范围裁剪建议 + +**判断:PRD 表 1-3 的 P0 全量(27 项中 23 项 P0、4 项 P1)不适合作为首期承诺。** 建议按下表裁剪: + +| 阶段 | 交付范围 | 对应 PRD 条目 | 退出标准 | +|---|---|---|---| +| **MVP-1 图片生产主线** | 平台上下文(得物) + 选品/物料 + 模板/三规格 + 商品图/Logo/促销合成 + 批量/预览 + 命名 + 导出 | 1(得物)、3、5、6、8、12、13、14、15、27(模板部分) | 一个真实商品从检索到导出全流程跑通;用 ≥5 个存量真实模板做回归,渲染差异在阈值内(模板供给见 §4.4 假设) | +| **MVP-2 投放闭环** | 提审清单/状态 + 批量送审 + 审核同步 + DPLink + 配置管理/一键复制 | 22、24、25、23(基础) | 送审真机成功率 ≥ 95%,审核状态可回查 | +| **M3 多平台** | 唯品会适配 + 平台切换 + 新增平台机制 | 1(唯品会)、2、4 | 唯品会完成一次选品→出图→提审验证 | +| **M4 AI 增强** | AI 生图(补充产线)+ AI 模特/脚模 + 商品位置 AI 调优 | 10、11、13(增强) | 抽样 100 张人工评估通过率 ≥ 80% | +| **M5 视频产线** | 脚本(AI/人工)→ 画面 → 组合,16:9 / 9:16 | 16~21 | 每条链路产出 20 条样片,人工评审通过 | +| **P1 增强** | 历史选品、粗词检索、批量配置替换、资产中心完整 | 4、7、26、27(完整) | 按迭代计划 | + +> 建议把"视频产线"明确为**独立里程碑且不设硬上线日期**:它的技术不确定性(模型质量/成本/时长)远高于图片产线,任何"首期必须交付"的承诺都会拖垮整体。 + +**关键假设与当前状态**: + +| 编号 | 假设 | 不成立时的后果 | 由谁确认 | +|---|---|---|---| +| A-01 | 设计资产由**设计师角色持续供给**(PSD 模板/展示方式/促销模板),M1 前提供 ≥5 个真实模板 + 规范 | **已确认(2026-10-30,含时间点)** | 产品 + 设计负责人(Q-06/Q-07/Q-08) | +| A-02a | 项目为**内部平台**,仅内部人员使用;**部署为公网可访问 + 登录鉴权** | **已确认(2026-10-30)**:单租户、内部账号;需公网安全加固 | 产品负责人 | +| A-02b | 客户授权我们使用其平台账号做**服务端托管与自动送审**(D-09) | **已确认(2026-10-30,客户授权;待补书面文件与范围)**:仍需保留半自动降级;平台方条款的残余风险由业务方接受并留档 | 业务 + 法务 + 客户(Q-01/Q-02) | +| A-03 | 唯品会在首期之外,可按同一适配层接入(不阻塞得物主线) | 多平台里程碑需重新评估,但图片主线不受影响 | 运营 + 客户(Q-03) | + +--- + +## 5 整合方案评估 + +### 5.1 候选方案对比 + +| 维度 | 方案 A:以 scgf 为基座扩展 | 方案 B:保留桌面端 + scgf Web 端 | 方案 C:新建统一工程 + 双项目资产迁移(您已选) | +|---|---|---|---| +| 形态 | Web | Electron + Web 双端 | Web | +| 复用率 | 高(scgf 全量) | 最高(两端都保留) | 中高(后端/逻辑/引擎复用,UI 重写) | +| 前期工作量 | 低 | 低 | 中(多 20~35 人日脚手架/迁移) | +| 架构债 | **继承单进程/本地磁盘/无平台维度三大债** | 继承两套架构 + 双端同步成本 | 可一次性清理 | +| 平台账号托管 | 需补 | 桌面端可本机登录,Web 端仍需补 | 集中托管(需合规确认) | +| 长期维护 | 中 | **高(双端双栈)** | 低 | +| 数据模型 | 19 表沿用,加列/加表 | 两套数据 | 可重新设计主数据 | +| 风险 | 中(改造成本易低估) | 高(双端不一致/人力分散) | 中(新建工程量大,但路径清晰) | +| 适合团队 | 1~2 人、求快 | 不想动桌面端 | **1~3 人 + AI 辅助、求长期可维护** | +| 结论 | 不推荐 | 不推荐(您已确认彻底 Web 化) | **推荐** | + +### 5.2 为什么"新建"不等于"重写" + +这是本次评估最需要说清的一点:**"新建统一工程"是重建骨架与边界,不是重写业务逻辑**。 + +| 资产类别 | 迁移方式 | 估算复用率 | +|---|---|---| +| scgf 后端工程地基(认证/权限/配置/迁移/队列/事件/通知/导出) | 代码级迁移;但数据访问层改 Prisma,模型/查询需重写 | 60%~75% | +| scgf PSD 解析/合成/抠图/命名 | 代码级迁移,渲染器改造 | 60%~70% | +| scgf 前端设计体系(token/布局/守卫) | 设计思想 + 布局/守卫思路迁移;Arco 组件与 token 校验脚本不复用 | 20%~30% | +| dewu 纯逻辑库(签名/映射/命名/混剪/DPLink/CSV) | npm 包级迁移,几乎零改动 | 90%+ | +| dewu 只读接口层/商品 SSR 直取 | 抽包 + 服务端化 | 70% | +| dewu 送审批次策略(串行/幂等/回查/审计) | 逻辑迁移,存储改 DB | 60% | +| dewu Electron 外壳/更新/签名/本地文件 | 废弃 | 0% | +| dewu 页面组件 | 交互信息架构复用;换 UI 库时组件重写 20%~30%,沿用 Semi 时页面壳/交互层 40%~50%(**均不含数据接入**) | 20%~50%(按前提) | +| scgf 素材制作页/首页 | 交互逻辑复用,页面重写 | 30%~40% | +| AI 生图/视频 | 代码从零;验证结论/语料/踩坑记录可复用 | 代码 0%,验证资产可复用 | + +**代价**:新建工程需要额外投入约 20~35 人日做 monorepo/CI/环境/迁移框架/部署基线,并承担"迁移期双系统并行"的沟通成本。 +**收益**:一次性解决单进程、本地磁盘、无平台维度、权限模型、对象存储、Worker 拆分等结构性问题,避免在 scgf 旧架构上"边跑边换轮子"。 + +> **口径提醒(UI 复用)**:任何 UI 库选型都省不掉"页面数据接入重接"——dewu 页面从 `window.electronAPI`(101 条 IPC)改为 HTTP/SSE、鉴权与数据模型重接,约 **30~40 人日**;scgf 管理类页面(用户/角色/客户/任务/日志,约 8,300 行)也要按新路由/权限重接。UI 库只影响"组件与样式"这一层:基础层约 **8~15 人日** 的差异,不应被当作页面整体复用收益。 + +### 5.3 技术选型建议 + +| 层 | 建议 | 理由 | 备选/注意 | +|---|---|---|---| +| 语言 | TypeScript 全栈(strict) | 两端均 TS,类型可共享 | 后端 strict 需补 `noUncheckedIndexedAccess` | +| Monorepo | pnpm workspace + Turborepo(可选) | scgf 已用 pnpm workspace | Node **24.15.0** + pnpm **11.4.0** | +| 前端框架 | React 19 + Vite | 两端现状 | 不引入 Next.js(纯内网后台,SSR 无收益) | +| UI | **Semi Design 2.104 + Tailwind CSS 4.3 + 自建 token 层** | §5.5 专章;Tailwind 4 与 Semi 的层叠需 M0 Spike 验证 | 不选 shadcn/ui(除非补设计师) | +| 前端状态 | zustand(会话/配置)+ TanStack Query(服务端状态) | scgf 只有 zustand,复杂列表/轮询需要缓存层 | 也可先用 axios + 手写 hooks,避免过度设计 | +| 表单/校验 | react-hook-form + zod(或 Semi Form + zod) | 表单密集(模板/配置/投放) | zod schema 与后端共享 | +| 后端框架 | **Express 5**(沿用 scgf) | 中间件/错误处理/上传/WS 可直接迁移;重写为 Nest/Fastify 收益低于成本 | 若追求性能可评估 Fastify,但不建议首期换 | +| ORM | **Prisma 7.10.1** + `@prisma/adapter-pg` | 类型/迁移一体;19 表模型需重写(+8~12 人日,见技术栈定稿) | 稳定线;8.x 仍 RC,不采用 | +| 数据库 | PostgreSQL **18**(18.4) | 开发机已有 Docker | JSONB 用于图层契约/配置/快照;PG18 原生 `uuidv7()` | +| 队列 | BullMQ + Redis | 现有;按产线拆队列 | 队列:`image-render` / `platform-task` / `ai-image` / `ai-video` / `export` | +| 浏览器自动化 | Playwright(服务端 Worker) | 客户端单机已验证;服务端 Worker 待 POC-1;送审默认页面自动化(可评估直连备选) | 独立 Worker 进程 + 账号级分布式锁 + 并发上限 | +| 图像处理 | sharp + @napi-rs/canvas + ag-psd + fontkit | 现有 | sharp 0.32.6 锁版;升级需回归 | +| 抠图 | imgly/ONNX(独立 Worker) | 现有 | 内存峰值高,必须与 API 隔离 | +| 对象存储 | S3 兼容(OSS/MinIO)+ `StorageAdapter` | 支持多实例、大文件、签名 URL | 本地开发用 MinIO;导出走签名 URL | +| 实时 | WebSocket(现有)+ Redis pub/sub | 多实例下 WS 需要跨进程广播 | 长任务进度也可用 SSE,二选一即可 | +| 认证 | JWT + refresh token + 平台账号凭据独立加密 | scgf 已有 JWT/pwdv | 平台凭据用 KMS/信封加密,**禁止进系统配置** | +| 部署 | Docker Compose(单机)+ 后续 K8s | 现有部署可用 | Worker 独立容器;PG/Redis 托管;公网入口前置 WAF/HTTPS/MFA | +| 观测 | pino 结构化日志 + 任务事件 + Prometheus 指标 | scgf 有事件目录/失败目录 | 首期至少:任务成功率/时长/失败 TopN/队列积压 | + +### 5.4 目标架构 + +``` +┌──────────────────────────────────────────────────────────────────────────────┐ +│ apps/web(React 19 + Semi + Tailwind) │ +│ 平台切换 │ 选品 │ 原始物料 │ 图片制作 │ 视频制作 │ 提审 │ 投放配置 │ 资产 │ 系统 │ +└───────────────────────────────┬──────────────────────────────────────────────┘ + │ HTTPS(REST)+ WS/SSE +┌───────────────────────────────▼──────────────────────────────────────────────┐ +│ apps/api(Express 5,无状态,可多副本) │ +│ 认证/权限 │ 客户/平台范围 │ 商品/物料 │ 模板/资产 │ 批次/素材 │ 提审/投放 │ 配置 │ +│ PostgreSQL(主数据/任务/审计) Redis(会话/锁/队列/缓存) │ +└──────┬──────────────────┬──────────────────┬──────────────────┬──────────────┘ + │ BullMQ │ BullMQ │ BullMQ │ BullMQ +┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ +│image-worker │ │platform- │ │ai-worker │ │export-worker│ +│PSD/合成/抠图 │ │worker │ │生图/视频 │ │ZIP/CSV/打包 │ +│(CPU/内存密集)│ │Playwright │ │(外部 API) │ │(IO 密集) │ +└──────┬──────┘ │登录/送审/审核│ └──────┬──────┘ └──────┬──────┘ + │ │/投放 │ │ │ + │ └──────┬──────┘ │ │ + └──────────────────┴──────────────────┴──────────────────┘ + │ + ┌───────────▼───────────┐ + │ 对象存储(S3/OSS/MinIO)│ ← 原始物料 / 模板 / 成片 / 导出包 + └───────────────────────┘ +``` + +**模块边界(建议的 monorepo 结构)**: + +``` +lingxi/ +├── apps/ +│ ├── web/ # React SPA +│ ├── api/ # Express 5 BFF +│ ├── worker-image/ # 渲染/抠图/合成 +│ ├── worker-platform/ # Playwright:登录/送审/审核/投放 +│ ├── worker-ai/ # 生图/视频 +│ └── worker-export/ # ZIP/CSV/导出 +├── packages/ +│ ├── shared/ # DTO、zod schema、枚举、错误码 +│ ├── domain-naming/ # 命名引擎(生产 + 提审两套 profile) +│ ├── domain-platform/ # 星光签名/字段映射/送审规则/DPLink +│ ├── ui/ # 设计 token + 通用组件 +│ └── config/ # 配置注册表(L1-L3) +├── infra/ +│ ├── docker/ migrations/ scripts/ nginx/ +└── docs/ +``` + +**关键架构决策(ADR 摘要)**: + +| 决策 | 选择 | 放弃的方案 | 理由 | +|---|---|---|---| +| API 与 Worker | 拆进程 | 同进程(scgf 现状) | AI/渲染/Playwright 三类负载差异大,同进程 OOM 会拖垮 API | +| 存储 | 对象存储 + 适配层 | 本地磁盘 | 多实例、大文件(视频 140–190MB)、导出包 | +| 平台账号 | 集中托管 + 账号级串行锁 | 每用户绑自己账号 / 不托管 | 客户已授权使用其账号(D-09);串行锁用于应对"单账号单会话"(若 POC-2 证实;证伪则可放宽) | +| 部署暴露面 | 公网 + 登录鉴权 + WAF/MFA | 纯内网/VPN | 用户确认公网可访问;需安全加固 4~8 人日(§7.2 第 28 项) | +| 平台适配 | Adapter + 注册表 | 写死得物 | 多平台/新增平台是 PRD P0 | +| 实时 | WS + Redis pub/sub | 纯前端轮询 | 批量任务进度体验;轮询作降级 | +| 权限 | 平台 × 客户双层范围 | 只按角色 | 多平台多品牌 | +| AI 调用 | 统一 AI 网关 + 队列 + 成本核算 | 页面直接调模型 | 限流/配额/成本/审计/降级 | + +### 5.5 UI 选型专章:Semi Design / Arco / shadcn/ui 对比(回答您的问题) + +**结论:本阶段建议 Semi Design 2(+ Tailwind + 自建 token 主题),但不建议把 UI 选型当成关键决策——Semi 与 Arco 在本项目上近似平手,shadcn/ui 在当前条件下不推荐。** + +#### 5.5.1 评分矩阵 + +权重按"后台密集 + 无专职设计师 + AI 辅助开发 + 追求交付速度"的项目特征设定: + +| 维度 | 权重 | Semi Design | Arco Design | shadcn/ui | 说明 | +|---|---|---|---|---|---| +| 后台复杂组件覆盖(表格/表单/上传/树/级联/日期) | 25% | **5** | **5** | 2 | Semi/Arco 开箱即用;shadcn 需自建 DataTable/Upload/Tree/DatePicker(中文) | +| 中文本地化与暗色主题 | 10% | **5** | **5** | 3 | 两者内置 zh_CN/暗色;shadcn 需接 date-fns locale + 自定义 | +| 与现有资产复用度 | 20% | 4 | 4 | 1 | Semi 贴合 dewu 作业端页面;Arco 贴合 scgf 管理端页面;两者各得一半,shadcn 两边都要重写 | +| 设计自由度 / 品牌化 | 15% | 3 | 3 | **5** | shadcn 代码归你所有、Tailwind 自由;Semi/Arco 需 token 覆盖 | +| 无设计师时的落地确定性 | 15% | **5** | **5** | 2 | 两者有默认规范;shadcn 每个决策都要人定,易风格漂移 | +| AI 辅助开发友好度(示例/API 稳定性) | 10% | 4 | 4 | **4** | 三者 LLM 都熟;shadcn 代码可读性更强,Semi/Arco 中文文档更全 | +| 长期维护与升级 | 5% | 3 | 3 | 4 | 组件库升级受库约束;shadcn 代码在你手里但升级要自己跟 | +| **加权得分** | 100% | **4.30** | **4.30** | **2.65** | — | + +#### 5.5.2 为什么最终仍略偏向 Semi + +1. **与 PRD 主链路页面的贴合度**:dewu 的选品/商品查询、素材下载、审核、送审预检、混剪配对页面,正好对应 PRD 的"选品 → 原始物料 → 提审 → 投放";这批页面在 Semi 下的交互与组件经验可直接复用(`Select`/`Table`/`Drawer`/`Progress` 等),而 scgf 的 Arco 页面中,素材制作页与首页本来就要按新信息架构重写。 +2. **作业端页面 > 管理端页面的迁移权重**:管理类页面总工作量约 8~12 人日,两库差异仅 2~4 人日;而作业端页面涉及大量交互细节与踩坑经验,保留 Semi 经验的收益更高。 +3. **中文后台生态与文档**:Semi 的组件文档、示例、Table/Form 能力更完整;无专职设计师时,默认视觉规范能减少风格漂移。 +4. **dewu 已验证 Tailwind 共存方案**:`@layer tailwind-base, semi, ...` 的层叠顺序坑已被踩清(`dw/src/styles/index.css`),新工程可直接沿用。 + +**反方也要说清**:如果团队对 Arco 更熟、或评审认为"素材生产页(scgf 最大页面)权重更高",选 Arco 完全可接受——两者加权同分,最终差异约 **5~12 人日**(Arco 略省管理页、Semi 略省作业端)。**不要为了 UI 库选型推迟项目**。 + +#### 5.5.3 为什么不推荐 shadcn/ui + +- 本产品是"高密度 B 端后台 + 少量作业端",shadcn/ui 是"组件代码片段"而非完整组件库,DataTable/Upload/Cascader/DatePicker/Tree/Form 都需要自建与长期维护; +- 无专职设计师时,shadcn 的自由度会变成"每个页面一个风格"的风险,AI 生成页面也难以保持一致; +- 预计额外 **4~6 人周** 搭后台组件层,且与"AI 辅助、求快"的约束冲突; +- 只有在"有设计师 + 强品牌化 + 愿意长期投入设计体系"时才更优。 + +#### 5.5.4 净影响与折中方案 + +| 方案 | 对 dewu 作业端页面 | 对 scgf 管理端页面 | 净影响(相对 Semi 基线) | +|---|---|---|---| +| Semi(推荐) | 作业端 UI 基础层省 8~15 人日;数据接入另计 30~40 | 管理页重写,可省 2~4 人日 | 基线 | +| Arco | 作业端需重写(+8~15 人日) | 可复用部分管理页结构(省 5~8 人日) | **约 -5~-12 人日** | +| shadcn | 重写 + 自建组件层 | 重写 + 自建组件层 | **+20~30 人日**(4~6 人周) | + +**折中方案(若您坚持"新项目改动大一些")**:用 Semi 作为**行为与可访问性底座**,通过 `ConfigProvider` + CSS 变量把视觉 token 全面替换为自有品牌色/圆角/字号/间距;页面壳层与营销页可用 Tailwind 自由布局。这样既保留组件能力,又不会"一看就是默认 Semi"。**不建议在同一后台里混用两套组件库**(双维护成本 + 样式冲突)。 + +### 5.6 数据模型统一建议 + +以 scgf 19 表为基础,新增/改造为以下核心域(**约 33 张表:迁移/改造约 18、新建约 15**): + +| 域 | 表 | 关键字段 | 来源/说明 | +|---|---|---|---| +| 组织 | `platform` | code, name, base_url, adapter_key, status | 新建(得物/唯品会) | +| 组织 | `project`(可选) | platform_id, name, resource_path, status | 新建(PRD"新增项目") | +| 组织 | `client` | name, naming_config, platform_id?, status | 由 scgf `clients` 扩展 | +| 组织 | `user` / `role` / `user_client` | 沿用 scgf(pwdv/强制改密/范围) | 迁移 | +| 凭据 | `platform_account` | platform_id, account_label, credential_cipher, owner_user_id, status, last_verified_at | 新建(信封加密 + 审计) | +| 商品 | `product_snapshot` | platform_id, spu_id, title, brand, article_no, price, payload(JSONB), fetched_at | 新建(来自 dewu SSR/接口) | +| 选品 | `selection_batch` / `selection_item` | batch_id, name, operator, status; spu_id, snapshot_id, raw_asset_status | 新建 | +| 物料 | `raw_asset` | selection_item_id, type(image/video), source_url, storage_key, md5, width/height, status | 新建(对象存储) | +| 模板 | `template` / `template_category` / `template_tag` / `template_spec` | 沿用 scgf + platform_id + asset refs | 迁移 + 扩展 | +| 资产 | `asset`(Logo/展示方式/促销/字体/脚本模板) | type, name, platform_id, client_id, config(JSONB), storage_key, status | 新建(统一资产中心) | +| 生产 | `production_batch` / `production_task` | 沿用 scgf(参数/命名快照/状态) | 迁移 | +| 素材 | `material` | 沿用 scgf + selection_item_id + storage_key + md5 + review_status | 迁移 + 关联 | +| 命名 | `naming_rule` | scope(platform/client), profile(production/submit), template, fields, version | 由 scgf `clients.naming_config` 拆出 | +| 提审 | `review_ticket` / `review_item` | platform_id, account_id, status, submitted_at, result, reason | 新建(内部状态机) | +| 提审 | `submit_ledger` | md5, ticket_id, result, payload(JSONB), created_at | 由 dewu JSONL 账本升级 | +| 投放 | `delivery_config` | platform_id, client_id, name, type(dp/landing/deeplink), fields(JSONB) | 新建 | +| 投放 | `delivery_link` | config_id, spu_id, url, generated_at, operator | 新建(DPLink 结果) | +| 任务 | `task_event` / `failure_catalog` | 沿用 scgf | `task_event` 迁移;`failure_catalog` 在 scgf 是代码常量目录,需**升为表**(新建) | +| 通知 | `notification` / `notification_template` | 沿用 scgf | `notification` 迁移;`notification_template` 在 scgf 是 `system_configs` 的 JSONB,需**拆为表**(新建) | +| 配置 | `system_config` / `system_config_audit` | 沿用 scgf + secret 类型 | 迁移(先补 secret) | +| 审计 | `user_audit` / `operation_audit` | 沿用 scgf + 平台操作审计 | 扩展 | + +**数据迁移策略**: +- scgf:**不迁移 19 表结构,迁移数据**。新库按上述模型建表,用一次性脚本把 clients/users/templates/template layer_config/materials/naming_config/notifications 导入;854MB 文件迁对象存储(保持路径映射表)。 +- dewu:**不迁移本地配置/凭据/账本**(safeStorage 跨机不可解);只导入 `submitted-md5.json`(防重复送审)与审计 JSONL(历史可查),其余重新登录/重新拉取。 +- 迁移脚本必须支持 dry-run + 对账(行数/大小/MD5)+ 可回滚。 + +### 5.7 安全与合规设计要点 + +| 项 | 要求 | +|---|---| +| 平台凭据 | 信封加密(KMS 或 `PLATFORM_CRED_KEY`),按平台账号存储;禁止进系统配置/日志/审计明文 | +| 账号串行 | 同一 `platform_account` 的写操作(送审/上传)必须分布式锁串行;读操作限并发 | +| 权限 | 平台 × 客户双层范围;提审/投放/AI 需要独立能力点;所有列表接口强制范围校验(scgf 已有 fail-closed 范式) | +| 审计 | 谁在何时对哪个商品/素材/账号做了什么(送审/投放/配置变更/凭据使用);审计表不随业务删除 | +| 敏感信息 | 星光签名盐/token/账号/内网地址属内部敏感:**调研报告与接口文档入库前必须脱敏**(原值存受控知识库),并加 pre-commit secret 扫描;仓库内不得再硬编码任何平台/运维凭据 | +| 内容合规 | AI 生成图/视频需人工复核闸门 + 合规词库 + 品牌 Logo 贴回校验(scgf 已验证方向) | +| 合规边界 | 区分两类:①**我方平台合规**(内部用户 + 公网访问,需登录鉴权/WAF/等保,按内部系统加固);②**对第三方平台后台的自动化访问合规**(客户已授权使用其账号,待补书面文件与范围;平台方条款残余风险由业务方接受并留档)。二者不可互相替代(§10.1 D-09) | +| 公网暴露面 | 虽为内部平台,但公网可达:HTTPS + WAF/限流 + 管理员 MFA + 登录风控 + 依赖与镜像扫描 + 渗透测试 + ICP 备案/等保评估(按公司要求) | + +--- + +## 6 关键技术难点与 POC 清单 + +> 这一章是本次评估的"不确定性清单"。**下列每一项都可能在 POC 阶段推翻或修正上面的工作量估算**,因此建议 M0 用 3~6 周集中验证,再锁定排期。 + +### 6.1 八个高不确定项 + +| # | 难点 | 现状证据 | 为什么难 | 不通过时的降级方案 | +|---|---|---|---|---| +| 1 | **服务端 Playwright 送审** | dewu 非混剪链路真机 1 条成功、混剪「是」未真机;项目选择"不直接调写接口"(`dw/electron/submit/page.ts:2-30`) | 平台上传走页面第一方 SDK + `duToken` 网关;写接口**技术上可重放**(需自实现 STS/OSS 分片/media/create/提交),但成本与风控更高;选择器随改版失效;140–190MB 大文件;机房 IP 风控 | 优先 A:页面自动化(默认);并行评估 C:服务端直连写接口。两者都不可行时降级为"服务端准备 + 人工浏览器收尾" | +| 2 | **平台账号集中托管** | **单账号单会话是【推断】**(源文档标注需两次同时登录对照实验);现有云端同步是 HTTP+FTP 明文共享 | 若成立:多用户并发会互相顶号;凭据集中存储有安全与合规责任;账号归属/审计需产品化 | 每用户绑定自己的平台账号(用户级授权),牺牲效率换合规;POC-2 先用实验证实/证伪"单会话" | +| 3 | **PSD 多资产渲染** | 1,773 行合成器,但所有图片替换图层**共用同一张商品图**;无自动化回归 | 四层信息(模板/展示方式/商品信息/Logo)要求按图层注入不同资产;改错是**静默错误**(图能出、内容错) | 先做"商品图 + 文本 + Logo"三层,AI 模特/脚模延后;保留旧渲染器开关 | +| 4 | **AI 生图产品化** | 仅 M2-0 验证:34/34 成功、中文逐字正确、透明底成立、flash 19–25s/张;**单价未获取、账号级限流真实、文字校验成本近翻倍** | 质量/成本/限流/一致性四重不确定;"生成图直接当成品"与"模板合成"两条路线未定 | 定位为"补充产线"(无模板场景),不替代 PSD;人工复核闸门 | +| 5 | **AI 视频产线** | 两项目均为 0;无模型选型、无样片、无验收标准 | 模型质量/时长/一致性/口播/字幕/成本全部未知;60s 成片可能需要多模型组合 + 剪辑 | 先做 5~15s 单镜头样片;不承诺首期上线 | +| 6 | **唯品会适配** | 两项目**零参考** | 登录方式/接口/提审流程/反爬策略全部未知 | 首期仅得物;唯品会单独立项摸底 | +| 7 | **单机 → 多实例** | scgf API 与 Worker 同进程、本地磁盘、内存限流 | 影响部署形态与所有文件/进度/锁的实现 | 首期单机 + Worker 独立容器 + 对象存储;多副本后置 | +| 8 | **PSD 兼容性与字体可用性** | ag-psd 只覆盖普通图层/剪贴蒙版/15 种混合模式;智能对象/文字特效/图层样式/PSB 未系统验证;生产镜像无中文字形,内置仅 1 个 `方正兰亭中黑简体` 且商用授权未知 | 存量模板一旦不兼容,渲染结果错误且静默;换字体会改变所有模板的排版 | POC-4 用 ≥5 个真实模板 + 字体替换做回归;不兼容模板登记清单,必要时设计侧重出 | + +### 6.2 M0 POC 清单(建议 3~6 周;7 个 POC,其中 1~4 为必需) + +| 编号 | POC | 验证内容 | 通过标准 | 估时 | 不通过的影响 | +|---|---|---|---|---|---| +| **POC-1** | 服务端送审 1 条真机(A/C 两路线) | A:登录态注入 → Playwright 打开送审抽屉 → 上传 140MB+ 成片 → 提交 → 回查;C:评估服务端直连写接口的可行性/成本 | A 端到端成功且选择器可配置;C 给出可行性结论(不一定实施) | 3~6 人日 | 整个"提审自动化"降级为半自动,MVP-2 价值下降 | +| **POC-2** | 账号集中托管 + 串行锁 | ①两次同时登录对照实验,证实/证伪"单账号单会话";②两个并发请求使用同一账号,验证锁、互踢检测、重登恢复 | "单会话"有明确结论;无互相顶号;失败可恢复;审计可追溯 | 2~4 人日 | 需改为用户级授权,账号体系重设计 | +| **POC-3** | 得物选品 + 物料入库 | SPUID/链接 → SSR 商品详情 → 主图/详情图/主视频下载 → 对象存储 → 物料表 | 10 个真实商品 100% 成功;原图非压缩衍生图;MD5 去重 | 2~3 人日 | 选品模块需改用浏览器抓取,成本上升 | +| **POC-4** | PSD 多资产渲染 + 兼容性 | ≥5 个存量真实模板(含剪贴蒙版/文字特效/智能对象)+ 商品图 + 主/副 Logo + 促销文本/图形 → 三规格输出;再做一次字体替换回归 | 5 个模板全部可渲染且差异在阈值内;Logo 拼接字符正确;不兼容模板有清单与降级方案 | 4~6 人日 | P-02 四层信息无法达标,需重新设计模板契约 | +| **POC-5** | AI 生图 30 张 | 9 要素表单 → 提示词 → 模型出图(pro/flash 各一组)→ 文字逐字校验 → 人工评估 | 可用率 ≥ 75%;中文文字正确率 ≥ 95%;单张成本/耗时拿到实测值;pro/flash 取舍有结论 | 2~3 人日 | AI 生图延后,不影响图片主线 | +| **POC-6** | AI 视频 3~5 条样片 | 脚本 → 画面 → 组合,16:9 与 9:16 各 2 条 | 业务方认可"可投";拿到单条成本/时长 | 3~5 人日 | 视频产线只做"脚本+素材管理",不做生成 | +| **POC-7** | 唯品会摸底 | 账号登录、后台结构、素材/提审流程、是否有可复用接口 | 形成《唯品会适配可行性说明》 | 2~5 人日 | 唯品会推迟到二期之后 | + +**M0 退出标准**:POC-1/2/3/4 全部通过 → 图片+提审主线可立项;POC-5 通过 → AI 生图可排期(生产验收门槛高于 POC:≥80%);POC-6 通过 → 视频可排期;POC-7 有结论 → 多平台可排期。 + +### 6.3 各难点的技术方案要点 + +**(1)服务端 Playwright** +- 独立 `platform-worker` 容器;每个平台账号一个持久化 browser context(加密 cookie 存储),**同一账号串行**(Redis 分布式锁 `lock:account:{id}`)。 +- 只读优先:素材/审核/枚举走 HTTP 签名接口(无浏览器);只有"写"(送审/登录兜底)走 Playwright。 +- **token 单一持有**:拆 api / platform-worker 后,平台 token 只能由凭据服务单写;api 只读同一份,禁止自行重登(否则会出现"接口说未登录、Worker 说已登录"或双写互踢)。401 统一标记失效 + 一次重登,由 platform-worker 执行。 +- 上传:浏览器端 → OSS 直传(STS 临时凭证)→ worker 下载到本地临时目录 → `setInputFiles`;或用户上传到服务端临时区。避免 140MB 文件穿 API 进程。 +- 选择器集中配置化(YAML/JSON),带"页面健康检查"(关键元素缺失即告警),平台改版时可热修不发版。 +- 失败显式:截图 + DOM 快照 + reasonCode 入库,便于事后排障。 + +**(2)账号集中托管** +- `platform_account` 表:平台、账号标签、**账号能力(软广/硬广/审核角色)**、加密凭据(信封加密)、归属运营、状态、最近验证时间。同一平台可有多账号(DPLink 依赖独立的星光硬广账号,软广账号调 `list-landing` 会 401)。 +- 登录方式优先接口验证码登录(dewu 接口登录通道实测 9/9),浏览器兜底;token 过期自动重登并告警。 +- 权限:谁能使用哪个账号、谁能看哪类操作,全部审计;敏感操作二次确认。 +- 合规:客户已授权使用其账号(待补书面文件与范围);仍需保留半自动降级与一键停用。注意"内部平台"只解决我方合规,平台方条款的残余风险由业务方接受并留档(D-09)。 + +**(3)原始物料** +- 得物:商品详情 SSR `__remixContext` 直取(无需浏览器),短链解析 + 域名白名单;图片取原图 URL(非 `webimg` 压缩图);视频 CDN 直连下载。 +- 唯品会:待摸底。 +- 入库:`raw_asset` + 对象存储 + MD5 去重 + 尺寸/时长元数据;保留 source_url 与抓取时间,便于追溯。 +- 限速:按平台/账号维度限流,避免机房 IP 被风控。 + +**(4)PSD 多资产渲染** +- 图层契约扩展:`image_replacement_*` 支持 `assetType`(product / model / foot-model / logo / promo)+ `assetRef` + 缩放/对齐;Logo 支持"主+副+拼接字符"组合器;文本层支持促销模板。 +- **渲染顺序保持 PSD 图层 z 序**:`assetType` 只决定该图层取哪类素材,不重排图层(否则会破坏"商品图在装饰框之后""Logo 在蒙版之后"这类真实版式);仅同层级内按语义排序。 +- **资产引用快照**:批次创建时把 `assetRef → storage_key + md5 + version` 固化进批次/子任务;Worker 只读快照,避免同批次前后图版本不一致(沿用 scgf 的命名/参数快照先例)。 +- 三规格:同一模板按目标尺寸派生(或设计侧提供三尺寸模板;需 POC-4 确认哪种更稳)。 +- **字体**:生产镜像内置可用中文字体并明确商用授权;换字体必须跑黄金样本回归(字体会改变排版与换行)。 +- **回归**:建立"存量模板黄金样本 + 像素级 diff"再动引擎;灰度客户;保留旧渲染器开关。 + +**(5)AI 生图** +- 路线:表单(9 要素:品类/主体/场景/文案/风格/尺寸/品牌元素/合规项/数量)→ 提示词合成 → 模型 → 文字校验(VLM 逐字)→ 人工挑图 → 入资产库。 +- **模型分层**:成品/交付默认 **pro**(效果优先,符合预算充足的定位);草稿/预览/大批量初筛用 **flash**(快 3 倍、成本更低)。单价与日/月上限做成配置,超限降级 flash 或排队。 +- 网关:统一 provider 接口(火山方舟/其他),配额/限流/重试/降级;成本按调用记账。 +- 合规:商标/肖像/功效宣称词库 + 人工复核闸门 + 品牌 Logo 程序贴回(不信任模型画 Logo)。 +- 定位:无模板场景的补充产线,不替代 PSD(POC-5 后确认)。 + +**(6)AI 视频** +- 三段解耦:脚本(LLM + 营销理论模板)→ 画面(文生图/图生视频/AI 模特)→ 组合(TTS/字幕/剪辑/拼接)。 +- 首期只做 16:9 或 9:16 其中一条;单镜头 5~15s;不做复杂转场。 +- 成本与时长必须单列预算(§7.5)。 + +**(7)单机 → 多实例** +- Worker 独立进程/容器(image/platform/ai/export 四类)。 +- 对象存储 + 签名 URL,替代本地磁盘与 `/uploads` 直出。 +- 限流迁 Redis;WS 用 Redis pub/sub 广播;任务锁用 Redis。 +- 首期可以单机多容器(docker compose),不必上 K8s;但代码必须"无本地状态"。 + +--- + +## 7 工作量与成本估算 + +### 7.1 估算方法与假设 + +| 项 | 说明 | +|---|---| +| 单位 | 人日 = 1 名熟悉本仓库的工程师全职 1 天(8h) | +| 包含 | 编码、自测、代码评审、必要重构、与前后端联调 | +| 不含 | 产品/设计/测试专岗、运维部署、项目管理、真机验证等待时间、平台改版返工 | +| AI 辅助 | 本节数字**已按 AI 辅助折算**(加权系数约 0.65~0.8,推导见 §7.4) | +| 传统估算 | 本节数字 ÷ 0.7 ≈ **1.4 倍** | +| 不确定性 | ±25%;POC 失败可能使单项翻倍 | +| 口径 | 逐项加总为唯一底稿;分阶段小计只做归类,不重复计算 | + +> 内部平台定位省去多租户约 2~3 人日;但部署为**公网可访问**,新增安全加固 4~8 人日(已单列第 28 项)。 + +### 7.2 工作分解(AI 辅助后人日) + +| 阶段 | # | 工作项 | 低 | 高 | 说明 | +|---|---|---|---|---|---| +| **M0** | 27 | 7 个 POC + 架构/模型定稿 | 16 | 31 | 见 §6.2;POC 估时按 AI 折算 13~26 + 定稿 3~5 | +| **地基** | 1 | monorepo/CI/环境/部署/迁移框架/对象存储适配 | 12 | 18 | 从零搭骨架 | +| 地基 | 2 | 账号/权限/客户范围/审计(迁移 scgf) | 8 | 12 | 加平台账号授权 | +| 地基 | 3 | 系统配置中心(迁移 + platform/ai 模块 + secret 类型) | 8 | 12 | AI Key 前置 | +| 地基 | 4 | 任务中心(队列拆分/实时/事件/失败目录/监控) | 12 | 16 | 拆 Worker | +| 地基 | 5 | 前端壳/设计系统/布局/路由/权限/通用组件 | 20 | 28 | Semi token 主题 | +| 地基 | 6 | 测试基础设施(契约测试/渲染黄金样本/E2E 骨架) | 10 | 15 | 必须,不是可选 | +| **平台** | 7 | 得物适配层(签名/只读接口/登录态/账号凭据/商品详情/素材库/审核) | 25 | 35 | 迁移 dewu + 服务端化 | +| **选品** | 8 | 选品与物料库(检索/圈选/历史/物料归档/去重/下载) | 18 | 26 | 新建部分 | +| **图片** | 9 | 模板资产(PSD 上传/解析/图层绑定/预览/分类/标签/规格,含 5 个模板页面) | 12 | 16 | 迁移 + 平台维度 | +| **图片** | 10 | 渲染引擎多资产化(Logo/促销/AI 模特/脚模/三规格/质量/回归) | 25 | 35 | 核心改造;含像素回归 | +| **图片** | 11 | 图片生产页与批量(筛选/上传识别/字段表/参数/预览/导出) | 18 | 26 | 重写 + 迁移逻辑 | +| **图片** | 12 | 命名引擎(生产 + 提审两套 profile + 自定义字段 + 校验) | 8 | 12 | 合并 | +| **提审** | 13 | 提审工作流 + 批量送审(状态机/预检/幂等/Playwright/审核/审计/混剪 P1) | 28 | 40 | 服务端重写 | +| **投放** | 14 | 投放配置(DPLink + DP/承接页 + 复制 + 批量) | 14 | 20 | 部分新建 | +| **多平台** | 15 | 多平台抽象(平台维度/资源路径/新增平台机制) | 8 | 12 | — | +| **多平台** | 16 | 唯品会适配(摸底后未知) | 18 | 30 | 零参考,区间大 | +| **资产** | 17 | 资产中心(模板/Logo/展示/促销/脚本统一管理) | 10 | 15 | — | +| **AI** | 18 | AI 生图产品化(网关/队列/表单/提示词/校验/合规/成本/挑图) | 20 | 30 | 从零 | +| **AI** | 19 | 视频产线 MVP(脚本/画面/组合/长任务/存储/审核) | 45 | 65 | 最大不确定 | +| **交付** | 20 | 联调/真机验证/压测/合规自查 | 15 | 22 | 不能省;安全见第 28 项 | +| **交付** | 21 | 上线/部署/监控/文档/培训 | 8 | 12 | — | +| **前端** | 22 | 管理类页面迁移(用户/角色/客户/任务/日志/登录,约 8,300 行) | 8 | 12 | scgf Arco 页面重接 HTTP/权限 | +| **迁移** | 23 | 数据迁移执行(19 表 + 854MB 文件 + 命名/图层映射 + 对账/回滚) | 5 | 8 | 不含迁移框架 | +| **文件** | 24 | 文件服务迁移(缩略图/鉴权 URL/清理策略,约 1,275 行) | 2 | 4 | 对象存储化 | +| **导出** | 25 | 导出 Worker(ZIP/CSV/打包/签名 URL 下载) | 4 | 6 | 从 scgf 迁 + 拆分 | +| **通知** | 26 | 通知中心页 + 事件扩展(提审/投放/失败) | 2 | 3 | 现只有下拉 | +| **安全** | 28 | 公网安全加固(WAF/限流/MFA/扫描/备案/渗透测试) | 4 | 8 | 公网可访问的前置 | +| **数据** | 29 | Prisma schema/Repository 重写(19 表映射 + 迁移基线 + 数据访问层) | 8 | 12 | ORM 由 Sequelize 改 Prisma | +| | | **合计** | **391** | **581** | | + +**分期小计**(与逐项加总一致,不重复计算): + +| 阶段 | 范围 | 低 | 高 | 累计(低/高) | 对应 §4.4 | +|---|---|---|---|---|---| +| **M0 验证** | 27 | 16 | 31 | 16 / 31 | 7 个 POC | +| **MVP-1 图片生产主线** | 1~12 + 22~25 + 28~29 + 20/21 一半 | 219 | 318 | 235 / 349 | 得物选品→物料→出图→命名→导出 | +| **MVP-2 投放闭环** | 13~14 + 20/21 另一半 | 53 | 77 | 288 / 426 | 提审 + DPLink/配置 | +| **M3 多平台** | 15~16 | 26 | 42 | 314 / 468 | 唯品会 + 平台扩展 | +| **M4 AI 增强** | 17~18 + 26 | 32 | 48 | 346 / 516 | 资产中心 + AI 生图 + 通知中心 | +| **M5 视频产线** | 19 | 45 | 65 | 391 / 581 | 视频 MVP | + +> **首期口径(建议)**:M0 + MVP-1 + MVP-2 = **288~426 人日**(含验证);若不含 M0,则为 **272~395 人日**。全量 = 391~581 人日。 + +### 7.3 人力与周期(含 AI 辅助,日历周期已含依赖等待) + +| 配置 | MVP-1(219~318) | 首期闭环累计(288~426) | 全量累计(391~581) | +|---|---|---|---| +| 1 人 + AI | 13~19 个月 | 17~25.5 个月 | 23~34.5 个月 | +| 2 人 + AI(1 前端 + 1 后端/全栈) | 6.5~9.5 个月 | 8.5~12.5 个月 | 11.5~17.5 个月 | +| 3 人 + AI(前端/后端/平台+AI) | 4.5~6.5 个月 | 5.5~8.5 个月 | 8~11.5 个月 | +| 4 人 + AI | 3~4.5 个月 | 4.5~6.5 个月 | 6~8.5 个月 | + +> 折算方式:人日 ÷ 人数 ÷ 21(工作日/月),再乘 1.2~1.35 的**依赖等待与联调系数**(多人并行不能线性加速)。**首期上线建议 3 人 + AI**;2 人也能做,但首期闭环需 8.5~12.5 个月。不要一开始就承诺唯品会与视频。 + +### 7.4 AI 辅助开发的现实预期(重要) + +"全程 AI 辅助"确实会显著改变成本结构,但**压缩的是"写代码",不是"确认代码对不对"**: + +| 工作类型 | 占比(估) | AI 提效 | 折算系数 | +|---|---|---|---| +| 脚手架/CRUD/表单/表格/迁移脚本 | 25% | 2~2.5 倍 | 0.40~0.50 | +| 样式/组件/页面重构 | 20% | 1.5~2 倍 | 0.50~0.67 | +| 业务逻辑/算法(命名/渲染/签名) | 20% | 1.2~1.6 倍 | 0.63~0.83 | +| 平台真机联调(Playwright/登录/上传) | 15% | 1.0~1.2 倍 | 0.83~1.0 | +| 需求澄清/评审/合规/验收 | 10% | 1 倍 | 1.0 | +| 线上排障/平台改版应急 | 10% | 1.0~1.3 倍 | 0.77~1.0 | + +加权后约 **0.65~0.8**,这就是 §7.2 采用的系数;也是"AI 提效 2~3 倍"与"整体只省 20%~35%"并不矛盾的原因。 + +**为什么本评估 391~581 人日,而两份调研的传统粗估合计只有 280~425?** 因为口径不同,不是数字打架: + +| 来源 | 覆盖范围 | 粗估 | +|---|---|---| +| dewu 调研 | dewu 模块迁移(含 UI) | 115~190 传统人日 | +| scgf 调研 | scgf 地基 + 图片产线 + AI + 多平台(不含视频深水区) | 165~235 传统人日 | +| 两者合计 | 有重叠、且都未单列下列工作 | 约 280~425(不可直接相加) | +| 本评估 WBS | 新增单列:M0 验证 16~31、管理页 8~12、数据迁移 5~8、文件服务 2~4、导出 Worker 4~6、通知中心 2~3、平台账号/凭据 8~12、对象存储/多实例 6~10、测试基础设施 10~15、前端数据重接 30~40、公网安全 4~8、Prisma 重写 8~12 | 391~581(AI 辅助) | + +> 换句话说:**若只看两份粗估覆盖的范围,本评估折算后约 288~420 人日,与 280~425 基本吻合**;多出来约 **103~161 人日** 是两份调研都没有单列的"新工程必做项"(其中"前端数据重接 30~40"已部分包含在两份粗估的 UI 工作内,净新增约 73~121 人日)。评审时请按"能力清单"逐项对账,而不是拿两个总数直接比较。 + +**建议**: +- 用 AI 并行推进"脚手架 + 测试 + 文档 + 迁移脚本",但**每个 AI 产出都必须有人评审 + 自动化验证**;AI 生成的渲染/签名/提审逻辑若没有回归测试,错误会静默上线。 +- 单人 + AI 的真实瓶颈是**评审与联调**,不是编码;若只有 1 人,建议把"提审自动化"与"真机验证"外协或延后。 +- M0 结束时用 POC 实际耗时校准系数(把 0.65~0.8 替换成实测值)。 + +### 7.5 成本估算(量级参考,非报价) + +| 项 | 估算 | 说明 | +|---|---|---| +| 服务器(API/4 类 Worker/PG/Redis) | **800~2,500 元/月** | 4C8G×1 + 2C4G×3 + 托管 PG/Redis;Playwright/渲染吃内存 | +| 对象存储 + CDN | **100~500 元/月** | 按 500GB 存量 + 月流量 200~500GB 估算;视频素材占大头 | +| 带宽/出网 | **200~800 元/月** | 送审大文件上传、素材下载;建议同地域 OSS 直传降低穿行 | +| **AI 生图** | **单价待确认**;按 0.2~0.5 元/张 × 月产量做预算上限 | M2-0 实测 flash 19~25s/张、16,428 token/张;文字校验使成本近翻倍;**必须把单价做成配置项** | +| **AI 视频** | **单价待询价**;按 5~15 元/条 × 月产量做上限 | 1000 条/月即 5,000~15,000 元/月;需先做 3~5 条样片再定 | +| 字体商用授权 | **一次性/年费,需法务确认** | `方正兰亭中黑简体` 商用授权状态未知;换字体会改变渲染结果 | +| 域名/证书/监控 | 100~300 元/月 | — | +| WAF/公网防护 | 100~500 元/月 | 公网访问可选云 WAF/高防;也可先用云厂商基础防护 | +| **合计(不含 AI 视频放量)** | **约 1,300~4,600 元/月 + AI 调用费** | 五项固定成本加总:800+100+200+100+100=1,300;2,500+500+800+300+500=4,600 | + +> 建议在系统配置中心增加"AI 单价 / 日调用上限 / 月预算 / 告警阈值",把成本控制做成产品能力(scgf 已有配置框架,加 `ai` 模块即可)。 + +### 7.6 与两项目历史投入的关系 + +- dewu:2026-05→10 约 5 个月,228 commits,65k 行(桌面端含大量发布/签名/更新链路)。 +- scgf:2026-03→09 约 6 个月(9 月集中 131 commits),63k 行(含 19 表/113 接口/PSD 引擎)。 +- **新平台不是"第三次重做"**:它把两条产线合并,节省的是"两端各自再演进"的长期成本;但短期内(6~12 个月)总投入会高于"只维护现状",这是整合的必然代价。评审时建议用"3 年总成本"而不是"首期成本"做决策。 + +### 7.7 投入产出:与"维持现状"的对比(3 年 TCO 框架) + +| 项 | 维持现状(两套系统并行) | 新统一平台 | 说明 | +|---|---|---|---| +| 建设投入 | 0(但新 PRD 能力无法交付) | **391~581 人日(≈1.9~2.8 人年)** | 按 210 工作日/人年 | +| 长期维护 | 1.0~1.5 人(两套 + 平台改版适配) | 0.8~1.2 人(一套 + 平台改版适配) | 平台适配约 0.5~1 人不变 | +| 基础设施 | 两套(桌面端无服务器成本,但 Web 端已有) | 一套(略增,因对象存储/Worker) | 见 §7.5 | +| 3 年人力 | ≈ 3.0~4.5 人年 | ≈ 建设 1.9~2.8 + 维护 2.4~3.6 ≈ **4.3~6.4 人年** | 不含 AI 调用费 | +| 能力 | 无法满足 PRD 的图片四层/视频/多平台/投放配置 | 满足 PRD 主链路,可扩展 | 这是主要收益 | +| 结论 | 短期便宜,长期被"两条产线 + 人工配置"锁死 | 首期投入大,但只维护一套、能力完整 | — | + +> **决策建议**:不要用"首期能省多少钱"评估整合,而用"3 年 TCO + 能力清单 + 风险"三维评估。如果只打算做图片产线、且能接受人工完成选品/提审/投放,那么"保留 scgf + 手工流程"更省;如果要交付 PRD 描述的完整链路,整合是唯一可控路径。 + +--- + +## 8 整合路线图 + +### 8.1 里程碑总览 + +> 工作量取自 §7.2 分期小计(逐项加总一致);日历周期见 §7.3,二者口径不同,不要混用。 + +| 阶段 | 工作量(人日) | 目标 | 核心交付物 | 退出标准 | +|---|---|---|---|---| +| **M0 验证与定稿** | 16~31 | 去风险 | 7 个 POC 结论、客户书面授权文件、模板/资产规范与首批样张、架构与数据模型定稿、调研报告与 scgf 文档脱敏入库 | POC-1~4 通过;授权文件到位;模板规范与 ≥5 个真实模板到位 | +| **M1 地基 + 图片主线(MVP-1)** | 219~318 | 跑通"选品→物料→出图→命名→导出" | 新工程骨架、账号/权限/配置、得物平台适配(读)、物料库、模板/渲染/生产页、命名/导出、管理页迁移 | ≥5 个真实模板回归通过;10 个真实商品端到端出图;权限/范围有测试 | +| **M2 提审 + 投放闭环(MVP-2)** | 53~77 | 跑通"送审→审核→投放链接" | 提审状态机/预检/批量送审 Worker/审核同步、DPLink/配置管理 | 送审真机成功率 ≥95%;审核可回查;账号串行锁有并发测试 | +| **M3 多平台** | 26~42 | 扩平台 | 唯品会适配、平台扩展机制、资源路径规则 | 唯品会完成一次闭环;新增平台不改核心代码 | +| **M4 AI 增强** | 32~48 | AI 补充产线 + 资产中心 | AI 生图产品化、资产中心、通知中心 | AI 生图可用率 ≥80%;成本/限额/复核闸门生效 | +| **M5 视频产线** | 45~65 | 视频素材 MVP | 脚本(AI/人工)→ 画面 → 组合;16:9/9:16 各一条 | 20 条样片人工评审通过;单条成本/时长可统计 | +| **合计** | **391~581** | — | — | — | + +### 8.2 关键路径与并行建议 + +``` +客户授权文件 ─┐ + ├──▶ POC-1/2(送审+账号)──▶ M2 提审 Worker ──▶ 上线 +POC-3/4 ───┘ ▲ + │ │ + └──▶ M1 图片主线(最长路径)───────────────┘ + │ + └──▶ M3 唯品会 / M4 AI 生图 ──▶ M5 视频 +``` + +- **最长路径是 M1 图片主线(渲染引擎 + 生产页 + 物料库)**,应优先投入最强的人力。 +- POC 与 M1 可并行:POC-4(渲染)本身就是 M1 的第一块。 +- 唯品会、AI 生图、视频都不在关键路径上,可以后置;**不要为了"PRD 全量"把三条不确定支线塞进首期**。 +- 提审 Worker 与 M1 的后半段可并行(一个前端/一个平台 Worker)。 + +### 8.3 每阶段的"完成定义"(DoD) + +| 阶段 | DoD | +|---|---| +| M0 | 每个 POC 有书面结论(通过/不通过/降级);架构图与数据模型评审通过;合规结论留档;两份调研报告 + scgf docs 入库 | +| M1 | 真实商品全链路可复现;渲染有黄金样本回归;任务失败可观测;权限/范围有测试;部署脚本可用 | +| M2 | 送审成功率与失败原因可统计;账号串行锁有并发测试;提审/审核状态与平台一致;审计可查 | +| M3 | 新增一个平台不改核心代码(只加 adapter + 配置) | +| M4 | AI 生图有成本/限额/复核闸门;资产中心可用 | +| M5 | 视频样片达到业务方"可投"标准;单条成本/时长可统计;失败可重试/降级 | + +### 8.4 上线、灰度与容灾 + +| 项 | 建议 | +|---|---| +| 切换策略 | 新旧系统并行 2~4 周:旧系统只读,新平台承接新任务;按客户/平台灰度,先 1 个客户 + 1 个平台 | +| 停服窗口 | 仅数据迁移需要,放周末 2~4 小时;提前 3 天公告;桌面端在切换完成后停止分发(D-01) | +| 灰度与回滚 | 镜像版本化 + 开关(送审/抓取/AI 分别可关);DB 迁移提供 down 脚本;回滚时限 30 分钟内 | +| 备份 | 每日全量 PG 备份 + WAL 增量;对象存储开版本化/生命周期;保留 ≥30 天 | +| 容灾目标 | 单机阶段:RTO ≤ 4h、RPO ≤ 24h;多副本阶段再收紧 | +| 演练 | 上线前至少 1 次"备份恢复 + 迁移回滚 + 送审开关"全流程演练 | +| 上线检查 | 配置项、账号凭据、队列健康、对象存储权限、监控告警、**公网安全(WAF/MFA/依赖与镜像扫描/渗透测试)**、客服/运营话术、值班表 | + +--- + +## 9 风险登记 + +> 概率/影响:高/中/低。每条风险必须有明确的触发信号与应对动作,禁止"持续关注"。 + +| 编号 | 风险 | 概率 | 影响 | 触发信号 | 应对措施 | 责任人 | +|---|---|---|---|---|---|---| +| **R-01** | **平台合规/封禁**:服务端集中托管账号 + 自动化送审被平台判定违规,导致账号限流/封禁 | 中 | 高(客户承担) | 登录频繁失效、接口 403/风控码、账号被限制 | 客户已授权使用其账号(待补文件);只读优先;写操作人工确认;账号级限速;`enableSubmitReview` 式一键停用;降级为"服务端准备 + 人工浏览器收尾";平台方条款残余风险由业务方接受并留档 | 业务负责人 + 法务 | +| **R-02** | **单账号单会话冲突**(**待 POC-2 验证的推断**):多人共用账号互踢,送审中断 | 中高 | 高 | 频繁"请先登录"、token 被顶 | 账号级分布式锁串行;登录态健康检查;失败自动重登+告警;按项目分配账号 | 平台 Worker 负责人 | +| **R-03** | **平台接口/页面改版**:签名盐、字段、选择器、权限菜单变化 | 高 | 高 | 签名自校验失败、关键元素缺失、接口 4xx | 适配层隔离;选择器配置化 + 页面健康检查;契约测试 + 抓包 fixture;预留维护人力(约 0.5~1 人持续) | 平台适配负责人 | +| **R-04** | **视频 AI 不达预期**:质量/成本/时长不可控 | 高 | 高 | POC-6 样片不通过、单条成本超预算 | 不设硬上线日期;先做 3~5 条样片;只做单镜头;不接受则降级为"脚本+素材管理" | 产品 + AI 负责人 | +| **R-05** | **唯品会零参考**:适配周期不可控 | 高 | 中高 | 摸底后无可用接口/流程差异大 | 单独立项;首期不做;合同中明确"平台适配另计" | 业务负责人 | +| **R-06** | **渲染引擎改造静默错误**:图能出但内容错 | 中高 | 高 | 存量模板产出与设计稿不一致 | 黄金样本 + 像素 diff 回归;灰度;旧渲染器开关;人工抽检 | 图片产线负责人 | +| **R-07** | **对象存储/大文件**:视频 140–190MB 上传失败/成本超预期 | 中 | 中高 | 上传失败率上升、流量费用异常 | 客户端/浏览器直传 OSS;分片 + 断点;限速与重试;成本看板 | 架构 + 运维 | +| **R-08** | **数据迁移丢失/错位**:854MB 文件 + 19 表 + 历史命名 | 中 | 中高 | 对账不一致、成片找不到 | dry-run + 对账(行数/大小/MD5)+ 备份 + 可回滚;先迁模板与资产,历史批次只读归档 | 后端负责人 | +| **R-09** | **AI 成本失控/限流**:账号级 IPM 限流、单价未知 | 中 | 中 | 429、账单超预算 | 网关排队 + 配额 + 日/月上限 + 告警;pro/flash 分层;先小流量 | AI 负责人 | +| **R-10** | **凭据泄露**:历史仓库已硬编码 Cookie 同步密钥/FTP 密码 | 高(既成事实) | 高 | 仓库/文档/产物中出现凭据 | 立即轮换;新平台全部走 KMS/环境变量;禁止写入配置/日志/审计;清理历史产物 | 安全 + 研发负责人 | +| **R-11** | **字体/许可证**:方正字体商用授权、sharp/onnx 许可证 | 中 | 中高 | 法务审核不通过 | 法务确认;替换开源字体并回归渲染;依赖许可证扫描入 CI | 法务 + 研发 | +| **R-12** | **单机架构扩展受限**:API+Worker 同进程、本地磁盘、内存限流 | 中 | 中 | OOM、任务堆积、接口超时 | 首期即拆 Worker + 对象存储 + Redis 限流;单机多容器起步 | 架构负责人 | +| **R-13** | **AI 生成内容合规**:商标/肖像/功效宣称/免责声明 | 中 | 高 | 平台拒审、客户投诉 | 合规词库 + 人工复核 + 品牌 Logo 程序贴回 + 留痕 | 合规 + 产品 | +| **R-14** | **文档与知识未入库**:scgf docs 110 文件 0 入库 | 高(既成事实) | 中高 | 人员/机器变动后上下文丢失 | **M0 第一件事**:文档入库 + 关键结论摘要进仓库;建立 ADR | 技术负责人 | +| **R-15** | **范围蔓延**:PRD 全量 P0 + 视频 + 唯品会同时压入首期 | 高 | 高 | 里程碑持续延期、质量下降 | 冻结首期范围(§4.4);变更走评审;视频/唯品会独立里程碑 | 产品负责人 | +| **R-16** | **公网暴露**:虽为内部平台,但公网可达,登录账号/平台凭据/客户素材面临外部攻击面 | 中 | 高 | 异常登录、凭据撞库、接口扫描 | WAF + 登录限流 + MFA(至少管理员)+ 最小权限 + 全量审计 + 依赖/镜像扫描 + 渗透测试 + 定期轮换密钥 | 安全 + 运维 | + +--- + +## 10 评审决策清单与待确认问题 + +### 10.1 需要您拍板的决策项 + +| 编号 | 决策 | 推荐 | 备选 | 影响 | +|---|---|---|---|---| +| **D-01** | 桌面端下线节奏 | 彻底 Web 化,桌面端冻结功能、只做安全维护,首期闭环(M2)上线后停止分发 | 过渡期保留双端 | 决定是否保留 Electron 维护人力 | +| **D-02** | 技术底座 | 新建统一工程(pnpm monorepo),技术栈沿用 Express 5 + Sequelize + PG + Redis/BullMQ | 以 scgf 为基座 / 前后端分离新建 | 已选新建;本项确认技术栈 | +| **D-03** | UI 组件库 | **Semi Design 2 + Tailwind + 自建 token**(与 Arco 近似平手,Semi 略优) | Arco / shadcn/ui(+4~6 人周) | 相对 Semi 基线,Arco 约 -3~+3 人日,shadcn 约 +20~30 人日;不影响主工期 | +| **D-04** | 平台账号模式 | 运营级集中托管 + 账号级串行锁 + 全量审计 | 用户级授权 | 已选集中托管;客户已授权使用其账号(D-09 待补文件) | +| **D-05** | 首期范围 | **MVP-1 图片主线 + MVP-2 投放闭环(首期闭环)**;唯品会/AI 生图/视频后置 | 仅 MVP-1(不含提审) | 决定上线时间与价值闭环;对应 §7.2 的 272~395 人日(不含 M0) | +| **D-06** | 平台顺序 | 得物先行;唯品会 M3 且单独立项 | 双平台并行 | 唯品会零参考,并行会拖垮主线 | +| **D-07** | AI 定位 | AI 生图为**补充产线**(无模板场景),不替代 PSD;AI 模特/脚模按"资产图"接入 | AI 生图替代 PSD | 决定渲染引擎改造方向 | +| **D-08** | 数据迁移 | 迁用户/客户/模板/图层/命名/通知;不迁历史批次与凭据;dewu 只导入 md5 账本 + 审计 | 全量迁移 | 决定迁移工作量与风险 | +| **D-09** | **平台侧合规(客户授权已确认,待补文件)** | 客户已授权使用其账号做服务端托管 + 自动送审;需补书面文件:账号范围/期限/允许操作/数据使用/封禁风险承担 | 降级半自动 / 停止自动送审 | 文件未到位前不得上线自动送审;平台方条款残余风险由业务方接受并留档;仍保留一键停用 | +| **D-10** | 部署形态 | 单机 Docker Compose(API + 4 Worker + PG + Redis + MinIO/OSS)+ 对象存储 | K8s | 首期够用;代码保持无本地状态 | +| **D-11** | 人力配置 | **3 人 + AI**(前端/后端/平台+AI),先 MVP-1 + MVP-2 | 2 人 / 1 人 + AI | 决定周期(§7.3):3 人首期 5~8 个月,2 人 7.5~11.5 个月 | +| **D-12** | 设计资产供给(**已确认**) | 已确认由设计师角色提供;本项转为"模板规范 + 首批样张 + 交付节奏"的落地项 | 系统内做模板编辑器(不必要) | 供给方已定;规范/样张不到位仍会阻塞 M1(A-01) | + +### 10.2 待确认问题(合并两项目调研,去重后 22 条) + +| 编号 | 问题 | 为什么影响整合 | 建议确认人 | 期望时间 | +|---|---|---|---|---| +| Q-01 | **客户已授权使用其账号(待补文件)**:授权范围/期限/允许操作/数据使用/封禁风险如何约定?平台方条款残余风险由谁接受? | 决定提审自动化能否上线(D-09) | 业务负责人 + 法务 + 客户 | M0 第 1 周 | +| Q-02 | 客户授权覆盖哪些账号:**软广与硬广(DPLink)两套**是否都在授权范围?账号归属、退出语义与封禁责任如何写进文件? | 决定账号体系、能力绑定、审计与责任边界 | 业务负责人 | M0 第 1 周 | +| Q-03 | 唯品会的后台登录方式、素材/提审流程、是否有接口或可复用页面? | 决定多平台工作量(18~30 人日起) | 运营 + 客户 | M0 | +| Q-04 | PRD 中的 DP 具体指什么?字段、生成规则、样例? | 决定投放配置模块是规则引擎还是固定拼接 | 业务方 | M1 前 | +| Q-05 | 提审是"平台后台提审"还是"系统内审批流"?需要几级? | 决定提审状态机与角色 | 产品 + 运营 | M1 前 | +| Q-06 | 模板是否只支持 PSD?是否允许非 PSD 图片模板并存? | 决定是否复活/重做 Schema 渲染路线 | 产品 + 设计 | M0 | +| Q-07 | "AI 模特/脚模"是生成图还是设计提供的素材图?"Logo 拼接字符"具体交互? | 决定渲染引擎与资产模型(差异可达 10+ 人日) | 设计 + 运营 | M0 | +| Q-08 | 三规格是固定枚举还是可扩展?同一模板如何派生三尺寸? | 决定模板/规格模型与设计侧交付方式 | 产品 + 设计 | M0 | +| Q-09 | 视频的时长/分辨率/口播/字幕/过审标准?样片由谁验收? | 视频无法验收的根因 | 产品 + 运营 | M0 | +| Q-10 | AI 生图定位与预算上限?是否必须"文字逐字校验 + 人工复核"双闸门? | 决定成本(近翻倍)与流程 | 产品 + 财务 + 合规 | M0 | +| Q-11 | 字体商用授权状态(方正兰亭中黑等)?新增字体如何管理? | 合规红线;换字体会改变渲染结果 | 法务 + 设计 | M0 | +| Q-12 | 存量数据迁移范围:scgf 19 表 + 854MB 文件;dewu md5 账本/审计? | 决定迁移方案与回滚 | 产品 + 运维 | M0 | +| Q-13 | 内部平台已收敛为单租户;仍需确认**多品牌/多客户**的数据隔离维度(客户范围 vs 物理隔离) | 决定权限模型与列表范围,但不再是架构分叉 | 技术 + 业务负责人 | M0 | +| Q-14 | 权限是否需要"平台 × 客户 × 项目"三层? | 决定权限模型与所有列表接口 | 产品 + 运营 | M1 前 | +| Q-15 | 表 1-4 成功指标的现状值/目标值? | 上线后无法判断成功 | 业务 + 数据 | M1 前 | +| Q-16 | 首期上线时间、验收方式、是否需要灰度/回滚演练? | 决定排期与发布策略 | 产品 + 技术 | M0 | +| Q-17 | 历史选品、粗词检索、批量配置替换等 P1 是否必须在首期? | 影响 MVP 范围 | 产品 | M0 | +| Q-18 | 平台改版后的适配责任人/SLA?是否接受"平台变更可能需要 1~3 天停机修复"? | 长期维护成本归属(约 0.5~1 人) | 业务 + 技术 | M0 | +| Q-19 | 选品主键与口径:得物用 SPUID,唯品会用什么?是否统一为内部商品主数据? | 决定选品/物料/命名/投放的主键设计 | 运营 + 平台对接人 | M0 | +| Q-20 | 促销信息(折扣/活动标识)的数据来源与更新频率?是模板叠加还是实时数据? | 决定促销图层模型与数据对接方式 | 运营 + 产品 | M1 前 | +| Q-21 | 需要哪些埋点与经营看板指标?口径与数据源? | 决定事件模型与统计聚合 | 产品 + 数据 | M1 前 | +| Q-22 | 混剪送审与 Excel/CSV 批量导入是否在首期? | 影响提审范围(6~10 人日)与优先级的判断 | 业务 + 产品 | M1 前 | + +### 10.3 评审 Go/No-Go 标准 + +**建议评审结论分为三档**: + +| 结论 | 条件 | 后续动作 | +|---|---|---| +| **Go(推荐)** | D-01~D-12 确认(D-09 待补文件、D-12 已确认);客户书面授权文件到位;启动 M0 的 7 个 POC | 立项,3 人 + AI,按 §8 路线图执行 | +| **Conditional Go** | 合规未闭环 / POC 未做 / 设计供给未定 | 先做 M0(3~6 周)再决策;期间冻结开发投入(只做 POC 与文档) | +| **No-Go(当前形态)** | 平台明确禁止服务端自动化,且不接受半自动降级 | 退回"桌面端 + Web 生产端"混合形态(方案 B),或只做图片产线 | + +### 10.4 组织、协作与合规(评审也需确认) + +| 项 | 建议/待确认 | +|---|---| +| **平台侧合规** | 客户已授权使用其账号(待补文件与范围);平台方条款残余风险由业务方接受并留档;文件未到位前不开放自动送审(D-09) | +| **设计师角色** | 设计资产由设计师提供 → 系统必须支持设计师上传/编辑/预览/版本与资产复用;需明确模板规范与交付节奏(A-01) | +| 人力来源 | 2~3 人从哪来?是否需要外协(前端/Playwright 适配)?谁做产品决策与验收? | +| 决策机制 | 范围变更、平台适配优先级、上线窗口由谁拍板?建议设"产品 + 技术"双负责人 | +| 素材版权 | 抓取的商品图/视频用于二次创作与投放,版权/授权依据需客户书面确认;AI 生成图不得侵犯商标/肖像 | +| 个人信息 | 平台账号手机号、运营人员信息属个人信息,需最小化收集、加密存储、审计访问 | +| 内容合规 | AI 图/视频需人工复核闸门;电商广告禁用词/功效宣称/免责声明按客户行业规则配置 | +| 审计与追溯 | 谁在何时用哪个账号对哪个商品/素材做了什么,必须可查、可导出、不可篡改 | + +--- + +## 11 结论与建议 + +### 11.1 结论 + +1. **整合可行,方向正确**:两项目是同一业务链路的上下游,合并后能形成"选品 → 原始物料 → 图片/视频生产 → 命名 → 提审 → 投放配置"的完整闭环,避免继续维护两条互不相通的产线。 +2. **技术上没有"不可逾越"的障碍,但有 3 个技术约束 + 1 个待验证假设**:①送审默认页面自动化(可并行评估直连写接口);②PSD 渲染需支持多资产;③单机架构必须拆分;④平台账号单会话是**推断**,需 POC-2 用两次同时登录实验证实/证伪。这四点应在 M0 用 POC 定论。 +3. **最大风险不在代码,而在外部依赖**:平台侧合规(客户已授权使用其账号、待补文件,平台条款残余风险仍在)、平台接口稳定性、视频 AI 质量/成本、唯品会零参考。**这四项任何一项不成立,都会显著改变产品形态或排期。** +4. **PRD 目前不足以直接开发**:2~10 章为空,27 项功能框架中 14 项完全空白;建议先补 §4.3 的 12 项,再冻结首期范围。 +5. **"新建统一工程"是正确的,但要把"新建"理解为"重建骨架 + 迁移资产"**,而不是重写。按人日计约 35%~40% 的工作可由存量资产覆盖(按代码行数约 40%~50%:后端 60%~70%、前端 25%~30%),这是 3 人 + AI 能在 5.5~8.5 个月内做出首期闭环的前提。 + +### 11.2 建议的下一步(未来 3~6 周,即 M0) + +| 优先级 | 动作 | 产出 | 负责人 | +|---|---|---|---| +| P0 | 补齐**客户书面授权文件**(账号范围/期限/操作/数据使用/封禁风险)并留档 | 授权文件 + 风险接受记录 | 业务负责人 + 法务 | +| P0 | 与设计师确认模板/图层/促销规范,锁定 M1 前首批 ≥5 个真实模板 | 模板规范 + 首批样张 + 排期 | 产品 + 设计负责人 | +| P0 | 抢救知识:scgf `docs/` 110 个文件 + 两份调研报告**脱敏后**入库;dewu 关键文档归档 | 统一文档库 + ADR + secret 扫描 | 技术负责人 | +| P0 | 执行 M0 的 7 个 POC(必需 POC-1~4 + 支线 POC-5~7) | POC 报告 + 修订后的估算 | 技术负责人 | +| P1 | 评审目标架构与数据模型(§5.4/§5.6) | 架构评审结论 | 技术 + 产品 | +| P1 | 补 PRD §4.3 的 12 项;冻结 MVP-1 范围 | PRD V0.2 + 范围基线 | 产品负责人 | +| P1 | UI 选型拍板(Semi / Arco / shadcn) | 设计技术选型 ADR | 产品 + 前端 | +| P2 | POC-5/6/7(AI 生图/视频/唯品会) | 三条支线的可行性结论 | AI/平台负责人 | + +### 11.3 明确不建议做的事 + +| # | 不建议 | 原因 | +|---|---|---| +| 1 | 直接把两个仓库合并/复制进一个目录 | 两套架构(Electron 本地 JSON vs Web/PG)无法共存,只会得到双份技术债 | +| 2 | 首期同时做"图片 + 视频 + 唯品会 + AI 生图" | 4 条不确定支线并行,任何一条失败都会拖垮整体 | +| 3 | 在没有渲染回归前改 `materialComposer.ts` | 静默错误风险最高;先建黄金样本 | +| 4 | 把 AI API Key/平台凭据放进系统配置表 | 现有审计不脱敏,会长期明文留痕 | +| 5 | 继续保留桌面端并把新功能只做在桌面端 | 与"统一 Web"目标冲突,双端维护成本高 | +| 6 | 用服务端多用户共享一个平台账号而不做串行锁 | 若 POC-2 证实"单账号单会话",则会互踢、送审失败;即使证伪,并发上传同一账号也有风控风险 | +| 7 | 在客户书面授权文件未到位前就上线自动送审 | 授权范围不清,封禁责任与数据使用无依据 | +| 8 | 在模板规范/首批样张未到位时承诺"四层信息完整产出" | 供给方已确认,但规范与样张不到位仍会让引擎改造失去验收基准(A-01) | +| 9 | 以"与设计稿像素级一致"作为验收标准 | 字体/渲染引擎差异客观存在;应改为"差异在约定阈值内 + 业务可接受" | + +--- + +## 附录 A 关键证据索引 + +| # | 结论 | 证据 | +|---|---|---| +| 1 | dewu 已从下载器演进为五段闭环工作台(v2.7.0,228 commits) | `参考项目/dewu-material-Downloader/` git 历史;调研报告 §1、§2 | +| 2 | dewu 全仓无唯品会代码 | 全仓检索 `唯品会\|vipshop\|vip.com` 零命中(本评估独立复核) | +| 3 | 星光只读接口可无浏览器复现(签名 + 信封) | `dw/scripts/lib/platform-sign.mjs:20-37`、`dw/docs/接口登录通道-实现说明.md:146-169` | +| 4 | 送审默认页面自动化(写接口技术上可重放,成本/风控更高) | `dw/electron/submit/page.ts:2-30,47,68`、`dw/docs/星光平台API接口文档.md:342-404`、`dw/docs/星光平台送审与审核查询-可行性评估.md:638,750` | +| 5 | 平台单账号单会话是【推断,待 POC-2 验证】 | `dw/docs/星光平台送审与审核查询-可行性评估.md:100`(源文档标注推断) | +| 6 | 送审判定/命名/预检为纯逻辑,可复用 | `dw/scripts/lib/submit-naming.mjs`(1,013 行)、`dw/docs/送审命名规范与预检规则.md:20-93` | +| 7 | 仓库仍硬编码 Cookie 同步密钥/FTP 密码 | `dw/electron/config/developer.ts:130,135` | +| 8 | scgf 为可部署生产态(容器化/迁移/CI) | `参考项目/sucaigongfang/deploy/*`、`backend/src/utils/migrator.ts` | +| 9 | scgf API 与 Worker 同进程 | `参考项目/sucaigongfang/backend/src/app.ts:65-66,402` | +| 10 | scgf 19 表 / 11 迁移 / 113 接口 | 调研报告 §4.1、§2;`backend/src/routes/*`、`models/*` | +| 11 | PSD 引擎所有替换图层共用一张商品图 | `backend/src/utils/materialComposer.ts:222-236,516-620` | +| 12 | 命名引擎成熟(变量/客户级/快照/校验) | `backend/src/utils/namingConfig.ts:28-72,240-403`、`types/naming.ts:19-40,104-119` | +| 13 | 系统配置框架 40 项 / L1-L3 / 审计 | `backend/src/utils/systemConfigRegistry.ts:33-100,192-760` | +| 14 | 客户范围 fail-closed | `backend/src/utils/clientScopeCore.ts:12-22` | +| 15 | `docs/` 110 文件 0 入库 | `参考项目/sucaigongfang/.gitignore:122`、`git ls-files docs` = 0(本评估独立复核) | +| 16 | AI 生图 main 分支零产品代码 | 调研报告 §5.3;`grep -rniE "seedream\|volc\|aigc" backend/src frontend/src` = 0 | +| 17 | M1 分支整体作废 | `docs/AI生图相关功能-实现方案.md:6` | +| 18 | M2-0 验证结论(34/34、flash 19~25s、单价未获取) | `docs/AI生图-M2-0验证记录.md:8-11,46-66,120-135` | +| 19 | AI Key 不能进系统配置 | `docs/AI素材生成-与现有系统整合方案.md:122-155` | +| 20 | 字体商用授权待确认 | 调研报告 §9.1;`backend/fonts/方正兰亭中黑简体.TTF` | +| 21 | 两项目 LOC 口径 | dewu 65,253(本评估复核 `git ls-files` + wc);scgf 63,632(调研报告 §6.1 命令) | +| 22 | scgf 单机架构(本地磁盘 + 内存限流) | `scgf/backend/src/utils/uploadPath.ts:20`、`middlewares/rateLimit.ts:11-18` | +| 23 | scgf 通知模板 5 类;`failure_catalog`/`notification_template` 非表 | `scgf/backend/src/utils/notificationTemplates.ts:130-156`、`utils/failureCatalog.ts:46` | +| 24 | 调研报告敏感值已脱敏(SALT 等不可入库) | `docs/评估/_调研/dewu-调研报告.md`(SALT 已替换为占位) | + +> 完整证据(合计 105 条 `文件:行`)见两份调研报告的"证据索引"章节。 + +## 附录 B 本次评估的局限 + +| 局限 | 说明 | 影响 | +|---|---|---| +| 未运行代码 | 未安装依赖、未构建、未跑测试、未真机验证 | "能跑通"的判断来自历史实测记录 + 静态阅读,需 POC 复核 | +| 未向平台方直接求证 | 未与得物/唯品会确认工具合规性;目前依据客户授权(待补文件) | R-01 的残余平台条款风险需业务/法务接受并留档 | +| 未取得报价 | AI 生图/视频、云资源、字体均未询价 | §7.5 为量级参考,预算需采购复核 | +| 设计资产样张未到位 | 供给方已确认(设计师角色),但尚未取得真实 PSD/展示方式/促销样张与规范 | POC-4 需在样张到位后执行;验收标准随规范确定 | +| 未做人力成本测算 | 只用人日/人年,未乘薪资 | 预算需财务按实际人力成本换算 | +| 估算为量级 | ±25%,且 POC 结果可能推翻 | 不建议把 §7.2 直接写进合同或对外承诺 | +| PRD 不完整 | 2~10 章为空,14 项功能无细节 | 范围与验收标准需产品补齐 | +| 图片/视频 AI 验证样本偏差 | scgf 的 AI 验证以券商素材为主,与电商场景不同 | AI 结论不能整体平移,需按电商素材重验 | + +## 附录 C 后续应产出的配套文档 + +| 文档 | 时点 | 负责人 | +|---|---|---| +| 《平台电商素材生产平台 PRD V0.2》(补 2~10 章) | M0 | 产品 | +| 《平台/客户/项目数据模型设计》 | M0 | 架构 | +| 《技术架构设计说明书 + ADR》 | M0 | 技术负责人 | +| 《API 契约(OpenAPI)+ DTO 类型》 | M1 | 前后端 | +| 《数据迁移方案(含对账/回滚)》 | M1 | 后端 | +| 《渲染引擎改造与回归测试方案》 | M1 | 图片产线 | +| 《平台适配层(得物/唯品会)接口与选择器说明》 | M1/M3 | 平台 Worker | +| 《AI 生成能力验证与成本预算》 | M3 | AI 负责人 | +| 《视频产线 MVP 方案与验收标准》 | M4 | 产品 + AI | +| 《部署/运维/应急手册(含备份/回滚/RTO-RPO)》 | M1 | 运维 | +| 《3 年 TCO 与年度预算表(人力/基础设施/AI 调用/字体)》 | M0 | 产品 + 财务 | +| 《设计资产供给方案与模板规范》 | M0 | 设计 + 产品 | + +## 附录 D 评审确认 + +| 角色 | 姓名 | 结论(Go / Conditional Go / No-Go) | 意见 | 日期 | +|---|---|---|---|---| +| 产品负责人 | | | | | +| 技术负责人 | | | | | +| 设计负责人 | | | | | +| 测试负责人 | | | | | +| 业务负责人 | | | | | + +--- + +*本文基于 2026-10-30 的代码与文档快照,参考项目版本分别为 dewu v2.7.0(`fe7646b`)与 scgf v1.0.0(`d1b01fa`)。所有估算随 POC 结论更新,版本号按"小改升次版本、范围/方案重大调整升主版本"维护。*