From 02d09c47fafb963c08954249a916921c116b7729 Mon Sep 17 00:00:00 2001 From: SpecialX <47072643+wangxiner55@users.noreply.github.com> Date: Fri, 10 Jul 2026 15:05:39 +0800 Subject: [PATCH] feat: auto committed --- .../issues/contracts/admin-portal_contract.md | 166 ++++++++----- .../issues/objections/admin-portal_issue.md | 109 ++++++++- .../issues/worklines/admin-portal_workline.md | 229 ++++++++++++++++-- 3 files changed, 424 insertions(+), 80 deletions(-) diff --git a/docs/architecture/issues/contracts/admin-portal_contract.md b/docs/architecture/issues/contracts/admin-portal_contract.md index c1567b9..be0575d 100644 --- a/docs/architecture/issues/contracts/admin-portal_contract.md +++ b/docs/architecture/issues/contracts/admin-portal_contract.md @@ -1,49 +1,71 @@ # admin-portal 对接契约 > 负责人:ai16 -> 关联:[matrix.md](./matrix.md)、[iam.proto](../../../packages/shared-proto/proto/iam.proto)、[events.proto](../../../packages/shared-proto/proto/events.proto) +> 关联:[matrix.md](./matrix.md)、[coord.md](./coord.md)、[ai-allocation.md §5 ai16](../../ai-allocation.md)、[iam.proto](../../../packages/shared-proto/proto/iam.proto)、[events.proto](../../../packages/shared-proto/proto/events.proto) +> 说明:本契约基于 GraphQL(ARB-001 admin 命名空间)+ 端口 4003 + ai16 归属,作为 01/02 文档修订基准(见 [objections/admin-portal_issue.md](../objections/admin-portal_issue.md) ISSUE-001~006)。 --- ## §1 我提供什么(对外接口) -### 1.1 gRPC 接口(如有) +### 1.1 gRPC 接口 -无。admin-portal 是前端微前端 Remote。 +无。admin-portal 是前端微前端 Remote,不提供 gRPC。 -### 1.2 HTTP 端点(如有) +### 1.2 前端路由(MF Remote 暴露给 Shell 动态加载) -| Method | Path | 用途 | 认证 | -| ------ | ----------- | ---------------- | --------------------- | -| GET | / | 管理后台首页 | JWT 必需 + admin 角色 | -| GET | /users | 用户管理 | JWT 必需 + admin | -| GET | /roles | 角色权限管理 | JWT 必需 + admin | -| GET | /classes | 班级管理(全局) | JWT 必需 + admin | -| GET | /teachers | 教师管理 | JWT 必需 + admin | -| GET | /students | 学生管理 | JWT 必需 + admin | -| GET | /audit-logs | 审计日志 | JWT 必需 + admin | -| GET | /dashboard | 管理员仪表盘 | JWT 必需 + admin | -| GET | /system | 系统配置 | JWT 必需 + admin | +> admin-portal 是前端,**不对外提供 HTTP 端点**。此处列出的是 admin-portal 在 Shell 路由树 `/admin/*` 下注册的前端页面路由,由 Shell 动态 import admin Remote 加载。 -### 1.3 GraphQL schema(如 BFF) +| 路由 | 页面 | 权限点 | 数据范围 | +| ------------------- | ---------------- | ---------------------- | --------------- | +| `/admin/dashboard` | 管理员仪表盘 | `ADMIN_DASHBOARD_VIEW` | L3-L5 | +| `/admin/users` | 用户管理 | `IAM_USER_READ` | L3-L5 | +| `/admin/roles` | 角色权限管理 | `IAM_ROLE_READ` | L3-L5 | +| `/admin/permissions`| 权限点管理 | `IAM_PERMISSION_READ` | L5 | +| `/admin/viewports` | 视口配置 | `IAM_VIEWPORT_READ` | L5 | +| `/admin/organization` | 组织管理 | `ORG_MANAGE` | L3-L5 | +| `/admin/system` | 学校设置 | `ADMIN_SYSTEM_MANAGE` | L5 | +| `/admin/classes` | 班级管理(全局) | `ADMIN_CLASS_READ` | L3-L5 | +| `/admin/teachers` | 教师管理 | `ADMIN_TEACHER_READ` | L3-L5 | +| `/admin/students` | 学生管理 | `ADMIN_STUDENT_READ` | L3-L5 | +| `/admin/audit-logs` | 审计日志 | `ADMIN_AUDIT_READ` | L5 | -不适用。admin-portal 消费 teacher-bff GraphQL admin namespace,自身不提供 schema。 +> 权限点使用 `ADMIN_` / `IAM_` / `ORG_` 前缀(ai-allocation §5:admin 权限点 `ADMIN_` 前缀)。`ADMIN_*` 常量由 coord 维护于 `packages/contracts/src/permissions.ts`,前端不硬编码。 -### 1.4 Kafka 事件发布(如有) +### 1.3 GraphQL schema -无。 +不适用。admin-portal **消费** teacher-bff GraphQL admin 命名空间,自身不提供 schema。 + +### 1.4 Kafka 事件发布 + +无。前端不发布 Kafka 事件。 ### 1.5 错误码前缀 -无(前端不定义错误码前缀,透传 BFF 错误码)。 +无(前端不定义错误码前缀,透传 BFF/网关错误码)。消费的错误码前缀见 §2.5。 -### 1.6 微前端架构(补充) +### 1.6 微前端架构 -| 角色 | 说明 | -| ---------------------- | ----------------------------------------------- | -| MF Remote | 管理后台是微前端远程模块 | -| 暴露的 remote 模块 | AdminApp(管理后台完整应用)、shared 管理端组件 | -| module federation 配置 | `apps/admin-portal/module-federation.config.ts` | +| 角色 | 说明 | +| ---- | ---- | +| MF Remote | admin-portal 是微前端远程模块,挂载到 teacher-portal Shell | +| Remote 名称 | `admin_app`(Shell `remotes` 中引用为 `admin: 'admin_app@http://localhost:4003/_next/static/chunks/remoteEntry.js'`) | +| 暴露模块 | `./AdminApp`(管理后台应用入口,供 Shell 动态 import) | +| MF 配置位置 | `apps/admin-portal/next.config.js`(NextFederationPlugin,对齐 ARB-002 §2.2 配置风格) | +| shared(singleton) | react / react-dom / urql / graphql / @edu/ui-tokens / @edu/ui-components / @edu/hooks / @edu/contracts | +| 复用 Shell 暴露 | `GraphQLProvider` / `AppShell` / `useAuth` / `usePermission` / `useGraphQLClient` / `ErrorBoundary` / `RequirePermission` 等(ARB-002 §2.2) | + +> admin-portal **不暴露共享组件给 Shell**(共享组件由 Shell 统一暴露,对齐 ARB-002)。admin 特有组件(UserManagementTable / RolePermissionMatrix / ViewportConfigEditor)仅 admin-portal 内部使用。 + +### 1.7 i18n 命名空间 + +| 命名空间 | 用途 | +| -------- | ---- | +| `admin.*` | 管理端 UI 文案(导航/按钮/表单标签等) | +| `iam.error.*` | iam 服务错误码 i18n(透传) | +| `bff.error.*` | teacher-bff 错误码 i18n(透传) | +| `gateway.error.*` | api-gateway 错误码 i18n(透传) | +| `network.error.*` | 前端网络层错误 i18n | --- @@ -55,28 +77,49 @@ ### 2.2 Kafka 事件订阅(异步) -无。前端不直接订阅 Kafka(审计日志通过 GraphQL 查询,非直接订阅)。 +无。前端不直接订阅 Kafka。审计日志经 teacher-bff 聚合后通过 GraphQL `auditLogs` Query 消费(链路:iam → Kafka `edu.iam.audit.created` → **teacher-bff 消费** → GraphQL → admin-portal)。 -### 2.3 HTTP 调用(如有) +> 注:[matrix.md §4](../matrix.md) 将 admin-portal 列为 `edu.iam.audit.created` 消费方,表述不精确,已提请 coord 修正为 teacher-bff(见 [objections ISSUE-007](../objections/admin-portal_issue.md))。 -| 被调用方 | Method.Path | 用途 | mock 策略 | -| ------------------- | ----------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------- | -| api-gateway (ai01) | POST /api/admin/graphql | 管理 GraphQL 查询(经网关代理到 teacher-bff admin namespace) | api-gateway/teacher-bff 就绪前使用 MSW 拦截返回 mock GraphQL 响应 | -| api-gateway (ai01) | POST /api/auth/login | 管理员登录 | api-gateway 就绪前使用 MSW 返回固定 JWT(admin 角色) | -| push-gateway (ai02) | GET /ws | WebSocket 实时通知 | push-gateway 就绪前使用 mock-socket 模拟 WS 推送 | +### 2.3 HTTP 调用 -### 2.4 GraphQL 查询域(经 api-gateway 代理到 teacher-bff admin namespace) +| 被调用方 | Method.Path | 用途 | mock 策略 | +| -------- | ----------- | ---- | --------- | +| api-gateway (ai01) | POST /api/admin/graphql | 管理 GraphQL 查询(经网关代理到 teacher-bff admin 命名空间) | api-gateway/teacher-bff 就绪前使用 MSW 拦截返回 mock GraphQL 响应 | +| push-gateway (ai02) | GET /ws | WebSocket 实时通知(审计告警/异常登录/系统异常) | push-gateway 就绪前使用 mock-socket 模拟 WS 推送(**ISSUE-006 待 coord 仲裁**) | -| Query/Mutation | 用途 | mock 策略 | -| ------------------------------------------------- | ------------------------------- | ----------------------------------------------------------------------------------- | -| currentUser | 当前管理员信息 | MSW 返回固定管理员(admin 角色) | -| adminUsers / createUser / updateUser / deleteUser | 用户管理 | MSW 返回固定 50 个用户 + CRUD success | -| adminRoles / updateRolePermissions | 角色权限管理 | MSW 返回固定 5 个角色 + 权限矩阵 | -| adminClasses | 班级管理(全局) | MSW 返回固定 20 个班级 | -| adminTeachers | 教师管理 | MSW 返回固定 50 个教师 | -| adminStudents | 学生管理 | MSW 返回固定 1200 个学生 | -| auditLogs | 审计日志(聚合 iam AuditEvent) | MSW 返回固定 100 条审计日志 | -| adminDashboard | 管理员仪表盘 | MSW 返回固定仪表盘(total_teachers=50, total_students=1200, school_avg_score=80.0) | +> **登录不自行实现**:admin-portal 复用 Shell 统一登录入口 `/login`(ARB-002 §2.3:登录页 P2 不走 MF,Shell 独占)。管理员登录后按 admin 角色重定向到 `/admin/dashboard`。开发期 mock 登录由 Shell 的 MSW handler 提供(admin 角色 JWT + permissions=["*"])。 + +### 2.4 GraphQL 查询域(经 api-gateway 代理到 teacher-bff admin 命名空间) + +> 依赖 teacher-bff admin 命名空间 schema(ARB-001,**ISSUE-005 待 ai03 补齐**)。以下为 admin-portal 消费的 Query/Mutation 清单,作为 ai03 补齐 schema 的输入。 + +| Query/Mutation | 类型 | 用途 | mock 策略 | +| -------------- | ---- | ---- | --------- | +| `currentUser` | Query | 当前管理员信息 | MSW 返回固定管理员(admin 角色) | +| `adminUsers` | Query | 用户列表(含筛选/分页) | MSW 返回固定 50 个用户 | +| `adminUser(id)` | Query | 用户详情 | MSW 返回对应用户 | +| `createUser` / `updateUser` / `deleteUser` / `toggleUserStatus` | Mutation | 用户 CRUD | MSW 返回 CRUD success | +| `adminRoles` | Query | 角色列表(含权限) | MSW 返回固定 5 个角色 + 权限矩阵 | +| `createRole` / `updateRolePermissions` | Mutation | 角色 CRUD + 权限矩阵 | MSW 返回 success | +| `adminPermissions` | Query | 全量权限点(按 resource 分组) | MSW 返回固定权限矩阵 | +| `adminViewports(scope)` | Query | 视口配置列表 | MSW 返回固定 7 个视口 | +| `updateViewport` | Mutation | 视口配置更新 | MSW 返回 success | +| `adminOrganization(parentId)` | Query | 组织树 | MSW 返回固定 school/grade/class 树 | +| `adminClasses` | Query | 班级管理(全局) | MSW 返回固定 20 个班级 | +| `adminTeachers` | Query | 教师管理 | MSW 返回固定 50 个教师 | +| `adminStudents` | Query | 学生管理 | MSW 返回固定 1200 个学生 | +| `auditLogs(filter)` | Query | 审计日志(聚合 iam AuditEvent) | MSW 返回固定 100 条审计日志 | +| `adminDashboard` | Query | 管理员仪表盘聚合 | MSW 返回固定仪表盘(total_teachers=50, total_students=1200, school_avg_score=80.0) | + +### 2.5 消费的错误码前缀(前端 i18n 路由) + +| 前缀 | 来源服务 | i18n key 模式 | +| ---- | -------- | ------------- | +| `IAM_` | iam | `iam.error.{{code}}` | +| `BFF_TEACHER_` | teacher-bff | `bff.error.{{code}}` | +| `GW_` | api-gateway | `gateway.error.{{code}}` | +| `NETWORK_` | 前端网络层 | `network.error.{{code}}` | --- @@ -85,18 +128,21 @@ ### 3.1 我依赖的上游就绪标志 - [ ] api-gateway HTTP :8080 启用(ai01)—— 前端请求入口 + admin 角色校验 -- [ ] teacher-bff GraphQL :3003 启用(ai03)—— admin namespace 可用 +- [ ] teacher-portal Shell MF exposes/shared 就绪(ai13,ARB-002)—— Remote 挂载前提 +- [ ] teacher-bff GraphQL :3003 启用 + **admin 命名空间 schema 就绪**(ai03)—— **ISSUE-005 待 ai03 补齐** - [ ] iam gRPC 50052 启用(ai06)—— 用户/角色/审计日志数据来源 -- [ ] edu.iam.audit.created topic 有事件发布(ai06)—— 审计日志来源 -- [ ] data-ana gRPC 50055 启用(ai11)—— adminDashboard 数据来源 -- [ ] push-gateway WebSocket :8081/ws 启用(ai02)—— 实时通知 +- [ ] `edu.iam.audit.created` topic 有事件发布(ai06)—— 审计日志来源(经 teacher-bff 消费) +- [ ] push-gateway WebSocket :8081/ws 启用(ai02)—— 实时通知(**ISSUE-006 待 coord 仲裁**) +- [ ] `packages/contracts` admin 权限点 `ADMIN_*` 常量就绪(coord) + +> 注:adminDashboard 的数据聚合由 teacher-bff 完成(teacher-bff 内部聚合 iam + core-edu + data-ana)。admin-portal **不直连 data-ana / core-edu gRPC**,统一经 teacher-bff GraphQL。原 contract 误列 data-ana gRPC 50055 为直接依赖,已修正。 ### 3.2 我的就绪标志(供下游消费) - [ ] admin-portal dev server :4003 启用 -- [ ] MF Remote 可被 AppShell 加载(暴露 AdminApp 模块) +- [ ] MF Remote 可被 AppShell 加载(暴露 `./AdminApp` 模块) - [ ] 独立壳渲染(首页 + 导航 + 路由守卫 + admin 角色校验) -- [ ] 登录流程可用(POST /api/auth/login 获取 JWT,前端校验 admin 角色) +- [ ] 登录流程可用(复用 Shell `/login`,admin 角色校验后重定向 `/admin/dashboard`) - [ ] GraphQL 查询可执行(currentUser / adminDashboard / auditLogs 返回数据) - [ ] 用户/角色 CRUD 可执行(createUser / updateRolePermissions) - [ ] WebSocket 通知可接收 @@ -117,13 +163,25 @@ admin-portal 是前端,无下游消费方。但对开发体验提供: 在真实上游就绪前,admin-portal 使用以下 mock: - **HTTP/GraphQL mock**:使用 MSW 拦截所有请求 - - POST /api/auth/login → 返回固定 JWT + UserInfo(admin 角色,permissions=["*"]) - - POST /api/admin/graphql → 根据 operationName 返回对应 mock 响应(与 teacher-bff admin namespace mock 数据一致) + - POST /api/admin/graphql → 按 operationName 返回对应 mock 响应(与 teacher-bff admin namespace mock 数据一致) - auditLogs mock 返回固定 100 条审计日志(含 action: create/update/delete/login/logout/permission_change) - adminDashboard mock 返回固定全校统计仪表盘 - 所有 mock 响应定义在 `apps/admin-portal/src/mocks/fixtures/*.json` - **WebSocket mock**:使用 mock-socket 库 - - 连接后每 30 秒推送 1 条 mock 系统通知 -- **JWT mock**:使用固定 mock JWT(admin 角色),存入 httpOnly cookie + - 连接后每 30 秒推送 1 条 mock 系统通知(审计告警/异常登录) +- **JWT mock**:使用固定 mock JWT(admin 角色,permissions=["*"]),由 Shell MSW handler 写入 httpOnly cookie(复用 Shell 登录 mock) - **权限矩阵 mock**:内置固定 5 个角色 + 完整权限矩阵(teacher/student/parent/admin/super_admin) - **环境切换**:通过 `NEXT_PUBLIC_API_MOCKING=enabled` 环境变量控制,上游就绪后设为 `disabled` + +--- + +## §5 跨模块契约确认清单(需对应 AI 确认) + +| 契约 | 提供方 | 当前状态 | +| ---- | ------ | -------- | +| teacher-bff admin 命名空间 schema(§2.4 全部 Query/Mutation) | ai03 | ⚠️ 待补齐(ISSUE-005) | +| Shell 暴露 GraphQLProvider / useGraphQLClient / AppShell / useAuth / usePermission | ai13 | ⏳ P2 交付(ARB-002) | +| iam 用户/角色/权限/视口 CRUD gRPC + AuditEvent Kafka | ai06 | ⏳ P2.1 | +| api-gateway /api/admin/graphql 代理路由 + admin 角色校验 | ai01 | ⏳ | +| push-gateway GET /ws(admin-portal 实时通知) | ai02 | ⚠️ 待 coord 仲裁(ISSUE-006) | +| `packages/contracts` ADMIN_* 权限点常量 | coord | ⏳ | diff --git a/docs/architecture/issues/objections/admin-portal_issue.md b/docs/architecture/issues/objections/admin-portal_issue.md index 818e03b..4178242 100644 --- a/docs/architecture/issues/objections/admin-portal_issue.md +++ b/docs/architecture/issues/objections/admin-portal_issue.md @@ -1,24 +1,109 @@ # admin-portal 问题记录 > 负责人:ai16 -> 关联:[coord.md](../coord.md)、[contracts/admin-portal_contract.md](../contracts/admin-portal_contract.md) +> 关联:[coord.md](../coord.md)、[contracts/admin-portal_contract.md](../contracts/admin-portal_contract.md)、[matrix.md](../matrix.md)、[ai-allocation.md §5 ai16](../../ai-allocation.md) > 规则:AI 遇到问题时在此追加条目,coord 仲裁后更新状态 --- +## §0 已有仲裁核查(ai16 复核) + +> 任务要求:对 coord 已有仲裁进行核查。以下为 ai16 对照 admin-portal 实际职责逐条复核结论。 + +### 0.1 ARB-001(teacher-bff GraphQL schema 第一版)— 核查结论:✅ 通过,但存在依赖缺口 + +- **核查点**:ARB-001 §1.3 裁决"admin 命名空间 P2 不包含,P6 admin-portal 阶段新增 admin 命名空间"。 +- **核查结论**:裁决方向正确(admin-portal 复用 teacher-bff + admin schema 命名空间,与 ai-allocation §5 ai16 设计重点一致)。 +- **发现的缺口**:teacher-bff 当前 [02-architecture-design.md](../../../services/teacher-bff/docs/02-architecture-design.md) **未定义 admin 命名空间的 GraphQL schema**(全文仅 1 处 audit 提及,无 adminUsers/adminRoles/auditLogs/adminDashboard 等 Query)。admin-portal P6 的全部业务查询依赖该 schema,属前置依赖缺失。 +- **建议**:请 coord 仲裁 admin 命名空间 schema 的归属与时间点——是否由 ai03(teacher-bff)在 P6 启动前补齐 `packages/shared-ts/contracts/graphql/teacher-bff.graphql` 的 admin 命名空间部分(参照本模块 [contract §2.4](../contracts/admin-portal_contract.md) 的 Query 清单)。 +- **状态**:待 coord 仲裁(见新异议 ISSUE-005) + +### 0.2 ARB-002(MF Shell 暴露清单)— 核查结论:✅ 通过,但 01/02 文档未跟进 + +- **核查点**:ARB-002 §2.2 Shell 暴露清单含 `GraphQLProvider` / `useGraphQLClient` / `useAuth` / `usePermission` / `AppShell` / `ErrorBoundary` / `Loading` / `Empty` / `RequirePermission`,**不含** `useApi` / `ApiClient`。 +- **核查结论**:裁决正确。admin-portal 应通过 `useGraphQLClient()` 消费 teacher-bff GraphQL,而非 REST ApiClient。 +- **发现的问题**:本模块 [01-understanding.md](../../../apps/admin-portal/docs/01-understanding.md) 与 [02-architecture-design.md](../../../apps/admin-portal/docs/02-architecture-design.md) 仍基于 REST `useApi()` / `ApiClient` 编写,未跟进 ARB-002。属本模块文档与仲裁不同步(见新异议 ISSUE-003)。 +- **状态**:本模块文档待修订(见 ISSUE-003) + +### 0.3 未仲裁但影响 admin-portal 的关键项 + +ARB-001/ARB-002 均未明确仲裁以下三项,而它们直接影响 admin-portal 实现,建议 coord 补充裁决: + +| 待裁决项 | 当前依据 | 影响 | +| -------- | -------- | ---- | +| admin-portal 端口 | matrix.md / ai-allocation.md = 4003 | 01/02 文档误用 3003(与 teacher-bff 冲突) | +| admin-portal 是否消费 push-gateway WebSocket | 同类 portal(parent-portal)契约 = 消费 | 01/02 文档误声明"不消费推送" | +| 审计日志消费机制(iam Kafka → teacher-bff → GraphQL auditLogs) | matrix.md §4 列 admin-portal 为 edu.iam.audit.created 消费方 | 前端不直连 Kafka,需经 teacher-bff 聚合,matrix.md 表述不精确 | + +--- + ## 问题列表 - +### ISSUE-002-ai16:01/02 文档端口错误(3003 → 4003),且 3003 与 teacher-bff 冲突 -(暂无问题) +- **提请方**:ai16 +- **日期**:2026-07-10 +- **类型**:契约不明确 / 编号冲突 +- **描述**:01 §1 与 02 §12.1 声明 admin-portal 端口 3003,并称"与 [full-stack-runbook](../../../docs/standards/full-stack-runbook.md) 端口矩阵对齐"。但 full-stack-runbook §2.1 中 **3003 = teacher-bff**,admin-portal 未列入该 runbook。coord 维护的 [matrix.md §1](../matrix.md) 与 ai-allocation.md 统一采用 4000 段:teacher-portal :4000 / student-portal :4001 / parent-portal :4002 / admin-portal :4003。 +- **建议方案**:确认 admin-portal 端口为 **4003**;同步更新 full-stack-runbook §2.1 补齐 4 个 portal 的 4000 段端口(消除 runbook 与 matrix.md 的端口双轨制)。 +- **状态**:待 coord 仲裁 + +### ISSUE-003-ai16:01/02 文档通信协议与 ARB-001/ARB-002 不一致(REST → GraphQL) + +- **提请方**:ai16 +- **日期**:2026-07-10 +- **类型**:契约不明确 / 前置依赖缺失 +- **描述**:01 §3.1 / 02 §1、§4 全文基于 REST(`/api/v1/iam/*` + `/api/v1/admin/*` + `useApi()` + `ApiClient`)。但 ARB-001 已裁决 admin-portal 复用 teacher-bff GraphQL **admin 命名空间**,ARB-002 已裁决 Shell 暴露 `GraphQLProvider` + `useGraphQLClient`(不含 `useApi`)。02 §11.3 仍将"GraphQL vs REST"列为未决,与仲裁结论冲突。根因:01/02 文档参照的 teacher-portal 02 文档(同样基于 REST、将 GraphQL 列为未决)早于 ARB-001/002(2026-07-09),未跟进仲裁。 +- **建议方案**:admin-portal 通信协议统一为 GraphQL(`POST /api/admin/graphql` → teacher-bff admin 命名空间);删除 `useApi`/`ApiClient` 依赖,改用 `useGraphQLClient()`;02 §11.3 移除已裁决项。本模块 [contract.md](../contracts/admin-portal_contract.md) 已按 GraphQL 编写,作为修订基准。 +- **状态**:待 coord 仲裁 + +### ISSUE-004-ai16:01/02 文档遗漏审计日志与学校设置(ai-allocation §5 明确职责) + +- **提请方**:ai16 +- **日期**:2026-07-10 +- **类型**:工作量超批 / 契约不明确 +- **描述**:[ai-allocation.md §5 ai16](../../ai-allocation.md) 第 282 行明确 admin-portal 设计重点含"用户管理 + 角色权限管理 + 学校设置 + 组织管理 + **审计日志消费**"。但 01 §2.1/§L1 导航/§L2 路由表均**无审计日志、无学校设置**(仅有 dashboard/users/roles/permissions/viewports/organization/monitoring 7 个视口)。本模块 [contract.md §1.2/§2.4](../contracts/admin-portal_contract.md) 已含 audit-logs / system 路由与 auditLogs Query,与 01/02 不一致。 +- **建议方案**:admin-portal 视口补齐为 9 个:dashboard / users / roles / permissions / viewports / organization / classes / teachers / students / audit-logs / system(按 ai-allocation §5 + contract §1.2 对齐);审计日志经 teacher-bff GraphQL `auditLogs` Query 消费(聚合 iam `AuditEvent`)。 +- **状态**:待 coord 仲裁 + +### ISSUE-005-ai16:teacher-bff 缺 admin 命名空间 GraphQL schema(前置依赖缺失) + +- **提请方**:ai16 +- **日期**:2026-07-10 +- **类型**:前置依赖缺失 +- **描述**:ARB-001 裁决 P6 新增 admin 命名空间,但 teacher-bff [02-architecture-design.md](../../../services/teacher-bff/docs/02-architecture-design.md) 未定义该 schema(无 adminUsers / adminRoles / adminClasses / adminTeachers / adminStudents / auditLogs / adminDashboard 等 Query/Mutation)。admin-portal P6 全部业务查询依赖此 schema,且需 SDL-first 存放于 `packages/shared-ts/contracts/graphql/teacher-bff.graphql`(ARB-001 §1.3)。 +- **建议方案**:请 coord 仲裁——由 ai03 在 P6 启动前补齐 teacher-bff admin 命名空间 schema(参照本模块 contract §2.4 Query 清单),作为 admin-portal P6 的前置就绪信号;并更新 [matrix.md §3](../matrix.md) teacher-bff 行的 schema 文件状态。 +- **状态**:待 coord 仲裁 + +### ISSUE-006-ai16:01/02 文档推送策略与同类 portal 契约不一致(轮询 → WebSocket) + +- **提请方**:ai16 +- **日期**:2026-07-10 +- **类型**:契约不明确 +- **描述**:01 §3.3 / 02 §5 声明 admin-portal"不消费 WebSocket/SSE,采用轮询"。但同类 portal 契约([parent-portal_contract.md §2.3](./parent-portal_contract.md))消费 push-gateway `GET /ws`,本模块 [contract.md §2.3](../contracts/admin-portal_contract.md) 亦声明消费 WebSocket 实时通知。matrix.md §5 列 push-gateway WS 消费方含全部 portal。管理端审计告警/异常登录等场景对实时性有合理需求。 +- **建议方案**:admin-portal 接入 push-gateway WebSocket(与同类 portal 一致),用于审计告警、异常登录、系统异常等实时通知;保留轮询仅用于监控指标(60s)与统计(5min)这类天然适合轮询的低频数据。 +- **状态**:待 coord 仲裁 + +### ISSUE-007-ai16:matrix.md §4 将 admin-portal 列为 Kafka 直消费方,与前端层级矛盾 + +- **提请方**:ai16 +- **日期**:2026-07-10 +- **类型**:契约不明确 +- **描述**:[matrix.md §4](../matrix.md) 第 111 行将 admin-portal 列为 `edu.iam.audit.created` 的消费方。但前端不直连 Kafka([contract.md §2.2](../contracts/admin-portal_contract.md) 已明确审计日志经 GraphQL 查询)。实际链路应为:iam → Kafka → **teacher-bff** 消费 → GraphQL `auditLogs` Query → admin-portal。 +- **建议方案**:matrix.md §4 该行消费方更正为 **teacher-bff**(admin-portal 经 teacher-bff 间接消费),避免误导架构分层。 +- **状态**:待 coord 仲裁 + +--- + +## §1 历史问题 + +(暂无已裁决问题) diff --git a/docs/architecture/issues/worklines/admin-portal_workline.md b/docs/architecture/issues/worklines/admin-portal_workline.md index 9e00175..5f34d7e 100644 --- a/docs/architecture/issues/worklines/admin-portal_workline.md +++ b/docs/architecture/issues/worklines/admin-portal_workline.md @@ -1,45 +1,246 @@ # admin-portal 工作排期 > 负责人:ai16 -> 关联:[workline.md](../workline.md)、[coord.md](../coord.md)、[contracts/admin-portal_contract.md](../contracts/admin-portal_contract.md) -> 模式:全并行(各 AI 一口气完成 P2-P6 全部代码,最后统一集成测试) +> 关联:[workline.md](../workline.md)、[coord.md](../coord.md)、[contracts/admin-portal_contract.md](../contracts/admin-portal_contract.md)、[ai-allocation.md §5 ai16](../../ai-allocation.md) +> 模式:全并行(各 AI 一口气完成 P2-P6 全部代码,开发期间用 mock,最后统一集成测试) +> 说明:本排期基于 GraphQL(ARB-001 admin 命名空间)+ 端口 4003 + ai16 归属,已对齐 [matrix.md](../matrix.md) 与 ai-allocation.md。01/02 文档中 REST/3003/ai07 表述待 coord 仲裁后修订(见 [objections/admin-portal_issue.md](../objections/admin-portal_issue.md))。 --- ## §1 总览 -admin-portal 是管理端微前端,通过 MF Remote 接入主应用,覆盖用户管理、角色权限、审计日志等场景。全阶段目标:P2 MF Remote 骨架 → P3 用户管理+角色权限+审计日志 → P4-P6 持续优化。 +admin-portal 是管理端微前端(MF Remote),挂载到 teacher-portal Shell,覆盖**用户管理 / 角色权限管理 / 学校设置 / 组织管理 / 审计日志消费**等管理场景(ai-allocation §5 ai16)。复用 teacher-bff GraphQL endpoint 的 **admin 命名空间**(ARB-001),admin 权限点使用 `ADMIN_` 前缀(ai-allocation §5)。 + +全阶段目标: + +- **P2**:MF Remote 骨架(next.config.js + MF 配置 + 独立壳渲染 + MSW mock) +- **P3**:用户管理 + 角色权限管理(admin 命名空间 Query/Mutation) +- **P4**:组织管理 + 学校设置 + 班级/教师/学生全局管理 +- **P5**:审计日志消费(auditLogs Query 聚合 iam AuditEvent)+ WebSocket 实时通知 +- **P6**:硬化(A11y WCAG 2.2 AA / Web Vitals / OTel / 测试覆盖率 ≥ 80% / Dockerfile 多阶段) + +> 跨阶段:开发期间全部经 MSW mock(见 [contract §4](../contracts/admin-portal_contract.md)),上游就绪后逐项切换真实。 --- -## §2 全阶段甘特图(P2-P6,各 AI 自行细化) +## §2 全阶段甘特图(P2-P6) ```mermaid gantt - title ai16 admin-portal 全阶段排期 + title ai16 admin-portal 全阶段排期(P2-P6) dateFormat YYYY-MM-DD axisFormat %m-%d - section P2-P6 - [阶段任务] :a16a, 2026-07-10, Xd + section P2 骨架 + 16.1 MF Remote 骨架(next.config+独立壳) :crit, a16a, 2026-07-10, 2d + 16.2 MSW handlers+fixtures+mock JWT :a16b, after a16a, 2d + 16.3 接入Shell共享(GraphQLProvider/AppShell/useAuth) :crit, a16c, after a16a, 2d + + section P3 用户/角色权限 + 16.4 用户管理页(users CRUD+UserManagementTable) :crit, a16d, after a16c, 3d + 16.5 角色权限矩阵(RolePermissionMatrix+updateRolePermissions) :a16e, after a16d, 3d + 16.6 权限点管理+视口配置(ADMIN_前缀) :a16f, after a16e, 2d + + section P4 组织/学校/全局实体 + 16.7 组织树管理(organization) :a16g, after a16f, 2d + 16.8 学校设置(system) :a16h, after a16g, 2d + 16.9 班级/教师/学生全局管理(adminClasses/Teachers/Students) :a16i, after a16h, 3d + + section P5 审计日志/实时通知 + 16.10 审计日志页(auditLogs Query+筛选/导出) :crit, a16j, after a16i, 3d + 16.11 WebSocket实时通知(审计告警/异常登录) :a16k, after a16j, 2d + 16.12 管理仪表盘(adminDashboard聚合) :a16l, after a16k, 2d + + section P6 硬化 + 16.13 A11y WCAG 2.2 AA审计+修复 :crit, a16m, after a16l, 3d + 16.14 Web Vitals+OTel browser SDK接入 :a16n, after a16m, 2d + 16.15 Vitest单测+Playwright E2E(≥80%) :crit, a16o, after a16n, 3d + 16.16 Dockerfile多阶段+/api/health+/api/ready :a16p, after a16o, 2d ``` -> **注意**:以上为 coord 初始规划,ai16 接管后必须自行细化为完整 P2-P6 排期。 +> 关键路径(crit):16.1 → 16.3 → 16.4 → 16.10 → 16.13 → 16.15。总工期约 34 个工作日。 --- ## §3 详细任务 -### 全阶段任务 +### P2 阶段 + +#### 16.1 MF Remote 骨架(next.config + 独立壳) - **负责人**:ai16 -- **交付物**:⚠️ 由 ai16 自行补充 -- **依赖**:见 [contracts/admin-portal_contract.md](../contracts/admin-portal_contract.md) -- **验收标准**:⚠️ 由 ai16 自行补充 +- **依赖**:teacher-portal Shell MF exposes/shared 配置就绪(ARB-002,ai13 P2 交付) +- **交付物**: + - `apps/admin-portal/next.config.js`(NextFederationPlugin,Remote 角色,`name: 'admin_app'`,`filename: 'static/chunks/remoteEntry.js'`,`exposes: { './AdminApp': './src/app/admin-app.tsx' }`,shared 全部 singleton) + - `apps/admin-portal/src/app/admin-app.tsx`(独立壳入口,供 Shell 动态加载 + 独立 dev 渲染) + - `apps/admin-portal/src/app/standalone.tsx`(独立 dev 壳:自实现 AppShell 占位 + mock providers,供 `pnpm --filter admin-portal dev` 在 :4003 独立预览) + - `tsconfig.json`(沿用 tsconfig.base.json)、`tailwind.config.js`(引入 `@edu/ui-tokens`)、`package.json` +- **验收标准**: + - `pnpm --filter admin-portal dev` 在 :4003 启动,独立壳渲染首页 + 导航占位 + - MF `remoteEntry.js` 可被 Shell `dynamic import` 加载(feature flag `NEXT_PUBLIC_MF_ENABLED` 控制) + - shared 单例配置通过(react/react-dom/urql/graphql/@edu/* 全 singleton) + +#### 16.2 MSW handlers + fixtures + mock JWT + +- **负责人**:ai16 +- **依赖**:无(mock 先行) +- **交付物**: + - `apps/admin-portal/src/mocks/handlers.ts`(拦截 `POST /api/admin/graphql` + `POST /api/auth/login` + `GET /ws`) + - `apps/admin-portal/src/mocks/fixtures/*.json`(50 用户 / 5 角色 / 20 班级 / 50 教师 / 1200 学生 / 100 审计日志 / 仪表盘统计) + - mock JWT(admin 角色,permissions=["*"],httpOnly cookie) +- **验收标准**: + - `NEXT_PUBLIC_API_MOCKING=enabled` 时所有请求被 MSW 拦截返回 mock + - GraphQL mock 按 operationName 返回对应 fixture(与 teacher-bff admin namespace mock 数据一致) + +#### 16.3 接入 Shell 共享(GraphQLProvider/AppShell/useAuth) + +- **负责人**:ai16 +- **依赖**:ARB-002 Shell 暴露清单就绪(ai13) +- **交付物**: + - `AdminApp` 通过 MF `import from 'teacher/GraphQLProvider'`、`'teacher/AppShell'`、`'teacher/useAuth'`、`'teacher/usePermission'`、`'teacher/useGraphQLClient'` + - `` 渲染管理端视口导航 + - GraphQL client 经 `useGraphQLClient()` 获取(**不使用 useApi/ApiClient**,对齐 ARB-002) +- **验收标准**: + - urql client 单例跨 Remote 共享(与 Shell 同一实例) + - `currentUser` Query 返回 mock 管理员信息 + - admin 角色校验:非 admin 角色重定向到登录页 + +### P3 阶段 + +#### 16.4 用户管理页(users CRUD + UserManagementTable) + +- **负责人**:ai16 +- **依赖**:teacher-bff admin 命名空间 `adminUsers`/`createUser`/`updateUser`/`deleteUser` schema(ISSUE-005 待 coord 仲裁 ai03 补齐) +- **交付物**: + - `/admin/users` 列表页(UserManagementTable:邮箱/姓名/角色/状态/数据范围/最后登录 + 筛选/分页/批量操作) + - `/admin/users/new` + `/admin/users/:id` 表单页(react-hook-form + zodResolver) + - admin 业务 Hooks:`useUsers` / `useUser` / `useCreateUser` / `useUpdateUser` / `useToggleUserStatus`(urql query/mutation) +- **验收标准**: + - 列表筛选/分页正常,mutation 后 invalidate 刷新 + - DataScope L3-L5 越权由后端强制,前端 `AdminDataScopeFilter` 仅作 UI 提示 + - 权限:`IAM_USER_READ` / `IAM_USER_CREATE` / `IAM_USER_UPDATE` + +#### 16.5 角色权限矩阵(RolePermissionMatrix + updateRolePermissions) + +- **负责人**:ai16 +- **依赖**:teacher-bff `adminRoles` / `updateRolePermissions` schema +- **交付物**: + - `/admin/roles` 页(RolePermissionMatrix:行=角色,列=权限按 resource 分组;checkbox 网格) + - 系统预置角色只读(isSystem=true 不可编辑/删除) + - Hooks:`useRoles` / `useRole` / `useCreateRole` / `useUpdateRolePermissions` +- **验收标准**: + - 勾选触发 `updateRolePermissions` Mutation,乐观更新 + 失败回滚 + - 删除前校验 userCount > 0 时禁用删除并提示 + +#### 16.6 权限点管理 + 视口配置(ADMIN_ 前缀) + +- **负责人**:ai16 +- **依赖**:`packages/contracts/src/permissions.ts`(coord 维护,admin 权限点 `ADMIN_*` 前缀) +- **交付物**: + - `/admin/permissions` 只读列表(DataTable,按 resource 分组) + - `/admin/viewports` 视口配置编辑器(ViewportConfigEditor:@dnd-kit 拖拽排序 + 权限绑定 + scope/isVisible) + - Hooks:`usePermissions`(30min 缓存)/ `useViewportsConfig` / `useUpdateViewport` +- **验收标准**: + - 权限点常量来自 `@edu/contracts`(不硬编码) + - 视口配置保存后 AppShell 导航即时刷新(invalidate viewports queryKey) + +### P4 阶段 + +#### 16.7 组织树管理(organization) + +- **交付物**:`/admin/organization` 页(树形 + DataTable,school/grade/class 层级 CRUD) +- **验收标准**:树形展开/折叠 + 拖拽调整层级(后端校验)+ DataScope 过滤 + +#### 16.8 学校设置(system) + +- **交付物**:`/admin/system` 页(学校基础信息 / 学年学期 / 系统参数表单) +- **验收标准**:表单 zod 校验 + 保存后 toast 反馈;仅 L5 系统管理员可编辑 + +#### 16.9 班级/教师/学生全局管理 + +- **交付物**:`/admin/classes` / `/admin/teachers` / `/admin/students` 三个全局管理页(adminClasses/adminTeachers/adminStudents Query) +- **验收标准**:跨班级/跨年级全局视角(区别于 teacher-portal 的教师自身视角);DataScope 控制可见范围 + +### P5 阶段 + +#### 16.10 审计日志页(auditLogs Query + 筛选/导出) + +- **负责人**:ai16 +- **依赖**:teacher-bff 消费 `edu.iam.audit.created` Kafka 并暴露 `auditLogs` Query(ISSUE-007 待 coord 修正 matrix.md §4 消费方为 teacher-bff) +- **交付物**: + - `/admin/audit-logs` 页(DataTable:时间/操作人/action/resource/ip + 筛选:action/user/dateRange + 导出 CSV) + - Hooks:`useAuditLogs`(含游标分页) +- **验收标准**: + - 审计日志经 GraphQL 查询(**非直接订阅 Kafka**,对齐 contract §2.2) + - 100 条 mock 审计日志覆盖 create/update/delete/login/logout/permission_change + +#### 16.11 WebSocket 实时通知(审计告警/异常登录) + +- **交付物**: + - 接入 push-gateway `GET /ws`(与 parent-portal 同类契约一致,对齐 ISSUE-006) + - 审计告警 / 异常登录 / 系统异常 toast + 通知中心入口 +- **验收标准**: + - mock-socket 每 30s 推送 1 条 mock 系统通知 + - WebSocket 断线自动重连 + +#### 16.12 管理仪表盘(adminDashboard 聚合) + +- **交付物**:`/admin/dashboard` 页(recharts:total_teachers / total_students / school_avg_score / 趋势图) +- **验收标准**:adminDashboard Query 返回聚合数据;60s 轮询监控指标 + 5min 轮询统计 + +### P6 阶段(硬化) + +#### 16.13 A11y WCAG 2.2 AA 审计 + 修复 + +- **交付物**:eslint-plugin-jsx-a11y(error 级)+ 手动审计修复 +- **验收标准**:0 个 error 级违规 + +#### 16.14 Web Vitals + OTel browser SDK 接入 + +- **交付物**:`next/web-vitals` → `POST /api/admin/web-vitals`;OTel browser SDK(复用 Shell TracerProvider,scope='admin') +- **验收标准**:LCP/CLS/FID/TTFB 上报 + trace 上报 collector + +#### 16.15 Vitest 单测 + Playwright E2E(覆盖率 ≥ 80%) + +- **交付物**:`apps/admin-portal/src/**/*.test.tsx` + `e2e/*.spec.ts` +- **验收标准**:覆盖率 ≥ 80%,E2E 覆盖登录 → dashboard → 用户 CRUD → 审计日志主链路 + +#### 16.16 Dockerfile 多阶段 + /api/health + /api/ready + +- **交付物**:`apps/admin-portal/Dockerfile`(builder + runtime,非 root)+ `src/app/api/health/route.ts` + `src/app/api/ready/route.ts` +- **验收标准**:`/api/health` 返回 200;`/api/ready` 检查 Shell URL 可达;Dockerfile HEALTHCHECK 配置 --- ## §4 依赖与就绪信号 -- **我依赖**:⚠️ 由 ai16 自行补充(见 contract.md) -- **我的就绪信号**:⚠️ 由 ai16 自行补充 +### 4.1 我依赖(上游就绪标志) + +- [ ] teacher-portal Shell MF exposes/shared 就绪(ai13,ARB-002)—— Remote 挂载前提 +- [ ] teacher-bff GraphQL :3003 启用(ai03)—— admin 命名空间可用(**ISSUE-005 待 ai03 补齐 schema**) +- [ ] api-gateway HTTP :8080 启用 + JWT 验签 + admin 角色校验(ai01) +- [ ] iam gRPC 50052 启用(ai06)—— 用户/角色/审计日志数据来源 +- [ ] `edu.iam.audit.created` topic 有事件发布(ai06)—— 审计日志来源(经 teacher-bff 消费) +- [ ] push-gateway WebSocket :8081/ws 启用(ai02)—— 实时通知(**ISSUE-006 待 coord 仲裁**) +- [ ] `packages/contracts` admin 权限点 `ADMIN_*` 常量就绪(coord) + +### 4.2 我的就绪信号(供下游消费) + +- [ ] admin-portal dev server :4003 启用 +- [ ] MF Remote 可被 AppShell 加载(暴露 `./AdminApp` 模块) +- [ ] 独立壳渲染(首页 + 导航 + 路由守卫 + admin 角色校验) +- [ ] 登录流程可用(复用 Shell `/login`,admin 角色校验后重定向 `/admin/dashboard`)—— **不自行实现登录页**(对齐 ARB-002 §2.3) +- [ ] GraphQL 查询可执行(currentUser / adminDashboard / auditLogs 返回数据) +- [ ] 用户/角色 CRUD 可执行(createUser / updateRolePermissions) +- [ ] WebSocket 通知可接收 + +--- + +## §5 风险跟踪 + +| 风险 | 影响 | 缓解 | 状态 | +| ---- | ---- | ---- | ---- | +| teacher-bff admin namespace schema 缺失(ISSUE-005) | P3+ 全部业务页阻塞 | 提请 coord 仲裁 ai03 在 P3 启动前补齐;P2 用 MSW mock 推进 | ⏳ 待仲裁 | +| 01/02 文档 REST/3003/ai07 与仲裁不一致 | 误导实现 | 已提 7 项异议(ISSUE-001~007),以 contract.md 为修订基准 | ⏳ 待仲裁 | +| Shell 延迟暴露 GraphQLProvider | P2 骨架阻塞 | P2 用独立壳 + mock providers,Shell 就绪后切换 | ⏳ | +| MF SSR 对齐复杂 | Remote SSR 上下文依赖 Shell | 优先 CSR,SSR 仅首屏 dashboard | ⏳ |