Dev Spec v2 · ← 返回文档首页

01 底座模块

1. 仓库结构

monorepo/
├── core/
│   ├── auth/ billing/ storage/ jobs/ notify/ audit/ analytics/
│   ├── labeling/      # AI 标识
│   ├── compliance/    # 年龄、内容安全、授权、删除、休息提醒
│   ├── gateway/       # 模型网关(见 02)
│   └── growth/        # 增长组件(见 03)
├── media/audio/  media/video/
├── products/pixorder/  products/sonicflow/  products/talktale/
├── web/  miniapp/  deploy/  tests/

依赖方向:products → core / media;core 不依赖任何产品;产品之间互不依赖(01 复用 02、03 的能力时,通过 core.gateway 和 media 调用,而不是 import 另一个产品的代码)。

2. 配置

全部走环境变量。关键项:

变量 说明
REGION global / cn
DATABASE_URL、REDIS_URL
STORAGE_* R2 或 OSS
GATEWAY_CONFIG 模型网关配置文件路径(见 02)
MOR_PROVIDER、MOR_* 海外代理商户
WECHAT_PAY_*、WECHAT_MINIAPP_* 国内
CONTENT_PRODUCER 隐式标识里的服务提供者名称或编码
ALERT_WEBHOOK 告警(企业微信 / Slack / Telegram 任选)

3. 账号 core/auth

区域 登录方式
global 邮箱魔法链接;Google 登录(可选)
cn 微信登录(小程序 wx.login);手机号验证码
  • 匿名优先:02 的预览、03 的免费工具都允许不登录使用,付款或保存作品时再绑定账号(匿名会话里的数据自动合并过去)
  • 管理员:密码 + TOTP,会话 12 小时
  • 表:core.users(id, region, email, phone_enc, wechat_openid, birth_year, created_at),以及 core.sessions

4. 支付 core/billing

统一接口:

class PaymentProvider(Protocol):
    name: str
    def checkout(self, *, user_id: str, product: str, sku: str, amount_cents: int,
                 currency: str, mode: Literal["payment", "subscription"],
                 metadata: dict) -> CheckoutSession: ...
    def parse_webhook(self, headers: dict, body: bytes) -> list[BillingEvent]: ...
    def refund(self, payment_id: str, amount_cents: int, reason: str) -> None: ...
    def cancel_subscription(self, sub_id: str) -> None: ...
实现 区域 说明
mor(Creem / Paddle / Lemon Squeezy 其中之一) global 第 0 周确认哪家接受中国居民(个人或公司)入驻;费率约 3.9%+$0.3 至 5%+$0.5
wechat cn JSAPI(小程序)+ H5;需要公司主体和商户号。只用于实物和 Android / 网页端
wechat_virtual cn 微信"小程序虚拟支付":iOS 小程序里购买电子版、订阅、额度等虚拟商品时必须使用(有平台费,计入成本);接入条件、费率、支持的商品类型以微信当期规则为准,第 0 周确认
card_key cn 闲鱼卡密(02 电子版)
app_store 两个区域 01 上架 App 后用应用内购买(RevenueCat 统一管理)

统一的事件:payment.succeeded、payment.refunded、subscription.started / renewed / canceled / past_due。

表:

