upgrade-roadmap.md 21 KB

P2 / P3 升级路线

本文档定义「本地单店专业工具」向稳定 SaaS 平台演进的落地路线。原则是:先不推翻现有 Node + 原生前端架构,而是先把任务、资产、配置三条核心数据流稳定下来;等 API 和测试稳定后,再逐步完成 TypeScript 化、CI/CD 和平台能力。

总体顺序

P2-A 任务中心
P2-B 配置引导
P2-C 历史资产库
P2-D 工程质量
P3-A 模板库
P3-B 审核流
P3-C 开放 API
P3-D 模型市场

推荐按「数据层 → 服务层 → API → UI → 工程化」推进,而不是先大规模重写前端。这样可以保持当前产品可用,同时降低迁移风险。


P2-A 任务中心

目标

让生成和采集任务具备持久化、可恢复、可观测、可重试的能力,解决刷新页面、重启服务、批量任务失败后状态不清楚的问题。

数据模型

本地版先使用 SQLite;后续 SaaS 可平滑迁移到 PostgreSQL。

CREATE TABLE jobs (
  id TEXT PRIMARY KEY,
  type TEXT NOT NULL,                 -- crawl | generation
  status TEXT NOT NULL,               -- queued | submitted | running | succeeded | failed | canceled | timeout
  workspace_root TEXT NOT NULL,
  folder_name TEXT,
  shop_name TEXT,
  kind TEXT,
  model TEXT,
  prompt TEXT,
  prompt_version TEXT,
  provider TEXT,
  provider_task_id TEXT,
  request_hash TEXT,
  idempotency_key TEXT UNIQUE,
  progress TEXT,
  cost REAL,
  attempts INTEGER NOT NULL DEFAULT 0,
  max_attempts INTEGER NOT NULL DEFAULT 3,
  error_code TEXT,
  error_message TEXT,
  warning TEXT,
  created_at TEXT NOT NULL,
  started_at TEXT,
  finished_at TEXT,
  updated_at TEXT NOT NULL
);

CREATE TABLE job_events (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  job_id TEXT NOT NULL,
  event TEXT NOT NULL,
  level TEXT NOT NULL,
  message TEXT,
  payload_json TEXT,
  created_at TEXT NOT NULL
);

后端改动

  1. 新增任务仓库模块:
    • packages/jobs/repository.js
    • packages/jobs/queue.js
    • packages/jobs/provider-client.js
  2. 任务状态机固定为:

    queued → submitted → running → succeeded
                          ↘ failed / timeout / canceled
    
  3. 服务启动时:

    • 加载未完成任务;
    • 对有 provider_task_id 的任务继续轮询;
    • 对仍处于 queued 的任务重新入队;
    • 对超过最大重试次数的任务标记失败。
  4. 任务创建时先写数据库,再提交供应商。

  5. 供应商返回任务 ID 后立即更新 provider_task_id

  6. 增加统一接口:

    GET    /api/tasks
    GET    /api/tasks/:id
    POST   /api/tasks/:id/retry
    POST   /api/tasks/:id/cancel
    DELETE /api/tasks/:id
    GET    /api/tasks/stream
    
  7. /api/tasks/stream 使用 SSE 推送:

    • 任务新增;
    • 进度更新;
    • 状态变化;
    • 日志摘要。

前端改动

  1. 在侧边栏增加「任务中心」入口。
  2. 顶栏增加全局任务状态图标:
    • 空闲;
    • N 个进行中;
    • 有失败;
    • 全部完成。
  3. 任务中心支持:
    • 按类型筛选:全部、采集、生成;
    • 按状态筛选:排队、进行中、成功、失败;
    • 查看任务详情;
    • 重试;
    • 取消;
    • 删除记录;
    • 跳转到结果。
  4. 生成页面保留轻量进度区,但复杂状态统一收敛到任务中心。
  5. 页面刷新后自动恢复未完成任务。

验收标准

  • 服务重启后,未完成任务仍可见。
  • 页面刷新后,正在生成的任务不丢失。
  • 失败任务能看到错误原因,并能手动重试。
  • 同一个任务的供应商任务 ID 可以追溯。
  • 批量任务不会因为页面关闭而中断。

P2-B 配置引导

目标

把「先配置成功,再使用产品」变成可视化流程,减少 API Key、Cookie、输出目录配置错误带来的隐性失败。

引导流程

1. 欢迎
2. 配置 API Key
3. 测试生成服务
4. 配置输出目录
5. 配置采集 Cookie
6. 测试采集账号
7. 选择或扫描门店
8. 完成首次生成

后端接口

