- 新增 SUMMARY.md:3 task / 3 commit / 32+42+26 行代码 / mask_token + CredentialSlot + 0004 迁移 - STATE.md:completed_plans 0→1(50%),下一步切到 Plan 01-02 - ROADMAP.md:Plan 01-01 勾选完成,进度表 1/2 In progress - REQUIREMENTS.md:CRED-01 勾选完成,traceability 状态 Pending→Done - 探针数据契约固化:DB pk=1 / access_token='probe_secret_xxxx' 留给 Plan 01-02 浏览器 checkpoint
9.6 KiB
phase, plan, subsystem, tags, requires, provides, affects, tech_stack, key_files, decisions, metrics, requirements
| phase | plan | subsystem | tags | requires | provides | affects | tech_stack | key_files | decisions | metrics | requirements | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-credential-data-layer | 01 | aiapp / common |
|
|
|
|
|
|
|
|
Phase 1 Plan 01-01:凭据槽位数据层 Summary
一句话:落地 Milestone v1.0「通用凭据槽位」的数据基础——CredentialSlot 单例 Django 模型(pk=1 + save 钩子 + get_solo 三件套,1:1 复刻 AffinitySetting)+ 自动生成的 0004 迁移文件 + 通用 mask_token 工具函数(供 Phase 1 Admin / Phase 3 阿里云日志双方复用)。
完成的 Tasks
| Task | 名称 | Commit | 文件 |
|---|---|---|---|
| 1 | 新建 common/utils.py 落地 mask_token 工具函数 | a9c25eb |
common/utils.py(新建,32 行) |
| 2 | 在 aiapp/models.py 末尾追加 CredentialSlot 单例模型 | 30c7caf |
aiapp/models.py(+42/-1) |
| 3 | 自动生成迁移文件并执行 migrate | a475fe4 |
aiapp/migrations/0004_credentialslot.py(自动生成,26 行) |
实际新增 / 修改的代码行数
common/utils.py:新建 32 行(含 docstring)aiapp/models.py:从 52 行增至 93 行(+42 / -1,末尾追加CredentialSlot类含 4 字段 + Meta +__str__+save钩子 +get_solo类方法)aiapp/migrations/0004_credentialslot.py:自动生成 26 行(依赖0003_create_rtc_bot)
迁移文件实际名称
确认为 aiapp/migrations/0004_credentialslot.py,与 PLAN 期望一致。
依赖:('aiapp', '0003_create_rtc_bot')。
operations:migrations.CreateModel(name='CredentialSlot', fields=[id BigAutoField, app_id CharField(128), access_token CharField(512), updated_at DateTimeField(auto_now=True)])。
自检 Shell 脚本输出
PLAN Task 3 <action> 段规定的探针 + 单例自检:
created= True app_id= '' access_token= '' pk= 1
after second save count= 1 obj2.pk= 1
PLAN Task 2 acceptance #9 规定的 N 次 save 守恒断言(4 次 save 验 count 恒为 1):
count_invariant_OK
PLAN <verification> 段完整脚本(assert 全部通过):
Plan 01 verification PASS
showmigrations aiapp 输出确认 [X] 0004_credentialslot:
aiapp
[X] 0001_initial
[X] 0002_initial
[X] 0003_create_rtc_bot
[X] 0004_credentialslot
makemigrations aiapp --check --dry-run 输出 No changes detected in app 'aiapp',退出码 0,CHECK_OK。
mask_token 验证结果
mask_token('sk-abcdef1234') == '*********1234' ✓ (末 4 位 '1234' 明文,前 9 字符脱敏)
mask_token('') == '' ✓ (空串短路)
mask_token(None) == '' ✓ (None 短路)
mask_token('abc') == '***' ✓ (短输入全脱敏)
mask_token('abcd') == '****' ✓ (恰等 visible_tail 全脱敏)
mask_token('abcde') == '*bcde' ✓ (长 1 位露 4 位)
mask_token('probe_secret_xxxx') == '*************xxxx' ✓ (与 Plan 02 浏览器 checkpoint 期望串一致)
探针数据当前值确认
SELECT app_id, access_token FROM aiapp_credentialslot WHERE pk=1 通过 ORM 等价:
pk=1, app_id='probe_app', access_token='probe_secret_xxxx', count=1
Plan 02 Task 2 浏览器 checkpoint mask 期望值算法:
- 原 token:
probe_secret_xxxx(长度 17) mask_token(...)返回:*************xxxx(13 个*+ 末 4 位xxxx,总长 17)- 故 Admin 列表页
access_token_masked列应渲染为*************xxxx
给下游的 Hand-off
| 下游 | 公开入口 / 契约 |
|---|---|
| Plan 01-02(Admin 注册) | from aiapp.models import CredentialSlot 取模型;from common.utils import mask_token 写 access_token_masked(self, obj);用 CredentialSlot.objects.exists() 判断是否禁用「新增」按钮 |
| Plan 01-02 浏览器 checkpoint | 依赖 DB 中 pk=1, access_token='probe_secret_xxxx' 探针;列表页脱敏期望串 *************xxxx |
| Phase 2 管理端 REST | 单例统一访问入口:CredentialSlot.get_solo()(不要直接 CredentialSlot.objects.first() 防止空 DB 时拿 None);GET 响应序列化时调用 mask_token(obj.access_token) |
| Phase 3 客户端 REST | 同样用 CredentialSlot.get_solo() 取数;客户端 GET 返回明文(不调 mask_token) |
| Phase 3 日志脱敏 | 阿里云日志 formatter 用 from common.utils import mask_token 直接复用,签名兼容 |
Deviations from Plan
自动调整(无需用户介入)
1. [Rule 3 - Blocking] verify 段 findstr /R 在 PowerShell + GBK 编码下不可靠
- 发现位置:Task 3 verify 命令
python manage.py showmigrations aiapp | findstr /R "0004.*\[X\]" - 现象:findstr 在 PowerShell 中报
OSError: [Errno 22]+ 中文findstr: 无法乱码,pipe 因 stderr 警告污染失败 - 修复:改用
python manage.py showmigrations aiapp 2>nul直接看输出,逐行肉眼+grep 校验[X] 0004_credentialslot命中 - 影响:仅影响 verify 显示方式,不影响功能 acceptance;showmigrations 输出已确认
[X]标记到位 - 文件:无代码改动,纯 verify 流程调整
观察(不阻塞)
2. 迁移文件头部注释显示 Generated by Django 5.2.12
- PLAN / PROJECT.md / CLAUDE.md 记录的版本是 Django 4.2.13
- 实际表现:本机 Python 环境的
django包是 5.2.12(pip 装的全局包),但项目代码是按 4.2 写的(迁移格式、字段属性、Meta 选项均跨 4.x/5.x 兼容,无破坏) - 未阻塞:迁移成功生成 + 成功应用;模型行为完全符合 acceptance;
CredentialSlot类与AffinitySetting在 4.2 / 5.2 下行为等价 - 建议:本仓库部署使用 Docker 镜像(CLAUDE.md 写明),Docker 内才是 4.2.13;本地开发版本漂移属于已知现象,不在本 plan 范围。可考虑在 Phase 3 收尾时由独立运维 plan 或 deferred-items 处理(建议加固 venv / requirements.txt 锁版本,但 PROJECT.md 已说"不锁版本,靠 Docker")。
不在本 Plan 范围(按 PLAN 约束严格执行)
- 未写 docs/修改记录.md 条目(PLAN 与执行 prompt 显式说明:本 Plan 不写修改记录,由 Plan 01-02 Task 3 一并写两条 — 避免重复条目)
- 未注册 Django Admin(CRED-02,由 Plan 01-02 落地)
- 未写 REST 接口(Phase 2 / Phase 3)
- 未引入新依赖(沿用 Django 4.2 / Python 3.8 已有栈)
覆盖的需求与 ROADMAP Success Criteria
- ✓ CRED-01:单例
CredentialSlot模型 + 迁移落地;DB 层 count 守恒为 1(save 钩子保证);含 app_id / access_token / updated_at 三字段 - ✓ ROADMAP Phase 1 Success Criterion #1:DB / 模型层强制最多一条(save() 钩子静默重定向 pk,count 守恒,与 AffinitySetting 等价语义)
- ✓ ROADMAP Phase 1 Success Criterion #2:迁移落地 + schema 字段齐全(migrate 退出码 0;showmigrations 显示
[X];CreateModel 含 4 列) - ✓ ROADMAP Phase 1 Success Criterion #3:
get_or_create(pk=1)首访拿到created=True / app_id='' / access_token=''空记录 - — Phase 1 Success Criterion #4 / #5 / #6(Admin 列表 / 编辑 / 禁删)→ Plan 01-02 负责
Self-Check: PASSED
文件存在确认:
common/utils.py -> FOUND
aiapp/models.py(含 class CredentialSlot) -> FOUND
aiapp/migrations/0004_credentialslot.py -> FOUND
.planning/phases/01-credential-data-layer/01-01-SUMMARY.md -> FOUND(本文件)
Commit 存在确认(git log --oneline 命中):
a9c25eb feat(01-01): 新增 common/utils.py 含 mask_token 工具函数 -> FOUND
30c7caf feat(01-01): aiapp 新增 CredentialSlot 单例模型 -> FOUND
a475fe4 feat(01-01): 自动生成并应用 0004_credentialslot 迁移 -> FOUND
DB 状态确认:aiapp_credentialslot 表存在 pk=1 单条记录,access_token='probe_secret_xxxx' 探针就绪供 Plan 01-02 使用。
由 /gsd-execute-phase 顺序执行器于 2026-05-07 生成