# API 参考手册

后端 API 基于 FastAPI 构建，所有端点均以 `/api/` 为前缀。  
在线文档：启动后访问 `http://localhost:8000/docs`（Swagger UI）或 `/redoc`（ReDoc）。

## 全局响应格式（RNS1.0）

所有 JSON 成功响应（HTTP 2xx）自动包装为统一格式：

```json
{ "code": 0, "data": { ... } }
```

异常响应格式：

```json
{ "code": 401, "message": "未认证" }
```

规则：
- `code=0` 表示成功，`data` 为业务数据
- `code≠0` 表示错误，`code` 为 HTTP 状态码，`message` 为错误描述
- SSE 流式端点（`text/event-stream`）和非 JSON 响应不包装，直接透传
- 所有小程序 API 响应字段名为 camelCase（如 `userId`、`storeName`）

---

## 1. 管理后台认证 `/api/auth`

### POST `/api/auth/login`
管理后台用户名密码登录。

请求体：
```json
{ "username": "admin", "password": "..." }
```
响应：
```json
{ "access_token": "...", "refresh_token": "...", "token_type": "bearer" }
```

### POST `/api/auth/refresh`
刷新访问令牌。

请求体：
```json
{ "refresh_token": "..." }
```

---

## 2. 小程序认证 `/api/xcx-auth`

小程序用户的完整生命周期：微信登录 → 提交申请 → 管理员审批 → 正式使用。

### POST `/api/xcx-auth/login`
微信登录。用 `wx.login()` 获取的 code 换取 JWT。

请求体：
```json
{ "code": "微信临时登录凭证" }
```
响应：
```json
{
  "access_token": "...",
  "refresh_token": "...",
  "token_type": "bearer",
  "user_status": "pending | approved | rejected | disabled",
  "user_id": 1
}
```
说明：
- 首次登录自动创建 `auth.users` 记录（status=new），前端引导至申请页
- new/pending/rejected 用户获得受限令牌（`limited=True`），仅可访问申请相关端点
- approved 用户获得完整令牌，包含 `site_id` 和 `roles`

### POST `/api/xcx-auth/apply`
提交入驻申请。需受限令牌或完整令牌。

请求体：
```json
{
  "site_code": "AB123",
  "applied_role_text": "助教",
  "phone": "13800138000",
  "employee_number": "E001",
  "nickname": "张三"
}
```
说明：
- `site_code` 格式：2 字母 + 3 数字（如 `AB123`），映射到 `auth.site_code_mapping`
- 后端自动进行人员匹配（`matching.py`），在 ETL 库中查找助教/员工记录

### GET `/api/xcx-auth/status`
查询当前用户状态和申请记录。需受限令牌或完整令牌。

响应：
```json
{
  "user_id": 1,
  "status": "approved",
  "nickname": "张三",
  "applications": [
    {
      "id": 1,
      "site_code": "AB123",
      "applied_role_text": "助教",
      "status": "approved",
      "review_note": null,
      "created_at": "2026-02-25T10:00:00",
      "reviewed_at": "2026-02-25T11:00:00"
    }
  ]
}
```

### GET `/api/xcx-auth/sites`
获取当前用户关联的门店列表。需完整令牌。

### POST `/api/xcx-auth/switch-site`
切换当前门店，返回新的令牌对。需完整令牌。

请求体：
```json
{ "site_id": 2 }
```

### POST `/api/xcx-auth/refresh`
刷新令牌。

请求体：
```json
{ "refresh_token": "..." }
```

### POST `/api/xcx-auth/dev-login`
开发模式 mock 登录（仅 `WX_DEV_MODE=true` 时注册）。

请求体：
```json
{ "openid": "模拟openid", "status": "approved" }
```
说明：
- `status` 可选，为空时保留已有用户当前状态，新用户默认 `new`
- 仅开发/测试环境可用

---

## 3. 任务配置 `/api/tasks`

所有端点需 JWT 认证。

### GET `/api/tasks/registry`
按业务域分组的 ETL 任务列表。

响应示例：
```json
{
  "groups": {
    "会员": [
      {
        "code": "DWD_LOAD_FROM_ODS",
        "name": "ODS → DWD 加载",
        "domain": "会员",
        "layer": "DWD",
        "requires_window": true,
        "is_ods": false,
        "is_dimension": false,
        "default_enabled": true,
        "is_common": true
      }
    ]
  }
}
```

### GET `/api/tasks/dwd-tables`
按业务域分组的 DWD 表定义。

### GET `/api/tasks/flows`
返回 7 种 Flow 定义和 4 种处理模式。