新增配置健康接口:

POST /api/config/test-api
POST /api/config/test-workspace
POST /api/config/test-crawl-cookie
GET  /api/config/status
POST /api/config/onboarding-complete

/api/config/status 返回:

{
  "apiConfigured": true,
  "apiReachable": true,
  "workspaceReady": true,
  "workspaceWritable": true,
  "crawlCookieConfigured": true,
  "crawlCookieValid": true,
  "shopsReady": true,
  "firstGenerationCompleted": false,
  "onboardingCompleted": false
}

交互设计

  1. 首次启动后弹出引导,不在首屏强制打断老用户。
  2. 侧边栏显示 Setup 状态点。
  3. 每个步骤包含:
    • 当前状态;
    • 填写入口;
    • 测试按钮;
    • 成功提示;
    • 错误原因;
    • 下一步。
  4. 失败信息必须给出可操作建议,例如:
    • API Key 无效;
    • API 地址不可达;
    • 目录不可写;
    • Cookie 缺少 ksid
    • 采集账号已过期。
  5. 完成后写入本地 onboarding 状态,可在系统设置中重新打开。

验收标准

  • 新用户能在引导中完成首次可用配置。
  • 每个配置项都有独立的健康状态。
  • 配置错误不会只显示「失败」,而是能定位到具体原因。
  • 用户完成引导后,首页能直接进入门店和生成流程。

P2-C 历史资产库

目标

把「历史创作图片墙」升级为可管理的资产库,支持筛选、版本、收藏、删除、恢复和稳定下载。

数据模型

CREATE TABLE assets (
  id TEXT PRIMARY KEY,
  job_id TEXT,
  workspace_root TEXT NOT NULL,
  folder_name TEXT NOT NULL,
  shop_name TEXT NOT NULL,
  kind TEXT NOT NULL,
  name TEXT NOT NULL,
  status TEXT NOT NULL,                -- generated | pending_review | approved | rejected | deleted
  local_path TEXT,
  object_key TEXT,
  remote_url TEXT,
  thumbnail_path TEXT,
  file_name TEXT NOT NULL,
  width INTEGER,
  height INTEGER,
  file_size_bytes INTEGER,
  checksum TEXT,
  model TEXT,
  prompt_version TEXT,
  cost REAL,
  version INTEGER NOT NULL DEFAULT 1,
  parent_asset_id TEXT,
  favorite INTEGER NOT NULL DEFAULT 0,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
);

CREATE TABLE asset_versions (
  id TEXT PRIMARY KEY,
  asset_group_id TEXT NOT NULL,
  version INTEGER NOT NULL,
  asset_id TEXT NOT NULL,
  created_at TEXT NOT NULL
);

后端接口

GET    /api/assets
GET    /api/assets/:id
PATCH  /api/assets/:id
POST   /api/assets/:id/favorite
POST   /api/assets/:id/review
POST   /api/assets/:id/regenerate
DELETE /api/assets/:id
GET    /api/assets/:id/download
GET    /api/assets/:id/thumbnail

支持查询参数:

keyword
shopName
kind
status
favorite
startDate
endDate
model
page
pageSize
sort

存储策略

本地版:

  • 保留本地文件作为主存储;
  • 数据库保存资产索引;
  • 生成缩略图;
  • 计算 checksum;
  • 删除默认进入回收站。

后续 SaaS:

  • 主存储迁移到 S3 / OSS / COS;
  • 本地路径仅作为缓存字段;
  • 下载使用短期签名 URL;
  • 历史记录不依赖供应商临时 URL。

前端改动

  1. 历史创作页升级为资产库。
  2. 增加筛选栏:
    • 门店;
    • 类型;
    • 状态;
    • 收藏;
    • 时间;
    • 模型;
    • 关键词。
  3. 图片墙继续默认一行 8 个,但大列表使用虚拟滚动。
  4. 卡片悬浮操作:
    • 放大;
    • 下载;
    • 收藏;
    • 重新生成;
    • 删除。
  5. 详情抽屉显示:
    • 大图;
    • 门店;
    • 类型;
    • 尺寸;
    • 模型;
    • 提示词版本;
    • 成本;
    • 创建时间;
    • 关联任务。
  6. 增加回收站入口。

验收标准

  • 重复生成不会覆盖历史索引。
  • 删除后可恢复。
  • 支持按门店、类型、状态、收藏、时间筛选。
  • 大量图片时页面不卡顿。
  • 每个资产都能追溯生成任务和提示词版本。

P2-D 工程质量

原则

不建议一次性重写成 TypeScript + 大型前端框架。推荐渐进式迁移:

