# Runtime Runbook

**Date:** 2026-02-24  
**Status:** Active

## 启动方式

### 一键启动 (推荐)

```bash
# 前提：基础设施已手动启动（redis + supabase）
# docker compose --env-file .env -f infra/docker/docker-compose.yml up -d

# 一键执行 bootstrap + 拉起 web/worker（tmux）
bash infra/scripts/dev-app-up.sh

# 查看窗口
tmux list-windows -t social-dev

# 进入会话观察日志
tmux attach -t social-dev
```

或者手动执行:

```bash
# 1. 启动基础设施（当前编排不包含 web/worker）
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d

# 2. 运行迁移和初始化
docker compose --env-file .env -f infra/docker/docker-compose.yml --profile job run --rm --build init-job

# 3. 一键执行应用层启动（bootstrap + web + workers）
bash infra/scripts/dev-app-up.sh
```

### 生产环境迁移防遗漏（必读）

- 生产发布前必须先通过 bootstrap gate，再启动业务进程；禁止绕过 gate 直接起服务。
- 使用容器执行迁移时必须带 `--build`，确保最新 Alembic 迁移已进入镜像。
- 建议在迁移后做一次版本核对，确认已到预期 head。

```bash
# 1) 先执行 bootstrap gate
make runtime-bootstrap-gate

# 2) 如采用 init-job 单跑，必须带 --build
docker compose --env-file .env -f infra/docker/docker-compose.yml --profile job run --rm --build init-job

# 3) 核对 Alembic 版本
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;"
```

### 本地 CLI (开发调试)

> 适用于本地开发调试，不依赖 Docker。
> 开发调试阶段推荐直接使用本地一次性迁移脚本，不通过 Docker 触发数据库迁移，避免反复重建镜像。

```bash
# 推荐：一次性迁移（开发调试）
PYTHONPATH=backend/src uv run python -m core.runtime.cli migrate

# 需要初始化数据时再执行
PYTHONPATH=backend/src uv run python -m core.runtime.cli init-data

# 或一键执行（migrate + init-data）
PYTHONPATH=backend/src uv run python -m core.runtime.cli bootstrap

# 启动 Web (gunicorn)
PYTHONPATH=backend/src uv run gunicorn app:app --bind 0.0.0.0:8000 --workers 2 --worker-class uvicorn.workers.UvicornWorker

# 启动 Worker (按队列分组)
PYTHONPATH=backend/src uv run celery -A core.celery.app worker --loglevel=info --queues=critical --concurrency=2
PYTHONPATH=backend/src uv run celery -A core.celery.app worker --loglevel=info --queues=default --concurrency=2
PYTHONPATH=backend/src uv run celery -A core.celery.app worker --loglevel=info --queues=bulk --concurrency=1
```

### tmux 会话管理

```bash
# 进入会话
tmux attach -t social-dev

# 杀掉会话（停止 web/workers）
tmux kill-session -t social-dev
```

## 服务说明

| 服务 | 说明 | 备注 |
|------|------|------|
| redis | 缓存与 Celery broker | docker-compose 编排 |
| supabase-* | 认证与数据库相关服务 | docker-compose 编排 |
| init-job | 数据库迁移和初始化 | docker-compose 按需 run |
| web | Web 服务 (gunicorn) | 本地 CLI 启动 |
| worker-* | Celery worker | 本地 CLI 启动 |

## 配置说明

### Web 服务器配置

| 环境变量 | 说明 | 默认值 | 有效范围 |
|----------|------|--------|----------|
| `SOCIAL_WEB__HOST` | 监听地址 | 0.0.0.0 | - |
| `SOCIAL_WEB__PORT` | 监听端口 | 8000 | 1-65535 |
| `SOCIAL_WEB__RELOAD` | 开发模式热重载 | false | true/false |
| `SOCIAL_WEB__GUNICORN__WORKERS` | Gunicorn 工作进程数 | 2 | 1-64 |
| `SOCIAL_WEB__GUNICORN__WORKER_CLASS` | Gunicorn worker 类 | uvicorn.workers.UvicornWorker | Python import path |
| `SOCIAL_WEB__GUNICORN__TIMEOUT` | 请求超时秒数 | 60 | 1-600 |
| `SOCIAL_WEB__GUNICORN__KEEPALIVE` | Keep-alive 秒数 | 5 | 1-120 |
| `SOCIAL_WEB__LOG_LEVEL` | 日志级别 | info | debug/info/warning/error/critical |

### Celery 队列路由

| 任务前缀 | 队列 |
|----------|------|
| tasks.critical.* | critical |
| tasks.bulk.* | bulk |
| 其他 | default |

## 健康检查

```bash
# Supabase 网关
curl -fsS http://127.0.0.1:${SOCIAL_SUPABASE__KONG_HTTP_PORT:-8000}/health

# 数据库迁移与初始化
docker compose --env-file .env -f infra/docker/docker-compose.yml --profile job run --rm --build init-job
```

## 查看服务状态

```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml ps
docker compose --env-file .env -f infra/docker/docker-compose.yml logs -f db

# init-job 为一次性任务（run --rm），如需查看日志请重跑：
docker compose --env-file .env -f infra/docker/docker-compose.yml --profile job run --rm --build init-job
```

## Auth/Profile 验证

```bash
# 注意：默认模板地址 http://mail-templates/* 仅在 Docker Compose 内网可用。
# 生产环境请替换为 gotrue 可访问的模板 URL。

# signup start: username + email + password（发送验证码）
curl -sS -X POST http://127.0.0.1:8000/api/v1/auth/signup/start \
  -H 'Content-Type: application/json' \
  -d '{"username":"demo","email":"demo@example.com","password":"secret123"}'

# signup verify: email + token（6位验证码）
curl -sS -X POST http://127.0.0.1:8000/api/v1/auth/signup/verify \
  -H 'Content-Type: application/json' \
  -d '{"email":"demo@example.com","token":"123456"}'

# signup resend: email（重发验证码）
curl -sS -X POST http://127.0.0.1:8000/api/v1/auth/signup/resend \
  -H 'Content-Type: application/json' \
  -d '{"email":"demo@example.com"}'

# login: email + password
curl -sS -X POST http://127.0.0.1:8000/api/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"demo@example.com","password":"secret123"}'

# by-email lookup
curl -sS "http://127.0.0.1:8000/api/v1/auth/users/by-email?email=demo@example.com"

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

---

## 变更日志

| 日期 | 变更 |
|------|------|
| 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（脚本仍使用环境变量启动服务） |
