10 KiB
Raw Permalink Blame History

Phase 2管理端读写接口 - Context

Gathered: 2026-05-07 Status: Ready for planning Source: 用户在 /gsd-plan-phase 2 调用时提供的内联约束PRD 快速通道,等同 Phase 1 同模式)

## Phase 边界

本 phase 仅负责 DRF 序列化器 + view + URL 路由 + 鉴权 + 修改记录

  • /api/v1/admin/credential-slot/ 暴露 GET脱敏返回+ PUT全字段覆写两个方法
  • 复用现有 RedisTokenAuthenticationadmin token 体系key admin_token:{token}
  • 响应必须经过 StandardResponseMiddleware 壳层
  • Access Token 在 GET 响应中通过 mask_token 脱敏(仅末 4 位)
  • PUT 响应也走脱敏(写入成功后用脱敏值返回,避免运营在 admin 工具里看到自己刚提交的明文回显)
  • 接口自动暴露到 /swagger/ + /redoc/drf-yasgschema 与实际行为一致
  • 修改记录在 qy_lty + qy-lty-admin 两端互引条目Phase 2 是首次跨项目接口契约落地需要前端记一条互引qy-lty-admin 那侧 Phase 1 plan 已定义 CRED-FE-01 API client 会消费这个接口契约)

不负责(留给后续 phase

  • Phase 3客户端读取接口GET /api/credential-slot/user token 鉴权,明文返回)+ 阿里云日志脱敏
  • 任何前端代码(在 qy-lty-admin 仓库的 CRED-FE-01 phase 里)
  • DB 字段加密、审计日志、token 轮换等增强项
## 实现决策(锁定)

URL 与路由

  • 路径/api/v1/admin/credential-slot/trailing slash 沿用 Django 默认风格)
  • HTTP 方法GET 和 PUT 在同一 URL不分两个 endpoint符合 RESTful 单例资源约定)
  • 路由注册位置:决策由 planner 基于 read_first 后选择
    • 候选 Aaiapp/urls.py(凭据槽位语义偏向 AI
    • 候选 B仓库现有的 admin namespace /api/v1/admin/ 在哪个 urls 文件汇总planner 必须 read_first 全仓 grep /api/v1/admin/ 找到现有汇总点(推测在 userapp/urls.pyqy_lty/urls.py),照抄注册风格
  • 新建 credential app凭据槽位不值得一个独立 app它就是 aiapp 的一个子能力)

View 实现

  • 不用 ModelViewSet(带不必要的 list / create / delete单例资源用不上
  • RetrieveUpdateAPIViewDRF 提供,开箱支持 GET + PUT/PATCH或自定义 APIView + 手写 get / put 方法
  • 推荐 自定义 APIView —— 单例语义不走 lookup_field/pk,调 get_or_create(pk=1) 取那条唯一记录;用 RetrieveUpdateAPIView 反而需要重写 get_object(),绕一圈不值得
  • View 类命名:CredentialSlotAdminView,放 aiapp/views.py(沿用现有 view 文件)

Serializer

  • DRF ModelSerializerCredentialSlotSerializer,放 aiapp/serializers.py如不存在则新建planner 检查 aiapp/ 是否已有 serializers.py
  • 字段:app_idaccess_tokenupdated_at
  • updated_at 在 GET 响应里 read_onlyauto_now 自动维护)
  • Access Token 脱敏在 view 层处理,不在 serializer 层serializer 直接把明文交给 viewview 在返回响应前用 mask_token 替换理由PUT 写入时需要明文走 serializer.is_valid + save(),脱敏放 view 层避免序列化器既要明文又要脱敏的双重责任
  • 写入校验:app_idaccess_token 都允许空字符串(与模型 blank=True 一致),但不允许 Noneserializer 字段配 allow_null=False

鉴权

  • 直接复用 RedisTokenAuthentication —— Phase 2 researcher 必须 read_first 找到该类的具体位置(推测 userapp/authentication.py),并 read 现有 /api/v1/admin/ namespace 下任一接口的鉴权配置(如 Bot 管理接口)作为照抄对象
  • View 类上配 authentication_classes = [RedisTokenAuthentication] + permission_classes = [IsAdminTokenAuthenticated](如果项目已有这种 admin-only permission否则用 IsAuthenticated + 在 view 里加 request.user.is_staff 检查)
  • 关键admin token 的语义是"该 token 来自 admin_token:{token} Redis key",普通 user token 来自 token:{token}planner 应在 read_first 阶段确认现有 admin 接口怎么区分这两类 token很可能 RedisTokenAuthentication 自身根据 key 前缀做了区分,且配套有一个 admin-only permission class
  • 拒绝时返回 401无 token或 403user token 但非 admin错误响应必须经过 StandardResponseMiddleware 壳层

Swagger / ReDoc

  • 接口必须出现在 /swagger/ + /redoc/drf-yasg 会自动扫描 DRF 视图
  • View 类上加 @swagger_auto_schema 装饰器method-level给 GET / PUT 各写一份),声明 request body schema 和 response schema
  • response schema 显式标注 access_token 字段语义为「末 4 位脱敏掩码」,避免前端误解为明文

跨项目联动(修改记录互引)

  • 本 phase 同期写两端 docs/修改记录.md
    • qy_lty/docs/修改记录.md 顶部写一条:"新增 Phase 2 管理端 REST 接口",跨项目联动字段引用 qy-lty-admin/docs/修改记录.md 的对应条目
    • qy-lty-admin/docs/修改记录.md 顶部写一条:"锁定 Phase 2 后端 API 契约(消费方文档化)",跨项目联动字段引用 qy_lty 的对应条目
  • 这是 Phase 2 与 Phase 1 的关键差异Phase 1 是纯服务端模型层、不涉及 API 契约所以前端不需要互引Phase 2 暴露 REST 接口给前端消费,必须互引

