卢天成
← 返回主页

私有产品 · 脱敏案例 · 迭代中

Ecom Image · 电商 AI 素材工作台

电商素材的「采集 → 参考 → 生成 → 审核 → 交付」全链路工作台,正在从本地工具硬化为可公开试用的多租户服务。

角色
独立开发 · 单人
周期
2026.07 – 至今(高强度迭代中)
规模
私有仓库 · 52 commits
状态
发布门槛驱动 · 暂未公开

背景问题

电商素材生产有三个真实痛点:版本爆炸——同一商品要按国家 / 平台出不同风格版本的图,靠人工管理 prompt 和产物很快失控;参考驱动——好图不是凭空生成的,运营需要先看热卖商品在卖什么图,把爆款图沉淀为可参考的视觉资产;成本与质量要闭环——每次生成都有算力成本,交付前要有质量检查,公开给外部用户前更要有身份、隔离、配额、账本。

以某海外电商设计 SaaS 为对标做功能 parity,但品牌、后端实现、模型路由、算力计费体系全部自有。当前处于持续迭代中,不是一次性 demo。

系统边界

运行时形状:Next.js Web UI + 统一 Python API(单进程)+ Postgres / Redis / MinIO。

层职责
Web(Next.js) 首页灵感流、主工作台、AI 工具工作台(画布内联 AI 编辑);只做同源 /api/* 代理,浏览器不直连任何模型 SDK
统一 API(Python 单包多模块) projects(主链路 + 任务执行器)、prompts(模板 + 风格档案)、model_gateway(通道路由)、billing(估价 → 账本)、qa(质量检查)、assets(资产 + 存储代理)、crawler(采集调度)、auth(身份与租户)、brand_profiles
基础设施 Postgres(元数据)、Redis(队列)、MinIO(图像对象,私有桶 + 签名 URL)
  • 主产品链路:Project → MarketVersion → GenerationJob → DeliveryAsset,一个商品一个项目、一个市场一个版本、交付资产全链血缘可追溯。

关键决策

  1. 1

    抛弃 n8n 与多服务拆分,收敛为单包模块化 FastAPI

    编排引擎对单人迭代是负资产——类型、测试、部署全部收敛到一个 Python 包(按领域分模块),入口只有一个 uvicorn 应用。早期 n8n 编排已从运行时完全移除(仅保留归档 JSON,不加载)。

  2. 2

    模型通道(Channel)抽象,而非绑定单一模型

    一个 Channel = 一条到上游的连接(认证、端点、模型列表、能力标签、优先级);支持 OpenAI 兼容 / Gemini / 阿里百炼 / 火山方舟(豆包)多类 provider,按能力路由 + 失败自动 fallback;密钥只存引用名(api_key_ref),不存明文;MOCK 模式仅作开发兜底,明确不属于产品验收能力。

  3. 3

    爆款采集 → 参考图的资产治理

    内嵌 APScheduler 调度(cron 化业务配置),两层幂等去重(来源+外部 ID、来源 URL),爆款图与参考图分库分标签,「加入参考集」显式升格;参考图 + 地区平台风格档案 + 版本化模板共同组装 prompt。

  4. 4

    无 mock 占位原则

    后端核心链路必须真实实现,不允许用 mock 伪装项目、任务、资产、计费——这是写进仓库规则的硬约束。

  5. 5

    Supabase 只做身份签发,授权永远在自有 API

    FastAPI 用 JWKS 非对称验签(签名 / issuer / audience / 过期 / kid 全验),不信任浏览器传来的 email / role;本地只存 subject 映射,不存密码。

  6. 6

    邀请制受控公开试用,先硬化后开放

    邀请码只存 HMAC-SHA256 指纹、防重放、持久化限流、同一本地事务内消费;上游建号后本地失败会触发补偿删除,失败则 critical 告警;运营重置密码必须填理由并写脱敏审计事件。

  7. 7

    发布门槛清单驱动(release-gate-driven)

    公开试用前必须逐项通过 6 大类检查——身份访问、租户隔离与存储、credits 与执行(报价 / 预占 / 扣减 / 释放全幂等 + 不可变账本)、运营 console、生产运行时、staging 演示证据(含跨租户负测试)。每一项要求留证据,未过门不开放。

查看脱敏架构图(Mermaid 源码) ›

架构图使用通用角色标注,无竞品名称、凭据与租户数据。

%% Ecom Image 脱敏架构图(公开版 · 2026-07 现役运行时)
%% 不含竞品名、真实域名、密钥、供应商内部细节
flowchart TB
  User([运营 / 设计者])
  Operator([平台运营者])

  subgraph Web["Web UI · Next.js"]
    Insp["灵感流首页<br/>热卖参考"]
    Bench["主工作台<br/>Project → MarketVersion → Job → DeliveryAsset"]
    Tools["AI 工具工作台<br/>画布内联 AI 编辑"]
    Web2["同源 /api/* 代理<br/>浏览器不直连模型 SDK"]
  end

  subgraph API["统一 Python API · FastAPI 单进程(ecom 包)"]
    Auth["auth<br/>JWT 验签(JWKS) · 邀请激活<br/>租户隔离 · 审计"]
    Projects["projects<br/>主链路 + 任务执行器"]
    Prompts["prompts<br/>模板 + 地区风格档案组装"]
    Gateway["model_gateway<br/>Channel 抽象 · 能力路由 · fallback<br/>密钥只存引用"]
    Billing["billing<br/>估价 → 报价/预占/扣减/释放 → 账本"]
    QA["qa<br/>质量检查"]
    Assets["assets<br/>资产 CRUD · 存储代理"]
    Crawler["crawler<br/>内嵌调度 · 两层幂等去重<br/>爆款图 → 参考集升格"]
  end

  subgraph Infra["基础设施"]
    DB[("Postgres<br/>元数据 / 租户 / 账本")]
    Redis[("Redis<br/>队列支持")]
    S3[("MinIO<br/>私有桶 + 签名 URL")]
  end

  IdP["身份提供方<br/>仅签发身份 · 授权在自有 API"]
  Models["外部模型服务(多 provider)<br/>OpenAI 兼容 / Gemini / 百炼 / 方舟<br/>按能力路由"]
  Sources["电商平台公开数据<br/>热卖榜 / 店铺 / 关键词"]

  User --> Web
  Web -->|同源| Auth
  Auth --> IdP
  Web --> Projects
  Projects --> Prompts --> Gateway
  Projects --> QA
  Projects --> Assets
  Gateway --> Billing
  Crawler --> Sources
  Crawler --> Assets
  API --> DB
  API --> Redis
  Assets --> S3
  Gateway --> Models
  Operator -->|"console · 邀请 / 配额 / 通道管理<br/>敏感操作写脱敏审计"| Auth

验证方式

  • 37 个 pytest 测试文件,覆盖 auth / assets / billing / brand_profiles / crawler / model_gateway / projects / prompts / shared;每次提交附带当次验证命令与结果(最近一轮 27 passed);
  • Web 端 tsc --noEmit 类型零错误为提交前置;
  • 生产运行时启动校验:缺 Supabase / Postgres / MinIO / 迁移 / 模型通道配置直接拒绝启动;
  • 已知风险公开记录:部分设置 / 日志路由在租户隔离完成前不具备公开条件,明确标记为发布阻塞项。

可公开结果

  • 状态声明:产品仍在迭代,公开试用发布门槛尚未全部通过(多租户资源隔离进行中),暂无公开 URL
  • 测试证据随仓库维护;截图与演示将在发布门通过后以合成品牌素材录制

脱敏边界

以下内容不公开,本案例全文与配图均已规避:

  • 对标竞品名称、竞品静态资源与抓取数据;
  • 模型供应商凭据、供应商内部响应原文;
  • 真实商家素材、未授权品牌元素;
  • 真实邀请码、审计数据、租户数据;
  • 截图 / 演示一律使用合成品牌与合成商品数据。