# IT 运营 / AI Coding 用量 - 测试场景文档

> **版本**: v0.1
> **最后更新**: 2026-05-15
> **维护者**: 后端/前端 + QA

---

## ✅ 机器读取区（必填）

### 测试层级覆盖

| 层 | 工具 | 范围 | 必跑场景数 |
|----|------|------|-----------|
| L0a/L0b | `testing/scripts/contract-check.ts` | 前端 interface ↔ 后端 DTO | 自动全覆盖 |
| L0c | 实发请求快照 | 真实响应 vs 前端 interface | 7 端点 |
| L1 | Jest + 真 DB（Docker） | 后端业务规则 + 状态机 + 权限 | 31 |
| L1c | 数据质量 | seed/snapshot 校验 | 3 |
| L2 | （跳过）| - | 0 |
| L3 | Playwright MCP + 人工 | 端到端流程 + 双语 | 12 |

---

## L1 集成测试场景（31 个，按文件组织）

### `ai-usage.token.spec.ts`（7 个）

1. ✅ 员工生成 token：响应 `token` 字段长度 = 40，prefix = 前 12 位，DB 落 bcrypt hash
2. ✅ 第二次 GET token 列表：响应不含 token 明文，只有 prefix
3. ✅ 员工撤销自己的 token：DB `revokedAt` 写入，audit log 写入
4. ✅ 员工撤销别人的 token：返回 404（DataScope 过滤）
5. ✅ Admin 代撤员工 token：成功 + audit log `by-admin`
6. ✅ 撤销后立即用该 token 上报：401 `INVALID_TOKEN`
7. ✅ 同员工生成 5 个 token：全部 ACTIVE，互不影响

### `ai-usage.ingestion.spec.ts`（12 个）

1. ✅ Bearer token 校验通过 → device 自动注册 ACTIVE + event 入库
2. ✅ Bearer token 无效 → 401，无 device 注册
3. ✅ Bearer token 撤销 → 401
4. ✅ Device 被拉黑 → 403 + DLQ 记录 `BLOCKED_DEVICE`
5. ✅ 单批 500 event → 全部入库（`createMany skipDuplicates: true`）
6. ✅ 单批 501 event → 413
7. ✅ 重复 `rawMessageId` → deduped 计数 +1，DB 不重复（同批 + 跨批两种 case）
8. ✅ ts > now+5min → DLQ `TS_OUT_OF_WINDOW`
9. ✅ ts < now-30d → DLQ `TS_OUT_OF_WINDOW`
10. ✅ Rate limit：61 req/min 同 token → 第 61 个 429
11. ✅ **离线 7 天后批量上报**：构造 ts 在 now-7d 范围的 500 event 批量上报 → 全部 accepted（验证 30d 窗口足够覆盖常见离线场景）
12. ✅ **响应 header `X-Pricing-Version`** 与最新版本一致；客户端 mock 旧版本时触发 `/api/v1/ai-usage/pricing` 重拉

### `ai-usage.dashboard.spec.ts`（9 个）

1. ✅ `/me/summary` 仅返回当前 user 数据（service 手工 `where.userId`）
2. ✅ `/me/breakdown?by=project` 按 project 正确聚合
3. ✅ Admin `/summary` 跨 user 聚合
4. ✅ Admin `/breakdown?by=user` 分页正确
5. ✅ Admin 无 `view-all` 权限调 `/summary` → 403
6. ✅ Trend 按日 / 周 / 月 粒度聚合数学正确
7. ✅ CSV 导出 UTF-8 BOM + 正确列顺序
8. ✅ 跨年查询 → fallback 到 daily_rollups 表
9. ✅ **跨 org 隔离**：创建 org-A 的 admin user + org-B 的 event 数据 → org-A admin 调 `/summary` 不应看到 org-B 数据（验证 service 层 `where.organizationId` 手工注入正确，DataScope 拦截器对 groupBy 不生效的兜底）

### `ai-usage.device.spec.ts`（3 个）

1. ✅ Admin 拉黑 device → audit log + 后续 ingestion 403
2. ✅ Admin 解黑 device → 后续 ingestion 恢复 ACTIVE
3. ✅ 同 hostname+osUser 但新 device_id → 创建新行 + 软指纹查询返回相关 device 列表

---

## L1c 数据质量（3 个）

1. seed 数据：测试 organization 至少 1 个，user 至少 2（admin + 普通员工），权限点齐全
2. seed 不应包含任何 `ai_usage_*` 业务数据（业务表 cleanup 后空）
3. 测试数据 cleanup 用前缀过滤 `WHERE name LIKE 't_%'`，cleanup 后种子不丢

---

## L3 人工验收（12 个）

### 接入流程

1. 在新机器（Linux/Mac/Windows）跑 `curl install.sh | bash` 全程顺利
2. `ffctk login <token>` 写文件权限 0600，错误 token 报错明确
3. `ffctk start` 后 1 分钟内 admin dashboard 出现新 device
4. 关机 → 开机 → 自启 → 上报恢复
5. 断网 1 小时 → 联网后离线数据自动续传

### Dashboard

6. Admin 在 30 秒内说出上月 Top 3 员工 / 项目 / 模型
7. 员工在 `/me/ai-usage` 看到跨 2+ device 累计
8. 切换 zh-CN ↔ en-US，所有页面文案完整，浏览器控制台无 `missing key` warning
9. 数字 / 日期按 locale 格式化（千分位、月日顺序）

### 安全

10. 撤销 token → 客户端下次上报 401 → 提示员工重新登录
11. Admin 拉黑陌生 device → 该 device 上报全 403
12. 隐私 FAQ 文案、生成 token 时的"仅一次可见"警示足够显著

---

## 边界场景手测清单（L3 配套）

- [ ] 0 数据时 admin dashboard 显示引导卡
- [ ] 0 token 时 `/me/ai-usage` 显示引导卡
- [ ] Token 复制按钮 + 全命令复制按钮工作正常
- [ ] 关闭生成 modal 前必须复制（30s 后强制启用兜底）
- [ ] DLQ 页面可查最近 DLQ 行
- [ ] CSV 在 Excel 中无乱码

---

## 数据准备

### Seed 不引入业务数据

业务数据全部由测试 setup 创建（前缀 `t_`），cleanup 时按前缀清。

### Mock 价目表

测试用固定价目表 fixture（`testing/fixtures/ai-usage-pricing.json`），不依赖 `/api/v1/ai-usage/pricing` 实际数据。

### 客户端 agent 测试

- 单元层：parser fixture（采几条真实 JSONL 脱敏后入 repo `testing/fixtures/jsonl/`）→ 期望输出 event
- 集成层：起本地 mock server 接 batch → 验证 retry / dedup / offset 持久化
- E2E：装 binary 到 Docker 容器跑一次完整流程

---

## 测试数据隔离铁律（CLAUDE.md）

- 测试创建的资源用 `t_<timestamp>_<random>` 前缀
- `beforeEach` 创建，cleanup 用前缀 DELETE（不 TRUNCATE）
- raw SQL `.catch()` 必输出 console.warn
- 写 raw SQL 查实际表名（`@@map`）
