- 02-02-SUMMARY.md:8 条 success criteria 全 PASS(28 项独立断言 + Swagger schema + 两端互引)+ 验收方法论 + 偏差记录 + Phase 3 起点准备 - STATE.md:进度 75% → 100%(4/4 plan 完成);Phase 2 整体 Complete;下一步 /gsd-plan-phase 3 - ROADMAP.md:Phase 2 标记 ✓ Complete(2/2 plan 完成;commits 6820fe7..46d72b8) - REQUIREMENTS.md:CRED-03 / CRED-04 traceability 表 Pending → Done
234 lines
15 KiB
Markdown
234 lines
15 KiB
Markdown
---
|
||
phase: 02-admin-rest
|
||
plan: 02
|
||
subsystem: verification + cross-project docs
|
||
tags: [verification, e2e-test, django-test-client, drf-yasg, swagger, cross-project-link, modification-log]
|
||
requirements_completed:
|
||
- CRED-03
|
||
- CRED-04
|
||
dependency_graph:
|
||
requires:
|
||
- phase: 02-admin-rest / Plan 01(serializer + view + URL + Swagger 全部就位)
|
||
provides: CredentialSlotSerializer / CredentialSlotAdminView / 路由 admin_credential_slot
|
||
provides:
|
||
- 02-VERIFICATION.md:8 条 success criteria 验收证据归档
|
||
- qy_lty/docs/修改记录.md Phase 2 条目(含跨项目联动 → qy-lty-admin)
|
||
- qy-lty-admin/docs/修改记录.md Phase 2 互引条目(含服务端联动 → qy_lty)
|
||
affects:
|
||
- Phase 3(CRED-05 客户端 GET 明文 / CRED-06 阿里云日志脱敏):以 Phase 2 收尾后的 DB 探针态 + 已上线接口为起点
|
||
- 后续 qy-lty-admin CRED-FE-01 phase:以本互引条目锁定的接口契约为消费方依据
|
||
tech_stack:
|
||
added: []
|
||
patterns:
|
||
- "端到端验收走 Django test client(in-process),不启 daphne,避免端口占用 / 脏环境"
|
||
- "drf-yasg schema 验收:通过 /swagger.json/ 拿 OpenAPI;本仓库 StandardResponseMiddleware 会把 schema 包进 data 字段,验证脚本需 unwrap"
|
||
- "跨项目修改记录互引:两端各写一条,跨项目联动 / 服务端联动字段相互引用对方文件路径(CLAUDE.md 强制规则首次落地)"
|
||
- "验收用临时 token 不入仓库(仅记长度 + PASS 判定,Redis 30 天 TTL 攻击面控制)"
|
||
key_files:
|
||
created:
|
||
- qy_lty/.planning/phases/02-admin-rest/02-VERIFICATION.md
|
||
modified:
|
||
- qy_lty/docs/修改记录.md
|
||
- qy-lty-admin/docs/修改记录.md
|
||
decisions:
|
||
- "[Plan 02-02] 端到端验收走 Django test client(in-process),不启 daphne:内存调用更快、可重复、零端口占用;本仓库鉴权 / 标准壳层 middleware 都是 Django MIDDLEWARE 而非 ASGI 层,test client 路径与生产路径功能等价"
|
||
- "[Plan 02-02] Swagger 验收走 /swagger.json/(带 trailing slash,url 模式 swagger<format>/):本仓库 StandardResponseMiddleware 也会包 OpenAPI schema 进 {success, code, message, data},验证脚本需 unwrap data;basePath=/api 所以 paths key 是 /v1/admin/credential-slot/(去掉 /api 前缀)"
|
||
- "[Plan 02-02] 测试 token 明文不入仓库:02-VERIFICATION.md 仅记录 token 长度(length=36)+ PASS 判定,不黏贴 UUID 字串;脚本结束自动 cache.delete 释放 Redis admin_token / token key"
|
||
- "[Plan 02-02] 验收脚本 _phase2_verify.py / _phase2_swagger_verify.py 验完即删:是一次性证据生成器,证据落地 02-VERIFICATION.md 后无需保留;如需复跑参考 SUMMARY 中的脚本片段"
|
||
- "[Plan 02-02] DB 探针态主动还原:app_id='probe_app' / access_token='probe_secret_xxxx' 是 Phase 1 留下的契约值;Phase 2 验收过程中临时写入 phase2_app / sk-phase2_verify_secret_ABCD1234 / after_delete 等值,验完必须还原以免污染 Phase 3 起点"
|
||
- "[Plan 02-02] qy-lty-admin 改动通过父级 Lila-Server/.git 仓库提交:qy-lty-admin/ 没有自己的 .git;条目相对路径 ../../qy_lty/docs/修改记录.md(位于 qy-lty-admin/docs/,跳上级 qy-lty-admin/ 再跳上级 Lila-Server/,然后进 qy_lty/docs/)"
|
||
metrics:
|
||
duration_seconds: 720
|
||
tasks_completed: 2
|
||
files_modified: 3
|
||
files_created: 1
|
||
commits:
|
||
- 3cfd481 test(02-02): 端到端验收 8 条 success criteria 全 PASS(qy_lty 仓库)
|
||
- 46d72b8 docs(02-02): 两端修改记录互引 Phase 2 接口契约(父 Lila-Server 仓库;qy_lty + qy-lty-admin 同时入库)
|
||
completed_date: 2026-05-07
|
||
---
|
||
|
||
# Phase 2 Plan 02-02:端到端验收 + 两端修改记录互引 Summary
|
||
|
||
Phase 2 收尾:把 Plan 02-01 落地的 GET/PUT 接口端到端验完(8 条 success criteria 全 PASS),并在 qy_lty + qy-lty-admin 两端 docs/修改记录.md 各写一条 Phase 2 互引条目,闭合 Milestone v1.0 首次跨项目接口契约的双向锚点。
|
||
|
||
## 一句话概述
|
||
|
||
Django test client 程序化跑 6 大验收点(28 项独立断言全 PASS)+ /swagger.json/ schema 验证暴露完整 + 两端修改记录互引闭环,Phase 2 整体 Complete,可进 Phase 3。
|
||
|
||
## Performance
|
||
|
||
- **Duration:** ~12 min
|
||
- **Started:** 2026-05-07T14:55:54Z(接到 02-02 prompt 时)
|
||
- **Completed:** 2026-05-07T15:07:54Z(SUMMARY 落地时)
|
||
- **Tasks:** 2
|
||
- **Files Created:** 1(02-VERIFICATION.md)
|
||
- **Files Modified:** 2(qy_lty + qy-lty-admin 各一份 docs/修改记录.md)
|
||
- **Commits:** 2 个 task 原子 commit(不计本 SUMMARY 落地的 metadata commit)
|
||
|
||
## Accomplishments
|
||
|
||
- **8/8 success criteria 全 PASS**:6 条 Django test client 验收(GET 脱敏 / PUT 全字段覆写 + 响应脱敏 / PUT 空记录 get_or_create / 401 无 token / 403 user token GET / 403 user token PUT)+ 1 条 Swagger schema 验收 + 1 条修改记录互引验收
|
||
- **DB 探针态主动还原**:Phase 1 留下的 probe_app / probe_secret_xxxx 在验收过程中被写穿(phase2_app / sk-phase2_verify_secret_ABCD1234 / after_delete 等),脚本结束主动 `slot.save()` 还原,给 Phase 3 留下稳定起点
|
||
- **跨项目互引闭环**:CLAUDE.md「跨项目联动两端各写一条互相引用」规则首次落地(Phase 2 是 Milestone v1.0 首次跨项目接口契约暴露);两端 grep 双向命中
|
||
- **临时验收脚本不入仓库**:`_phase2_verify.py` / `_phase2_swagger_verify.py` 验完即删;token 明文不入 02-VERIFICATION.md(Redis 30 天 TTL 攻击面控制)
|
||
|
||
## Task Commits
|
||
|
||
每个 task 原子提交:
|
||
|
||
1. **Task 1:端到端 8 条 success criteria 验收** — `3cfd481` (test) — qy_lty 仓库 dev 分支
|
||
2. **Task 2:两端修改记录互引 Phase 2 条目** — `46d72b8` (docs) — 父 Lila-Server 仓库 dev 分支(qy_lty + qy-lty-admin 同时入库)
|
||
|
||
## Files Created / Modified
|
||
|
||
| 文件 | 类型 | 描述 | 所属仓库 |
|
||
|------|------|------|---------|
|
||
| `qy_lty/.planning/phases/02-admin-rest/02-VERIFICATION.md` | 新增 | 8 条 success criteria 验收摘要 + ROADMAP SC 映射 + 28 项独立断言 PASS 日志 + Swagger schema 验收输出 + DB 终态记录 | qy_lty |
|
||
| `qy_lty/docs/修改记录.md` | 修改(顶部新增条目) | Phase 2 服务端条目(5 字段 + 跨项目联动字段引用 qy-lty-admin) | qy_lty(父 Lila-Server 提交) |
|
||
| `qy-lty-admin/docs/修改记录.md` | 修改(顶部新增条目) | Phase 2 前端互引条目(5 字段 + 服务端联动字段引用 qy_lty) | qy-lty-admin(父 Lila-Server 提交) |
|
||
|
||
## DB 终态
|
||
|
||
Phase 2 收尾后 `aiapp_credentialslot` 表唯一一条记录(pk=1)的字段值:
|
||
|
||
| 字段 | 值 |
|
||
| -------------- | --------------------------------------------------- |
|
||
| pk | 1(单例) |
|
||
| app_id | `probe_app` |
|
||
| access_token | `probe_secret_xxxx`(明文)/ `*************xxxx`(脱敏返回) |
|
||
| updated_at | 2026-05-07(验收脚本最后一次 `slot.save()` 触发) |
|
||
|
||
**Phase 1 探针契约保持有效**,Phase 3 / 后续测试脚本可直接基于此继续。
|
||
|
||
## 8 条 Success Criteria 验收结果
|
||
|
||
| # | 验收点 | 方法 | 结果 |
|
||
| --- | ------------------------------------------------------- | --------------------------------------------- | --------- |
|
||
| 1 | GET 携 admin token 返回脱敏壳层 | Django test client | ✓ PASS |
|
||
| 2 | PUT 携 admin token 全字段覆写 + 响应脱敏 | Django test client | ✓ PASS |
|
||
| 3 | PUT 在空记录场景自动 `get_or_create` | Django test client(手动 delete + PUT) | ✓ PASS |
|
||
| 4 | 无 `Authorization` 头 → 401 + 标准壳层 | Django test client | ✓ PASS |
|
||
| 5 | 携普通 user token GET → 403 + `message` 含 "管理员" | Django test client | ✓ PASS |
|
||
| 6 | PUT 携 user token → 403(PUT 也走 `_ensure_admin`) | Django test client | ✓ PASS |
|
||
| 7 | `/swagger.json/` 含路径 + GET/PUT + 脱敏 description | Django test client(命中 drf-yasg schema) | ✓ PASS |
|
||
| 8 | 修改记录两端互引(qy_lty + qy-lty-admin 各一条) | grep 双向命中 | ✓ PASS |
|
||
|
||
完整 28 项独立断言日志见 [02-VERIFICATION.md](./02-VERIFICATION.md)。
|
||
|
||
## ROADMAP Phase 2 Success Criteria 映射
|
||
|
||
| ROADMAP SC | 内容 | 对应验收点 |
|
||
| ---------- | ------------------------------- | ------------------- |
|
||
| SC#1 | GET 脱敏(admin token) | #1 |
|
||
| SC#2 | PUT 全字段覆写 + `get_or_create`| #2 + #3 |
|
||
| SC#3 | 鉴权拒绝矩阵(无 token / user token) | #4 + #5 + #6 |
|
||
| SC#4 | Swagger / ReDoc schema 一致 | #7 |
|
||
|
||
ROADMAP Phase 2 4 条 SC 全部覆盖。
|
||
|
||
## Decisions Made
|
||
|
||
见 frontmatter `decisions:` 段;关键决策汇总:
|
||
|
||
1. 走 Django test client 而非 daphne / runserver — in-process 调用、零端口占用、可重复
|
||
2. /swagger.json/ schema 在 StandardResponseMiddleware 的 `data` 字段内 — basePath=/api,paths key 去掉 /api 前缀
|
||
3. 测试 token 不入仓库 — 仅记长度 + PASS 判定
|
||
4. 临时验收脚本验完即删 — 一次性证据生成器
|
||
5. DB 探针态主动还原 — Phase 1 留下的契约不能被破坏
|
||
6. qy-lty-admin 改动走父级 Lila-Server/.git — 子目录无独立 .git
|
||
|
||
## Deviations from Plan
|
||
|
||
### 偏差 1:/swagger.json URL 形态调整(Rule 1 等价 — 现实修正)
|
||
|
||
- **Found during:** Task 1 Step 3
|
||
- **Plan 假设:** `curl http://localhost:8000/swagger.json` 直返 OpenAPI JSON
|
||
- **实际仓库状态:** 两点偏差:
|
||
1. urls.py 中 schema-json 路径模式是 `swagger<format>/`(trailing slash),所以正确路径是 `/swagger.json/`(带尾斜线);不带尾斜线 → 301 redirect → follow 后变成 swagger UI 页面(HTML)
|
||
2. 本仓库 `StandardResponseMiddleware` 也会把 drf-yasg 返回的 OpenAPI JSON 包进 `{success, code, message, data}` 壳层,真正的 OpenAPI schema 在 `data` 字段内(basePath=/api,所以 paths key 是去掉 /api 前缀的 `/v1/admin/credential-slot/`)
|
||
- **Adjustment:** 验证脚本(1)改用 `/swagger.json/` 带尾斜线(2)unwrap `body['data']` 取真正 schema(3)匹配 `/v1/admin/credential-slot/` 而非 `/api/v1/admin/credential-slot/`
|
||
- **Reason:** Plan 假设的 URL 形态没考虑本仓库 StandardResponseMiddleware 对 drf-yasg JSON 也会包壳;这是仓库自有的 middleware 行为,不是 plan 错;验证脚本即时调整即可
|
||
- **Files modified:** 无(仅一次性验收脚本,已删)
|
||
- **Commit:** 包含在 `3cfd481` 的 02-VERIFICATION.md "Step 4 关键发现" 段中说明
|
||
|
||
### 偏差 2:Plan 的 verify auto 命令在裸 python 下需要手动 setup(Rule 3 等价)
|
||
|
||
- **Found during:** Task 1 Step 2 / Step 3
|
||
- **Issue:** Plan 写的验收脚本片段(直接 `from django.test import Client` 这种 top-level import)在裸 `python -c` 中会触发 `ImproperlyConfigured`;需要 `os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'qy_lty.settings'); django.setup()`
|
||
- **Adjustment:** 临时验收脚本顶部加 `os.environ.setdefault + django.setup()` 头部 boilerplate;功能等价
|
||
- **Reason:** Plan 假设了 `python manage.py shell <<'EOF'` 这种隐式 setup 环境;裸 python 调用需显式 setup(Plan 02-01 偏差 2 同款问题,已知)
|
||
- **Files modified:** 无(仅一次性脚本,已删)
|
||
|
||
### 其余偏差
|
||
|
||
无。Plan 两个 task 的核心目标、acceptance criteria、修改记录条目模板(含跨项目联动字段)全部按 Plan 1:1 落地。
|
||
|
||
**Total deviations:** 2 处现实修正(均不涉及代码改动,仅一次性验收脚本调整)
|
||
**Impact on plan:** 零功能影响 — 验收点 #7 + 全部断言 PASS;无 Plan 漂移、无 scope creep
|
||
|
||
## Issues Encountered
|
||
|
||
无。
|
||
|
||
## Next Phase Readiness
|
||
|
||
**Phase 2 整体 Complete**:
|
||
|
||
- ROADMAP Phase 2 4 条 SC 全部 ✓
|
||
- CRED-03 + CRED-04 已 done(REQUIREMENTS.md 待 STATE 更新阶段标记)
|
||
- 02-VERIFICATION.md 是 Phase 2 收尾时的证据来源
|
||
- DB 探针态稳定(probe_app / probe_secret_xxxx)
|
||
|
||
**进 Phase 3 的准备**:
|
||
|
||
- Phase 3 目标:CRED-05(客户端 GET `/api/credential-slot/`,user token 鉴权,**明文**返回)+ CRED-06(阿里云日志 formatter 用 `mask_token` 过滤 access_token)
|
||
- 依赖:本 phase 已落地的 `CredentialSlot.get_solo()` / `mask_token` 工具 / `RedisTokenAuthentication` 鉴权
|
||
- 区别:客户端 GET 必须返回**明文**(手机端/设备端实际调用第三方需要),与 Phase 2 管理端 GET 脱敏正交;service 层数据流不同(直接走 `instance.access_token`,不走 `mask_token`)
|
||
|
||
## 与 02-01-SUMMARY 的关系
|
||
|
||
| Plan | 交付物 | 验收方式 |
|
||
|------|--------|---------|
|
||
| 02-01 | serializer + view + URL + swagger 装饰器 | 落地后单元级 import / reverse / Django check(Plan 内自验证据) |
|
||
| 02-02 | 端到端 8 条 SC + 互引 | E2E 验收(Django test client 跑真实 HTTP 路径)+ 跨项目互引 |
|
||
|
||
两个 plan 联合构成 Phase 2 完整交付证据:02-01 证明"代码就位",02-02 证明"接口跑通 + 跨项目锚点闭环"。
|
||
|
||
## Threat Flags
|
||
|
||
无。本 plan 改动严格落在 02-02-PLAN 的 `<threat_model>` 4 条已声明威胁内(T-02P2-01 ~ T-02P2-04):
|
||
|
||
- T-02P2-01(验收 token 误入 git)→ mitigated:02-VERIFICATION.md 仅记长度,临时脚本验完即删
|
||
- T-02P2-02(验收数据覆盖探针)→ accepted + mitigated:脚本主动还原 probe_app / probe_secret_xxxx
|
||
- T-02P2-03(误改 Phase 1 修改记录条目)→ mitigated:git diff 校验 Phase 1 两条 [2026-05-07] Phase 1 — ... 标题位置不变,仅顶部追加新条目
|
||
- T-02P2-04(互引文档泄露内部路径)→ accepted:与本仓库 README 同等暴露面
|
||
|
||
## Self-Check: PASSED
|
||
|
||
### Files
|
||
|
||
- FOUND: `.planning/phases/02-admin-rest/02-VERIFICATION.md`(本 plan 创建,Task 1 commit 3cfd481)
|
||
- FOUND: `qy_lty/docs/修改记录.md`(顶部 line 26 新增 `### [2026-05-07] Phase 2 — 管理端通用凭据槽位 REST 接口(GET 脱敏 / PUT 覆写)`,Task 2 commit 46d72b8)
|
||
- FOUND: `qy-lty-admin/docs/修改记录.md`(顶部 line 28 新增 `### [2026-05-07] Phase 2 — 锁定后端通用凭据槽位 REST 接口契约(消费方文档化)`,Task 2 commit 46d72b8)
|
||
|
||
### Commits
|
||
|
||
- FOUND: `3cfd481` test(02-02): 端到端验收 8 条 success criteria 全 PASS(qy_lty 仓库)
|
||
- FOUND: `46d72b8` docs(02-02): 两端修改记录互引 Phase 2 接口契约(父 Lila-Server 仓库)
|
||
|
||
### 互引闭环
|
||
|
||
- FOUND: `qy_lty/docs/修改记录.md` line 44 含 `qy-lty-admin/docs/修改记录.md`(指向前端互引)
|
||
- FOUND: `qy-lty-admin/docs/修改记录.md` line 47 含 `qy_lty/docs/修改记录.md`(指向后端互引)
|
||
- 双向 grep 命中 → 闭环
|
||
|
||
### Phase 1 条目位置不变
|
||
|
||
- VERIFIED: `git diff qy_lty/docs/修改记录.md` 仅显示新增条目(顶部追加 20 行),Phase 1 已有的两条 `[2026-05-07] Phase 1 — ...` 标题位置 unchanged
|
||
|
||
---
|
||
|
||
*Phase: 02-admin-rest / Plan: 02*
|
||
*Executed: 2026-05-07 by gsd-executor(顺序执行模式,无 worktree 隔离;qy-lty-admin 改动走父级 Lila-Server/.git 提交)*
|