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