Flow 列表：
| ID | 名称 | 层级 |
|----|------|------|
| `api_ods` | API → ODS | ODS |
| `api_ods_dwd` | API → ODS → DWD | ODS, DWD |
| `api_full` | API → ODS → DWD → DWS → INDEX | ODS, DWD, DWS, INDEX |
| `ods_dwd` | ODS → DWD | DWD |
| `dwd_dws` | DWD → DWS汇总 | DWS |
| `dwd_dws_index` | DWD → DWS → INDEX | DWS, INDEX |
| `dwd_index` | DWD → DWS指数 | INDEX |

处理模式：
| ID | 名称 | 说明 |
|----|------|------|
| `increment_only` | 仅增量处理 | 只处理新增和变更的数据 |
| `verify_only` | 仅校验修复 | 校验现有数据并修复不一致 |
| `increment_verify` | 增量 + 校验修复 | 先增量处理，再校验并修复 |
| `full_window` | 全窗口处理 | 用 API 返回数据的实际时间范围处理全部层 |

### POST `/api/tasks/validate`
验证任务配置并返回 CLI 命令预览。`store_id` 从 JWT 自动注入。

### GET `/api/tasks/sync-check`
对比后端硬编码任务列表与 ETL 真实注册表，返回差异。

---

## 4. 任务执行 `/api/execution`

所有端点需 JWT 认证，`site_id` 从 JWT 提取。

### POST `/api/execution/run`
直接执行任务（不经过队列）。异步启动 ETL CLI 子进程。

请求体：`TaskConfigSchema`（flow、tasks、window 等）

响应：
```json
{ "execution_id": "uuid", "message": "任务已提交执行" }
```

### GET `/api/execution/queue`
获取当前门店的待执行队列。

### POST `/api/execution/queue`
将任务配置添加到执行队列。

### PUT `/api/execution/queue/reorder`
调整队列中任务的执行顺序。

### DELETE `/api/execution/queue/{task_id}`
从队列中删除待执行任务（仅 pending 状态）。

### POST `/api/execution/{execution_id}/cancel`
取消正在执行的任务。

### GET `/api/execution/history`
执行历史记录（按 `started_at` 降序，默认 50 条，最多 200 条）。

### GET `/api/execution/{execution_id}/logs`
获取指定执行的完整日志。优先从内存缓冲区读取（执行中），否则从数据库读取（已完成）。

---

## 5. 调度管理 `/api/schedules`

所有端点需 JWT 认证。

### GET `/api/schedules`
列出当前门店的所有调度任务。

### POST `/api/schedules`
创建调度任务，自动计算 `next_run_at`。

### PUT `/api/schedules/{schedule_id}`
更新调度任务（部分更新，仅更新请求中提供的字段）。

### DELETE `/api/schedules/{schedule_id}`
删除调度任务。

### PATCH `/api/schedules/{schedule_id}/toggle`
切换启用/禁用状态。禁用时 `next_run_at` 置 NULL；启用时重新计算。

---

## 6. 数据库查看器 `/api/db`

所有端点需 JWT 认证。使用 ETL 只读连接 + RLS 门店隔离。

### GET `/api/db/schemas`
返回 ETL 数据库中的 Schema 列表。

### GET `/api/db/schemas/{name}/tables`
返回指定 Schema 下所有表的名称和行数统计。

### GET `/api/db/tables/{schema}/{table}/columns`
返回指定表的列定义（列名、数据类型、是否可空、默认值）。

### POST `/api/db/query`
只读 SQL 执行。

安全措施：
- 拦截写操作关键词（INSERT / UPDATE / DELETE / DROP / TRUNCATE）
- 返回行数上限 1000 行
- 查询超时 30 秒
- 连接级 `read_only` 保护

请求体：
```json
{ "sql": "SELECT * FROM dwd.member_info LIMIT 10" }
```

---

## 7. ETL 状态 `/api/etl-status`

### GET `/api/etl-status/cursors`
返回各 ODS 表的最新数据游标（查询 `meta.etl_cursor`）。

### GET `/api/etl-status/recent-runs`
返回最近 50 条任务执行记录。

---

## 8. 环境配置 `/api/env-config`

### GET `/api/env-config`
读取根 `.env` 文件内容（敏感值脱敏显示）。

### PUT `/api/env-config`
更新 `.env` 文件中的配置项。

---

## 9. 运维面板 `/api/ops`

### GET `/api/ops/system`
服务器系统资源概况（CPU、内存、磁盘、启动时间）。

### GET `/api/ops/services`
所有环境（test/prod）的服务运行状态（PID、端口、内存、CPU、运行时长）。

### POST `/api/ops/services/{env}/start`
启动指定环境的后端服务。

