docs(01-01): 完成凭据槽位数据层 plan,落地 SUMMARY 与 state 更新
- 新增 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
This commit is contained in:
parent
a475fe4600
commit
20036eeb2f
@ -95,7 +95,7 @@
|
|||||||
|
|
||||||
### 通用凭据槽位(CRED)
|
### 通用凭据槽位(CRED)
|
||||||
|
|
||||||
- [ ] **CRED-01** 单例 `CredentialSlot` Django 模型 + 迁移;DB 层强制最多一条记录(`pk=1` 固定主键或单字段唯一约束);含 `app_id`、`access_token`、`updated_at` 字段
|
- [x] **CRED-01** 单例 `CredentialSlot` Django 模型 + 迁移;DB 层强制最多一条记录(`pk=1` 固定主键或单字段唯一约束);含 `app_id`、`access_token`、`updated_at` 字段 ✓ Plan 01-01 完成(2026-05-07,commits a9c25eb / 30c7caf / a475fe4)
|
||||||
- [ ] **CRED-02** Django Admin 注册:列表态/查看态对 `access_token` 字段脱敏;新增/编辑态可见明文(运营录入需要);隐藏"新增"按钮(强制单例语义)
|
- [ ] **CRED-02** Django Admin 注册:列表态/查看态对 `access_token` 字段脱敏;新增/编辑态可见明文(运营录入需要);隐藏"新增"按钮(强制单例语义)
|
||||||
- [ ] **CRED-03** 管理端 GET `/api/v1/admin/credential-slot/`:admin token 鉴权(`admin_token:{token}` Redis key 体系);返回 `{ app_id, access_token: <masked>, updated_at }`,Access Token 仅返回末 4 位脱敏掩码
|
- [ ] **CRED-03** 管理端 GET `/api/v1/admin/credential-slot/`:admin token 鉴权(`admin_token:{token}` Redis key 体系);返回 `{ app_id, access_token: <masked>, updated_at }`,Access Token 仅返回末 4 位脱敏掩码
|
||||||
- [ ] **CRED-04** 管理端 PUT `/api/v1/admin/credential-slot/`:admin token 鉴权;接受 `{ app_id, access_token }` 全字段覆写更新;空记录场景自动 `get_or_create`;变更写入 `updated_at`
|
- [ ] **CRED-04** 管理端 PUT `/api/v1/admin/credential-slot/`:admin token 鉴权;接受 `{ app_id, access_token }` 全字段覆写更新;空记录场景自动 `get_or_create`;变更写入 `updated_at`
|
||||||
@ -138,7 +138,7 @@
|
|||||||
|
|
||||||
| Requirement | Phase | Status |
|
| Requirement | Phase | Status |
|
||||||
|-------------|-------|--------|
|
|-------------|-------|--------|
|
||||||
| CRED-01 单例 `CredentialSlot` 模型 + 迁移 | Phase 1 凭据槽位数据层 | Pending |
|
| CRED-01 单例 `CredentialSlot` 模型 + 迁移 | Phase 1 凭据槽位数据层 | Done(Plan 01-01,2026-05-07) |
|
||||||
| CRED-02 Django Admin 注册(脱敏 + 隐藏新增按钮) | Phase 1 凭据槽位数据层 | Pending |
|
| CRED-02 Django Admin 注册(脱敏 + 隐藏新增按钮) | Phase 1 凭据槽位数据层 | Pending |
|
||||||
| CRED-03 管理端 GET(admin token,脱敏返回) | Phase 2 管理端读写接口 | Pending |
|
| CRED-03 管理端 GET(admin token,脱敏返回) | Phase 2 管理端读写接口 | Pending |
|
||||||
| CRED-04 管理端 PUT(admin token,全字段覆写 + get_or_create) | Phase 2 管理端读写接口 | Pending |
|
| CRED-04 管理端 PUT(admin token,全字段覆写 + get_or_create) | Phase 2 管理端读写接口 | Pending |
|
||||||
|
|||||||
@ -31,7 +31,9 @@
|
|||||||
2. 运行 `python manage.py migrate` 后,schema 中存在 `app_id`、`access_token`、`updated_at` 三个字段,且首次访问时通过 `get_or_create(pk=1)` 拿到一条空记录
|
2. 运行 `python manage.py migrate` 后,schema 中存在 `app_id`、`access_token`、`updated_at` 三个字段,且首次访问时通过 `get_or_create(pk=1)` 拿到一条空记录
|
||||||
3. 登录 Django Admin(SimpleUI 主题)打开凭据槽位页面:列表态/查看态下 `access_token` 显示为脱敏掩码(仅末 4 位),编辑态下显示明文供运营录入
|
3. 登录 Django Admin(SimpleUI 主题)打开凭据槽位页面:列表态/查看态下 `access_token` 显示为脱敏掩码(仅末 4 位),编辑态下显示明文供运营录入
|
||||||
4. Admin 列表页**不显示**「新增」按钮(强制单例语义,避免运营误建第二条)
|
4. Admin 列表页**不显示**「新增」按钮(强制单例语义,避免运营误建第二条)
|
||||||
**Plans**: TBD
|
**Plans:** 2 plans
|
||||||
|
- [x] 01-01-PLAN.md — 凭据槽位单例模型 + 迁移 + mask_token 工具(CRED-01)✓ 2026-05-07 完成(commits a9c25eb / 30c7caf / a475fe4)
|
||||||
|
- [ ] 01-02-PLAN.md — Django Admin 注册(脱敏/单例新增/禁删)+ 修改记录两条(CRED-02)
|
||||||
|
|
||||||
### Phase 2: 管理端读写接口
|
### Phase 2: 管理端读写接口
|
||||||
**Goal**: Web 管理后台(qy-lty-admin)能通过 `/api/v1/admin/credential-slot/` 读取脱敏后的凭据槽位、并以全字段覆写方式更新它
|
**Goal**: Web 管理后台(qy-lty-admin)能通过 `/api/v1/admin/credential-slot/` 读取脱敏后的凭据槽位、并以全字段覆写方式更新它
|
||||||
@ -62,7 +64,7 @@ Phase 按数值顺序执行:1 → 2 → 3(如出现紧急插入,记为 1.1
|
|||||||
|
|
||||||
| Phase | Plans Complete | Status | Completed |
|
| Phase | Plans Complete | Status | Completed |
|
||||||
|-------|----------------|--------|-----------|
|
|-------|----------------|--------|-----------|
|
||||||
| 1. 凭据槽位数据层 | 0/TBD | Not started | - |
|
| 1. 凭据槽位数据层 | 1/2 | In progress(Plan 01-01 完成) | - |
|
||||||
| 2. 管理端读写接口 | 0/TBD | Not started | - |
|
| 2. 管理端读写接口 | 0/TBD | Not started | - |
|
||||||
| 3. 客户端读取与日志脱敏 | 0/TBD | Not started | - |
|
| 3. 客户端读取与日志脱敏 | 0/TBD | Not started | - |
|
||||||
|
|
||||||
|
|||||||
@ -3,20 +3,20 @@ gsd_state_version: 1.0
|
|||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: 通用凭据槽位
|
milestone_name: 通用凭据槽位
|
||||||
status: executing
|
status: executing
|
||||||
stopped_at: ROADMAP.md / STATE.md / REQUIREMENTS.md traceability 三文件落地,Phase 1 待启动
|
stopped_at: Plan 01-01 完成,等待启动 Plan 01-02(Admin 注册 + 修改记录)
|
||||||
last_updated: "2026-05-07T09:30:51.094Z"
|
last_updated: "2026-05-07T09:36:30Z"
|
||||||
last_activity: 2026-05-07
|
last_activity: 2026-05-07
|
||||||
progress:
|
progress:
|
||||||
total_phases: 3
|
total_phases: 3
|
||||||
completed_phases: 0
|
completed_phases: 0
|
||||||
total_plans: 2
|
total_plans: 2
|
||||||
completed_plans: 0
|
completed_plans: 1
|
||||||
percent: 0
|
percent: 50
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State — QY LTY Backend
|
# Project State — QY LTY Backend
|
||||||
|
|
||||||
**最后更新**: 2026-05-07(ROADMAP.md 已生成,Milestone v1.0 待启动 Phase 1)
|
**最后更新**: 2026-05-07(Phase 1 Plan 01-01 完成,模型 + 迁移 + mask_token 落地)
|
||||||
|
|
||||||
## 项目引用
|
## 项目引用
|
||||||
|
|
||||||
@ -24,37 +24,37 @@ progress:
|
|||||||
|
|
||||||
**核心价值**:设备端与手机端通过同一个 user_id 实时互通——`device_{user_id}` 分组语义必须始终成立。
|
**核心价值**:设备端与手机端通过同一个 user_id 实时互通——`device_{user_id}` 分组语义必须始终成立。
|
||||||
|
|
||||||
**当前重点**:Milestone v1.0 通用凭据槽位(APP ID + Access Token)— Phase 1「凭据槽位数据层」待启动
|
**当前重点**:Milestone v1.0 通用凭据槽位(APP ID + Access Token)— Phase 1 Plan 01-02 待启动(Admin 注册 + 修改记录)
|
||||||
|
|
||||||
## 当前位置
|
## 当前位置
|
||||||
|
|
||||||
```
|
```
|
||||||
Phase: 1 of 3(凭据槽位数据层)
|
Phase: 1 of 3(凭据槽位数据层)
|
||||||
Plan: — of TBD
|
Plan: 01-02 of 02(Admin 注册 + 修改记录)
|
||||||
Status: Ready to execute
|
Status: Plan 01-01 完成,等待启动 01-02
|
||||||
Last activity: 2026-05-07
|
Last activity: 2026-05-07
|
||||||
```
|
```
|
||||||
|
|
||||||
Progress: [░░░░░░░░░░] 0%
|
Progress: [█████░░░░░] 50%(Phase 1 内 plan 进度:1/2)
|
||||||
|
|
||||||
## 性能指标
|
## 性能指标
|
||||||
|
|
||||||
**速度:**
|
**速度:**
|
||||||
|
|
||||||
- 已完成 plan 数:0
|
- 已完成 plan 数:1
|
||||||
- 平均耗时:—
|
- 平均耗时:~3 min(顺序执行模式)
|
||||||
- 总执行时间:—
|
- 总执行时间:184 s(Plan 01-01)
|
||||||
|
|
||||||
**按 Phase:**
|
**按 Phase:**
|
||||||
|
|
||||||
| Phase | Plans | Total | Avg/Plan |
|
| Phase | Plans | Total | Avg/Plan |
|
||||||
|-------|-------|-------|----------|
|
|-------|-------|-------|----------|
|
||||||
| — | — | — | — |
|
| 1 | 1/2 | 184 s | 184 s |
|
||||||
|
|
||||||
**最近趋势:**
|
**最近趋势:**
|
||||||
|
|
||||||
- 最近 5 个 plan:—
|
- 最近 5 个 plan:01-01(184 s,3 task / 3 commit / 3 文件)
|
||||||
- 趋势:—
|
- 趋势:—(数据不足,需 ≥2 plan)
|
||||||
|
|
||||||
*每完成一个 plan 后更新*
|
*每完成一个 plan 后更新*
|
||||||
|
|
||||||
@ -67,6 +67,10 @@ Progress: [░░░░░░░░░░] 0%
|
|||||||
|
|
||||||
- 凭据槽位以 `pk=1 + get_or_create` 模式落地单例语义(PROJECT.md「关键约束」段)
|
- 凭据槽位以 `pk=1 + get_or_create` 模式落地单例语义(PROJECT.md「关键约束」段)
|
||||||
- 客户端 GET 接口必须返回**明文** Access Token(手机端/设备端实际调用第三方需要),仅管理端 GET 与日志做脱敏
|
- 客户端 GET 接口必须返回**明文** Access Token(手机端/设备端实际调用第三方需要),仅管理端 GET 与日志做脱敏
|
||||||
|
- **[Plan 01-01]** `CredentialSlot` 单例 1:1 复刻 `userapp.models.AffinitySetting`(pk=1 + save 钩子重定向 + get_solo),不发明新模式
|
||||||
|
- **[Plan 01-01]** `CredentialSlot` 字段集合最小化:app_id(128) / access_token(512) / updated_at;不加 `created_at`(单例无创建语义)
|
||||||
|
- **[Plan 01-01]** Admin 与 Phase 3 日志共用同一 `mask_token` 工具(放 `common/utils.py`),不引入第三方加密 / 脱敏库
|
||||||
|
- **[Plan 01-01]** 探针数据契约:DB pk=1 留 `access_token='probe_secret_xxxx'`,Plan 01-02 Admin 列表脱敏 checkpoint 期望串 `*************xxxx`
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@ -94,10 +98,10 @@ Progress: [░░░░░░░░░░] 0%
|
|||||||
## 下一步
|
## 下一步
|
||||||
|
|
||||||
```
|
```
|
||||||
/gsd-plan-phase 1
|
/gsd-execute-phase 1
|
||||||
```
|
```
|
||||||
|
|
||||||
进入 Phase 1「凭据槽位数据层」的规划环节,把 CRED-01 / CRED-02 拆为可执行 plan。
|
继续执行 Phase 1 Plan 01-02(Admin 注册 + 修改记录)。Plan 01-01 已完成,DB 中已留 `pk=1, access_token='probe_secret_xxxx'` 探针,Plan 01-02 浏览器 checkpoint 直接登录 Admin 验证脱敏列显示 `*************xxxx`。
|
||||||
|
|
||||||
## 工作流配置
|
## 工作流配置
|
||||||
|
|
||||||
@ -128,9 +132,9 @@ CLAUDE.md 两条强制规则(任何 phase 都必须遵守):
|
|||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-05-07
|
Last session: 2026-05-07
|
||||||
Stopped at: ROADMAP.md / STATE.md / REQUIREMENTS.md traceability 三文件落地,Phase 1 待启动
|
Stopped at: Plan 01-01 完成(mask_token + CredentialSlot 模型 + 0004 迁移 + 探针数据),等待启动 Plan 01-02
|
||||||
Resume file: None(直接 `/gsd-plan-phase 1` 即可)
|
Resume file: `.planning/phases/01-credential-data-layer/01-02-PLAN.md`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*由 /gsd-roadmap 于 2026-05-07 更新*
|
*由 /gsd-execute-phase 顺序执行器于 2026-05-07 更新(Plan 01-01 完成时点)*
|
||||||
|
|||||||
@ -0,0 +1,194 @@
|
|||||||
|
---
|
||||||
|
phase: 01-credential-data-layer
|
||||||
|
plan: 01
|
||||||
|
subsystem: aiapp / common
|
||||||
|
tags: [credential, singleton, migration, mask, masking-util]
|
||||||
|
requires: []
|
||||||
|
provides:
|
||||||
|
- "aiapp.models.CredentialSlot(单例模型 + get_solo + save 钩子)"
|
||||||
|
- "common.utils.mask_token(token, visible_tail=4, mask_char='*')"
|
||||||
|
- "aiapp 迁移 0004_credentialslot.py(CreateModel)"
|
||||||
|
- "DB 探针数据契约:pk=1 / app_id='probe_app' / access_token='probe_secret_xxxx'(供 Plan 02 浏览器 checkpoint 验证脱敏显示)"
|
||||||
|
affects:
|
||||||
|
- "Plan 01-02 Admin 注册 / 列表页脱敏将复用 mask_token 与 CredentialSlot.get_solo()"
|
||||||
|
- "Phase 2 / Phase 3 REST 视图统一从 CredentialSlot.get_solo() 取数"
|
||||||
|
- "Phase 3 阿里云日志 formatter 复用 common.utils.mask_token"
|
||||||
|
tech_stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Django 单例 = pk=1 + get_or_create + save() 钩子重定向(1:1 复刻 userapp.models.AffinitySetting 247-314 行)"
|
||||||
|
- "中文字面量 verbose_name(与仓库 14 个模型实操一致;不引入 gettext_lazy)"
|
||||||
|
key_files:
|
||||||
|
created:
|
||||||
|
- common/utils.py
|
||||||
|
- aiapp/migrations/0004_credentialslot.py
|
||||||
|
modified:
|
||||||
|
- aiapp/models.py
|
||||||
|
decisions:
|
||||||
|
- "字段集合最小化:app_id(128) / access_token(512) / updated_at;不加 created_at(单例无创建语义)"
|
||||||
|
- "单例靠 save() 钩子 + pk=1 静默重定向(不抛异常),与 AffinitySetting 一致;ROADMAP success criterion #1 解读为 count 守恒为 1,非异常拒绝"
|
||||||
|
- "mask_token 短输入(len <= visible_tail)走全脱敏分支,防长度信号泄露"
|
||||||
|
- "探针数据 probe_secret_xxxx 写入 DB 后保留不清理(Plan 02 浏览器 checkpoint 依赖)"
|
||||||
|
metrics:
|
||||||
|
duration_seconds: 184
|
||||||
|
tasks_completed: 3
|
||||||
|
tasks_total: 3
|
||||||
|
files_created: 2
|
||||||
|
files_modified: 1
|
||||||
|
commits: 3
|
||||||
|
completed_at: "2026-05-07T09:36Z"
|
||||||
|
requirements:
|
||||||
|
- CRED-01
|
||||||
|
---
|
||||||
|
|
||||||
|
# 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>` 段规定的探针 + 单例自检:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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):
|
||||||
|
|
||||||
|
```text
|
||||||
|
count_invariant_OK
|
||||||
|
```
|
||||||
|
|
||||||
|
PLAN `<verification>` 段完整脚本(assert 全部通过):
|
||||||
|
|
||||||
|
```text
|
||||||
|
Plan 01 verification PASS
|
||||||
|
```
|
||||||
|
|
||||||
|
`showmigrations aiapp` 输出确认 `[X] 0004_credentialslot`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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 验证结果
|
||||||
|
|
||||||
|
```text
|
||||||
|
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 等价:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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
|
||||||
|
|
||||||
|
文件存在确认:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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` 命中):
|
||||||
|
|
||||||
|
```text
|
||||||
|
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 生成*
|
||||||
Loading…
x
Reference in New Issue
Block a user