Files
yingqing/docs/todo/admin-后台-进度.md
T
seaislee1209andClaude Opus 4.8 45a4ceae51 feat(admin): Phase 2 邀请码发放管理 — apps/adminpanel 跨团队端点 + Admin 邀请码页
后端:新建 apps/adminpanel(跨团队后台容器,/api/admin/);GET/POST invitations(列跨团队码+筛选分页 /
平台发 create_team 开团队码,写审计)+ revoke(写审计),全程 IsPlatformAdmin。
前端:adminApi 分层;Admin 邀请码页(类型筛选段控 + 表格 + 发码弹窗 + 复制邀请链接 + 撤销)接入 AdminApp toast;
Invitation 类型补 kind/team_name;admin-page.css 补段控/表格/弹窗(仅 token)。
测试:adminpanel 9 + accounts 22 = 31 单测过;无头 e2e _admin-p2.mjs 6 断言过 + 0 console error
+ 端到端凭 UI 发的码注册开团队 201;tsc+build 绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 21:29:55 +08:00

6.6 KiB
Raw Blame History

平台 Admin 后台 + 注册邀请码 · 落地进度

计划:C:/Users/Air-work/.claude/plans/gleaming-sleeping-ullman.md(Phase 0–9 全做)。 每个 Phase 走完「★测试底座」(后端单测 + 无头浏览器 e2e + tsc/build + 回归)才 commit。 全程本地、不 push;测试服 DB 可动。


测试基线(回归红线)

  • apps.accounts / apps.billing / apps.products:全绿(Phase 0 后 15/15 OK)。
  • apps.projects:进 Phase 0 前已有 3 failures + 1 error(均为 AI provider image_edit mock 相关,与本工程无关)——非本次引入,Phase 0 改动仅在 accounts + 前端,未触碰 projects/ai。后续 Phase 不得新增 fail。

✅ Phase 0 · 基础(角色 + 壳 + 审计)— 完成 2026-06-19

后端

  • User.is_platform_admin(bool)+ migration 0004_user_is_platform_admin_adminauditlog(已 apply 到测试 MySQL)。
  • apps/accounts/permissions.py · IsPlatformAdmin(超管放行 / 普通拒 / 停用拒)。
  • apps/accounts/management/commands/create_platform_admin.py · 建 admin/admin123(幂等;--reset-password 才重置;也置 is_staff)。已对测试 MySQL 执行,真账号可登。
  • AdminAuditLog 模型(operator/operator_name/action/target_*/before/after/ip)+ apps/accounts/audit.py log_admin_action()(失败不阻断主流程)。
  • me / login 对无团队的平台超管优雅返回 team=null(新增 current_team_or_none);UserSerializer 暴露 is_platform_admin。

前端

  • 新 routes/admin/admin-app.tsx:超管后台外壳(折叠分组侧栏 6 组 11 项 + 顶栏 + 概览 + 占位页),全程复用 restraint 共享类。
  • 路由:route-config.ts 解析 /admin、/admin/<section>;App.tsx 分流渲染 AdminApp + gating(超管无团队登录直落 /admin、非超管访问 /admin 纠回工作台)。
  • app-shell.tsx 侧栏「平台」入口(仅超管可见)。
  • admin-page.css(仅 token,无裸 hex)+ IconKitSvg 补 8 个 Lucide-line 图标。

测试底座(全过)

  • 后端单测:apps.accounts 11/11 OK(新增 PlatformAdminTests:建超管命令幂等/权限类放行拒绝/登录+me 返回标志且 team 为空/普通注册非超管)。
  • 无头 e2e:core/qa/visual-parity/_admin-p0.mjs —— 全部断言通过 + 0 console error:
    • admin/admin123 真登录 → 落 /admin;
    • 超管壳:6 分组 / 11 导航 / [ PLATFORM ADMIN ] 徽标 / 概览标题 / 点「邀请码」→ /admin/invites 占位「模块即将上线」;
    • 普通用户访问 /admin → 纠回 /dashboard、admin 壳不渲染。
    • 截图:output/admin/p0-*.png。
  • 类型/构建:tsc --noEmit + npm run build 全绿。
  • 视觉:概览截图核对 —— 冷灰底 + 单橙 accent + 8px 圆角 + 准星,符合 design.md 克制调性。

测试账号:平台超管 admin/admin123(测试 MySQL 已建);普通 demo airshelf/Restraint2026。

