# 模块理解确认书 — admin-portal

> AI：ai16（TS/React · 管理场景域前端 remote）
> 阶段：阶段 1 交付物（仲裁后修订版 v2）
> 日期：2026-07-10
> 关联：
>
> - [004 架构影响地图](../../../docs/architecture/004_architecture_impact_map.md) §1.1a/1.1b/§5.4
> - [AI 分配方案](../../../docs/architecture/ai-allocation.md) §5 ai16
> - [总统最终裁决](../../../docs/architecture/president-final-rulings.md) §5.1-5.5（ISSUE-044~048）
> - [admin-portal 对接契约](../../architecture/issues/contracts/admin-portal_contract.md)
> - [admin-portal 工作线](../../architecture/issues/worklines/admin-portal_workline.md)
> - [known-issues §2.16](../../../docs/troubleshooting/known-issues.md)

---

## 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 `auditLogs` Query 消费）
- 管理仪表盘（聚合统计 + 服务健康）
- 实时通知（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
