# parent-portal 下游待办事项（Next Steps）

> 版本：v1
> 日期：2026-07-13
> 用途：记录 parent-portal 切换至真实 API 集成所需的下游模块工作
> 背景：parent-portal 已完成 Docker Desktop 验证（容器健康、25 路由生成、/login 200、/api/health 200），现需下游服务就绪才能完成端到端真实 API 联调

---

## 1. 当前状态摘要

| 项目                       | 状态              | 说明                                                                   |
| -------------------------- | ----------------- | ---------------------------------------------------------------------- |
| parent-portal Docker 镜像  | ✅ 已就绪         | `edu-parent-portal:test`，standalone 模式，25 路由                     |
| parent-portal 容器健康检查 | ✅ 通过           | `/api/health` 200，`/login` 200，`/parent/dashboard` 307 auth redirect |
| Mock 数据                  | ✅ 已禁用         | `NEXT_PUBLIC_API_MOCKING=disabled`                                     |
| GraphQL 端点配置           | ✅ 已配置         | `NEXT_PUBLIC_GRAPHQL_ENDPOINT=/api/v1/parent/v1/graphql`               |
| parent-bff 服务            | ❌ 未就绪         | 端点路径错配 + 27 query / 5 mutation 缺失                              |
| api-gateway 路由           | ⚠️ 已配置但未验证 | `/api/v1/parent/*` → parent-bff:3010，但 parent-bff 未运行             |
| iam GetChildrenByParent    | ✅ 已就绪         | gRPC + HTTP 均已实现                                                   |
| push-gateway /ws           | ✅ 已就绪         | 完整 WebSocket 实现                                                    |

---

## 2. P0 阻塞项：parent-bff 端点路径错配

### 问题描述

前端调用 GraphQL 端点：`/api/v1/parent/v1/graphql`（ARB-022 §24.4 ISSUE-003 方案 A 双 /v1 前缀）

api-gateway 代理路径转换：

- 入站：`/api/v1/parent/v1/graphql`
- 剥离 `/api` 后转发：`/v1/parent/v1/graphql` → parent-bff:3010

但 parent-bff 当前 controller 仅注册 `/graphql`，导致 `/v1/parent/v1/graphql` 在 parent-bff 找不到匹配的 handler，返回 404。

### 修复位置（parent-bff 模块）

| 文件                                                  | 当前                          | 应改为                                                         |
| ----------------------------------------------------- | ----------------------------- | -------------------------------------------------------------- |
| `services/parent-bff/src/entry/graphql.controller.ts` | `@Controller("graphql")`      | `@Controller("v1/parent/v1/graphql")` 或使用 `setGlobalPrefix` |
| `services/parent-bff/src/graphql/yoga.ts`             | `graphqlEndpoint: "/graphql"` | `graphqlEndpoint: "/v1/parent/v1/graphql"`                     |
| `services/parent-bff/src/graphql/graphql.module.ts`   | `forRoutes("graphql")`        | `forRoutes("v1/parent/v1/graphql")`                            |

### 验证步骤

1. 修改后构建 parent-bff 镜像
2. 启动 parent-bff 容器，验证 `http://parent-bff:3010/v1/parent/v1/graphql` 返回 200
3. 经 api-gateway 代理访问 `http://api-gateway:8080/api/v1/parent/v1/graphql` 返回 200

---

## 3. P0 阻塞项：parent-bff 缺失 pnpm-lock.yaml

### 问题描述

`services/parent-bff/Dockerfile` 第 6 行 `RUN pnpm install --frozen-lockfile` 失败，因为 `services/parent-bff/` 目录下没有 `pnpm-lock.yaml` 文件。

### 修复方案

在 `services/parent-bff/` 目录执行 `pnpm install` 生成 lockfile，并提交到仓库。

```bash
cd services/parent-bff
pnpm install
git add pnpm-lock.yaml
git commit -m "chore(parent-bff): add pnpm-lock.yaml for Docker build"
```

---

## 4. P0 阻塞项：parent-bff GraphQL Schema 严重不对齐

### 问题描述

