14 KiB
parent-portal 对接契约
负责人:ai15 关联:matrix.md、parent-bff_contract.md、iam_contract.md、push-gateway_contract.md 依据:ARB-001(BFF GraphQL)、ARB-002(MF Shell 暴露清单)、port-allocation.md §4 待仲裁:ISSUE-001 ~ ISSUE-010(见 objections/parent-portal_issue.md),仲裁前本契约按 ARB-001 GraphQL 方向编写
§1 我提供什么(对外接口)
1.1 gRPC 接口(如有)
无。parent-portal 是前端微前端 Remote,不提供 gRPC。
1.2 HTTP 端点(如有)
无对外 HTTP API 端点。parent-portal 是 Next.js 前端应用(MF Remote),不对外暴露 REST API。
说明(ISSUE-006):parent-portal 的页面路由(
/parent/dashboard、/parent/grades等)是前端 SSR/CSR 路由,不是 HTTP API 端点。页面路由清单见 01-understanding.md §8 L2 路由表。parent-portal 仅提供两个内部健康检查端点(非业务 API):
| Method | Path | 用途 | 认证 |
|---|---|---|---|
| GET | /api/health | Dockerfile HEALTHCHECK | 无 |
| GET | /api/ready | K8s readinessProbe | 无 |
1.3 GraphQL schema(如 BFF)
不适用。parent-portal 消费 parent-bff GraphQL,自身不提供 schema。
1.4 Kafka 事件发布(如有)
无。前端不发布 Kafka 事件。
1.5 错误码前缀
parent-portal 不产生错误码前缀(前端不定义错误码)。消费侧错误码前缀见 §2.5。
1.6 微前端架构
| 角色 | 说明 |
|---|---|
| MF 角色 | Remote(Shell = teacher-portal :4000) |
| Remote name | parent_app |
| remoteEntry 路径 | static/chunks/remoteEntry.js |
| 暴露模块 | ./pages(家长场景页面)、./ChildSwitcher(多子女切换组件) |
| MF 配置文件 | apps/parent-portal/next.config.js(NextFederationPlugin,见 02-architecture-design §1.2) |
| MF shared(singleton) | react / react-dom / urql / graphql / @tanstack/react-query / zustand / nuqs / @edu/ui-tokens / @edu/ui-components / @edu/hooks(ARB-002) |
| dev/prod 端口 | 4002(port-allocation.md §4) |
| feature flag | NEXT_PUBLIC_MF_ENABLED(ARB-002,P4 默认开) |
注(ISSUE-007):MF 配置文件统一为
next.config.js,不使用module-federation.config.ts(与 02-architecture-design + teacher-portal Shell 一致)。
§2 我消费什么(依赖上游)
2.1 gRPC 调用(同步)
无。前端不直接调 gRPC。
2.2 Kafka 事件订阅(异步)
无。前端不直接订阅 Kafka。
2.3 HTTP 调用(非 GraphQL)
| 被调用方 | Method.Path | 用途 | mock 策略 |
|---|---|---|---|
| api-gateway (ai01) | POST /api/v1/iam/login | 家长登录 | api-gateway 就绪前 MSW 返回固定 JWT(parent 角色) |
注(ISSUE-004):
- 登录端点统一为
POST /api/v1/iam/login(与 matrix.md §5/api/v1/iam/*+ 01 §3.1 前缀一致)- 登录是 parent-portal 唯一走 REST(非 GraphQL)的端点:登录前无 JWT,GraphQL endpoint 需鉴权
- 待 coord 确认登录是否走 REST,其余走 GraphQL
2.4 GraphQL 查询域(经 api-gateway 代理到 parent-bff)
依据:ARB-001(BFF GraphQL)+ parent-bff_contract.md §1.3
端点:
POST /api/v1/parent/graphql(api-gateway 代理/api/v1/parent/*→ parent-bff :3010/graphql)
注(ISSUE-001 / ISSUE-008):
- 01/02 文档描述为 REST 消费,与 ARB-001 冲突,待 coord 仲裁
- 仲裁前本表按 GraphQL 方向编写(与 parent-bff contract + matrix.md 一致)
- 路径前缀统一为
/api/v1/parent/graphql(与 matrix.md §5 一致,旧版缺v1)
| Query/Mutation | 类型 | 用途 | 对应 parent-bff 聚合 | mock 策略 |
|---|---|---|---|---|
| currentUser | Query | 当前家长信息 | iam.GetUserInfo + GetEffectivePermissions + GetViewports | MSW 返回固定家长(parent-001 王家长) |
| myChildren | Query | 我的子女列表(核心) | iam.GetChildrenByParent(I3/ISSUE-047 裁决) | MSW 返回固定 2 个子女(student-001 + student-002) |
| childSummary(childId) | Query | 子女仪表盘概览 | data-ana.GetParentDashboard | MSW 返回固定仪表盘 |
| childGrades(childId) | Query | 子女成绩 | core-edu.ListGradesByStudent | MSW 返回固定 5 个成绩 |
| childAttendance(childId) | Query | 子女考勤 | core-edu.ListAttendanceByStudent | MSW 返回固定 10 条考勤 |
| childHomework(childId) | Query | 子女作业 | core-edu.ListHomeworkByClass | MSW 返回固定 3 个作业 |
| childWeakness(childId) | Query | 子女薄弱点 | data-ana.GetStudentWeakness | MSW 返回固定 3 个 weak_points |
| childTrend(childId) | Query | 子女学习趋势 | data-ana.GetLearningTrend | MSW 返回固定趋势数据 |
| myNotifications | Query | 通知列表(P5) | msg.ListNotifications | MSW 返回固定 10 条通知 |
| markAsRead(notificationId) | Mutation | 标记已读(P5) | msg.MarkAsRead | MSW 返回 success=true |
| updateNotificationPreferences | Mutation | 更新通知偏好 | msg(待 ai05 确认) | MSW 返回 success=true |
| switchChild(childId) | Mutation | 切换当前子女 | 待 ISSUE-009 仲裁确认 | 见 ISSUE-009 |
switchChild 说明(ISSUE-009):
- parent-bff_contract.md §1.3 未列 switchChild Mutation
- 待 coord 仲裁:switchChild 是 GraphQL Mutation(后端记录当前子女)还是纯前端状态(localStorage + Zustand)
- 若纯前端:本表移除 switchChild,切换逻辑在
useChildSwitcher内直接写 Zustand + localStorage
2.5 消费的错误码前缀(前端 i18n 路由)
parent-portal 不产生错误码,仅消费。前端 API 请求层根据 error.code 前缀路由到对应 i18n key:
| 前缀 | 来源服务 | i18n key 模式 |
|---|---|---|
IAM_ |
iam | error.iam.{{code}} |
CORE_EDU_ |
core-edu | error.core_edu.{{code}} |
BFF_PARENT_ |
parent-bff | error.bff_parent.{{code}} |
GW_ |
api-gateway | error.gw.{{code}} |
NETWORK_ |
前端网络层 | error.network.{{code}} |
注:与 matrix.md §6 错误码前缀矩阵对齐。
BFF_PARENT_前缀由 parent-bff 定义(见 parent-bff_contract.md §1.5)。
2.6 WebSocket 推送(P5)
| 被调用方 | 协议 | 路径 | 用途 | mock 策略 |
|---|---|---|---|---|
| push-gateway (ai02) | WebSocket | /ws | 实时推送 | mock-socket 模拟 WS 推送(每 30s 1 条) |
| push-gateway (ai02) | SSE(降级) | /sse | SSE 降级 | — |
WebSocket 连接由 Shell 建立(统一连接管理),parent-portal 通过 Zustand ui-store 订阅事件流。
2.7 消费的 MF Shell 暴露(ARB-002)
| 暴露模块 | 来源 | 用途 |
|---|---|---|
| AppShell | teacher-portal Shell | 左栏导航 + 主内容区布局 |
| GraphQLProvider | teacher-portal Shell | urql client 单例(ARB-002) |
| useAuth | packages/hooks | 会话状态 |
| usePermission | packages/hooks | 权限查询 |
| useGraphQLClient | packages/hooks | urql client 获取 |
| ErrorBoundary | packages/ui-components | React 渲染异常兜底 |
| Loading / Empty | packages/ui-components | 骨架屏 / 空态 |
| RequirePermission | packages/ui-components | L3 组件级视口控制 |
MF shared(singleton):react / react-dom / urql / graphql / @tanstack/react-query / zustand / nuqs / @edu/ui-tokens / @edu/ui-components / @edu/hooks(ARB-002 裁决,见 coord.md §2)
§3 就绪信号
3.1 我依赖的上游就绪标志
| 上游 | 就绪信号 | 提供方 | 状态 |
|---|---|---|---|
| api-gateway | HTTP :8080 启用 + JWT 验签 + /api/v1/parent/* 代理 |
ai01 | ⏳ |
| parent-bff GraphQL | POST /graphql :3010 + currentUser/myChildren/childSummary/childGrades Query |
ai05 | ⏳ P4 |
| iam GetChildrenByParent | gRPC 50052 + iam_student_guardians 表(I3/ISSUE-047 裁决) |
ai06 | ⏳ P3 补全 |
| teacher-portal Shell | MF exposes(AppShell + GraphQLProvider + hooks + UI 组件)+ shared singleton | ai13 | ⏳ P2 |
| push-gateway | WebSocket :8081/ws | ai02 | ⏳ P5 |
| msg | gRPC 50056 + NotificationService | ai10 | ⏳ P5 |
| shared-ts / contracts | ApiClient / Logger / Permissions 常量 | coord | ⏳ |
| ui-tokens / ui-components / hooks | 三层令牌 + shadcn + usePermission/useAuth | ai07/ai13 | ⏳ P2 收尾 |
P0 阻塞(ISSUE-010):iam
GetChildrenByParent缺失,多子女场景无法落地。补全前用 mock(固定 2 个子女 student-001 + student-002)开发。
3.2 我的就绪标志(供下游消费)
与 matrix.md §8 就绪信号跟踪表对齐
| 信号 | 说明 | 阶段 |
|---|---|---|
| parent-portal dev server :4002 启用 | MF Remote 可被 Shell 加载 | P4-1 |
| MF Remote remoteEntry.js 可加载 | Shell 端 remotes.parent = parent_app@http://localhost:4002/... 可解析 |
P4-1 |
| 独立壳渲染 | 首页 + 导航 + 路由守卫 | P4-1 |
| 登录流程可用 | POST /api/v1/iam/login 获取 JWT 存入 httpOnly cookie |
P4-2 |
| GraphQL 查询可执行 | currentUser / myChildren / childSummary 返回数据(mock 或真实) | P4-2 |
| 多子女切换可用 | ChildSwitcher + invalidate 流程通过 | P4-3 |
| 数据范围校验生效 | 前端路由守卫校验 childId 是否在 myChildren 返回列表中 | P4-3 |
| Dashboard 可访问 | 家长登录 → 看到 Dashboard(含子女卡片) | P4-4 |
| 健康检查通过 | GET /api/health + GET /api/ready 200 |
P4-1 |
| 测试覆盖率达标 | 单元 ≥ 85% + 集成 ≥ 75% | P4-9 |
| Docker 镜像可构建 | docker build 成功 |
P4-10 |
| WebSocket 通知可接收 | push-gateway WS 事件正确处理 | P5-1 |
§4 Mock 策略
4.1 我提供的 mock
parent-portal 是前端,无下游消费方。但对开发体验提供:
- Storybook:各组件独立 story
- MSW handlers:
apps/parent-portal/src/mocks/handlers.ts,拦截所有 GraphQL/HTTP 请求
4.2 我消费的 mock
在真实上游就绪前,parent-portal 使用以下 mock(由 NEXT_PUBLIC_API_MOCKING=enabled 控制):
- GraphQL mock:MSW 拦截
POST /api/v1/parent/graphql- 按 operationName 返回对应 mock 响应(与 parent-bff mock 数据一致)
- currentUser → 固定家长(id="parent-001", name="王家长", roles=["parent"])
- myChildren → 固定 2 个子女(id="student-001" 李同学 + id="student-002" 李妹妹)
- childSummary → 固定仪表盘(child_avg_score=85.0, child_class_rank=5)
- childGrades → 固定 5 个成绩
- childAttendance → 固定 10 条考勤
- childHomework → 固定 3 个作业
- myNotifications → 固定 10 条通知
- 所有 mock 响应定义在
apps/parent-portal/src/mocks/fixtures/*.json
- HTTP mock:MSW 拦截
POST /api/v1/iam/login→ 返回固定 JWT + UserInfo(parent 角色) - WebSocket mock:mock-socket 库,连接后每 30 秒推送 1 条 mock 通知
- JWT mock:固定 mock JWT,存入 httpOnly cookie
- 环境切换:
NEXT_PUBLIC_API_MOCKING=enabled(开发)/disabled(上游就绪后) - 数据一致性:myChildren mock 必须返回固定 2 个孩子(student-001 + student-002),与所有 child* 查询的 student_id 一致(否则前端数据范围校验失败)
§5 待协调事项(指向 objections)
以下事项已提请 coord 仲裁,仲裁结果可能影响本契约:
| ISSUE | 影响章节 | 当前处理 |
|---|---|---|
| ISSUE-001(REST vs GraphQL) | §2.4 | 按 GraphQL 编写(依 ARB-001),待 coord 确认 |
| ISSUE-004(登录端点) | §2.3 | 暂用 POST /api/v1/iam/login,待 coord 确认 |
| ISSUE-006(HTTP 端点分类) | §1.2 | 已修正为"无对外 HTTP API" |
| ISSUE-007(MF 配置文件名) | §1.6 | 已修正为 next.config.js |
| ISSUE-008(GraphQL 路径前缀) | §2.4 | 已修正为 /api/v1/parent/graphql |
| ISSUE-009(switchChild Mutation) | §2.4 | 列为待仲裁,标注两种方案 |
| ISSUE-010(iam GetChildrenByParent 缺失) | §3.1 | P0 阻塞,用 mock 开发 |