# admin-portal 对接契约 > 负责人:ai16 > 关联:[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 接口 无。admin-portal 是前端微前端 Remote,不提供 gRPC。 ### 1.2 前端路由(MF Remote 暴露给 Shell 动态加载) > admin-portal 是前端,**不对外提供 HTTP 端点**。此处列出的是 admin-portal 在 Shell 路由树 `/admin/*` 下注册的前端页面路由,由 Shell 动态 import admin Remote 加载。 | 路由 | 页面 | 权限点 | 数据范围 | | ------------------- | ---------------- | ---------------------- | --------------- | | `/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_` / `IAM_` / `ORG_` 前缀(ai-allocation §5:admin 权限点 `ADMIN_` 前缀)。`ADMIN_*` 常量由 coord 维护于 `packages/contracts/src/permissions.ts`,前端不硬编码。 ### 1.3 GraphQL schema 不适用。admin-portal **消费** teacher-bff GraphQL admin 命名空间,自身不提供 schema。 ### 1.4 Kafka 事件发布 无。前端不发布 Kafka 事件。 ### 1.5 错误码前缀 无(前端不定义错误码前缀,透传 BFF/网关错误码)。消费的错误码前缀见 §2.5。 ### 1.6 微前端架构 | 角色 | 说明 | | ---- | ---- | | 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 | --- ## §2 我消费什么(依赖上游) ### 2.1 gRPC 调用(同步) 无。前端不直接调 gRPC。 ### 2.2 Kafka 事件订阅(异步) 无。前端不直接订阅 Kafka。审计日志经 teacher-bff 聚合后通过 GraphQL `auditLogs` Query 消费(链路:iam → Kafka `edu.iam.audit.created` → **teacher-bff 消费** → GraphQL → admin-portal)。 > 注:[matrix.md §4](../matrix.md) 将 admin-portal 列为 `edu.iam.audit.created` 消费方,表述不精确,已提请 coord 修正为 teacher-bff(见 [objections ISSUE-007](../objections/admin-portal_issue.md))。 ### 2.3 HTTP 调用 | 被调用方 | 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 仲裁**) | > **登录不自行实现**: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}}` | --- ## §3 就绪信号 ### 3.1 我依赖的上游就绪标志 - [ ] api-gateway HTTP :8080 启用(ai01)—— 前端请求入口 + admin 角色校验 - [ ] 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)—— 审计日志来源(经 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` 模块) - [ ] 独立壳渲染(首页 + 导航 + 路由守卫 + admin 角色校验) - [ ] 登录流程可用(复用 Shell `/login`,admin 角色校验后重定向 `/admin/dashboard`) - [ ] GraphQL 查询可执行(currentUser / adminDashboard / auditLogs 返回数据) - [ ] 用户/角色 CRUD 可执行(createUser / updateRolePermissions) - [ ] WebSocket 通知可接收 --- ## §4 Mock 策略 ### 4.1 我提供的 mock admin-portal 是前端,无下游消费方。但对开发体验提供: - **Storybook**:各组件独立 story(含权限矩阵编辑器、审计日志表格等复杂组件) - **MSW handlers**:`apps/admin-portal/src/mocks/handlers.ts`,拦截所有 GraphQL/HTTP 请求 ### 4.2 我消费的 mock 在真实上游就绪前,admin-portal 使用以下 mock: - **HTTP/GraphQL mock**:使用 MSW 拦截所有请求 - 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 角色,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 | ⏳ |