05 · Operations

运营与排障 SOP

Vivi 日常运营的所有"剧本"集合:用户报问题先查啥、紧急回滚怎么操作、加角色怎么走、Lark 推送怎么写、需求怎么提才能落地。这一页是运营 / PM / 客服 / 值班工程师的应急手册。

Admin 后台

访问入口

URL:https://vivi-app-e7m.pages.dev/admin

密码:对应 Fly.io secret ADMIN_SECRET —— 找 owner 索取,禁止放进任何公开文档 / 截图 / Slack。

修改密码:fly secrets set ADMIN_SECRET="新密码" -a vividreams(自动重启生效)

能做什么:查 Dashboard 统计 / 用户能量 / 钻石 / 订阅;改用户的 gems / energy / subscription;查 / 改 prompt overrides;导出对话样本。

常用 Admin API(Bearer Token = ADMIN_SECRET)

端点用途
GET /api/admin/dashboardDAU / 总用户 / 7 日营收
GET /api/admin/user/{user_id}查用户能量 / 钻石 / 订阅 / 语言
POST /api/admin/set-gems给用户加扣💎 {"user_id": int, "gems": int}
POST /api/admin/set-energy设置能量
POST /api/admin/set-subscription设置订阅状态 + 过期时间
GET /api/admin/prompts列出 prompt overrides
PUT /api/admin/prompts/{char}/{story}覆写某个 story 的 system_prompt
GET /api/admin/export-samples导出对话样本

用户问题排查 Checklist

用户报"消息发不出去 / AI 回复有问题 / 付了钱没到账"等问题时,不要先猜代码。按这个顺序查:

  1. 查 Fly.io 日志flyctl logs --app vividreams --no-tail | grep -E "ERROR|failed|exception" 看具体异常
  2. 查用户数据turso db shell vividreams 直接查 users / transactions / conversations
  3. 发测试消息:用 Bot API sendMessage 验证 Telegram 链路本身通不通
  4. 区分错误类型
    • "AI service error" → LLM 流式异常(openrouter.py),查 LLM stream failed 日志
    • "Request failed" / HTTP 状态码 → FastAPI 500,看 traceback
    • "Insufficient energy" → 业务限制(正常),查 energy 字段
    • 付款没到账 → 查 transactions 表 + telegram_payment_charge_id,没记录就是 webhook 没收到
  5. 确认影响范围:让另一个用户也测试一下 —— 看似个案常常是全局问题
历史教训:2026-04-01 排查"AI service error"花了大量时间查 DB schema / gift 数据 / conversation —— 真正的根因是 OpenRouter 模型 404 被封号。第一步永远查日志。

紧急回滚

后端回滚(Fly.io)

# 看历史 release
fly releases list -a vividreams

# 回到上一版
fly releases rollback <version> -a vividreams

# 验证
curl https://vividreams.fly.dev/health

Fly.io 回滚是部署级(image 替换),秒级生效。回滚不会回滚 DB schema —— 如果是 migration 引发的问题,回滚后还要手动还原表结构。

前端回滚(Cloudflare Pages)

CF Pages dashboard → vivi-app 项目 → Deployments → 选上一个绿色部署 → "Promote to Production"。或者:

# git revert 上一次推送,再推
git revert <commit-sha>
git push origin main
⚠️ CDN 缓存:CF Pages CDN 可能缓存 24h+,回滚后必须 curl https://vivi-app-e7m.pages.dev/index.html | grep "?v=" 验证版本号。

关 Bot(极端情况,全停服)

# 取消 webhook,让 Telegram 不再推 update
curl https://api.telegram.org/bot<BOT_TOKEN>/setWebhook -d url=

# 修复后重新设置
curl https://api.telegram.org/bot<BOT_TOKEN>/setWebhook \
     -d url=https://vividreams.fly.dev/webhook

新增角色 SOP(3 分钟扩容)

数据源

