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

86 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 平台 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(匿名)。