1. 先补测试和模块边界
2. 引入 ESLint / Prettier
3. 开启 TypeScript checkJs
4. 核心模块改为 .ts
5. 前端复杂度超过阈值后再引入 Vite + Vue/React

第一阶段:模块拆分

目标不是马上引入框架,而是让 server.js 不再继续膨胀。

src/
  server.js
  config/
  routes/
  services/
  jobs/
  assets/
  crawl/
  providers/
  image/
  storage/
  db/
  shared/

拆分顺序:

  1. config:读取、校验、默认值;
  2. db:SQLite 连接和 migration;
  3. jobs:任务状态机和队列;
  4. assets:资产索引、缩略图、下载;
  5. crawl:门店采集;
  6. providers:图片生成供应商适配;
  7. routes:HTTP 路由;
  8. image:图片处理。

TypeScript 路线

先引入最小可用配置:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "allowJs": true,
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*.js", "src/**/*.ts"]
}

优先补充类型的模块:

  1. config
  2. db
  3. jobs
  4. assets
  5. providers
  6. API 请求和响应。

建议补充 zod

  • 启动时校验配置;
  • API 请求体校验;
  • 供应商响应校验;
  • 数据库写入前校验。

测试策略

单元测试

优先覆盖:

  1. 路径安全;
  2. 文件名清洗;
  3. 配置校验;
  4. 提示词渲染;
  5. 模型参数构建;
  6. 任务状态机;
  7. 资产状态机;
  8. 图片尺寸解析。

集成测试

覆盖 API:

  1. /healthz
  2. /readyz
  3. 设置读写;
  4. 输出根目录限制;
  5. 门店扫描;
  6. 生成任务创建;
  7. 任务状态查询;
  8. 资产筛选和下载。

供应商和淘宝闪购接口必须 mock,不能在 CI 中真实调用或产生费用。

E2E 测试

使用 Playwright 覆盖:

  1. 启动进入门店采集;
  2. 添加店铺;
  3. 系统设置保存;
  4. 视觉生成页面扫描;
  5. 任务中心状态;
  6. 历史资产筛选;
  7. 悬浮放大和下载;
  8. 页面刷新后任务恢复。

CI/CD

第一阶段 GitHub Actions:

install → lint → typecheck → unit → build → integration → e2e → docker build

建议脚本:

{
  "scripts": {
    "dev": "node --watch src/server.js",
    "build": "vite build",
    "lint": "eslint .",
    "format": "prettier --write .",
    "typecheck": "tsc --noEmit",
    "test": "vitest run",
    "test:e2e": "playwright test",
    "db:migrate": "node src/db/migrate.js"
  }
}

分支策略:

