Skip to content

从零发布你的第一个 SaaS(worked example:口语搭子)

状态基准:2026-08-30(SM4-1 试点 ECS-B 真栈验收;完整证据包 = 仓库内 docs/design/3.task/packages/SM4-1/artifacts/ecs_b_acceptance.md,属内部过程资产,不入对外站点)。 读者:要孵化第一个自营 SaaS 的建设者(人类工程师或 AI coding agent)。 性质:本文是真实跑通的完整叙事——下面每一步都在 2026-08-30 的 ECS-B 真栈上实际发生过,数字、事件、回复摘录全部来自验收证据,不是示例假数据。机制的完整参数表在 saas-mode-b-integration-guide.md(§7 有同源 15 步 checklist),本文负责把它讲成一个故事。 契约事实源openapi.yaml


0. 你要造什么

「口语搭子」——一个职场英语口语 SaaS,两个会话 Agent:

Agent人设单价
日常口语陪练咖啡馆场景日常对话陪练10 分/轮
面试模拟官产品经理行为面试英文模拟15 分/轮

用户注册登录、钱包扣点、租户后台——一行代码都不用写。你写的只有:从模板派生的前端(品牌与页面定制)。

1. 平台侧准备(运营动作,15 步 checklist 的 1~7)

  1. Keycloak SPA client(public + PKCE,client id agenthub-oral-buddy)+ 四个 protocol mapper(aud-… / tenant_id / user_id / permissions)——形状参照 mode-b 指南 §1。验收实测:试发 token 的 aud 同时含 oral-buddy 与 console,四 claim 齐。
  2. 建正式租户:运营首登 JIT 自动建个人租户后,POST /tenants 升级正式租户(slug oral-buddy,kind=formal,name=口语搭子)。
  3. 建项目「口语搭子 Web」挂该租户——这是计费归因维度,ID 填进前端 VITE_PROJECT_ID。建项目的 curl 见 hello-agent 教程 §2.1POST /api/v1/builder/projects;或经 web-builder 界面 Projects 页创建。该端点契约收录登记为跟进项)。
  4. 建模型组(LLM-chat,空组走平台 fallback 即可起步)。
  5. 建双 Agent 并发布(人设 / 模型组 / 单价 10 与 15 / 护栏齐全——单价与护栏强制配对,缺一发布被拒)。

判据:GET /api/v1/app/agents?agent_type=conversation 返回的 items 数组长度 = 2(响应无 count 字段)、points_per_turn 10/15(响应键为 snake_case)。

2. 派生你的前端(checklist 8~11)

bash
cd frontend
node scripts/new-saas-app.mjs --name oral-buddy --target ../oral-buddy
  • workspace 依赖二选一(源码内联或私有 registry),填 env(VITE_KEYCLOAK_CLIENT_ID / VITE_KEYCLOAK_URL / VITE_PROJECT_ID…),VITE_USE_MOCKS=true 先离线冒烟。
  • 部署:把 deploy/compose-snippet.yml 的 service 块加进编排(服务名 web-oral-buddy)。验收实测:GET https://<网关>/oral-buddy/ → HTTP 200,登录页标题即你的品牌「口语搭子 · 职场英语口语陪练」。

3. 用户进来(checklist 12~13)

  1. 终端用户在你的站点注册 → 平台 JIT 自动建域内用户行;被邀请入域(redeem + active-tenant 切换)后,活跃域 = 口语搭子。
  2. 运营给首批种子积分:tenant_grant 手动入账(投产开闸前的标准形态;平台充值中心已代码收口,开闸属运维外部前置)。验收实测:+200 分source=tenant_grant,流水 operation_id 可对账(请求体 expires_at 必填——长效积分到期时间)。

4. 见到钱动起来:双轮对话(checklist 14)

用户从目录选 Agent 开会话、各发一轮。验收实测(SSE 事件序列 turn_started → turn_delta → turn_completed):

  • 日常口语陪练(扣 10 分),真实上游英文回复开场:

    "Hey there! Welcome to the café. What can I get for you today? We've got a great latte special on right now."

  • 面试模拟官(扣 15 分)

    "Welcome! For a product manager behavioral round, let's kick off with a 1-minute English self-introduction. …"

每轮 turn_completed 携带 points_charged(10 / 15)——前端展示即扣点回显。

5. 对账(checklist 15):每分钱都能回答「花在哪、买了什么」

以运营身份读 GET /api/v1/billing/points/ledger?user_id=<终端>&project_id=<项目>,验收实测五行流水:

时间线typeamountoperation_id含义
t0manual_adjust+200sm41-grant-…种子入账
t1freeze10turn:25d4ddf8-…陪练轮冻结
t2deduct10turn:25d4ddf8-…陪练轮划扣
t3freeze15turn:1b1cc78a-…面试轮冻结
t4deduct15turn:1b1cc78a-…面试轮划扣

同一 turn 的 freeze/deduct 共享 operation_idcost_records 另有两行 call_kind=llmproject_id 指向「口语搭子 Web」——模型成本也按项目归因。这就是「强治理执行」在你 SaaS 上的样子。

6. 常见卡点(真栈踩过的坑)

症状原因与处置
终端用户积分页 403saas_user 目录缺 billing:points:read/ledger:read(已登记平台任务 SM5-1);开闸前对账走运营侧 ledger
发布被拒(409)单价与五项护栏强制配对,缺一不可(cookbook 计费章)
SSE 一次性整段到达检查网关 proxy_buffering off(模板 nginx 已配,勿删)
切换租户后行为怪active-tenant 响应恒 token_refresh_required: true,客户端必须强制 refresh token(mode-b 指南 §3)

7. 你学到了什么

  • 你的 SaaS = 业务壳;平台 = headless 会话运行时 + 身份 + 钱包(模式 B,ADR-0058 唯一路线)。
  • 每一轮消费都可对账:operation_id 串起 freeze/deduct,cost_records 记录模型成本与项目归因。
  • 下一步深入:conversation-runtime-protocol.md(SSE 帧与状态机)→ saas-integration-cookbook.md(若后续需要自有后端 / 服务端集成)→ 多模态(语音 / 图片 / 文生图,同一会话通道按需启用)。