# Runtime Runbook

**Date:** 2026-02-25  
**Status:** Active  
**Audience:** 运维 / 后端值班

## Scope & Preconditions

本手册用于日常值班、发布前检查、故障处置与回滚。

### 前置条件

- 已配置 `.env`（仓库根目录）。
- 主机可用：`docker`、`docker compose`、`tmux`、`uv`。
- 已拉取最新代码并确认当前分支与目标发布版本一致。

### 红线规则

- 禁止跳过 bootstrap gate 直接启动 web/worker。
- 迁移/初始化容器执行时必须带 `--build`，避免旧镜像导致迁移不生效。

---

## Bootstrap Gate (Mandatory)

以下流程必须按顺序执行。

### Step 1: 启动基础设施

```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d
```

通过标准：`docker compose ... ps` 中 redis/supabase 相关容器为 `running`。

### Step 2: 执行迁移与初始化

#### 生产环境
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm --build init-job uv run python -m core.runtime.cli bootstrap
```

#### 开发环境（推荐）
开发阶段推荐使用脚本，直接使用本地代码，无需构建镜像：

```bash
bash infra/scripts/dev-migrate.sh bootstrap
```

可选命令：
- `bash infra/scripts/dev-migrate.sh migrate` - 仅运行迁移
- `bash infra/scripts/dev-migrate.sh init-data` - 仅初始化数据

通过标准：命令退出码为 0，日志中无 migration/init-data 错误。

### Step 3: 版本核对（建议）

```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml exec -T db \
  psql -U postgres -d postgres -c "SELECT version_num FROM public.alembic_version;"
```

通过标准：返回 1 行版本号，且与发布预期版本一致。

---

## Service Start / Stop (tmux)

### 启动应用进程

```bash
bash infra/scripts/app-up.sh
```

该脚本会在 tmux `social-dev` 会话中拉起：

- web
- worker-critical
- worker-default
- worker-bulk

通过标准：`tmux list-windows -t social-dev` 可见上述窗口。

### 常用 tmux 命令

```bash
tmux list-windows -t social-dev
tmux attach -t social-dev
tmux kill-session -t social-dev
```

### 日志文件

| 服务 | 日志文件 |
|------|---------|
| Web | `logs/web.log`, `logs/errors/web.error.log` |
| Worker Critical | `logs/worker-critical.log`, `logs/errors/worker-critical.error.log` |
| Worker Default | `logs/worker-default.log`, `logs/errors/worker-default.error.log` |
| Worker Bulk | `logs/worker-bulk.log`, `logs/errors/worker-bulk.error.log` |

---

## Operational Verification

按优先级分层执行。

### L1 必跑（发布前/故障恢复后必须）

```bash
# 先导入 .env，确保端口与配置一致
set -a
. ./.env
set +a

WEB_BASE_URL="http://127.0.0.1:${SOCIAL_WEB__PORT:-5775}"

# 基础健康
curl -fsS http://127.0.0.1:${SOCIAL_SUPABASE__KONG_HTTP_PORT:-8000}/health

# compose 状态
docker compose --env-file .env -f infra/docker/docker-compose.yml ps

# 核心接口 smoke
curl -sS -X POST "${WEB_BASE_URL}/api/v1/auth/login" \
  -H 'Content-Type: application/json' \
  -d '{"email":"demo@example.com","password":"secret123"}'
```

通过标准：health 返回 2xx，关键容器 `running`，核心接口返回预期业务状态码。

### L2 可选（Auth/Profile 业务回归）

```bash
# signup start
curl -sS -X POST "${WEB_BASE_URL}/api/v1/auth/verifications" \
  -H 'Content-Type: application/json' \
  -d '{"username":"demo","email":"demo@example.com","password":"secret123"}'

# signup verify
curl -sS -X POST "${WEB_BASE_URL}/api/v1/auth/verifications/verify" \
  -H 'Content-Type: application/json' \
  -d '{"email":"demo@example.com","token":"123456"}'

# signup resend
curl -sS -X POST "${WEB_BASE_URL}/api/v1/auth/verifications/resend" \
  -H 'Content-Type: application/json' \
  -d '{"email":"demo@example.com"}'

# profile patch
curl -sS -X PATCH "${WEB_BASE_URL}/api/v1/profile/me" \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer <access_token>" \
  -d '{"username":"demo2","bio":"hello"}'

# profile get
curl -sS "${WEB_BASE_URL}/api/v1/profile/me" \
  -H "Authorization: Bearer <access_token>"
```

通过标准：接口返回符合预期的 2xx 或受控业务错误，无 5xx。

### L3 可选（Agent Chat 回归）

```bash
PYTHONPATH=backend/src uv run pytest backend/tests/unit -k agent_chat -q
PYTHONPATH=backend/src uv run pytest backend/tests/integration -k agent_chat -q
PYTHONPATH=backend/src uv run pytest backend/tests/e2e/test_agent_chat_flow.py backend/tests/e2e/test_agent_chat_recent_session_home.py -q

curl -sS -X POST "${WEB_BASE_URL}/api/v1/agent" \
  -H 'Content-Type: application/json' \
  -d '{"message":"hello"}'
