# parent-bff 对接契约

> 负责人：ai05
> 关联：[matrix.md](./matrix.md)、[iam.proto](../../../packages/shared-proto/proto/iam.proto)、[core_edu.proto](../../../packages/shared-proto/proto/core_edu.proto)、[analytics.proto](../../../packages/shared-proto/proto/analytics.proto)、[msg.proto](../../../packages/shared-proto/proto/msg.proto)

---

## §1 我提供什么（对外接口）

### 1.1 gRPC 接口（如有）

无对外 gRPC。parent-bff 是 GraphQL 聚合层。

### 1.2 HTTP 端点（如有）

| Method | Path     | 用途                                      | 认证                   |
| ------ | -------- | ----------------------------------------- | ---------------------- |
| POST   | /graphql | 家长 BFF GraphQL 端点                     | JWT 必需 + parent 角色 |
| GET    | /graphql | GraphQL Playground（开发环境）            | 开发环境公开           |
| GET    | /healthz | 健康检查（liveness）                      | 公开                   |
| GET    | /readyz  | 就绪检查（readiness，含下游 gRPC 连通性） | 公开                   |

### 1.3 GraphQL schema（如 BFF）

GraphQL schema 文件路径：`apps/parent-bff/src/schema/*.graphql`（端口 :3010）

核心 Query / Mutation 域：

- **auth**：currentUser（聚合 iam.GetUserInfo + GetEffectivePermissions + GetViewports）
- **children**：myChildren（聚合 iam.GetChildrenByParent，核心依赖 I3 裁决）
- **childSummary**：childSummary（聚合 data-ana.AnalyticsService.GetParentDashboard）
- **childGrades**：childGrades（聚合 core-edu.GradeService.ListGradesByStudent）
- **childAttendance**：childAttendance（聚合 core-edu.AttendanceService.ListAttendanceByStudent）
- **childHomework**：childHomework（聚合 core-edu.HomeworkService.ListHomeworkByClass）
- **childWeakness**：childWeakness（聚合 data-ana.AnalyticsService.GetStudentWeakness）
- **childTrend**：childTrend（聚合 data-ana.AnalyticsService.GetLearningTrend）
- **notifications**：myNotifications / markAsRead（聚合 msg.NotificationService）

### 1.4 Kafka 事件发布（如有）

无。parent-bff 不发布事件，仅做 gRPC 聚合。

### 1.5 错误码前缀

`BFF_PARENT_`（如 BFF_PARENT_UPSTREAM_UNAVAILABLE、BFF_PARENT_AGGREGATION_FAILED、BFF_PARENT_NO_CHILDREN、BFF_PARENT_FORBIDDEN）

---

## §2 我消费什么（依赖上游）

### 2.1 gRPC 调用（同步）

| 被调用方        | Service.RPC                               | 用途                     | mock 策略                                              |
| --------------- | ----------------------------------------- | ------------------------ | ------------------------------------------------------ |
| iam (ai06)      | IamService.GetUserInfo                    | 获取当前家长信息         | iam 就绪前返回固定 UserInfo（parent 角色）             |
| iam (ai06)      | IamService.GetEffectivePermissions        | 权限校验                 | iam 就绪前返回家长权限集                               |
| iam (ai06)      | IamService.GetViewports                   | 家长导航菜单             | iam 就绪前返回固定视口列表                             |
| iam (ai06)      | IamService.GetChildrenByParent            | 查询关联孩子列表（核心） | iam 就绪前返回固定 2 个 ChildInfo（I3/ISSUE-047 裁决） |
| core-edu (ai08) | GradeService.ListGradesByStudent          | 孩子成绩                 | core-edu 就绪前返回固定 5 个 Grade                     |
| core-edu (ai08) | AttendanceService.ListAttendanceByStudent | 孩子考勤                 | core-edu 就绪前返回固定 10 条 Attendance               |
| core-edu (ai08) | HomeworkService.ListHomeworkByClass       | 孩子作业                 | core-edu 就绪前返回固定 3 个 Homework                  |
| data-ana (ai11) | AnalyticsService.GetParentDashboard       | 家长仪表盘               | data-ana 就绪前返回固定仪表盘（child_avg_score=85.0）  |
| data-ana (ai11) | AnalyticsService.GetStudentWeakness       | 孩子薄弱点               | data-ana 就绪前返回固定 3 个 weak_points               |
| data-ana (ai11) | AnalyticsService.GetLearningTrend         | 孩子学习趋势             | data-ana 就绪前返回固定趋势数据                        |
| msg (ai10)      | NotificationService.ListNotifications     | 家长通知                 | msg 就绪前返回固定 10 条通知                           |
| msg (ai10)      | NotificationService.MarkAsRead            | 标记已读                 | msg 就绪前返回 success=true                            |

### 2.2 Kafka 事件订阅（异步）

无。parent-bff 不订阅 Kafka 事件，仅做同步 gRPC 聚合。

### 2.3 HTTP 调用（如有）

无。

---

## §3 就绪信号

### 3.1 我依赖的上游就绪标志

- [ ] iam gRPC 50052 启用（ai06）—— **核心依赖 GetChildrenByParent（I3/ISSUE-047 裁决）**
- [ ] core-edu gRPC 50053 启用（ai08）
- [ ] data-ana gRPC 50055 启用（ai11）
- [ ] msg gRPC 50056 启用（ai10）

### 3.2 我的就绪标志（供下游消费）

- [ ] parent-bff GraphQL :3010 启用（/healthz 返回 200）
- [ ] /readyz 返回 200（含 4 个下游 gRPC 连通性检查）
- [ ] GraphQL schema 可内省（POST /graphql 返回 schema）
- [ ] 核心 Query 可执行：currentUser / myChildren / childSummary / childGrades
- [ ] 核心 Mutation 可执行：markAsRead
- [ ] 数据范围校验生效（家长只能查自己孩子的数据，基于 iam.GetChildrenByParent 返回的 user_id 校验）

---

## §4 Mock 策略

### 4.1 我提供的 mock

在 parent-bff 真实就绪前，为下游（parent-portal）提供以下 mock：

- **GraphQL mock**：使用 Apollo Server mockProviders 或 MSW 拦截 POST /graphql
  - 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 条考勤
  - myNotifications 返回固定 10 条通知

### 4.2 我消费的 mock

在真实上游就绪前，parent-bff 使用以下 mock（详见 §2.1 mock 策略列）：

- **iam mock**：固定 UserInfo + 家长权限 + 固定视口 + 固定 2 个 ChildInfo（家长-学生关联核心数据）
- **core-edu mock**：固定孩子成绩/考勤/作业
- **data-ana mock**：固定家长仪表盘/孩子薄弱点/趋势
- **msg mock**：固定通知列表 + MarkAsRead success

> 关键：iam.GetChildrenByParent 的 mock 必须返回与 core-edu mock 数据一致的 student_id，否则数据范围校验会失败。parent-bff 启动时校验 myChildren 返回的 user_id 与下游查询的 student_id 一致性。