兼容性 / 不引入新依赖

  • 沿用 Django 4.2.13、DRF 3.x现版、Python 3.8
  • drf-yasg 已在依赖里,复用即可
  • 不引入新依赖

Claude's Discretion

  • 序列化器是否拆 CredentialSlotReadSerializer(脱敏返回) + CredentialSlotWriteSerializer(明文写入)两个类,还是用同一个 + view 层脱敏 —— planner 决定
  • view 是放 aiapp/views.py 末尾,还是新建 aiapp/views/credential_slot.py 子文件 —— 取决于 aiapp/views.py 现有规模
  • 错误响应的具体 message 文案(中文),如 "凭据槽位需要管理员权限" / "未提供有效的管理员 token"
  • View 里如何确保 get_or_create(pk=1) 在并发请求下不出竞态(最简:用 select_for_update 或单例语义本身已经被 pk=1 + save 钩子 兜底,可以不加锁)

<canonical_refs>

Canonical References

下游 agent 必读

项目宪法

  • qy_lty/CLAUDE.md — 沟通语言(中文)+ 修改记录强制规则 + 跨项目互引强制
  • qy_lty/.planning/PROJECT.md — Milestone v1.0「本期 Milestone」段、关键约束响应壳层 / token 命名)
  • qy_lty/.planning/REQUIREMENTS.md — Active 段 CRED-03 + CRED-04 完整描述
  • qy_lty/.planning/ROADMAP.md — Phase 2 详情段Goal、Success Criteria 4 条)
  • qy_lty/.planning/phases/01-credential-data-layer/01-CONTEXT.md — 上一 phase 决策pk=1 单例 + mask_token 工具的来源)
  • qy_lty/.planning/phases/01-credential-data-layer/01-VERIFICATION.md — 上一 phase 验证证据mask_token 行为、CredentialSlot.get_solo() 用法)

DRF / 鉴权 / 路由现成模式(必读)

  • qy_lty/aiapp/views.py — 同 app 内现有 view 写法
  • qy_lty/aiapp/models.pyCredentialSlot + get_solo() + mask_token 复用入口
  • qy_lty/userapp/authentication.pyRedisTokenAuthentication 实现推测路径researcher 确认)
  • qy_lty/userapp/views.py —— 现有 admin 接口写法(推测含 /api/v1/admin/ 命名空间下的 view 模板)
  • qy_lty/qy_lty/urls.pyqy_lty/userapp/urls.py/api/v1/admin/ 路由汇总点researcher 找出来)
  • qy_lty/common/middleware.pyStandardResponseMiddleware(确认它如何处理 DRF Response 对象)
  • qy_lty/common/utils.pymask_token 工具Phase 1 落地)

Swagger

  • qy_lty/qy_lty/urls.py 或独立的 swagger 注册文件 — 看 drf-yasg 如何配 schema_view照搬 @swagger_auto_schema 风格

修改记录

  • qy_lty/docs/修改记录.md — 头部「修改格式说明」+ Phase 1 已落地的两条条目可作模板
  • qy-lty-admin/docs/修改记录.md — 头部「修改格式说明」(如有;如不存在 planner 应在 task 中提示用同款骨架格式新建)

</canonical_refs>

## 具体要点Success Criteria 显式化)
# 验证点 检查方式
1 GET 携 admin token 返回脱敏壳层 curl -H "Authorization: Bearer <admin_token>" /api/v1/admin/credential-slot/ 返回 200 + JSON 含 success: true / data.access_token: <末 4 位掩码>
2 PUT 携 admin token 全字段覆写 curl -X PUT -H "Authorization: Bearer <admin_token>" -d '{"app_id": "x", "access_token": "y"}' .../credential-slot/ 返回 200 + DB 更新 + updated_at 刷新
3 PUT 在空记录场景自动 get_or_create DB 删除 pk=1 后调 PUT依旧成功创建
4 无 token 返回 401 + 标准壳层 curl /api/v1/admin/credential-slot/ 返回 401 + JSON 含 success: false / code != 0 / message != ""
5 仅 user token非 admin返回 403 + 标准壳层 token:{token}(非 admin_token调用返回 403 + 标准壳层
6 Swagger 暴露 /swagger/ HTML 页面含 /api/v1/admin/credential-slot/ 路径条目,含 GET + PUT 两个方法及对应 schema
7 drf-yasg request/response schema 与实际一致 /swagger.jsonapp_id / access_token / updated_at 字段定义 + access_token schema description 标注「末 4 位脱敏掩码」
8 修改记录两端互引 qy_lty/docs/修改记录.mdqy-lty-admin/docs/修改记录.md 顶部各有一条 Phase 2 条目,跨项目联动字段相互引用
## 推迟事项(明确不在 Phase 2 范围)
  • 客户端 GET /api/credential-slot/ — Phase 3
  • 阿里云日志脱敏过滤器 — Phase 3
  • PUT 写入时旧 access_token 的审计日志 — 不在 v1.0 milestone 范畴
  • token 鉴权失败时尝试用其它 token 类型重试 / fallback — 当前架构禁止此类降级,无 token 就 401
  • API 限流(防暴力 PUT — 现有架构未上限流,不在本 phase 范畴
  • DB at-rest 加密 — 未来评估,不在 v1.0 范畴

Phase: 02-admin-rest Context gathered: 2026-05-07 via inline PRD用户在 /gsd-plan-phase 2 调用时提供完整约束)