### POST `/api/ops/services/{env}/stop`
停止指定环境的后端服务。

### POST `/api/ops/services/{env}/restart`
重启指定环境的后端服务。

### GET `/api/ops/git`
所有环境的 Git 状态（分支、最新提交、是否有本地修改）。

### POST `/api/ops/git/{env}/pull`
对指定环境执行 `git pull --ff-only`。

### POST `/api/ops/git/{env}/sync-deps`
对指定环境执行 `uv sync --all-packages`。

### GET `/api/ops/env-file/{env}`
读取指定环境的 `.env` 文件（敏感值脱敏）。

---

## 10. 其他端点

### GET `/health`
健康检查。返回 `{"status": "ok"}`。

### GET `/api/xcx-test`
MVP 全链路验证端点，从 `test."xcx-test"` 表读取数据。

### GET/POST `/api/wx-callback`
微信消息推送回调。GET 用于签名验证，POST 用于接收消息。

---

## 11. 管理端申请审核 `/api/admin/applications`

### GET `/api/admin/applications`
获取待审核申请列表。需管理后台 JWT。

### POST `/api/admin/applications/{id}/approve`
批准申请。

### POST `/api/admin/applications/{id}/reject`
拒绝申请。

---

## 12. 营业日配置 `/api/business-day`

### GET `/api/business-day/config`
获取营业日分割点配置（`BUSINESS_DAY_START_HOUR`）。

---

## 13. 小程序任务 `/api/xcx/tasks`

所有端点需 JWT（approved 状态）。

### GET `/api/xcx/tasks`
获取当前助教的活跃任务列表。

响应：`TaskListItem[]`

### POST `/api/xcx/tasks/{id}/pin`
置顶任务。

### POST `/api/xcx/tasks/{id}/unpin`
取消置顶。

### POST `/api/xcx/tasks/{id}/abandon`
放弃任务（需填写原因）。

请求体：
```json
{ "reason": "放弃原因" }
```

### POST `/api/xcx/tasks/{id}/restore`
取消放弃，恢复为活跃状态。

### GET `/api/xcx/tasks/{id}`
获取任务详情（TASK-2）。返回单个任务的完整信息，含服务记录、备注、AI 分析、维客线索。

响应包含 `customerId` 字段，供前端跳转客户详情/对话页面使用。

---

## 14. 小程序绩效 `/api/xcx/performance`

所有端点需 JWT（approved 状态）。

### GET `/api/xcx/performance`
绩效概览（PERF-1）。返回指定月份的收入档位、DateGroup 分组记录、新客/常客列表。

查询参数：
- `month`：月份（格式 `YYYY-MM`，默认当月）

响应包含：`currentTier`/`nextTier`/`upgradeHoursNeeded`/`upgradeBonus`（收入档位）、`thisMonthRecords`（DateGroup 分组）、`lastMonthIncome`、`incomeItems`（含 desc）、`newCustomers`/`regularCustomers`。

### GET `/api/xcx/performance/records`
绩效明细（PERF-2）。返回指定月份的服务记录明细，按日期分组，支持分页。

查询参数：
- `month`：月份（格式 `YYYY-MM`，默认当月）
- `page`：页码（默认 1）
- `page_size`：每页条数（默认 20）

---

## 15. 小程序备注 `/api/xcx/notes`

所有端点需 JWT（approved 状态）。

### POST `/api/xcx/notes`
创建备注（含星星评分，可选关联任务）。

请求体：
```json
{
  "target_type": "member",
  "target_id": 1,
  "content": "备注内容",
  "task_id": null,
  "rating_service_willingness": 4,
  "rating_revisit_likelihood": 3
}
```

### GET `/api/xcx/notes`
查询某目标的备注列表（按创建时间倒序）。

查询参数：
- `target_type`：目标类型（默认 `member`）
- `target_id`：目标 ID（必填）

### DELETE `/api/xcx/notes/{id}`
删除备注（验证归属后硬删除）。

---

## 15. 维客线索 `/api/member-retention-clue`

替代原 `member-birthday` 端点，提供维客线索管理能力。

### WebSocket `/ws/logs/{execution_id}`
实时日志推送。连接后自动接收指定执行的日志流。

---

## 错误码约定

| HTTP 状态码 | 含义 |
|-------------|------|
| 200 | 成功 |
| 201 | 创建成功 |
| 400 | 请求参数错误 / SQL 执行错误 |
| 401 | 未认证 / 令牌无效 / 受限令牌 |
| 404 | 资源不存在 |
| 408 | 查询超时 |
| 409 | 状态冲突（如删除非 pending 任务） |
| 422 | 请求体验证失败 |
| 500 | 服务器内部错误 |