| 类别     | 前端定义 | 后端实现 | 差距                                                            |
| -------- | -------- | -------- | --------------------------------------------------------------- |
| Query    | 32 个    | 11 个    | 21 个缺失（含 6 个命名不一致 + 15 个完全缺失 + 3 个签名不一致） |
| Mutation | 6 个     | 3 个     | 3 个缺失（含 2 个命名不一致 + 1 个完全缺失 + 1 个签名不一致）   |

### 4.1 命名不一致的 Query（6 个）

| 前端 operation              | 后端 operation            | 修复方式                                                         |
| --------------------------- | ------------------------- | ---------------------------------------------------------------- |
| `currentUser`               | `me`                      | 二选一统一命名（建议后端改 `me` → `currentUser`）                |
| `myChildren`                | `children`                | 二选一统一命名（建议后端改 `children` → `myChildren`）           |
| `myNotifications`           | `notifications`           | 二选一统一命名（建议后端改 `notifications` → `myNotifications`） |
| `myNotificationPreferences` | `notificationPreferences` | 二选一统一命名                                                   |
| `childSummary`              | `child`                   | 字段不同，需明确语义                                             |
| `childAnalytics`            | （前端未使用）            | 后端已有但前端未对接，保留                                       |

### 4.2 完全缺失的 Query（15 个，后端需新增）

| 前端 operation           | 涉及下游服务 |
| ------------------------ | ------------ |
| `childAttendance`        | core-edu     |
| `childWeakness`          | data-ana     |
| `childTrend`             | data-ana     |
| `childExamResult`        | core-edu     |
| `childClasses`           | classes      |
| `childLearningPath`      | data-ana     |
| `childLeaveRequests`     | core-edu     |
| `academicYears`          | core-edu     |
| `childReportCard`        | core-edu     |
| `childErrorBookStats`    | data-ana     |
| `childTopWrongQuestions` | data-ana     |
| `childWeakKps`           | data-ana     |
| `childMasterySummary`    | data-ana     |
| `childDiagnosticReports` | data-ana     |
| `childPracticeStats`     | data-ana     |
| `childPracticeSessions`  | data-ana     |
| `childCoursePlans`       | core-edu     |
| `childCoursePlanDetail`  | content      |
| `childLessonPlans`       | core-edu     |
| `childLessonPlanDetail`  | content      |
| `childElective`          | content      |
| `childDetail`            | data-ana     |
| `childGrowthArchive`     | data-ana     |

### 4.3 签名不一致的 Query（3 个）

| 前端 operation  | 不一致点                                                                                                                                                                                                         |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `childGrades`   | 前端 `(childId, subject, limit)` vs 后端 `(childId, page, pageSize, subject)`；返回字段不同（前端 `examName/examDate/studentScore/classMax/classMin/gradeLevel` vs 后端 `examId/examTitle/score/rank/gradedAt`） |
| `childHomework` | 前端有 `status` 过滤参数，后端无；字段差异大（前端 `subject/className/assignedDate/score/maxScore/feedback` vs 后端 `title/classId/dueDate/status`）                                                             |
| `childExams`    | 字段差异大（前端 `name/subject/startsAt/expiresAt/durationSeconds/questionCount/totalScore` vs 后端 `title/examDate/publishedAt`）                                                                               |

### 4.4 缺失的 Mutation（3 个）

| 前端 operation       | 涉及下游服务                                               |
| -------------------- | ---------------------------------------------------------- |
| `markAsRead`         | parent-bff（重命名 `markNotificationRead` → `markAsRead`） |
| `markAllAsRead`      | parent-bff（新增）                                         |
| `switchChild`        | parent-bff（重命名 `selectChild` → `switchChild`）         |
| `createLeaveRequest` | core-edu（新增）                                           |
| `exportChildGrades`  | core-edu（新增）                                           |

### 4.5 签名不一致的 Mutation（1 个）

| 前端 operation                  | 不一致点                                                                                                   |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `updateNotificationPreferences` | 前端 `(parentId, preferences: JSON, defaults: JSON)` vs 后端 `(input: UpdateNotificationPreferencesInput)` |

### 修复步骤

