本文档定义「本地单店专业工具」向稳定 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 → 工程化」推进,而不是先大规模重写前端。这样可以保持当前产品可用,同时降低迁移风险。
让生成和采集任务具备持久化、可恢复、可观测、可重试的能力,解决刷新页面、重启服务、批量任务失败后状态不清楚的问题。
本地版先使用 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
);
packages/jobs/repository.jspackages/jobs/queue.jspackages/jobs/provider-client.js任务状态机固定为:
queued → submitted → running → succeeded
↘ failed / timeout / canceled
服务启动时:
provider_task_id 的任务继续轮询;queued 的任务重新入队;任务创建时先写数据库,再提交供应商。
供应商返回任务 ID 后立即更新 provider_task_id。
增加统一接口:
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
/api/tasks/stream 使用 SSE 推送:
把「先配置成功,再使用产品」变成可视化流程,减少 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
}
ksid;把「历史创作图片墙」升级为可管理的资产库,支持筛选、版本、收藏、删除、恢复和稳定下载。
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
本地版:
后续 SaaS:
不建议一次性重写成 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/
拆分顺序:
config:读取、校验、默认值;db:SQLite 连接和 migration;jobs:任务状态机和队列;assets:资产索引、缩略图、下载;crawl:门店采集;providers:图片生成供应商适配;routes:HTTP 路由;image:图片处理。先引入最小可用配置:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"allowJs": true,
"checkJs": true,
"noEmit": true,
"strict": true,
"skipLibCheck": true
},
"include": ["src/**/*.js", "src/**/*.ts"]
}
优先补充类型的模块:
config;db;jobs;assets;providers;建议补充 zod:
优先覆盖:
覆盖 API:
/healthz;/readyz;供应商和淘宝闪购接口必须 mock,不能在 CI 中真实调用或产生费用。
使用 Playwright 覆盖:
第一阶段 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/* 发布准备
发布流程:
本地版使用多阶段构建:
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 阶段先落地本地可观测性:
/metrics;核心指标:
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
把提示词和视觉模板从分散配置升级为可复用、可版本化、可分发的模板库。
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}}
渲染时必须校验:
让生成结果可以进入“待审核 → 通过 / 驳回 → 发布”的标准流程,适合团队和连锁门店运营。
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
);
允许门店系统、ERP、运营平台或自动化脚本安全调用生成和查询能力。
内部 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
创建生成任务必须支持:
Idempotency-Key: <uuid>
服务端根据 Key 和请求 hash 判断:
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
);
事件类型:
generation.succeeded
generation.failed
generation.canceled
asset.approved
asset.rejected
asset.published
Webhook 要求:
把固定模型列表升级为可配置、可评价、可路由的模型市场,降低供应商锁定风险。
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"
}
.genpic/tasks.json 保存任务快照;jobs / job_events 模型。近期只做三件事:
TypeScript、CI/CD、Docker 应该与任务中心和资产库并行推进,但不要先做大规模前端重写。P3 能力必须等 P2 数据模型稳定后再开启,否则模板、审核、开放 API 和模型市场都会建立在脆弱的文件扫描和内存任务状态上。