```

通过标准：测试通过，`/api/v1/agent` 返回有效 `session_id` 与事件序列。

---

## Incident Playbook

### 1) 迁移未生效（常见于旧镜像）

- 症状：字段/表结构与代码不一致，接口报 schema 错误。
- 定位：检查 `alembic_version` 与容器镜像构建时间。
- 修复：重新执行 `init-job --build`，并复核版本号。

### 2) Worker 不消费任务

- 症状：队列堆积，任务长时间 pending。
- 定位：检查 `worker-*` tmux 窗口和对应日志文件。
- 修复：重启 tmux 会话，确认并发配置与队列名（critical/default/bulk）。

### 3) JWT 或认证异常

- 症状：接口持续 401/403。
- 定位：核对 `.env` 中 Supabase JWT 配置与签发方设置。
- 修复：修正配置后重启 web 进程并执行 L1/L2 验证。

### 4) Agent Chat 启动后异常

- 症状：`/api/v1/agent` 返回 5xx 或事件不完整。
- 定位：先跑 L3 测试，再看 `logs/errors/web.error.log`。
- 修复：先恢复到可用版本，再排查迁移、配置与依赖差异。

### 5) Auth 邮件模板未生效 / 注册返回超时但邮件已发送

- 症状：
  - 收到默认英文模板（非 `infra/mail-templates`）。
  - `signup/start` 偶发 500 或超时，但邮箱仍收到验证码邮件。
- 根因：容器配置漂移（旧容器未按最新 compose/.env 重建），导致：
  - `supabase-auth` 缺少 `GOTRUE_MAILER_TEMPLATES_*` 环境变量。
  - `supabase-mail-templates` 仍挂载旧路径。
- 定位：

```bash
docker inspect supabase-auth --format '{{ range .Config.Env }}{{ println . }}{{ end }}' | grep GOTRUE_MAILER_TEMPLATES
docker inspect supabase-mail-templates --format '{{ range .Mounts }}{{ .Source }} -> {{ .Destination }}{{ println }}{{ end }}'
```

- 修复：强制重建 auth 和 mail-templates（不改其他服务）：

```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d --force-recreate --no-deps mail-templates auth
```

- 复核标准：
  - `docker inspect supabase-auth` 能看到 `GOTRUE_MAILER_TEMPLATES_CONFIRMATION/RECOVERY`。
  - `supabase-mail-templates` 挂载源为 `infra/mail-templates`。
   - `POST /api/v1/auth/verifications` 返回 `202` 且耗时恢复正常。

---

## Rollback Procedure

### 回滚前检查

- 确认目标回滚提交或版本号。
- 确认是否涉及不可逆数据变更。

### 回滚执行

1. 停止应用进程：`tmux kill-session -t social-dev`
2. 切换代码到目标版本。
3. 按目标版本要求执行迁移回滚（如有）。
4. 重新执行 bootstrap gate 与 service 启动。

### 回滚后复核

- 执行 L1 必跑检查。
- 记录回滚原因、时间、影响范围和后续修复计划。

---

## Change Log

| 日期 | 变更 |
|------|------|
| 2026-02-24 | 创建运行时手册，删除 legacy 脚本，统一使用 gunicorn |
| 2026-02-24 | 清理配置：合并 AppSettings 到 WebSettings，删除 Worker 旧配置 (enabled_queues/queues)，统一使用 SOCIAL_WEB__GUNICORN__* 命名 |
| 2026-02-24 | 开发阶段 compose 暂不编排 web/worker，仅保留 redis/supabase 与 init-job |
| 2026-02-24 | 新增 dev-app-up 脚本：手动基础设施后，一键 bootstrap + tmux 拉起 web/worker |
| 2026-02-25 | 补充迁移防遗漏规则：容器迁移命令统一追加 --build；开发调试优先使用本地 CLI 一次性迁移脚本 |
| 2026-02-25 | Auth 注册切换为 OTP 三段式：signup/start、signup/verify、signup/resend；邮件模板改为纯验证码展示 |
| 2026-02-25 | 清理未使用配置类：删除 WebSettings/GunicornSettings/WorkerSettings/WorkerGroupSettings（脚本仍使用环境变量启动服务） |
| 2026-02-25 | 新增 Agent Chat 验证章节：bootstrap gate、分层测试命令与 run 接口 smoke 示例 |
| 2026-02-25 | 简化启动方式：dev-app-up -> app-up，分离 bootstrap 与服务启动 |
| 2026-02-25 | 重构为运维分层手册：Bootstrap Gate、分层验证、故障与回滚流程 |
| 2026-02-25 | 新增配置漂移故障条目：修复 Auth 邮件模板失效与 signup 超时场景 |
| 2026-02-27 | 用户搜索支持邮箱精确匹配：query 含 @ 符号时走 auth.users → profiles 两步查询 |
| 2026-02-28 | 邀请码功能：新增 invite_codes 表、profiles.referred_by，注册时可选填邀请码并记录邀请关系 |
| 2026-03-02 | 文档整理：修正 auth 端点名称（/verifications）、补充 profile 路由文档、修复 L2/L3 验证命令 |
| 2026-03-02 | 修正 bootstrap 命令：init-job 需要使用 `uv run python -m core.runtime.cli bootstrap` |