Softieweb Neon DB(连接串在 Softieweb 仓库 .env.localDATABASE_URL),媒体走 https://media.softie.ai CDN(图片 / 视频直链)。

  1. 读 Softieweb .env.local 确认 DATABASE_URL 没变
  2. 用 Python psycopg2 查询,跳过 Vivi 已有角色:
    SELECT id, name, description, image, video, category, age,
           personality, prompt, first_message, sparks_cost, sort_order
    FROM characters
    WHERE is_active = true AND is_private = false AND category = 'FEMALE'
      AND name NOT IN (...)
    ORDER BY sort_order ASC NULLS LAST LIMIT N;
  3. 转成 Vivi 格式(id 用首词小写 slug,重名加数字后缀),追加到 app/characters/data/characters.json
  4. 检查脏数据:first_message 偶尔属于另一个角色(DB 历史问题),对不上就自己写问候语;prompt 中的 NSFW 描述(如 "Sexual Features: ...")必须删掉,保留性格部分
  5. 媒体不需要下载 / base64 —— resolveImg()http:// 前缀时直接返回 CDN URL
  6. Bump webapp/index.html?v=N(破坏 CDN 缓存)
  7. git add + git commit -m "feat(characters): add ..." + git push origin main
  8. 等 GitHub Actions 跑完,curl https://vivi-app-e7m.pages.dev/index.html | grep "?v=N" 验证

批量生图(角色图库预生成)

这部分走 n8n + ComfyUI + RunPod,不在 Vivi 仓库

R2 上传延迟:历史曾出现 67% R2 HEAD 验证失败(上传完读不到)。API 路径已改 base64 直传,不再依赖 R2 HEAD 验证。批量路径仍然走 R2,但有重试。

Adsgram 充值 SOP

Adsgram 是 Telegram Mini App 的官方广告投放渠道,按预算充值后投流。流程:

  1. 打开 https://partner.adsgram.ai/balance(用户已登录)
  2. "Payment in fiat" 标签页
  3. Country 保持 Thailand
  4. Currency 选 CNY 或 USD(按预算折算)
  5. 填金额 → 提交 → 跳 Changelly 支付页
  6. 到输入卡号环节 交给用户接管(Mastercard 支付)

当前活跃 Campaign ID:62741(2026-04 最新投放,旧 ID 60508 已废弃)。日预算约 $10,定向中东 + 欧美。

Lark 推送规范

所有推送必须用交互式卡片msg_type: "interactive"),结构:

{
  "msg_type": "interactive",
  "card": {
    "config": { "wide_screen_mode": true },
    "header": {
      "title": { "tag": "plain_text", "content": "标题(带 emoji 前缀)" },
      "template": "indigo"
    },
    "elements": [
      { "tag": "markdown", "content": "**第一部分标题**\n\n正文..." },
      { "tag": "hr" },
      { "tag": "markdown", "content": "**第二部分标题**\n\n正文..." },
      { "tag": "note", "elements": [{ "tag": "plain_text", "content": "脚注信息" }] }
    ]
  }
}

颜色约定(header.template)

规则

需求写作模板(PM/同事提需求时)

需求必须满足"工程师看完不需要追问就能动手"的标准。常见问题:只描述现状没说改成什么 / 给了选项没做决策 / 一条混了多个改动 / 缺关键参数 / 没验收标准。

需求模板

## 需求标题(一句话)

现状:当前是怎样的(截图 / 录屏更好)
改为:要变成怎样(明确终态,不是"是否要改")
参数:涉及的具体数值 / 选项
优先级:P0 必须 / P1 重要 / P2 可以后做

不符合模板的需求收到后,先指出缺失项,要求补全后再排期。不要凭猜测开发。

常用命令速查

场景命令
看后端日志flyctl logs -a vividreams
SSH 进容器flyctl ssh console -a vividreams
查 Turso 数据turso db shell vividreams
看 Fly.io secrets 列表fly secrets list -a vividreams
设置 Fly.io secretfly secrets set KEY=value -a vividreams
触发部署推 main 分支即可(git push origin main
看 GHA 运行结果gh run list --limit 5
看失败日志gh run view <run-id> --log-failed
验证生产前端curl -s https://vivi-app-e7m.pages.dev/ | grep "?v="
验证生产 APIcurl https://vividreams.fly.dev/health

凭据 / Secret 索取入口

所有 secret 不放在公开文档里。需要时找 owner 索取,或在内部记忆库(~/.claude/projects/-Users-gloom-Vivi/memory/)查:

需要 Admin 后台密码?reference_admin_secret.md 或找 owner
需要 Lark Webhook URL?reference_lark_webhook.md
需要 Telegram Bot Token? Fly.io secret TELEGRAM_BOT_TOKEN,找 owner
需要 OpenRouter API Key? Fly.io secret OPENROUTER_API_KEY
需要 Turso DB Token? Fly.io secret TURSO_AUTH_TOKEN
需要 Telegram 扫号账号?reference_telegram_scrape_account.md
← 上一篇
04 · 数据与监控体系