CREATE TABLE core.payments (
  id TEXT PRIMARY KEY, user_id TEXT, product TEXT NOT NULL, sku TEXT NOT NULL,
  provider TEXT NOT NULL, external_id TEXT NOT NULL,
  amount_cents INT NOT NULL, currency TEXT NOT NULL, status TEXT NOT NULL,
  ref_kind TEXT, ref_id TEXT,              -- 关联到产品侧的订单
  raw JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (provider, external_id)
);
CREATE TABLE core.subscriptions (
  id TEXT PRIMARY KEY, user_id TEXT NOT NULL, product TEXT NOT NULL, plan TEXT NOT NULL,
  provider TEXT NOT NULL, external_id TEXT NOT NULL UNIQUE,
  status TEXT NOT NULL, current_period_end TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE core.entitlements (            -- 产品统一查这里判断权限和额度
  user_id TEXT NOT NULL, product TEXT NOT NULL, key TEXT NOT NULL,   -- 如 'pro', 'songs_month', 'season:s1'
  value JSONB NOT NULL, expires_at TIMESTAMPTZ,
  PRIMARY KEY (user_id, product, key)
);

所有回调都以 (provider, external_id) 做幂等;产品代码只读 entitlements,不直接判断订阅状态。

5. 存储 core/storage

  • 预签名直传和下载;大文件分片上传(S3 兼容接口)
  • 对象键:{product}/{kind}/{yyyy}/{mm}/{owner_id}/{uuid}.{ext},键里不出现个人信息
  • 生命周期(按前缀):tmp/ 1 天;preview/ 7 天;upload/ 30 天;deliver/ 30 天;content/(01 的剧集素材)永久
  • 按对象延期:以下对象不适用前缀的默认期限,由产品在元数据里写入 retain_until,删除任务以它为准:
  • 02 的印刷文件(print/):保留到"签收后 45 天"(覆盖 30 天售后期 + 重印处理时间)
  • 03 付费用户的源文件:90 天(用户付费时,对其已有作品自动延期)
  • 产品判断购买行为时,按平台区分支付方式:iOS 小程序的虚拟商品 → wechat_virtual;其余 → wechat

6. 队列 core/jobs

队列 消费者
core.cpu 通知、删除、打包、支付后处理
pix.gen 02 生成、质检、放大(主要是调用 API,CPU worker 即可)
snd.cpu / snd.gpu 03 音频
tt.content / tt.runtime 01 内容生产 / 运行时
media.video 视频渲染

规则:任务函数必须幂等;默认重试 1 次,之后进死信队列并告警;GPU worker 不直连数据库,完成后投递 record_job_result 任务到 core.cpu(RQ 的回调在执行任务的进程里运行,所以不能用来写库)。

7. 通知 core/notify

渠道 用途
邮件(海外) 交付、物流、召回、周报
微信订阅消息(国内) 同上(用户需要先授权订阅)
网页推送 01 的角色消息
告警 Webhook 给运营者自己

模板存在数据库里,按 (product, template_id, locale) 管理。

8. AI 标识 core/labeling

依据《人工智能生成合成内容标识办法》(2025-09-01 施行),并满足欧盟 AI 法案和 Etsy 等平台的披露要求。

函数 说明
badge_image(img, text) 显式角标
watermark_preview(img) 预览图全屏水印
label_file(path, content_id) 隐式标识:PNG tEXt / JPEG XMP / MP3 ID3 / WAV RIFF / MP4 元数据
spoken_disclosure(audio) 合成语音类内容开头的语音提示(03 声音克隆、01 如有需要)

隐式标识字段按国家标准《网络安全技术 人工智能生成合成内容标识方法》的要求实现,开发时以标准原文为准。

9. 合规组件 core/compliance

能力 说明
年龄确认 首次使用时询问出生年份;按区域和产品配置门槛(01:13 岁以上,未成年人受限;02:16 岁以上;03:13 岁以上,13~17 岁不开放声音克隆)。欧盟部分国家对 16 岁以下处理个人数据要求监护人同意,按国家配置
内容安全 输入和输出都检查(文本、图像、音频转写文本);国内接入已备案的内容安全服务
授权存证 consents(user_id, product, kind, text_version, ip, ua, at)
数据删除 按生命周期自动删除 + 用户主动删除账号(30 天内完成)
休息提醒 01 使用:连续使用超过 3 小时(国内 2 小时)提醒
危机处理 01 使用:检测到自伤、自杀相关表达时中止对话,给出当地求助资源

10. 审计 core/audit

只追加的 core.audit_log,记录:授权、退款、删除、内容安全拦截、异常队列里的人工操作、网关熔断。

11. 异常队列

core.exceptions(id, product, ref_kind, ref_id, reason, detail, status, created_at, resolved_at)

  • 各产品按规则写入;后台只有一个统一页面
  • 积压超过 10 条,或最旧一条超过 24 小时 → 告警
  • 日报统计原因分布,用来改进自动化规则

12. 分析 core/analytics

事件统一命名为 {product}.{object}.{action}(例如 pix.preview.generated、snd.song.exported、tt.episode.completed)。海外发送到 PostHog;国内写入自部署实例。每个产品 PRD 里的数据指标都必须能从这些事件算出来。