main        可发布
develop     集成分支
feature/*   功能分支
fix/*       修复分支
release/*   发布准备

发布流程:

  1. CI 全绿;
  2. 版本号更新;
  3. 生成 Changelog;
  4. 构建 Docker 镜像;
  5. 打 tag;
  6. 本地版发布压缩包或安装器;
  7. SaaS 版部署到预发环境;
  8. 预发验证后发布生产。

Docker 化

本地版使用多阶段构建:

FROM node:22-bookworm-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-bookworm-slim AS app
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY . .
EXPOSE 5177
CMD ["node", "server.js"]

docker-compose.yml

services:
  app:
    build: .
    ports:
      - "127.0.0.1:5177:5177"
    environment:
      NODE_ENV: production
      HOST: 0.0.0.0
    volumes:
      - ./workspace:/app/workspace
      - ./data:/app/data
      - ./config.json:/app/config.json:ro
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:5177/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
      interval: 30s
      timeout: 5s
      retries: 3

后续 SaaS 增加:

postgres
redis
minio
worker
nginx / caddy

可观测性

P2 阶段先落地本地可观测性:

  1. 结构化日志;
  2. request id;
  3. job id;
  4. 错误码;
  5. 日志文件轮转;
  6. /metrics
  7. 任务耗时统计;
  8. 供应商成功率;
  9. 队列长度;
  10. 存储增长。

核心指标:

generation_jobs_total
generation_jobs_failed_total
generation_job_duration_seconds
provider_request_duration_seconds
provider_error_total
queue_depth
crawl_shop_success_total
crawl_image_failed_total
asset_storage_bytes

P3-A 模板库

目标

把提示词和视觉模板从分散配置升级为可复用、可版本化、可分发的模板库。

数据模型

CREATE TABLE templates (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  description TEXT,
  category TEXT NOT NULL,
  kind TEXT NOT NULL,
  latest_version INTEGER NOT NULL,
  visibility TEXT NOT NULL,            -- private | workspace | public
  status TEXT NOT NULL,
  created_by TEXT,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
);

CREATE TABLE template_versions (
  id TEXT PRIMARY KEY,
  template_id TEXT NOT NULL,
  version INTEGER NOT NULL,
  prompt TEXT NOT NULL,
  negative_prompt TEXT,
  variables_json TEXT NOT NULL,
  default_params_json TEXT NOT NULL,
  preview_asset_id TEXT,
  changelog TEXT,
  status TEXT NOT NULL,
  created_at TEXT NOT NULL
);

变量系统

支持变量:

{{shopName}}
{{dishName}}
{{brandColor}}
{{brandStyle}}
{{platform}}
{{aspectRatio}}

渲染时必须校验:

  1. 必填变量;
  2. 变量类型;
  3. 变量长度;
  4. 禁用占位符残留;
  5. 模板版本;
  6. 渲染结果快照。

功能

  1. 模板列表;
  2. 模板预览;
  3. 模板复制;
  4. 模板编辑;
  5. 版本对比;
  6. 默认模板;
  7. 门店覆盖模板;
  8. 模板试运行;
  9. 模板评分;
  10. 使用统计。

验收标准

  • 每个生成任务都能追溯到模板 ID 和版本。
  • 修改模板不会影响历史任务。
  • 模板变量渲染后不允许出现未替换占位符。
  • 用户可以基于历史作品反向保存模板。

P3-B 审核流

目标

让生成结果可以进入“待审核 → 通过 / 驳回 → 发布”的标准流程,适合团队和连锁门店运营。

状态机

generated → pending_review
pending_review → approved
pending_review → rejected
rejected → regenerated
approved → published
published → archived

数据模型

CREATE TABLE reviews (
  id TEXT PRIMARY KEY,
  asset_id TEXT NOT NULL,
  status TEXT NOT NULL,
  reviewer_id TEXT,
  comment TEXT,
  reasons_json TEXT,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
);

审核规则

  1. 自动初审:
    • 图片是否生成成功;
    • 尺寸是否符合要求;
    • 文件是否损坏;
    • 是否包含禁止内容;
    • 敏感词检查。
  2. 人工复审:
    • 品牌一致性;
    • LOGO 位置;
    • 菜品是否失真;
    • 文案是否正确;
    • 是否符合平台规范。
  3. 驳回时必须选择原因:
    • 品牌不一致;
    • LOGO 错误;
    • 菜品失真;
    • 文案错误;
    • 分辨率不足;
    • 其他。

功能

  1. 审核队列;
  2. 批量通过;
  3. 批量驳回;
  4. 审核评论;
  5. 对比原图和生成图;
  6. 驳回后一键重新生成;
  7. 审核历史;
  8. 责任人统计。

验收标准

  • 每个资产的状态变化都有记录。
  • 驳回后能带着原因重新生成。
  • 团队成员只能处理自己有权限的工作空间。
  • 发布后的资产不可被普通删除操作直接影响。

P3-C 开放 API

目标

允许门店系统、ERP、运营平台或自动化脚本安全调用生成和查询能力。

API 分层

内部 UI API:/api/*
开放 API:/open/v1/*
Webhook:/open/v1/events/*

核心接口

POST /open/v1/generations
GET  /open/v1/generations/:id
GET  /open/v1/assets/:id
GET  /open/v1/shops
GET  /open/v1/templates
POST /open/v1/templates/:id/render

认证

  1. 开放 API Key 独立于 UI 登录态;
  2. Key 哈希存储;
  3. 只显示一次完整 Key;
  4. 支持设置:
    • 过期时间;
    • 权限范围;
    • IP 白名单;
    • QPS 限制;
    • 日配额;
    • 月配额。

幂等

创建生成任务必须支持:

Idempotency-Key: <uuid>

服务端根据 Key 和请求 hash 判断:

  • 首次请求:创建任务;
  • 重复请求:返回原任务;
  • 冲突请求:返回 409。

限流和配额

CREATE TABLE api_keys (
  id TEXT PRIMARY KEY,
  tenant_id TEXT NOT NULL,
  name TEXT NOT NULL,
  key_hash TEXT NOT NULL,
  scopes_json TEXT NOT NULL,
  rate_limit_per_minute INTEGER,
  daily_quota INTEGER,
  monthly_quota INTEGER,
  expires_at TEXT,
  last_used_at TEXT,
  status TEXT NOT NULL,
  created_at TEXT NOT NULL
);

Webhook

事件类型:

generation.succeeded
generation.failed
generation.canceled
asset.approved
asset.rejected
asset.published

Webhook 要求:

  1. HMAC 签名;
  2. 重试退避;
  3. 事件幂等;
  4. 可查询投递日志;
  5. 支持手动重发。

验收标准

  • 第三方可以用 API Key 安全创建任务。
  • 重复 Idempotency-Key 不会重复扣费。
  • 超过配额返回明确错误码。
  • 所有开放 API 操作都有审计日志。

P3-D 模型市场

目标

把固定模型列表升级为可配置、可评价、可路由的模型市场,降低供应商锁定风险。

数据模型

CREATE TABLE models (
  id TEXT PRIMARY KEY,
  provider TEXT NOT NULL,
  slug TEXT NOT NULL,
  display_name TEXT NOT NULL,
  description TEXT,
  capabilities_json TEXT NOT NULL,
  price_json TEXT NOT NULL,
  status TEXT NOT NULL,
  health_status TEXT,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
);

CREATE TABLE model_routes (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  strategy TEXT NOT NULL,              -- manual | best | price | speed | success_rate
  fallback_model_ids_json TEXT NOT NULL,
  status TEXT NOT NULL
);

模型能力

每个模型声明:

{
  "maxImages": 4,
  "sizes": ["1K", "2K", "4K"],
  "aspectRatios": ["1:1", "4:3", "16:9"],
  "supportsReferenceImage": true,
  "supportsLogoOverlay": true,
  "supportsNegativePrompt": false,
  "estimatedSeconds": 45,
  "billing": "per_image"
}

路由策略

  1. 指定模型;
  2. 综合最优;
  3. 价格优先;
  4. 速度优先;
  5. 成功率优先;
  6. 指定回退链。

市场信息

  1. 模型名称;
  2. 提供商;
  3. 单价;
  4. 预计耗时;
  5. 支持比例;
  6. 支持尺寸;
  7. 参考图数量;
  8. 成功率;
  9. 健康状态;
  10. 最近生成示例。

验收标准

  • 新增模型不需要重写业务流程。
  • 模型不可用时能自动或手动切换回退模型。
  • 每次生成记录实际使用的模型和成本。
  • 模型失败原因能归类为限流、余额不足、参数错误、供应商故障等。

实施节奏

Sprint 1:任务持久化

  • 本地单店阶段先用 .genpic/tasks.json 保存任务快照;
  • 生成任务创建、进行中和终态状态落盘;
  • 服务重启后恢复供应商轮询,无法安全恢复的排队任务标记失败;
  • 任务中心 MVP 支持状态统计、筛选和结果查看。
  • 后续批量/SaaS 阶段再迁移到 SQLite 的 jobs / job_events 模型。

Sprint 2:任务体验

  • SSE;
  • 重试 / 取消;
  • 批量任务汇总;
  • 失败原因展示;
  • 任务日志。

Sprint 3:配置引导

  • 配置状态接口;
  • API / Cookie / 目录测试;
  • Onboarding 弹窗;
  • 侧边栏健康状态。

Sprint 4:资产库

  • assets / asset_versions;
  • 历史创作迁移;
  • 筛选、收藏、详情;
  • 回收站;
  • 稳定下载。

Sprint 5:工程质量

  • 模块拆分;
  • ESLint / Prettier;
  • TypeScript checkJs;
  • 单元和集成测试;
  • GitHub Actions;
  • Docker。

Sprint 6:模板库

  • 模板和版本表;
  • 变量渲染;
  • 模板选择;
  • 历史任务版本追溯;
  • 模板保存入口。

Sprint 7:审核流

  • 资产状态机;
  • 审核队列;
  • 批量操作;
  • 驳回原因;
  • 重新生成联动。

Sprint 8:开放 API

  • API Key;
  • 幂等;
  • 限流;
  • 开放任务和资产接口;
  • Webhook。

Sprint 9:模型市场

  • 模型注册;
  • 能力声明;
  • 路由策略;
  • 健康检查;
  • 成本与成功率面板。

当前阶段建议

近期只做三件事:

  1. 任务持久化 + 任务中心 MVP:这是所有批量生成体验的基础。
  2. 配置引导 + 健康检查:减少 API Key、Cookie、目录配置错误。
  3. 资产库数据化:把历史创作从文件扫描升级为数据库索引。

TypeScript、CI/CD、Docker 应该与任务中心和资产库并行推进,但不要先做大规模前端重写。P3 能力必须等 P2 数据模型稳定后再开启,否则模板、审核、开放 API 和模型市场都会建立在脆弱的文件扫描和内存任务状态上。