e2e 端口提示:5173 被同机另一项目(AirDrama)抢占且不稳;AirShelf e2e 改用专用端口 5188(npx vite --port 5188 --strictPort)。e2e 脚本默认 BASE 已指向 5188。


✅ Phase 1 · 注册邀请码逻辑 — 完成 2026-06-19

后端

  • Invitation.kind(join_team / create_team)+ team 可空 + migration 0005_invitation_kind_alter_invitation_team(已 apply 测试 MySQL)。
  • RegisterSerializer:invite_code 必填;按 kind 分流 —— create_team 开新团队当 owner + 发试用额度(回填 invite.team),join_team 幂等加入该团队、不重复发额度;删除「空码=开团队」。
  • validate-invite 端点(免登录,POST /api/auth/validate-invite/):验码 → {valid, kind, role, team_name?},无效始终 200+valid:false。
  • 团管发码恒为 kind=join_team;InvitationSerializer 增 kind/team/team_name。

前端

  • 注册页重做(码优先):先填邀请码 → 点「验证」(或 Enter)→ 验过才展开;create_team 显示「团队名」输入,join_team 显示只读团队名(不暴露团队列表);CTA 文案随 kind 切换(创建团队 / 加入团队)。
  • 邀请链接 ?invite=CODE 进页自动回填 + 验码;改码即重置验证态。
  • api.validateInvite;field-note.ok/err + invite-verify-row + 只读团队样式(仅 token)。

测试底座(全过)

  • 后端单测:apps.accounts 22/22 OK(新增 RegisterInviteCodeTests 6 项 + ValidateInviteTests 5 项:无码拒/空码拒/create_team 开团队+试用额度/join_team 入伙不开新团队/已用·过期拒/验码返回正确 kind+team_name)。
  • 无头 e2e:_admin-p1.mjs(端口 5188)—— 全断言过 + 0 console error:create_team 验码→展开团队名→注册落工作台;join_team 验码→只读团队名「演示团队」→入伙;错码不展开+报错;URL 自动验码。截图 output/admin/p1-*.png。
  • 类型/构建:tsc --noEmit + npm run build 全绿。
  • 视觉:两态注册截图核对 —— 黑块等高、验证按钮对齐、绿色 ok 提示、只读团队名灰底,符合 restraint。

✅ Phase 2 · 邀请码发放管理(Admin)— 完成 2026-06-19

后端(新建 apps/adminpanel/)

  • 新 Django app apps.adminpanel(跨团队后台端点容器),注册进 INSTALLED_APPS + 主 urls path("api/admin/", ...)。
  • GET/POST /api/admin/invitations/:列所有邀请码(跨团队,按 kind/status/search 过滤 + 分页);POST 平台超管发 create_team「开团队码」(写审计 invite.issue_create_team)。
  • POST /api/admin/invitations/<id>/revoke/:撤销待用码(写审计 invite.revoke)。
  • 全程 IsPlatformAdmin,非超管 403。

前端

  • adminApi(api.ts 分层):invitations / createInvite / revokeInvite。
  • Admin「邀请码」页(routes/admin/admin-invites.tsx):类型筛选段控(全部/开团队码/加入码)+ 表格(码/类型/团队/状态徽章/创建时间/使用者)+「发开团队码」弹窗 + 复制邀请链接(剪贴板 + 反馈)+ 撤销;接入 AdminApp(本地 toast notify)。
  • Invitation 类型补 kind/team/team_name;admin-page.css 补段控/表格/弹窗样式(仅 token)。

测试底座(全过)

  • 后端单测:apps.adminpanel 9 项 + apps.accounts 22 = 31 OK(列权限 403/发码+审计/跨团队列表/kind 过滤/撤销+审计/端到端凭发出的码注册开团队/撤销后码失效)。
  • 无头 e2e:_admin-p2.mjs(5188)—— 6 断言全过 + 0 console error:页面加载、发码弹窗、新码入列、复制链接反馈「已复制」、端到端用 UI 发的码 API 注册开团队 201。截图 output/admin/p2-*.png。
  • 类型/构建:tsc --noEmit + npm run build 全绿。
  • 视觉:列表截图核对 —— 类型/状态橙/中性 pill、段控黑激活、成功 toast,符合 restraint。
  • 回归:accounts 22 仍全绿;live 后端自动 reload 后 /api/admin/invitations/ 200(admin)/401(匿名)。