1. **契约先行**：更新 `packages/shared-ts/contracts/graphql/parent-bff.graphql`，扩充至前端 32 query + 6 mutation
2. **resolver 实现**：在 `services/parent-bff/src/graphql/resolvers/` 新增对应 resolver
3. **下游 gRPC client**：在 `services/parent-bff/src/clients/` 新增/对接 core-edu / data-ana / content / classes 的 gRPC client
4. **测试**：parent-bff 单测 + parent-portal 端到端联调

---

## 5. P1 阻塞项：api-gateway 镜像构建问题

### 问题描述

`services/api-gateway/Dockerfile` 使用 `golang:1.22-alpine` 和 `alpine:3.20` 基础镜像，但本地 Docker Desktop 未拉取这两个镜像，且 daocloud 镜像源返回 401。

### 修复方案

1. 提前在服务器执行：`docker pull golang:1.22-alpine && docker pull alpine:3.20`
2. 或在 Dockerfile 中改用本地已有的镜像源

---

## 6. 已就绪的下游服务（无需等待）

| 服务                    | 状态                    | 验证位置                                                                                        |
| ----------------------- | ----------------------- | ----------------------------------------------------------------------------------------------- |
| iam.GetChildrenByParent | ✅ gRPC + HTTP 均已实现 | `services/iam/src/iam/iam.grpc.controller.ts:116`、`services/iam/src/iam/iam.controller.ts:116` |
| push-gateway /ws        | ✅ 完整实现             | `services/push-gateway/internal/ws/handler.go`                                                  |

---

## 7. 验证 Checklist（下游就绪后执行）

- [ ] parent-bff 添加 pnpm-lock.yaml
- [ ] parent-bff GraphQL 端点路径改为 `/v1/parent/v1/graphql`
- [ ] parent-bff schema 扩充至 32 query + 6 mutation
- [ ] parent-bff 所有 resolver 实现完成
- [ ] api-gateway 镜像可构建
- [ ] 在 Docker Desktop 启动完整服务栈：api-gateway + parent-bff + iam + core-edu + data-ana + content + classes + push-gateway
- [ ] parent-portal 端到端联调：登录 → /parent/dashboard → 各功能页面
- [ ] 验证 WebSocket 推送：通知功能
- [ ] 验证 25 个路由全部可访问（无 500 错误）

---

## 8. 关键文件路径

| 文件                                                      | 用途                                                 |
| --------------------------------------------------------- | ---------------------------------------------------- |
| `apps/parent-portal/Dockerfile`                           | parent-portal Docker 构建（已修复，standalone 模式） |
| `apps/parent-portal/next.config.js`                       | Next.js 配置（已添加 `output: "standalone"`）        |
| `apps/parent-portal/src/lib/graphql-client.ts`            | GraphQL 客户端配置                                   |
| `apps/parent-portal/src/lib/graphql/operations.ts`        | 前端所有 GraphQL operations 定义                     |
| `apps/parent-portal/.env.example`                         | 环境变量模板（`NEXT_PUBLIC_API_MOCKING=disabled`）   |
| `services/parent-bff/Dockerfile`                          | parent-bff Docker 构建（待修复：缺 pnpm-lock.yaml）  |
| `services/parent-bff/src/entry/graphql.controller.ts`     | GraphQL 端点路径（待修复）                           |
| `services/parent-bff/src/graphql/yoga.ts`                 | GraphQL Yoga 配置（待修复）                          |
| `services/parent-bff/src/graphql/graphql.module.ts`       | GraphQL 模块路由（待修复）                           |
| `services/parent-bff/src/graphql/resolvers/index.ts`      | resolver 实现（待扩充）                              |
| `packages/shared-ts/contracts/graphql/parent-bff.graphql` | GraphQL schema 契约（待扩充）                        |
| `services/api-gateway/main.go:86`                         | parent 代理注册                                      |
| `services/api-gateway/Dockerfile`                         | api-gateway Docker 构建（待修复：基础镜像缺失）      |

---

**总结**：parent-portal 前端已完全就绪（Docker 镜像构建成功、容器健康、25 路由可用、mock 已禁用），等待下游 parent-bff 完成端点路径修复 + schema 扩充 + resolver 实现后，即可完成端到端真实 API 联调。
