docs: update api-gateway workline and contract based on new arbitration
update workline to detail full P2-P6 tasks with clear milestones and dependencies revise contract to correct route prefix, JWKS method and dependency descriptions clean up outdated issue content
This commit is contained in:
@@ -1,40 +1,90 @@
|
||||
# api-gateway 对接契约
|
||||
|
||||
> 负责人:ai01
|
||||
> 关联:[matrix.md](./matrix.md)、[iam.proto](../../../packages/shared-proto/proto/iam.proto)
|
||||
> 关联:[matrix.md](./matrix.md)、[iam.proto](../../../packages/shared-proto/proto/iam.proto)、[objections/api-gateway_issue.md](../objections/api-gateway_issue.md)、[worklines/api-gateway_workline.md](../worklines/api-gateway_workline.md)、[02-architecture-design.md](../../../services/api-gateway/docs/02-architecture-design.md)
|
||||
> 依据:[coord-final-decisions.md](../../coord-final-decisions.md) §3.8 W1-W8、[president-final-rulings.md](../../president-final-rulings.md) §2.15/§2.16/§2.19
|
||||
> 版本:v2(2026-07-10 修正:路径前缀 /api→/api/v1、JWKS 拉取方式 gRPC→HTTP、删除 GetEffectiveAccess、错误码加 GW_ 前缀)
|
||||
|
||||
---
|
||||
|
||||
## §1 我提供什么(对外接口)
|
||||
|
||||
### 1.1 gRPC 接口(如有)
|
||||
### 1.1 gRPC 接口
|
||||
|
||||
无。api-gateway 是 HTTP 入口,不对外提供 gRPC。
|
||||
无。api-gateway 是 HTTP 入口,不对外提供 gRPC(依据 [president-final-rulings.md](../../president-final-rulings.md) §2.16 裁决:gateway 保持 HTTP 透传,不改为 gRPC 客户端)。
|
||||
|
||||
### 1.2 HTTP 端点(如有)
|
||||
### 1.2 HTTP 端点
|
||||
|
||||
| Method | Path | 用途 | 认证 |
|
||||
| ------ | -------------- | ------------------------------------------- | ---------------------- |
|
||||
| ANY | /api/auth/* | 代理到 iam 认证相关(登录/注册/刷新 token) | 公开(登录注册免认证) |
|
||||
| ANY | /api/teacher/* | 代理到 teacher-bff GraphQL(:3003) | JWT 必需 |
|
||||
| ANY | /api/student/* | 代理到 student-bff GraphQL(:3009) | JWT 必需 |
|
||||
| ANY | /api/parent/* | 代理到 parent-bff GraphQL(:3010) | JWT 必需 |
|
||||
| ANY | /api/admin/* | 代理到 teacher-bff GraphQL admin namespace | JWT 必需 + admin 角色 |
|
||||
| GET | /healthz | 网关健康检查(liveness) | 公开 |
|
||||
| GET | /readyz | 网关就绪检查(readiness,含 iam 连通性) | 公开 |
|
||||
| GET | /metrics | Prometheus 指标端点 | 公开(内网) |
|
||||
#### 1.2.1 健康检查与指标端点(公开,无鉴权)
|
||||
|
||||
### 1.3 GraphQL schema(如 BFF)
|
||||
| Method | Path | 用途 | 认证 | 阶段 |
|
||||
| ------ | ---------- | ------------------------------------------- | ---- | ---- |
|
||||
| GET | /healthz | 网关存活探针(liveness) | 公开 | P1 |
|
||||
| GET | /readyz | 网关就绪探针(readiness,并行 ping 下游 /healthz)| 公开 | P2 |
|
||||
| GET | /metrics | Prometheus 指标端点(7 个业务指标 + Go runtime)| 公开(内网)| P2 |
|
||||
|
||||
不适用。api-gateway 仅做 HTTP 反向代理 + JWT 验签,不解析 GraphQL。
|
||||
#### 1.2.2 反向代理路由(JWT 必需,除白名单外)
|
||||
|
||||
### 1.4 Kafka 事件发布(如有)
|
||||
> **路径前缀**:所有业务路由统一 `/api/v1/*` 前缀(与 [main.go](../../../services/api-gateway/main.go) L59 `r.Group("/api/v1")` 一致)。
|
||||
>
|
||||
> **API 版本化**:按 [president-final-rulings.md](../../president-final-rulings.md) §2.15 裁决,各服务 Controller 内加 `/v1` 前缀。Gateway 透传时不改路径,前端调用 `/api/v1/<service>/v1/*`(ISSUE-003 待 coord 仲裁最终方案,本表暂列方案 A)。
|
||||
|
||||
无。api-gateway 不发布事件。
|
||||
| Method | Path(Gateway 外部路径) | 目标服务 | 端口 | 鉴权 | 公开子路径 | 阶段 |
|
||||
| ------ | --------------------------------------------------- | ------------------------- | ----- | ---- | --------------------------------------- | ---- |
|
||||
| ANY | /api/v1/iam/v1/*path + /api/v1/iam/v1 | iam | 3002 | JWT | `/iam/v1/register` `/login` `/refresh` | P2 |
|
||||
| ANY | /api/v1/teacher/v1/*path + /api/v1/teacher/v1 | teacher-bff(GraphQL) | 3003 | JWT | — | P2 |
|
||||
| ANY | /api/v1/student/v1/*path + /api/v1/student/v1 | student-bff(GraphQL) | 3009 | JWT | — | P3 |
|
||||
| ANY | /api/v1/parent/v1/*path + /api/v1/parent/v1 | parent-bff(GraphQL) | 3010 | JWT | — | P4 |
|
||||
| ANY | /api/v1/classes/v1/*path + /api/v1/classes/v1 | core-edu(classes 合并) | 3004 | JWT | — | P3 |
|
||||
| ANY | /api/v1/exams/v1/*path + /api/v1/homework/v1/*path + /api/v1/grades/v1/*path | core-edu | 3004 | JWT | — | P3 |
|
||||
| ANY | /api/v1/textbooks/v1/*path + /api/v1/chapters/v1/*path + /api/v1/knowledge-points/v1/*path + /api/v1/questions/v1/*path | content | 3005 | JWT | — | P4 |
|
||||
| ANY | /api/v1/analytics/v1/*path + /api/v1/dashboard/v1/*path | data-ana | 3006 | JWT | — | P4 |
|
||||
| ANY | /api/v1/notifications/v1/*path + /api/v1/messages/v1/*path | msg | 3007 | JWT | — | P5 |
|
||||
| ANY | /api/v1/ai/v1/*path + /api/v1/ai/v1 | ai | 3008 | JWT | — | P5 |
|
||||
| ANY | /api/v1/admin/v1/*path + /api/v1/admin/v1 | teacher-bff admin namespace | 3003 | JWT + admin 角色 | — | P6 |
|
||||
|
||||
> **注 1**:每个前缀同时注册无尾斜杠与通配符两条路由(`/iam/v1` + `/iam/v1/*path`),因为 `r.RedirectTrailingSlash = false`([main.go](../../../services/api-gateway/main.go) L34)。
|
||||
>
|
||||
> **注 2**:admin-portal P6 阶段复用 teacher-bff + admin schema 命名空间(依据 [coord.md](../coord.md) §1.3 ARB-001 裁决)。
|
||||
>
|
||||
> **注 3**:当前 P1 代码暂未加 `/v1` 前缀(如 `/api/v1/iam/*path`),待 ISSUE-003 仲裁后 P2.7 任务统一迁移。
|
||||
|
||||
#### 1.2.3 透传请求头(Gateway 注入,下游读取)
|
||||
|
||||
| 头名 | 来源 | 用途 | 下游消费方 |
|
||||
| -------------- | ----------------------------- | ----------------------------- | ---------- |
|
||||
| `x-user-id` | JWT `sub` claim | 用户身份传递 | 所有下游 |
|
||||
| `x-user-roles` | JWT `roles` claim(逗号分隔)| 角色传递 | 所有下游 |
|
||||
| `x-data-scope` | JWT `data_scope` claim | 数据范围传递(P2 新增) | 所有下游 |
|
||||
| `X-Request-Id` | 客户端透传或 Gateway 生成 UUID | 请求 ID(全链路追踪) | 所有下游 |
|
||||
| `traceparent` | OTel SDK 自动处理 | W3C Trace Context(链路追踪)| 所有下游 |
|
||||
| `tracestate` | OTel SDK 自动处理 | W3C Trace Context 扩展 | 所有下游 |
|
||||
|
||||
### 1.3 GraphQL schema
|
||||
|
||||
不适用。api-gateway 仅做 HTTP 反向代理 + JWT 验签,不解析 GraphQL(GraphQL 由 BFF 层处理)。
|
||||
|
||||
### 1.4 Kafka 事件发布
|
||||
|
||||
无。api-gateway 不发布 Kafka 事件(纯同步 HTTP 反向代理)。
|
||||
|
||||
### 1.5 错误码前缀
|
||||
|
||||
`GW_`(如 GW_UNAUTHORIZED、GW_RATE_LIMITED、GW_CIRCUIT_OPEN、GW_BACKEND_UNAVAILABLE)
|
||||
`GW_`(依据 [coord-final-decisions.md](../../coord-final-decisions.md) W1 / G14 裁决)
|
||||
|
||||
### 1.6 错误码清单
|
||||
|
||||
| 错误码 | HTTP | 触发条件 | 响应体(ActionState 信封) |
|
||||
| ------------------------ | ---- | --------------------- | ----------------------------------------------------------------------- |
|
||||
| `GW_UNAUTHORIZED` | 401 | 缺失 Authorization 头 | `{success:false,error:{code:"GW_UNAUTHORIZED",message:"..."}}` |
|
||||
| `GW_INVALID_TOKEN` | 401 | JWT 签名/格式错误 | 同上 |
|
||||
| `GW_INVALID_CLAIMS` | 401 | JWT claims 解析失败 | 同上 |
|
||||
| `GW_RATE_LIMITED` | 429 | 超出令牌桶限流 | `{success:false,error:{code:"GW_RATE_LIMITED",message:"...",retry_after:60}}` |
|
||||
| `GW_CIRCUIT_OPEN` | 503 | 下游熔断打开 | `{success:false,error:{code:"GW_CIRCUIT_OPEN",message:"...",retry_after:30}}` |
|
||||
| `GW_REQUEST_TOO_LARGE` | 413 | 请求体超 10MB | `{success:false,error:{code:"GW_REQUEST_TOO_LARGE",message:"..."}}` |
|
||||
| `GW_INTERNAL_ERROR` | 500 | panic 兜底 | `{success:false,error:{code:"GW_INTERNAL_ERROR",message:"...",request_id:"..."}}` |
|
||||
|
||||
> 依据 W1 / W2 裁决:错误码统一 `GW_` 前缀,响应体统一 ActionState 信封 `{success,error:{code,message}}`。
|
||||
|
||||
---
|
||||
|
||||
@@ -42,22 +92,48 @@
|
||||
|
||||
### 2.1 gRPC 调用(同步)
|
||||
|
||||
| 被调用方 | Service.RPC | 用途 | mock 策略 |
|
||||
| ---------- | ----------------------------- | ---------------------------------------- | ----------------------------------------------------------------- |
|
||||
| iam (ai06) | IamService.GetPublicKey | 启动时拉取 RS256 公钥,用于 JWT 验签 | iam 就绪前使用本地固定 mock 公钥(与 mock 私钥配对签发 mock JWT) |
|
||||
| iam (ai06) | IamService.GetEffectiveAccess | 权限校验(可选,部分路由需要细粒度权限) | iam 就绪前放行所有请求(仅校验 JWT 签名) |
|
||||
**无**。依据 [president-final-rulings.md](../../president-final-rulings.md) §2.16 裁决"gateway 保持 HTTP 透传,不改为 gRPC 客户端",api-gateway 不消费任何 gRPC 接口。
|
||||
|
||||
### 2.2 Kafka 事件订阅(异步)
|
||||
> **勘误**(v1 版本曾错误声明消费 `IamService.GetPublicKey` 和 `IamService.GetEffectiveAccess`,v2 已删除):
|
||||
> - JWT 公钥拉取走 HTTP JWKS 端点,非 gRPC(见 §2.3)
|
||||
> - Gateway 不做权限点校验,不消费 `GetEffectiveAccess`(权限由下游服务 Controller `@RequirePermission` 自校验,见 [01-understanding.md](../../../services/api-gateway/docs/01-understanding.md) §2 + B3 裁决)
|
||||
> - [matrix.md](./matrix.md) §2 gRPC 接口提供方矩阵中"iam 消费方"应移除 api-gateway(已提请 ISSUE-001)
|
||||
|
||||
### 2.2 Kafka 事件订阅
|
||||
|
||||
无。api-gateway 不订阅 Kafka 事件。
|
||||
|
||||
### 2.3 HTTP 调用(如有)
|
||||
### 2.3 HTTP 调用(同步)
|
||||
|
||||
| 被调用方 | Method.Path | 用途 | mock 策略 |
|
||||
| ------------------ | ------------- | --------------------------- | -------------------------------------------------- |
|
||||
| teacher-bff (ai03) | POST /graphql | 反向代理教师端 GraphQL 请求 | teacher-bff 就绪前返回 502,前端使用本地 mock 数据 |
|
||||
| student-bff (ai04) | POST /graphql | 反向代理学生端 GraphQL 请求 | student-bff 就绪前返回 502 |
|
||||
| parent-bff (ai05) | POST /graphql | 反向代理家长端 GraphQL 请求 | parent-bff 就绪前返回 502 |
|
||||
| 被调用方 | Method.Path | 用途 | mock 策略 | 阶段 |
|
||||
| ------------------ | ----------------------------------- | ------------------------------------------ | --------------------------------------------------------------- | ---- |
|
||||
| iam (ai06) | `GET /.well-known/jwks.json` | 拉 RS256 公钥集(JWKS),TTL 5min 缓存 | iam 就绪前使用本地固定 mock RS256 公钥(与 mock 私钥配对签发 mock JWT)| P2 |
|
||||
| iam (ai06) | `GET /healthz` | /readyz 下游健康检查 | iam 就绪前 /readyz 软失败(返回 200 + degraded) | P2 |
|
||||
| teacher-bff (ai03) | `POST /graphql`(反向代理) | 代理教师端 GraphQL 请求 | teacher-bff 就绪前返回 503 + Retry-After,前端降级到本地 mock | P2 |
|
||||
| student-bff (ai04) | `POST /graphql`(反向代理) | 代理学生端 GraphQL 请求 | student-bff 就绪前返回 503 | P3 |
|
||||
| parent-bff (ai05) | `POST /graphql`(反向代理) | 代理家长端 GraphQL 请求 | parent-bff 就绪前返回 503 | P4 |
|
||||
| core-edu (ai08) | `GET /healthz` + 业务 REST(反向代理)| /readyz 检查 + 业务请求代理 | core-edu 就绪前 /readyz 软失败 | P3 |
|
||||
| content (ai09) | `GET /healthz` + 业务 REST | /readyz 检查 + 业务请求代理 | content 就绪前 /readyz 软失败 | P4 |
|
||||
| data-ana (ai11) | `GET /healthz` + 业务 REST | /readyz 检查 + 业务请求代理 | data-ana 就绪前 /readyz 软失败 | P4 |
|
||||
| msg (ai10) | `GET /healthz` + 业务 REST | /readyz 检查 + 业务请求代理 | msg 就绪前 /readyz 软失败 | P5 |
|
||||
| ai (ai12) | `GET /healthz` + 业务 REST | /readyz 检查 + 业务请求代理 | ai 就绪前 /readyz 软失败 | P5 |
|
||||
|
||||
> **JWKS 缓存策略**([packages/shared-go/jwks/jwks.go](../../../packages/shared-go/jwks/jwks.go)):
|
||||
> - TTL 5min,到期后台异步刷新(不阻塞请求)
|
||||
> - kid 未命中时强制同步刷新一次
|
||||
> - 刷新失败保留旧公钥集继续服务(fail-open 1 次后 fail-close)
|
||||
> - 启动时同步拉取一次,失败则 panic 拒绝启动
|
||||
|
||||
### 2.4 shared-go 包依赖
|
||||
|
||||
依据 [president-final-rulings.md](../../president-final-rulings.md) §2.19 裁决,ai01 直接 import `packages/shared-go`:
|
||||
|
||||
| 模块 | 用途 | 接入阶段 |
|
||||
| ----------------- | ------------------------------------------ | -------- |
|
||||
| `shared-go/jwks` | JWKS Fetcher(HTTP 拉 RS256 公钥 + 缓存) | P2.2 |
|
||||
| `shared-go/logger`| 结构化日志(zap 或 slog,待 ISSUE-004 仲裁)| P2.1 |
|
||||
| `shared-go/tracer`| OTel tracer 初始化(评估接入,若接口兼容) | P2.1 |
|
||||
| `shared-go/env` | 环境变量加载(评估接入,若接口兼容) | P2.1 |
|
||||
|
||||
---
|
||||
|
||||
@@ -65,38 +141,70 @@
|
||||
|
||||
### 3.1 我依赖的上游就绪标志
|
||||
|
||||
- [ ] iam gRPC 50052 启用(ai06)—— GetPublicKey 拉取验签公钥
|
||||
- [ ] teacher-bff GraphQL :3003 启用(ai03)
|
||||
- [ ] student-bff GraphQL :3009 启用(ai04)
|
||||
- [ ] parent-bff GraphQL :3010 启用(ai05)
|
||||
| 上游 | 就绪标志 | 阶段 | 状态 |
|
||||
| ---- | -------- | ---- | ---- |
|
||||
| coord | shared-go 包骨架(tracer/logger/jwks/env 4 模块)| 批次 0 | ✅ 已完成 |
|
||||
| coord | ISSUE-001 仲裁(JWKS HTTP 确认)| P2 启动前 | ⏳ 待仲裁 |
|
||||
| coord | ISSUE-002 仲裁(shared-go 接入)| P2 启动前 | ⏳ 待仲裁 |
|
||||
| coord | ISSUE-003 仲裁(API 版本化路由方案)| P2.7 前 | ⏳ 待仲裁 |
|
||||
| coord | ISSUE-004 仲裁(zap vs slog)| P2.1 前 | ⏳ 待仲裁 |
|
||||
| iam (ai06) | `GET /.well-known/jwks.json` HTTP 端点 + RS256 JWT 签发 | P2 | ⏳ |
|
||||
| iam (ai06) | `GET /healthz` 端点 | P2 | ⏳ |
|
||||
| teacher-bff (ai03) | `POST /graphql` :3003 启用 + `GET /healthz` | P2 | ⏳ |
|
||||
| student-bff (ai04) | `POST /graphql` :3009 启用 + `GET /healthz` | P3 | ⏳ |
|
||||
| core-edu (ai08) | `GET /healthz` + classes 合并 | P3 | ⏳ |
|
||||
| parent-bff (ai05) | `POST /graphql` :3010 启用 + `GET /healthz` | P4 | ⏳ |
|
||||
| content (ai09) | `GET /healthz` + REST 端点 | P4 | ⏳ |
|
||||
| data-ana (ai11) | `GET /healthz` + REST 端点 | P4 | ⏳ |
|
||||
| msg (ai10) | `GET /healthz` + REST 端点 | P5 | ⏳ |
|
||||
| ai (ai12) | `GET /healthz` + REST 端点 | P5 | ⏳ |
|
||||
| push-gateway (ai02) | :8081 启用 + /internal/push(WebSocket 协作评估)| P5 | ⏳ |
|
||||
|
||||
### 3.2 我的就绪标志(供下游消费)
|
||||
|
||||
- [ ] api-gateway HTTP :8080 启用(/healthz 返回 200)
|
||||
- [ ] /readyz 返回 200(含 iam 连通性检查通过)
|
||||
- [ ] JWT 验签链路打通(使用 iam 公钥校验 access_token)
|
||||
- [ ] /api/auth/* 代理到 iam 认证链路可用
|
||||
- [ ] /api/teacher/* /api/student/* /api/parent/* 反向代理到各 BFF 可用
|
||||
- [ ] 限流(IP 级令牌桶)+ 熔断(各后端独立熔断器)生效
|
||||
| 阶段 | 就绪标志 | 状态 |
|
||||
| ---- | -------- | ---- |
|
||||
| P2 | api-gateway HTTP :8080 启用(/healthz 返回 200)| ⏳ |
|
||||
| P2 | /readyz 返回 200(含 iam + teacher-bff 连通性检查通过)| ⏳ |
|
||||
| P2 | JWT RS256 验签链路打通(使用 iam JWKS 公钥校验 access_token)| ⏳ |
|
||||
| P2 | /api/v1/iam/v1/* 代理到 iam 认证链路可用 | ⏳ |
|
||||
| P2 | /api/v1/teacher/v1/* 反向代理到 teacher-bff GraphQL 可用 | ⏳ |
|
||||
| P2 | 限流(IP 级令牌桶)+ 熔断(共享 downstream)+ CORS 白名单生效 | ⏳ |
|
||||
| P2 | 7 个业务指标暴露在 /metrics | ⏳ |
|
||||
| P2 | 错误响应统一 ActionState 信封 + GW_ 前缀 | ⏳ |
|
||||
| P3 | /api/v1/student/v1/* + /api/v1/exams/v1/* 等路由可用 | ⏳ |
|
||||
| P4 | /api/v1/parent/v1/* + /api/v1/textbooks/v1/* + /api/v1/analytics/v1/* 路由可用 | ⏳ |
|
||||
| P5 | /api/v1/notifications/v1/* + /api/v1/ai/v1/* 路由可用 | ⏳ |
|
||||
| P6 | 限流迁 Redis + 测试覆盖率 ≥ 80% | ⏳ |
|
||||
|
||||
---
|
||||
|
||||
## §4 Mock 策略
|
||||
|
||||
### 4.1 我提供的 mock
|
||||
### 4.1 我提供的 mock(供下游各前端 portal 消费)
|
||||
|
||||
在 api-gateway 真实就绪前,为下游(各前端 portal)提供以下 mock:
|
||||
在 api-gateway 真实就绪前,为下游(teacher-portal / student-portal / parent-portal / admin-portal)提供以下 mock:
|
||||
|
||||
- **HTTP mock**:使用 MSW(Mock Service Worker)或本地 nginx 拦截
|
||||
- /api/auth/login 返回固定 JWT(mock 签发)+ UserInfo
|
||||
- /api/teacher/* /api/student/* /api/parent/* 直接返回各 BFF 的 mock GraphQL 响应
|
||||
- /healthz /readyz 返回 200
|
||||
- **HTTP mock**(由各前端 portal 自行用 MSW 拦截,api-gateway 不提供 mock 服务):
|
||||
- `/api/v1/iam/v1/login` 返回固定 JWT(mock 签发)+ UserInfo
|
||||
- `/api/v1/teacher/v1/*` `/api/v1/student/v1/*` `/api/v1/parent/v1/*` 直接返回各 BFF 的 mock GraphQL 响应
|
||||
- `/healthz` `/readyz` 返回 200
|
||||
- **JWT mock**:前端开发期使用固定 mock JWT(api-gateway 就绪前不走真实验签)
|
||||
|
||||
### 4.2 我消费的 mock
|
||||
### 4.2 我消费的 mock(在真实上游就绪前)
|
||||
|
||||
在真实上游就绪前,api-gateway 使用以下 mock:
|
||||
|
||||
- **iam 公钥**:使用本地固定 mock RS256 公钥(与 mock 私钥配对),验签 mock JWT
|
||||
- **iam 权限校验**:GetEffectiveAccess 返回 allowed=true,放行所有请求
|
||||
- **各 BFF 代理**:BFF 就绪前返回 503 + Retry-After,前端降级到本地 mock 数据
|
||||
- **iam JWKS 公钥**:使用本地固定 mock RS256 公钥(与 mock 私钥配对),验签 mock JWT(DevMode 下生效)
|
||||
- **iam /readyz 检查**:iam 就绪前软失败,返回 200 + `degraded: true`
|
||||
- **各 BFF 代理**:BFF 就绪前返回 503 + `Retry-After`,前端降级到本地 mock 数据
|
||||
- **下游 /healthz 检查**:未就绪服务软失败(返回 200 + degraded),已就绪服务硬失败(返回 503)
|
||||
|
||||
---
|
||||
|
||||
## §5 变更记录
|
||||
|
||||
| 版本 | 日期 | 变更内容 | 变更者 |
|
||||
| ---- | ---------- | ------------------------------------------------------------------------ | ------ |
|
||||
| v1 | 2026-07-09 | 初始创建(含错误:/api/* 路径、gRPC GetPublicKey、GetEffectiveAccess) | ai01 |
|
||||
| v2 | 2026-07-10 | 修正:路径 /api→/api/v1、JWKS 拉取 gRPC→HTTP、删除 GetEffectiveAccess、错误码加 GW_ 前缀、对齐 ActionState 信封、补充 shared-go 依赖、补充 admin-portal P6 路由 | ai01 |
|
||||
|
||||
@@ -1,24 +1,3 @@
|
||||
# api-gateway 问题记录
|
||||
|
||||
> 负责人:ai01
|
||||
> 关联:[coord.md](../coord.md)、[contracts/api-gateway_contract.md](../contracts/api-gateway_contract.md)
|
||||
> 规则:AI 遇到问题时在此追加条目,coord 仲裁后更新状态
|
||||
|
||||
---
|
||||
|
||||
## 问题列表
|
||||
|
||||
<!--
|
||||
追加条目格式:
|
||||
|
||||
### ISSUE-[编号]-[AI标识]:[标题]
|
||||
|
||||
- **提请方**:aiXX
|
||||
- **日期**:YYYY-MM-DD
|
||||
- **类型**:契约不明确 / 工作量超批 / 前置依赖缺失 / 编号冲突 / 其他
|
||||
- **描述**:[详细描述问题]
|
||||
- **建议方案**:[AI 的建议]
|
||||
- **状态**:待 coord 仲裁 / 已裁决(见 coord.md §X)
|
||||
-->
|
||||
|
||||
(暂无问题)
|
||||
> 负
|
||||
@@ -1,57 +1,393 @@
|
||||
# api-gateway 工作排期
|
||||
|
||||
> 负责人:ai01
|
||||
> 关联:[workline.md](../workline.md)、[coord.md](../coord.md)、[contracts/api-gateway_contract.md](../contracts/api-gateway_contract.md)
|
||||
> 关联:[workline.md](../workline.md)、[coord.md](../coord.md)、[contracts/api-gateway_contract.md](../contracts/api-gateway_contract.md)、[objections/api-gateway_issue.md](../objections/api-gateway_issue.md)
|
||||
> 模式:全并行(各 AI 一口气完成 P2-P6 全部代码,最后统一集成测试)
|
||||
> 依据:[coord-final-decisions.md](../../coord-final-decisions.md) §3.8 W1-W8、[president-final-rulings.md](../../president-final-rulings.md) §2.15/§2.16/§2.19、[02-architecture-design.md](../../../services/api-gateway/docs/02-architecture-design.md) §9
|
||||
|
||||
---
|
||||
|
||||
## §1 总览
|
||||
|
||||
api-gateway 是 Edu 系统统一入口,负责路由、JWT 验签、限流、熔断、CORS。全阶段目标:P2 路由+JWT → P3 限流加固 → P4-P6 持续优化。
|
||||
api-gateway 是 Edu 系统统一入口(L3 网关层),负责路由转发、JWT RS256 验签、限流、熔断、CORS、可观测性。无业务状态,纯 HTTP 反向代理。
|
||||
|
||||
**全阶段目标**:
|
||||
- **P2**:路由表 + JWT RS256(HTTP JWKS) + shared-go 接入 + 错误码 GW_ 前缀 + ActionState 信封 + slog + /readyz 真实检查 + 业务 metrics + tracer 资源属性 + DevMode 防护(遵循 W1-W8 / G1-G17 裁决)
|
||||
- **P3**:路由扩展(student-bff :3009)+ core-edu 路由
|
||||
- **P4**:路由扩展(parent-bff :3010)+ content / data-ana 路由
|
||||
- **P5**:路由扩展(msg / ai 路由)+ 接入 push-gateway 协作(WebSocket 升级透传评估)
|
||||
- **P6**:限流迁 Redis + per-服务实例熔断评估 + 测试覆盖率 ≥ 80% + 安全加固
|
||||
|
||||
**当前状态(2026-07-10)**:P1 已交付(classes 域 CRUD 端到端跑通),P2 升级未启动。已有仲裁核查发现 6 项未遵循裁决(见 [objections/api-gateway_issue.md](../objections/api-gateway_issue.md) §0.4)。
|
||||
|
||||
---
|
||||
|
||||
## §2 全阶段甘特图(P2-P6,各 AI 自行细化)
|
||||
## §2 全阶段甘特图(P2-P6)
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
title ai01 api-gateway 全阶段排期
|
||||
title ai01 api-gateway 全阶段排期(P2-P6)
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %m-%d
|
||||
|
||||
section P2 基础
|
||||
路由表+双入口+shared-go :a1a, 2026-07-10, 3d
|
||||
JWT校验+JWKS fetcher :a1b, after a1a, 3d
|
||||
限流+熔断+CORS :a1c, after a1b, 2d
|
||||
section P2 基础升级(批次1)
|
||||
P2.0 修复P0遗留 :crit, p2a, 2026-07-10, 1d
|
||||
P2.1 shared-go接入 :crit, p2b, after p2a, 2d
|
||||
P2.2 JWT RS256+JWKS :crit, p2c, after p2b, 3d
|
||||
P2.3 错误码GW_+ActionState :crit, p2d, after p2c, 1d
|
||||
P2.4 slog+metrics+tracer :crit, p2e, after p2d, 2d
|
||||
P2.5 /readyz真实检查 :crit, p2f, after p2e, 1d
|
||||
P2.6 DevMode防护 :p2g, after p2f, 1d
|
||||
P2.7 路由表扩展iam/teacher :p2h, after p2g, 1d
|
||||
|
||||
section P3-P6 持续优化
|
||||
路由扩展(student/parent/admin) :a1d, after a1c, 2d
|
||||
指标+链路加固 :a1e, after a1d, 2d
|
||||
section P3 路由扩展(批次2)
|
||||
P3.1 student-bff路由 :p3a, after p2h, 1d
|
||||
P3.2 core-edu路由 :p3b, after p3a, 1d
|
||||
P3.3 API版本化/v1迁移 :p3c, after p3b, 2d
|
||||
|
||||
section P4 路由扩展(批次3)
|
||||
P4.1 parent-bff路由 :p4a, after p3c, 1d
|
||||
P4.2 content路由 :p4b, after p4a, 1d
|
||||
P4.3 data-ana路由 :p4c, after p4b, 1d
|
||||
|
||||
section P5 路由扩展(批次4)
|
||||
P5.1 msg路由 :p5a, after p4c, 1d
|
||||
P5.2 ai路由 :p5b, after p5a, 1d
|
||||
P5.3 push-gateway协作评估 :p5c, after p5b, 2d
|
||||
|
||||
section P6 硬化(批次5)
|
||||
P6.1 限流迁Redis :p6a, after p5c, 3d
|
||||
P6.2 per-服务熔断评估 :p6b, after p6a, 2d
|
||||
P6.3 测试覆盖率80% :p6c, after p6b, 3d
|
||||
P6.4 安全加固 :p6d, after p6c, 2d
|
||||
```
|
||||
|
||||
> **注意**:以上为 coord 初始规划,ai01 接管后必须自行细化为完整 P2-P6 排期。
|
||||
**关键路径**(红色 crit):P2.0 → P2.1 → P2.2 → P2.3 → P2.4 → P2.5 → P2.6 → P2.7
|
||||
**总时间线**:P2 约 11 天 + P3-P5 约 9 天 + P6 约 10 天 = 约 30 天
|
||||
|
||||
---
|
||||
|
||||
## §3 详细任务
|
||||
|
||||
### P2:路由表 + JWT + 限流
|
||||
### P2.0:修复 P0 遗留问题
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:无
|
||||
- **交付物**:
|
||||
- `services/api-gateway/internal/routing/router.go` — 路由表
|
||||
- `/api/v1/teacher/*` → teacher-bff:3003 代理
|
||||
- `/api/v1/iam/*` → iam:3002 代理
|
||||
- JWT RS256 验签(shared-go/jwks)
|
||||
- 限流 + 熔断 + CORS
|
||||
- **依赖**:shared-go 骨架(批次 0 已完成)+ iam GetPublicKey(ai06)
|
||||
- **验收标准**:路由双入口 + JWT 验签 + 限流 + CORS 白名单
|
||||
- **完整 P3-P6 任务**:⚠️ 由 ai01 自行补充
|
||||
- `services/api-gateway/go.mod` L3 改为 `go 1.22`(修复 ISSUE-005)
|
||||
- `go.work` L1 改为 `go 1.22`
|
||||
- 删除 [01-understanding.md](../../../services/api-gateway/docs/01-understanding.md) §7.1 issue #3 死代码引用(ISSUE-008)
|
||||
- 修正 [01-understanding.md](../../../services/api-gateway/docs/01-understanding.md) §6 审计表 metrics 行(ISSUE-007)
|
||||
- 修正 [README.md](../../../services/api-gateway/README.md) L38 删除不存在的 `/health` 兼容端点描述
|
||||
- 修正 [proxy.go](../../../services/api-gateway/internal/proxy/proxy.go) L24 删除冗余 `TrimPrefix("/api")`
|
||||
- **验收标准**:`go build ./...` + `go vet ./...` 通过;文档与代码一致
|
||||
- **对应 ISSUE**:ISSUE-005 / ISSUE-007 / ISSUE-008
|
||||
|
||||
### P2.1:shared-go 包接入
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:[packages/shared-go](../../../packages/shared-go/) 已建立(批次 0 已完成);coord 仲裁 ISSUE-002 / ISSUE-004
|
||||
- **交付物**:
|
||||
- `go.work` 增加 `./packages/shared-go`
|
||||
- `services/api-gateway/go.mod` 增加 `github.com/edu-cloud/shared-go` 依赖
|
||||
- 按 ISSUE-004 仲裁结果接入 shared-go/logger(zap 或 slog,取决于 coord 裁决)
|
||||
- [tracer.go](../../../services/api-gateway/internal/observability/tracer.go) 评估接入 shared-go/tracer(若接口兼容)
|
||||
- [config.go](../../../services/api-gateway/internal/config/config.go) 评估接入 shared-go/env
|
||||
- **验收标准**:`go build ./...` 通过;import shared-go 成功;logger 输出结构化 JSON
|
||||
- **对应 ISSUE**:ISSUE-002 / ISSUE-004
|
||||
|
||||
### P2.2:JWT RS256 升级 + JWKS 缓存
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:iam (ai06) 暴露 `GET /.well-known/jwks.json` HTTP 端点;coord 仲裁 ISSUE-001(确认 HTTP JWKS)
|
||||
- **交付物**:
|
||||
- [auth.go](../../../services/api-gateway/internal/middleware/auth.go) 改用 shared-go/jwks.Fetcher(`jwks.NewFetcher(cfg.JWKSURL)`)
|
||||
- HS256 逻辑废弃,`cfg.JWTSecret` 仅 DevMode 下用作 mock 密钥
|
||||
- JWKS 缓存策略:TTL 5min(shared-go/jwks 默认),kid 未命中时强制刷新,刷新失败保留旧公钥
|
||||
- 启动时同步拉取一次 JWKS,失败则 panic 拒绝启动
|
||||
- claims 增加 `data_scope` 字段提取,注入 `x-data-scope` 头
|
||||
- `internal/config/config.go` 增加 `JWKSURL` 字段(环境变量 `IAM_JWKS_URL`)
|
||||
- **验收标准**:JWT RS256 验签通过;JWKS 缓存命中率达 99%+;kid 未命中自动刷新
|
||||
- **对应裁决**:W1(错误码加 GW_ 前缀)、§2.16(HTTP JWKS,非 gRPC)
|
||||
|
||||
### P2.3:错误码 GW_ 前缀 + ActionState 信封
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:无
|
||||
- **交付物**:
|
||||
- [auth.go](../../../services/api-gateway/internal/middleware/auth.go) 错误码改为 `GW_UNAUTHORIZED` / `GW_INVALID_TOKEN` / `GW_INVALID_CLAIMS`
|
||||
- [ratelimit.go](../../../services/api-gateway/internal/middleware/ratelimit.go) 响应体改为 `{success:false,error:{code:"GW_RATE_LIMITED",message:"...",retry_after:60}}`
|
||||
- [circuit-breaker.go](../../../services/api-gateway/internal/middleware/circuit-breaker.go) 响应体改为 `{success:false,error:{code:"GW_CIRCUIT_OPEN",message:"...",retry_after:30}}`
|
||||
- [recovery.go](../../../services/api-gateway/internal/middleware/recovery.go) 响应体改为 `{success:false,error:{code:"GW_INTERNAL_ERROR",message:"...",request_id:"..."}}`
|
||||
- `RequestBodyLimit` 超限响应改为 `{success:false,error:{code:"GW_REQUEST_TOO_LARGE",message:"..."}}`
|
||||
- **验收标准**:所有错误响应符合 ActionState 信封;错误码统一 `GW_` 前缀
|
||||
- **对应裁决**:W1 / W2 / G14
|
||||
- **对应 ISSUE**:ISSUE-009
|
||||
|
||||
### P2.4:slog + 业务 metrics + tracer 资源属性
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:P2.1 shared-go 接入完成
|
||||
- **交付物**:
|
||||
- 按 ISSUE-004 仲裁结果统一 logger(zap 或 slog)
|
||||
- 所有 `log.Printf` / `log.Println` / `log.Fatal` 改为结构化日志(带 `request_id` / `trace_id` / `user_id` / `method` / `path` / `status` / `latency_ms` 字段)
|
||||
- 新增 `internal/observability/metrics.go`,注册 7 个业务指标:
|
||||
- `api_gateway_http_requests_total`(Counter,method/endpoint/status)
|
||||
- `api_gateway_http_request_duration_seconds`(Histogram,method/endpoint)
|
||||
- `api_gateway_circuit_breaker_state`(Gauge,service/state)
|
||||
- `api_gateway_rate_limited_total`(Counter,ip)
|
||||
- `api_gateway_proxy_upstream_duration_seconds`(Histogram,upstream)
|
||||
- `api_gateway_jwks_refresh_total`(Counter,result)
|
||||
- `api_gateway_auth_failures_total`(Counter,reason)
|
||||
- [tracer.go](../../../services/api-gateway/internal/observability/tracer.go) 资源属性补全:`service.name` + `service.version`(编译时注入)+ `deployment.environment`(ENV 变量)+ `host.name`
|
||||
- Metrics 中间件:在 Auth 之后、CircuitBreaker 之前注册(统计通过鉴权的请求)
|
||||
- **验收标准**:`/metrics` 端点返回 7 个业务指标;日志为 JSON 结构化;tracer 资源属性完整
|
||||
- **对应裁决**:W3 / W5 / W6 / G4 / G5 / G6
|
||||
|
||||
### P2.5:/readyz 真实健康检查
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:所有下游服务实现 `/healthz`(P2 阶段 iam / teacher-bff 已就绪)
|
||||
- **交付物**:
|
||||
- [health.go](../../../services/api-gateway/internal/health/health.go) `Readyz` 重构为并行 ping 下游 `/healthz`
|
||||
- 下游清单从 `cfg.ServicesURL` 动态读取(iam / classes / teacher-bff / core-edu / content / msg / ai / data-ana)
|
||||
- 超时 2s,任一不可达返回 503 + `{"status":"error","unhealthy":["iam","core-edu"]}`
|
||||
- 全部可达返回 200 + `{"status":"ok"}`
|
||||
- 可选依赖软失败规则:未启用 gRPC 的下游(P3-P5 阶段未就绪的服务)失败仅告警,返回 200 + `degraded: true`(依据 president-final-rulings.md §3.3)
|
||||
- **验收标准**:/readyz 真实检查下游;某服务下线时返回 503
|
||||
- **对应裁决**:W4 / G2
|
||||
|
||||
### P2.6:DevMode 生产防护
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:无
|
||||
- **交付物**:
|
||||
- [config.go](../../../services/api-gateway/internal/config/config.go) `Load()` 增加 `ENV` 环境变量读取
|
||||
- 若 `DevMode=true && ENV=production` 则 `panic` 拒绝启动
|
||||
- 启动日志打印 `ENV` / `DevMode` 状态
|
||||
- **验收标准**:`DEV_MODE=true ENV=production` 启动失败;`DEV_MODE=true ENV=development` 启动成功
|
||||
- **对应裁决**:W7
|
||||
|
||||
### P2.7:路由表扩展(iam / teacher)
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:coord 仲裁 ISSUE-003(API 版本化路由规则);iam (ai06) / teacher-bff (ai03) P2 就绪
|
||||
- **交付物**:
|
||||
- 按 ISSUE-003 仲裁结果更新路由(方案 A/B/C 之一)
|
||||
- 若方案 A:iam 路由改为 `/api/v1/iam/v1/*path`,proxy 透传 `/iam/v1/*path`
|
||||
- teacher-bff 路由保持 `/api/v1/teacher/*path`
|
||||
- [02-architecture-design.md](../../../services/api-gateway/docs/02-architecture-design.md) §4.1 路由表同步更新
|
||||
- **验收标准**:路由表与代码一致;前端调用 `/api/v1/iam/v1/auth/login` 透传到 iam 服务
|
||||
- **对应裁决**:§2.15
|
||||
|
||||
---
|
||||
|
||||
### P3.1:student-bff 路由
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:student-bff (ai04) P3 就绪
|
||||
- **交付物**:
|
||||
- `main.go` 增加 student-bff 路由:`/api/v1/student` + `/api/v1/student/*path` → `cfg.StudentBffURL`(:3009)
|
||||
- `config.go` 增加 `StudentBffURL` 字段(环境变量 `STUDENT_BFF_URL`)
|
||||
- **验收标准**:`/api/v1/student/*` 代理到 student-bff:3009
|
||||
|
||||
### P3.2:core-edu 路由
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:core-edu (ai08) P3 就绪;classes 服务已合并入 core-edu(C1 裁决)
|
||||
- **交付物**:
|
||||
- `main.go` classes 路由目标改为 core-edu(`cfg.ClassesServiceURL` → `cfg.CoreEduServiceURL`)
|
||||
- 或保留 classes 路由别名,proxy 到 core-edu
|
||||
- exams / homework / grades 路由已在 P1 实现,无需修改
|
||||
- **验收标准**:`/api/v1/classes/*` 代理到 core-edu:3004
|
||||
|
||||
### P3.3:API 版本化 /v1 迁移
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:P2.7 路由规则仲裁结果;core-edu (ai08) P3 就绪
|
||||
- **交付物**:
|
||||
- 按 ISSUE-003 仲裁结果,全服务路由统一加 `/v1` 前缀
|
||||
- core-edu 路由:`/api/v1/exams/v1/*path` 等(若方案 A)
|
||||
- 更新 [02-architecture-design.md](../../../services/api-gateway/docs/02-architecture-design.md) §4.1 路由表
|
||||
- **验收标准**:所有业务路由含 `/v1` 版本前缀
|
||||
|
||||
---
|
||||
|
||||
### P4.1:parent-bff 路由
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:parent-bff (ai05) P4 就绪
|
||||
- **交付物**:
|
||||
- `main.go` 增加 parent-bff 路由:`/api/v1/parent` + `/api/v1/parent/*path` → `cfg.ParentBffURL`(:3010)
|
||||
- `config.go` 增加 `ParentBffURL` 字段
|
||||
- **验收标准**:`/api/v1/parent/*` 代理到 parent-bff:3010
|
||||
|
||||
### P4.2:content 路由
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:content (ai09) P4 就绪
|
||||
- **交付物**:
|
||||
- `main.go` 已有 content 路由(P1 实现:textbooks / chapters / knowledge-points / questions)
|
||||
- 验证路由目标 `cfg.ContentServiceURL`(:3005)正确
|
||||
- 按 P3.3 版本化规则加 `/v1` 前缀
|
||||
- **验收标准**:content 路由可用 + 版本化
|
||||
|
||||
### P4.3:data-ana 路由
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:data-ana (ai11) P4 就绪
|
||||
- **交付物**:
|
||||
- `main.go` 已有 data-ana 路由(P1 实现:analytics)
|
||||
- 增加 `dashboard` 路由别名:`/api/v1/dashboard` + `/*path` → data-ana
|
||||
- 按版本化规则加 `/v1` 前缀
|
||||
- **验收标准**:data-ana 路由可用 + dashboard 别名可用
|
||||
|
||||
---
|
||||
|
||||
### P5.1:msg 路由
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:msg (ai10) P5 就绪
|
||||
- **交付物**:
|
||||
- `main.go` 已有 msg 路由(P1 实现:notifications)
|
||||
- 增加 `messages` 路由别名:`/api/v1/messages` + `/*path` → msg
|
||||
- 按版本化规则加 `/v1` 前缀
|
||||
- **验收标准**:msg 路由可用 + messages 别名可用
|
||||
|
||||
### P5.2:ai 路由
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:ai (ai12) P5 就绪
|
||||
- **交付物**:
|
||||
- `main.go` 已有 ai 路由(P1 实现)
|
||||
- 按版本化规则加 `/v1` 前缀
|
||||
- **验收标准**:ai 路由可用
|
||||
|
||||
### P5.3:push-gateway 协作评估
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:push-gateway (ai02) P5 就绪
|
||||
- **交付物**:
|
||||
- 评估 WebSocket 升级请求是否需要 Gateway 透传到 push-gateway
|
||||
- 若需要:增加 `/ws` + `/sse` 路由透传到 push-gateway(:8081)
|
||||
- 若不需要:文档说明 WebSocket 直连 push-gateway,不经过 Gateway
|
||||
- 更新 [02-architecture-design.md](../../../services/api-gateway/docs/02-architecture-design.md) §7 交互点清单
|
||||
- **验收标准**:WebSocket 推送链路可用(透传或直连)
|
||||
|
||||
---
|
||||
|
||||
### P6.1:限流迁 Redis
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:Redis 基础设施就绪
|
||||
- **交付物**:
|
||||
- [ratelimit.go](../../../services/api-gateway/internal/middleware/ratelimit.go) 改用 Redis 令牌桶(`github.com/go-redis/redis_rate/v10`)
|
||||
- 支持多副本一致限流
|
||||
- 增加用户级限流(基于 `x-user-id` 头)
|
||||
- 登录接口额外加用户级限流(防爆破)
|
||||
- 保留 DevMode 下内存令牌桶回退
|
||||
- **验收标准**:多副本部署时限流一致;用户级限流生效
|
||||
|
||||
### P6.2:per-服务实例熔断评估
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:P6.1 完成
|
||||
- **交付物**:
|
||||
- 评估是否将共享 `downstream` 熔断器拆分为 per-服务实例(iam / core-edu / teacher-bff 等)
|
||||
- 若拆分:每个下游服务独立熔断状态,互不影响
|
||||
- 若不拆分:保持 W8 裁决现状,文档说明理由
|
||||
- 按 W8 裁决,此项 P6 单独评估,不强制拆分
|
||||
- **验收标准**:评估报告 + 决策记录
|
||||
|
||||
### P6.3:测试覆盖率 80%
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:P2-P5 全部完成
|
||||
- **交付物**:
|
||||
- 补全 [auth_test.go](../../../services/api-gateway/internal/middleware/auth_test.go):JWKS 验签 / claims 解析 / DevMode 旁路 / 公开路径白名单
|
||||
- 补全 [cors_test.go](../../../services/api-gateway/internal/middleware/cors_test.go):白名单匹配 / 预检请求 / Vary 头
|
||||
- 补全 [security_test.go](../../../services/api-gateway/internal/middleware/security_test.go):安全头设置 / Server 头移除
|
||||
- 补全 [recovery_test.go](../../../services/api-gateway/internal/middleware/recovery_test.go):panic 捕获 / request_id 生成 / ActionState 信封
|
||||
- 补全 [requestid_test.go](../../../services/api-gateway/internal/middleware/requestid_test.go):透传 / 生成 / 响应头
|
||||
- 补全 [proxy_test.go](../../../services/api-gateway/internal/proxy/proxy_test.go):路径前缀去除 / Host 改写
|
||||
- 补全 [health_test.go](../../../services/api-gateway/internal/health/health_test.go):/readyz 下游检查 / 软失败规则
|
||||
- **验收标准**:`go test ./... -cover` 覆盖率 ≥ 80%
|
||||
|
||||
### P6.4:安全加固
|
||||
|
||||
- **负责人**:ai01
|
||||
- **依赖**:P6.1-P6.3 完成
|
||||
- **交付物**:
|
||||
- 评估 IP 黑名单 / WAF 规则是否在 Gateway 层实现(建议在 Istio 层做,本服务不介入)
|
||||
- 限流策略表 per-路由细化(02 §4.2)
|
||||
- 熔断阈值 per-服务配置(02 §4.3)
|
||||
- CORS 白名单生产环境强制配置(禁止 `*`)
|
||||
- 审计日志:记录所有 401 / 403 / 429 / 503 响应
|
||||
- **验收标准**:安全扫描通过;审计日志可追溯
|
||||
|
||||
---
|
||||
|
||||
## §4 依赖与就绪信号
|
||||
|
||||
- **我依赖**:iam GetPublicKey RPC(ai06)
|
||||
- **我的就绪信号**:api-gateway :8080 可访问 + JWT 验签可用
|
||||
### 4.1 我依赖的上游就绪标志
|
||||
|
||||
| 上游 | 就绪标志 | 阶段 | 状态 |
|
||||
| ---- | -------- | ---- | ---- |
|
||||
| coord | shared-go 包骨架(tracer/logger/jwks/env)| 批次 0 | ✅ 已完成 |
|
||||
| coord | ISSUE-001 仲裁(JWKS vs gRPC)| P2 启动前 | ⏳ 待仲裁 |
|
||||
| coord | ISSUE-002 仲裁(shared-go 接入)| P2 启动前 | ⏳ 待仲裁 |
|
||||
| coord | ISSUE-003 仲裁(API 版本化路由)| P2.7 前 | ⏳ 待仲裁 |
|
||||
| coord | ISSUE-004 仲裁(zap vs slog)| P2.1 前 | ⏳ 待仲裁 |
|
||||
| iam (ai06) | `GET /.well-known/jwks.json` HTTP 端点 + RS256 签发 | P2 | ⏳ |
|
||||
| iam (ai06) | gRPC 50052 启用(不影响 Gateway,Gateway 走 HTTP)| P2 | ⏳ |
|
||||
| teacher-bff (ai03) | `POST /graphql` :3003 启用 | P2 | ⏳ |
|
||||
| student-bff (ai04) | `POST /graphql` :3009 启用 | P3 | ⏳ |
|
||||
| core-edu (ai08) | gRPC 50053 启用 + classes 合并 | P3 | ⏳ |
|
||||
| parent-bff (ai05) | `POST /graphql` :3010 启用 | P4 | ⏳ |
|
||||
| content (ai09) | gRPC 50054 启用 | P4 | ⏳ |
|
||||
| data-ana (ai11) | gRPC 50055 启用 | P4 | ⏳ |
|
||||
| msg (ai10) | gRPC 50056 启用 | P5 | ⏳ |
|
||||
| ai (ai12) | gRPC 50058 启用 | P5 | ⏳ |
|
||||
| push-gateway (ai02) | :8081 启用 + /internal/push | P5 | ⏳ |
|
||||
|
||||
### 4.2 我的就绪标志(供下游消费)
|
||||
|
||||
| 阶段 | 就绪标志 | 状态 |
|
||||
| ---- | -------- | ---- |
|
||||
| P2 | api-gateway :8080 可访问 + JWT RS256 验签可用 + 7 个业务指标 + /readyz 真实检查 | ⏳ |
|
||||
| P2 | /api/v1/iam/* + /api/v1/teacher/* 路由可用 | ⏳ |
|
||||
| P3 | /api/v1/student/* + /api/v1/exams/* 等路由可用 | ⏳ |
|
||||
| P4 | /api/v1/parent/* + /api/v1/textbooks/* + /api/v1/analytics/* 路由可用 | ⏳ |
|
||||
| P5 | /api/v1/notifications/* + /api/v1/ai/* 路由可用 | ⏳ |
|
||||
| P6 | 限流迁 Redis + 测试覆盖率 ≥ 80% | ⏳ |
|
||||
|
||||
---
|
||||
|
||||
## §5 风险与应对
|
||||
|
||||
| 风险 | 概率 | 影响 | 应对 |
|
||||
| ---- | ---- | ---- | ---- |
|
||||
| coord 仲裁延期(ISSUE-001/002/003/004)| 中 | P2 阻塞 | ai01 先按 HTTP JWKS + shared-go + 方案 A 推进,仲裁后调整 |
|
||||
| iam JWKS 端点延期 | 中 | P2.2 阻塞 | DevMode 下用本地 mock RS256 公钥(与 mock 私钥配对) |
|
||||
| shared-go 接口不兼容 | 低 | P2.1 阻塞 | ai01 自行适配,或反馈 coord 修改 shared-go |
|
||||
| 下游服务未实现 /healthz | 中 | /readyz 误报 | 软失败规则:未就绪服务失败仅告警,返回 200 + degraded |
|
||||
| JWKS 缓存过期时 iam 不可达 | 低 | 全量 401 | fail-open 1 次后 fail-close;监控 `jwks_refresh_total` 指标 |
|
||||
| DevMode 旁路误开到生产 | 低 | 鉴权绕过 | P2.6 生产防护(W7 裁决) |
|
||||
|
||||
---
|
||||
|
||||
## §6 与其他模块的协作
|
||||
|
||||
| 模块 | 协作内容 | 时机 |
|
||||
| ---- | -------- | ---- |
|
||||
| iam (ai06) | JWKS HTTP 端点 + JWT RS256 签发 | P2 |
|
||||
| teacher-bff (ai03) | 反向代理 :3003 GraphQL | P2 |
|
||||
| student-bff (ai04) | 反向代理 :3009 GraphQL | P3 |
|
||||
| parent-bff (ai05) | 反向代理 :3010 GraphQL | P4 |
|
||||
| core-edu (ai08) | 反向代理 :3004 + classes 合并 | P3 |
|
||||
| content (ai09) | 反向代理 :3005 | P4 |
|
||||
| data-ana (ai11) | 反向代理 :3006 | P4 |
|
||||
| msg (ai10) | 反向代理 :3007 | P5 |
|
||||
| ai (ai12) | 反向代理 :3008 | P5 |
|
||||
| push-gateway (ai02) | WebSocket 升级透传评估 | P5 |
|
||||
| coord | shared-go 包维护 + ISSUE 仲裁 | 持续 |
|
||||
|
||||
Reference in New Issue
Block a user