21 KiB
模块理解确认书 — admin-portal
AI:ai16(TS/React · 管理场景域前端 remote) 阶段:阶段 1 交付物(仲裁后修订版 v2) 日期:2026-07-10 关联:
- 004 架构影响地图 §1.1a/1.1b/§5.4
- AI 分配方案 §5 ai16
- 总统最终裁决 §5.1-5.5(ISSUE-044~048)
- admin-portal 对接契约
- admin-portal 工作线
- known-issues §2.16
0. 仲裁结果摘要(ARB-001~006)
| 编号 | 议题 | 裁决 |
|---|---|---|
| ARB-001 | BFF 归属(ISSUE-044) | 复用 teacher-bff GraphQL endpoint,不新建 admin-bff;ai03 预留 admin.* 命名空间 |
| ARB-002 | 错误码前缀(ISSUE-045) | ADMIN_ 前缀(合并 SCHOOL_/ORG_ 入 ADMIN_);i18n key error.admin.* |
| ARB-003 | 权限点命名(ISSUE-046) | admin 自身资源用 ADMIN_*;跨服务资源保留原前缀(IAM_USER_READ 等) |
| ARB-004 | GraphQL 客户端(ISSUE-047) | MF 模式复用 Shell 暴露的 GraphQL client 单例;standalone 模式自建 urql client |
| ARB-005 | 审计日志归属(ISSUE-048) | 审计事件归 iam 发布到 edu.iam.audit.created;teacher-bff 消费聚合;admin-portal 经 GraphQL auditLogs Query 消费 |
| ARB-006 | WebSocket 实时通知 | 接入 push-gateway GET /ws(审计告警/异常登录/系统异常),不再用轮询 |
| 端口分配 | admin-portal dev server | 4003(非旧文档的 3003) |
1. 我在架构中的位置
- 层级:L2 微前端层(004 §3.1 六层架构中的前端层)
- MF 角色:Remote 子应用,挂载到 teacher-portal Shell(主应用,端口 4000)
- 上游(谁调用我):浏览器(系统管理员 / 校管理员)
- 下游(同步):api-gateway(GraphQL
POST /api/admin/graphql+ REST/api/auth/login) - 下游(推送):push-gateway
GET /ws(WebSocket 实时通知,ARB-006) - BFF 对接:复用 teacher-bff GraphQL admin 命名空间(ARB-001),不新建 admin-bff
- 通信方式:GraphQL(业务数据)+ HTTP(登录)+ WebSocket(实时通知)
- 不直连:前端不直连任何业务服务或 BFF 后端实例,全部经 api-gateway 代理
说明:
- admin-portal 作为 Remote 子应用,挂载到 teacher-portal Shell
- Shell 暴露
GraphQLProvider/useGraphQLClient/AppShell/useAuth/usePermission等,admin-portal MF 模式复用,standalone 模式自建 - 路由前缀
/admin/*由 teacher-portal Shell 动态加载 admin-portal Remote 模块(暴露./AdminApp) - 场景域 BFF 复用策略(004 §5.4 + ARB-001):复用 teacher-bff GraphQL endpoint,admin 命名空间(
admin.*Query/Mutation)
2. 我的限界上下文
2.1 我负责的聚合 / 实体(前端视图模型)
- 用户、角色、权限、视口(管理场景域前端视图,调 iam 经 GraphQL)
- 组织(学校/年级/班级层级)
- 学校设置(system 路由)
- 班级/教师/学生全局管理(admin 视角,只读 + 状态管理)
- 审计日志(只读,经 teacher-bff GraphQL
auditLogsQuery 消费) - 管理仪表盘(聚合统计 + 服务健康)
- 实时通知(WebSocket 推送:审计告警/异常登录/系统异常)
2.2 业务领域
- 管理场景域(前端场景域:管理场景域,对应后端 iam 限界上下文 + teacher-bff admin 命名空间)
2.3 不负责
- 教学业务编排(班级/考试/作业/成绩 CRUD,归 teacher-portal)
- 学生作答界面(归 student-portal)
- 家长多子女切换(归 parent-portal)
- 教师仪表盘(归 teacher-portal,admin-portal 仅有管理仪表盘)
- 审计事件发布(归 iam,admin-portal 仅消费)
2.4 数据范围
- DataScope L3-L5(校管理员 L3 学校 / 区教研员 L4 / 系统管理员 L5 全平台)
- 不出现 L1(班级)/ L2(年级)级别的教师数据视角
3. 我与外部的契约
3.1 消费的后端 API(经 api-gateway 代理)
| 路径 | Method | 下游 BFF/服务 | 用途 |
|---|---|---|---|
/api/admin/graphql |
POST | teacher-bff(admin 命名空间) | 全部业务 GraphQL 查询(ARB-001) |
/api/auth/login |
POST | api-gateway → iam | 登录(standalone 模式用,MF 模式复用 Shell 登录) |
GET /ws(push-gateway) |
WS | push-gateway | 实时通知(审计告警/异常登录/系统异常,ARB-006) |
3.2 GraphQL Operations(contract §2.4)
admin-portal 消费 teacher-bff admin 命名空间的 18 个 GraphQL operations:
| Operation | 类型 | 用途 |
|---|---|---|
currentUser |
Query | 当前管理员信息 |
adminUsers / adminUser(id) |
Query | 用户列表 / 详情 |
createUser / updateUser / toggleUserStatus |
Mutation | 用户 CRUD |
adminRoles |
Query | 角色列表(含权限) |
createRole / updateRolePermissions |
Mutation | 角色 CRUD + 权限矩阵 |
adminPermissions |
Query | 全量权限点(按 resource) |
adminViewports(scope) |
Query | 视口配置列表 |
updateViewport |
Mutation | 视口配置更新 |
adminOrganization(parentId) |
Query | 组织树 |
adminClasses |
Query | 班级管理(全局) |
adminTeachers |
Query | 教师管理 |
adminStudents |
Query | 学生管理 |
auditLogs(filter) |
Query | 审计日志(聚合 iam AuditEvent) |
adminDashboard |
Query | 管理员仪表盘聚合 |
systemSettings / updateSystemSettings |
Query/Mutation | 学校设置 |
3.3 推送契约(ARB-006)
admin-portal 接入 push-gateway GET /ws,消费 3 类实时通知:
| 通知类型 | severity | 用途 |
|---|---|---|
audit_alert |
warning | 审计告警(敏感操作触发) |
abnormal_login |
error | 异常登录(异地/异常时段) |
system_error |
error | 系统异常(服务降级/宕机) |
不再用轮询:旧文档的"60s 轮询监控 + 5min 轮询统计"策略已被 ARB-006 替换为 WebSocket 实时推送。开发期用 mock-socket + 30s 定时器模拟推送。
3.4 proto 不直接消费
前端不调用 gRPC,teacher-bff 把 gRPC 聚合为 GraphQL 暴露给前端。前端仅消费 packages/contracts/src/permissions.ts 中的权限点常量(TS 文件,非 proto 生成)。
4. 我的技术栈
| 维度 | 选型 | 说明 |
|---|---|---|
| 框架 | Next.js 14+(App Router) | server components 默认,client components 按需 |
| 语言 | TypeScript 5.5+(strict) | 沿用 tsconfig.base.json |
| 微前端 | Module Federation 2.0(@module-federation/nextjs-mf) | admin-portal = Remote,端口 4003 |
| 数据层 | urql GraphQL client | standalone 自建 / MF 复用 Shell 单例(ARB-004) |
| 样式 | Tailwind CSS 3.4+ | 配合设计令牌三层(复用 Shell) |
| UI 组件库 | shadcn/ui 风格(复用 Shell @edu/ui-components) |
admin-portal 内部 ui.tsx 封装 PaperCard/Button/Table 等纸面组件 |
| 表单 | react-hook-form + zod | 用户表单/学校设置 |
| 拖拽排序 | @dnd-kit/sortable | 视口配置拖拽排序 |
| 图表 | recharts | 仪表盘趋势表(实际以纯表格为主,纸面风格) |
| i18n | 轻量 i18n(messages 字典 + t() 函数) |
命名空间 admin.*,不依赖 next-intl |
| Mock | MSW(Mock Service Worker)+ mock-socket | 开发期拦截全部 GraphQL/HTTP + WebSocket mock |
| Web Vitals | web-vitals v4 | LCP/CLS/FCP/INP/TTFB 采集,navigator.sendBeacon 上报 |
| A11y | eslint-plugin-jsx-a11y(error 级) | WCAG 2.2 AA |
| 字体 | Inter(sans)/ Fraunces(serif)/ JetBrains Mono(mono) | RootLayout 加载(standalone);MF 模式复用 Shell |
| 测试 | Vitest + @testing-library/react | jsdom 环境,覆盖率 ≥ 80% |
| ESLint | ESLint 9 flat config | jsx-a11y + tseslint + prettier(注:@next/eslint-plugin-next 14.x 与 ESLint 9 不兼容,已移除) |
技术栈差异(vs teacher-portal):MF 角色(Remote)、GraphQL 为主(非 REST)、消费 WebSocket 推送(非 SSE)、纸面 UI 风格、数据范围 L3-L5。
5. 我的阶段归属
- 阶段:P6(硬化阶段),批次 5
- 当前状态:✅ 已实现(P2-P6 全阶段交付完成,含 11 路由 + MSW mock + A11y + Web Vitals + Dockerfile)
- 依赖上游阶段:P6(依赖 teacher-portal Shell 已就绪 + teacher-bff GraphQL admin 命名空间 + iam 已实现用户/角色/权限/视口 CRUD + push-gateway WebSocket)
6. 路由表(11 路由,contract §1.2)
| 路由 | 页面 | 权限点 | 数据范围 |
|---|---|---|---|
/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 |
组织管理 | ADMIN_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 |
权限点前缀规则(ARB-003):admin 自身资源用
ADMIN_*;跨服务资源保留原前缀(如IAM_USER_READ)。ADMIN_*常量由 coord 维护于packages/contracts/src/permissions.ts,admin-portal 引用src/lib/permissions.ts,不硬编码。
7. 黄金模板对齐清单(前端等价)
| 对齐项 | 后端等价 | admin-portal 实现 | 状态 |
|---|---|---|---|
| 权限校验 | @RequirePermission(Permissions.XXX) |
usePermission().hasPermission("XXX") Hook + AuthGuard |
✅ |
| 错误码前缀 | IAM_* / ADMIN_* |
CONSUMED_ERROR_PREFIXES 常量 + i18n 路由 |
✅ |
| logger | pino | console + 结构化(生产 → 上报) | ✅ |
| metrics | prom-client /metrics |
Web Vitals v4 → navigator.sendBeacon 上报 |
✅ |
| /health + /ready | GET /healthz GET /readyz |
Next.js Route Handler /api/health + /api/ready |
✅ |
| 优雅关闭 | SIGTERM handler | N/A(Next.js 无长连接) | ✅ |
| 测试覆盖率 ≥ 80% | Vitest | Vitest + @testing-library/react | ⚠️ |
| Dockerfile 多阶段构建 | builder + runtime | node:22-alpine 多阶段,standalone 输出,EXPOSE 4003 |
✅ |
| Zod 输入验证 | class-validator + Zod schema | react-hook-form + zod | ✅ |
| GlobalErrorFilter | NestJS 全局异常过滤器 | React ErrorBoundary + Toast 错误处理 | ✅ |
| 设计令牌三层 | — | globals.css(primitive/semantic)+ tailwind-theme |
✅ |
| A11y 工具集 | — | eslint-plugin-jsx-a11y(error 级)+ skip-link + focus-visible | ✅ |
| Module Federation | — | next.config.js Remote 角色,NEXT_PUBLIC_MF_ENABLED 控制 |
✅ |
| MSW mock | — | 18 GraphQL operation + /api/auth/login mock |
✅ |
附:admin-portal 实现清单(v2,仲裁后修订)
文件结构
apps/admin-portal/
├─ package.json # 依赖(urql/msw/@dnd-kit/web-vitals/eslint-plugin-jsx-a11y)
├─ next.config.js # MF Remote 配置 + rewrites(GraphQL 代理)
├─ tsconfig.json # extends tsconfig.base.json
├─ tailwind.config.js # paper/ink/accent/rule 色板
├─ eslint.config.js # ESLint 9 flat config(jsx-a11y + tseslint + prettier)
├─ Dockerfile # 多阶段构建,node:22-alpine,standalone
├─ vitest.config.ts # jsdom + coverage ≥80%
├─ .env.example # 环境变量模板
├─ public/mockServiceWorker.js # MSW worker
└─ src/
├─ app/
│ ├─ globals.css # 设计令牌 + A11y 样式
│ ├─ layout.tsx # RootLayout(字体加载)
│ ├─ page.tsx # 根页面(redirect /admin/dashboard)
│ ├─ admin-app.tsx # MF Remote 入口(exposes ./AdminApp)
│ ├─ login/page.tsx # 登录页(standalone mock 登录)
│ ├─ admin/
│ │ ├─ layout.tsx # admin 路由组 layout(Provider 链 + AuthGuard + AdminShell)
│ │ ├─ dashboard/page.tsx # 管理仪表盘
│ │ ├─ users/page.tsx # 用户管理
│ │ ├─ roles/page.tsx # 角色权限
│ │ ├─ permissions/page.tsx # 权限点管理
│ │ ├─ viewports/page.tsx # 视口配置(@dnd-kit 拖拽)
│ │ ├─ organization/page.tsx # 组织管理
│ │ ├─ system/page.tsx # 学校设置
│ │ ├─ classes/page.tsx # 班级管理
│ │ ├─ teachers/page.tsx # 教师管理
│ │ ├─ students/page.tsx # 学生管理
│ │ └─ audit-logs/page.tsx # 审计日志(CSV 导出)
│ └─ api/
│ ├─ health/route.ts # Liveness 检查
│ └─ ready/route.ts # Readiness 检查
├─ components/
│ ├─ ui.tsx # 通用 UI(PaperCard/Button/Input/Select/Badge/Table/Pagination)
│ ├─ admin-shell.tsx # AdminShell(左栏 11 项导航 + 主内容 + 跳过链接)
│ ├─ user-management-table.tsx # 用户管理表格
│ ├─ user-form-modal.tsx # 用户表单弹窗
│ ├─ role-permission-matrix.tsx# 角色权限矩阵
│ ├─ organization-tree.tsx # 组织树(A11y treeitem)
│ ├─ notification-panel.tsx # 通知面板(WebSocket)
│ ├─ msw-initializer.tsx # MSW 初始化
│ └─ web-vitals-initializer.tsx# Web Vitals 初始化
├─ hooks/
│ ├─ use-graphql.ts # useGraphQuery + useGraphMutation
│ ├─ use-users.ts # 用户 CRUD
│ ├─ use-roles.ts # 角色 CRUD
│ ├─ use-permissions.ts # 权限点查询
│ ├─ use-viewports.ts # 视口配置
│ ├─ use-organization.ts # 组织树
│ ├─ use-classes.ts # 班级
│ ├─ use-teachers.ts # 教师
│ ├─ use-students.ts # 学生
│ ├─ use-audit-logs.ts # 审计日志 + CSV 导出
│ ├─ use-dashboard.ts # 仪表盘
│ ├─ use-system-settings.ts # 学校设置
│ └─ use-websocket.ts # WebSocket 实时通知
├─ providers/
│ ├─ graphql-provider.tsx # GraphQLProvider(standalone 自建 urql client)
│ ├─ auth-provider.tsx # AuthProvider + useAuth + usePermission
│ └─ toast-provider.tsx # ToastProvider + useToast
├─ lib/
│ ├─ graphql-client.ts # urql client + 18 个 GraphQL operations
│ ├─ auth.ts # 认证工具
│ ├─ permissions.ts # 权限常量(ADMIN_ + IAM_)
│ ├─ i18n.ts # 轻量 i18n
│ └─ web-vitals.ts # Web Vitals 采集
├─ types/
│ └─ view-models.ts # 视图模型类型定义
└─ mocks/
├─ browser.ts # MSW Browser Worker
├─ server.ts # MSW Node Server(vitest)
├─ fixtures.ts # mock 数据库
└─ handlers.ts # MSW handlers(18 GraphQL + login)
质量校验
pnpm run typecheck→ ✅ 通过(0 errors)pnpm run lint→ ✅ 通过(0 errors)
AI Agent: ai16 (admin-portal remote) Branch: admin-portal-arbitration-done-TaFkyb Coordinator: coord-ai