docs(api-gateway): 补充完整架构问题记录与裁决核查
完成api-gateway模块边界确认,添加W1-W8裁决遵循情况核查与架构不一致问题梳理 汇总8项待coord仲裁的issue,包含模块契约、依赖、版本、文档等问题
This commit is contained in:
@@ -1,3 +1,168 @@
|
||||
# api-gateway 问题记录
|
||||
|
||||
> 负
|
||||
> 负责人:ai01
|
||||
> 关联:[coord.md](../coord.md)、[contracts/api-gateway_contract.md](../contracts/api-gateway_contract.md)、[worklines/api-gateway_workline.md](../worklines/api-gateway_workline.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
|
||||
> 规则:AI 遇到问题时在此追加条目,coord 仲裁后更新状态
|
||||
|
||||
---
|
||||
|
||||
## §0 模块边界确认(审查结论)
|
||||
|
||||
### 0.1 边界定义(来自 [01-understanding.md](../../../services/api-gateway/docs/01-understanding.md) §2)
|
||||
|
||||
- **层级**:L3 网关层(004 §3.1 六层架构)
|
||||
- **职责**:所有外部请求的统一入口、JWT 校验、用户身份注入(`x-user-id`/`x-user-roles`/`x-data-scope`)、限流、熔断、CORS、安全头、请求 ID 注入、反向代理
|
||||
- **不负责**:
|
||||
- WebSocket 长连接管理(push-gateway 负责)
|
||||
- 用户身份认证逻辑(iam 负责,本服务只校验 JWT 签名)
|
||||
- 权限点解析(下游服务 Controller `@RequirePermission` 自校验,本服务只透传身份头)
|
||||
- 业务数据持久化(无 DB)
|
||||
- **通信方式**:入口 HTTP/REST,出口 HTTP 反向代理(`httputil.ReverseProxy`),不消费 gRPC,不接入 Kafka
|
||||
|
||||
> **边界审查结论**:边界定义清晰,与 [02-architecture-design.md](../../../services/api-gateway/docs/02-architecture-design.md) §7 交互点清单、[contracts/api-gateway_contract.md](../contracts/api-gateway_contract.md) v2 一致。本服务是纯同步 HTTP 反向代理,不持有业务状态。
|
||||
|
||||
### 0.2 W1-W8 裁决遵循情况核查(2026-07-10)
|
||||
|
||||
对照 [coord-final-decisions.md](../../coord-final-decisions.md) §3.8 W1-W8 裁决,逐项核查当前代码(P1 交付态):
|
||||
|
||||
| # | 裁决项 | 强制最终方案 | 当前代码状态 | 遵循 | 对应 ISSUE |
|
||||
| --- | -------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---- | ---------- |
|
||||
| W1 | **错误码前缀** | `GW_*`(GW_UNAUTHORIZED 等) | [auth.go](../../../services/api-gateway/internal/middleware/auth.go) 用 `UNAUTHORIZED`/`INVALID_TOKEN`/`INVALID_CLAIMS`(无 GW_ 前缀) | ❌ | ISSUE-009 |
|
||||
| W2 | **错误信封** | 首次实现即对齐 ActionState | [ratelimit.go](../../../services/api-gateway/internal/middleware/ratelimit.go) L51-54 响应 `{"error":"rate_limited","retry_after":60}`(无 success/error.code 结构);[circuit-breaker.go](../../../services/api-gateway/internal/middleware/circuit-breaker.go) L55-58 同样无信封;[recovery.go](../../../services/api-gateway/internal/middleware/recovery.go) L24-27 无信封;auth.go 部分对齐 | ❌ | ISSUE-009 |
|
||||
| W3 | **slog** | 首次实现即用 slog | 全部用 `log.Printf`:[main.go](../../../services/api-gateway/main.go) L70/160/169/176、[config.go](../../../services/api-gateway/internal/config/config.go) L38/41、[recovery.go](../../../services/api-gateway/internal/middleware/recovery.go) L22、[circuit-breaker.go](../../../services/api-gateway/internal/middleware/circuit-breaker.go) L38、[tracer.go](../../../services/api-gateway/internal/observability/tracer.go) L25/31/43/51/65/70 | ❌ | ISSUE-004 |
|
||||
| W4 | **/readyz** | 首次实现即真实健康检查(轮询下游 /healthz) | [health.go](../../../services/api-gateway/internal/health/health.go) L19-23 直接返回 200,有 TODO 注释"P7 接入服务发现后" | ❌ | — |
|
||||
| W5 | **业务 metrics** | 首次实现即基础业务指标 | [main.go](../../../services/api-gateway/main.go) L56 已注册 `/metrics` 端点(promhttp.Handler),但未注册 7 个业务指标(无 `internal/observability/metrics.go` 文件) | ⚠️ | ISSUE-007 |
|
||||
| W6 | **tracer 资源属性** | 首次实现即完整(version/env/host) | [tracer.go](../../../services/api-gateway/internal/observability/tracer.go) L47-49 只有 `service.name`,缺 `service.version`/`deployment.environment`/`host.name` | ❌ | — |
|
||||
| W7 | **DevMode 防护** | 首次实现即生产防护(DEV_MODE 仅非生产环境生效)| [config.go](../../../services/api-gateway/internal/config/config.go) `Load()` 无 `ENV` 环境变量读取,DevMode=true 时无生产防护 | ❌ | — |
|
||||
| W8 | **per-服务实例熔断** | 保持共享 downstream 熔断,per-实例 P6 单独评估 | [main.go](../../../services/api-gateway/main.go) L61 `middleware.CircuitBreaker("downstream")` 共享熔断 | ✅ | — |
|
||||
|
||||
**核查结论**:W1/W2/W3/W4/W6/W7 共 6 项未遵循裁决,W5 部分遵循,W8 已遵循。未遵循项需在 P2.0-P2.6 任务中修复(见 [workline.md](../worklines/api-gateway_workline.md) §3)。
|
||||
|
||||
### 0.3 架构文档与代码不一致问题
|
||||
|
||||
| # | 文件 | 问题 | 修复建议 |
|
||||
| --- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------ |
|
||||
| D1 | [02-architecture-design.md](../../../services/api-gateway/docs/02-architecture-design.md) §1 | 中间件链图标注顺序 `Auth → CircuitBreaker`,但 [main.go](../../../services/api-gateway/main.go) L61-63 实际顺序为 `CircuitBreaker → Auth` | 统一文档与代码(建议代码保持 CircuitBreaker 在 Auth 之前,避免未鉴权请求消耗下游配额,更新文档图) |
|
||||
| D2 | [README.md](../../../services/api-gateway/README.md) L38 | 提到 `GET /health` 兼容端点,但 [main.go](../../../services/api-gateway/main.go) 未注册 `/health` 路由 | 删除 README L38 描述(已在 workline P2.0 列出) |
|
||||
| D3 | [proxy.go](../../../services/api-gateway/internal/proxy/proxy.go) L24 | 连续两次 `TrimPrefix`(L23 去 `/api/v1`,L24 再去 `/api`),第二次无效果(首字符已是 `/`) | 删除 L24 冗余 `TrimPrefix("/api")`(已在 workline P2.0 列出) |
|
||||
| D4 | [01-understanding.md](../../../services/api-gateway/docs/01-understanding.md) §3.1 | 提到"P2 起 RS256 公钥校验时通过 IAM `/auth/jwks` 端点拉公钥",但 [contract.md](../contracts/api-gateway_contract.md) v2 §2.3 已修正为 `GET /.well-known/jwks.json` | 统一为 `/.well-known/jwks.json`(RFC 8414 标准路径) |
|
||||
|
||||
---
|
||||
|
||||
## §1 问题列表
|
||||
|
||||
<!--
|
||||
追加条目格式:
|
||||
|
||||
### ISSUE-[编号]-[AI标识]:[标题]
|
||||
|
||||
- **提请方**:aiXX
|
||||
- **日期**:YYYY-MM-DD
|
||||
- **类型**:契约不明确 / 工作量超批 / 前置依赖缺失 / 编号冲突 / 其他
|
||||
- **描述**:[详细描述问题]
|
||||
- **建议方案**:[AI 的建议]
|
||||
- **状态**:待 coord 仲裁 / 已裁决(见 coord.md §X)
|
||||
-->
|
||||
|
||||
### ISSUE-001-ai01:matrix.md gRPC 矩阵错误声明 api-gateway 消费 iam gRPC
|
||||
|
||||
- **提请方**:ai01
|
||||
- **日期**:2026-07-10
|
||||
- **类型**:契约不明确
|
||||
- **描述**:[matrix.md](../matrix.md) §2 gRPC 接口提供方矩阵中,iam 的"消费方"列包含 `api-gateway`,暗示 api-gateway 消费 iam gRPC。但依据 [president-final-rulings.md](../../president-final-rulings.md) §2.16 裁决"gateway 保持 HTTP 透传,不改为 gRPC 客户端",api-gateway 通过 HTTP JWKS 端点(`GET /.well-known/jwks.json`)拉取 RS256 公钥,不消费任何 gRPC。同时 [matrix.md](../matrix.md) §7 Mock 策略表中"api-gateway 消费 iam.GetPublicKey"也需修正为 HTTP JWKS。
|
||||
- **建议方案**:
|
||||
1. matrix.md §2 iam 行"消费方"列移除 `api-gateway`
|
||||
2. matrix.md §7 Mock 策略表中 api-gateway 行改为"硬编码 RS256 公钥(DEV_MODE)→ HTTP JWKS 端点"
|
||||
- **状态**:待 coord 仲裁
|
||||
|
||||
### ISSUE-002-ai01:shared-go 接入方式与时机
|
||||
|
||||
- **提请方**:ai01
|
||||
- **日期**:2026-07-10
|
||||
- **类型**:前置依赖缺失
|
||||
- **描述**:依据 [president-final-rulings.md](../../president-final-rulings.md) §2.19 裁决,ai01 应直接 import `packages/shared-go`(jwks/logger/tracer/env 4 模块)。但当前 [go.work](../../../go.work) L3-4 仅声明 `./services/api-gateway` 和 `./services/push-gateway`,未包含 `./packages/shared-go`;[go.mod](../../../services/api-gateway/go.mod) 也无 `github.com/edu-cloud/shared-go` 依赖。需确认 shared-go 包骨架是否已建立、模块路径命名、go.work 接入方式。
|
||||
- **建议方案**:
|
||||
1. coord 确认 `packages/shared-go` 骨架已建立(批次 0.14 任务)
|
||||
2. go.work 增加 `./packages/shared-go`
|
||||
3. ai01 go.mod 增加 `github.com/edu-cloud/shared-go` 依赖
|
||||
4. P2.1 任务接入 jwks/logger/tracer/env
|
||||
- **状态**:待 coord 仲裁
|
||||
|
||||
### ISSUE-003-ai01:API 版本化路由方案(/v1 前缀位置)
|
||||
|
||||
- **提请方**:ai01
|
||||
- **日期**:2026-07-10
|
||||
- **类型**:契约不明确
|
||||
- **描述**:依据 [president-final-rulings.md](../../president-final-rulings.md) §2.15 裁决,全服务统一加 `/v1` 前缀,Controller 内加 `v1` 前缀,Gateway 透传时不改路径。但当前 [main.go](../../../services/api-gateway/main.go) 路由为 `/api/v1/iam/*path`(无服务级 `/v1`),而 [contract.md](../contracts/api-gateway_contract.md) v2 §1.2.2 路由表列为 `/api/v1/iam/v1/*path`(方案 A,双 v1)。裁决第 4 条"避免双 v1"与 contract v2 路由表存在矛盾,需 coord 仲裁最终方案:
|
||||
- 方案 A:Gateway 路由 `/api/v1/iam/v1/*path`,proxy 透传 `/iam/v1/*path`(前端调用 `/api/v1/iam/v1/auth/login`)
|
||||
- 方案 B:Gateway 路由 `/api/v1/iam/*path`,proxy 透传 `/iam/*path`,下游 Controller 内加 `/v1`(前端调用 `/api/v1/iam/v1/auth/login`,Gateway 不含 `/v1`)
|
||||
- 方案 C:其他
|
||||
- **建议方案**:采纳方案 B(Gateway 路由不含服务级 `/v1`,由下游 Controller 添加),符合裁决第 4 条"避免双 v1"和第 3 条"Gateway 不改路径直接透传"
|
||||
- **状态**:待 coord 仲裁
|
||||
|
||||
### ISSUE-004-ai01:zap vs slog 选型
|
||||
|
||||
- **提请方**:ai01
|
||||
- **日期**:2026-07-10
|
||||
- **类型**:契约不明确
|
||||
- **描述**:W3 裁决"首次实现即用 slog",但 [shared-go/logger](../../../packages/shared-go/logger/logger.go) 的实现选型(zap 还是 slog)影响 ai01 接入方式。若 shared-go 用 zap,ai01 需通过 shared-go/logger 间接使用 zap;若 shared-go 用 slog,ai01 可直接用标准库 `log/slog` 或 shared-go 封装。需 coord 仲裁 shared-go/logger 最终选型。
|
||||
- **建议方案**:shared-go/logger 基于 `log/slog` 封装(标准库零依赖,W3 裁决原文即 slog),ai01 直接 import shared-go/logger
|
||||
- **状态**:待 coord 仲裁
|
||||
|
||||
### ISSUE-005-ai01:go.mod 与 Dockerfile Go 版本不一致
|
||||
|
||||
- **提请方**:ai01
|
||||
- **日期**:2026-07-10
|
||||
- **类型**:其他
|
||||
- **描述**:[go.mod](../../../services/api-gateway/go.mod) L3 声明 `go 1.25.0`,[go.work](../../../go.work) L1 声明 `go 1.26.0`,但 [Dockerfile](../../../services/api-gateway/Dockerfile) L1 用 `golang:1.22-alpine`。三者不一致,可能导致构建环境与本地开发环境行为差异。
|
||||
- **建议方案**:统一为 `go 1.22`(与 Dockerfile 一致,与 [01-understanding.md](../../../services/api-gateway/docs/01-understanding.md) §4 声明一致),或升级 Dockerfile 到 `golang:1.25-alpine` 并同步 go.mod/go.work
|
||||
- **状态**:待 coord 仲裁
|
||||
|
||||
### ISSUE-007-ai01:01-understanding.md §6 审计表 metrics 行过时
|
||||
|
||||
- **提请方**:ai01
|
||||
- **日期**:2026-07-10
|
||||
- **类型**:其他
|
||||
- **描述**:[01-understanding.md](../../../services/api-gateway/docs/01-understanding.md) §6 审计表 metrics 行标注 `❌ 无`,§7.1 issue #1 也说"无 `/metrics` 端点,Prometheus 404"。但实际 [main.go](../../../services/api-gateway/main.go) L56 已注册 `r.GET("/metrics", gin.WrapH(promhttp.Handler()))`,`/metrics` 端点已存在。文档过时,需更新为"⚠️ 端点已注册,但缺 7 个业务指标"。
|
||||
- **建议方案**:更新 01-understanding.md §6 审计表 metrics 行为 `⚠️ 端点已注册,缺业务指标`;§7.1 issue #1 更新为"已注册 /metrics,需补 7 个业务指标"
|
||||
- **状态**:待 coord 仲裁
|
||||
|
||||
### ISSUE-008-ai01:01-understanding.md §7.1 issue #3 死代码引用过时
|
||||
|
||||
- **提请方**:ai01
|
||||
- **日期**:2026-07-10
|
||||
- **类型**:其他
|
||||
- **描述**:[01-understanding.md](../../../services/api-gateway/docs/01-understanding.md) §7.1 issue #3 引用"auth.go L124-139 死代码 `RequestIDMiddleware()` + `generateUUID()`",但实际 [auth.go](../../../services/api-gateway/internal/middleware/auth.go) 当前仅 121 行,L124-139 不存在,死代码已删除。文档引用过时。
|
||||
- **建议方案**:删除 01-understanding.md §7.1 issue #3 整行(死代码已修复)
|
||||
- **状态**:待 coord 仲裁
|
||||
|
||||
### ISSUE-009-ai01:W1/W2 错误码 GW_ 前缀 + ActionState 信封未遵循
|
||||
|
||||
- **提请方**:ai01
|
||||
- **日期**:2026-07-10
|
||||
- **类型**:其他
|
||||
- **描述**:W1 裁决要求错误码统一 `GW_` 前缀,W2 裁决要求错误响应统一 ActionState 信封 `{success:false,error:{code,message}}`。但当前代码:
|
||||
- [auth.go](../../../services/api-gateway/internal/middleware/auth.go) 错误码用 `UNAUTHORIZED`/`INVALID_TOKEN`/`INVALID_CLAIMS`(无 GW_ 前缀),但响应体已部分对齐信封(L44-50 有 `success`/`error.code`/`error.message`)
|
||||
- [ratelimit.go](../../../services/api-gateway/internal/middleware/ratelimit.go) L51-54 响应 `{"error":"rate_limited","retry_after":60}`(无 GW_ 前缀,无信封)
|
||||
- [circuit-breaker.go](../../../services/api-gateway/internal/middleware/circuit-breaker.go) L55-58 响应 `{"error":"circuit_open","retry_after":30}`(无 GW_ 前缀,无信封)
|
||||
- [recovery.go](../../../services/api-gateway/internal/middleware/recovery.go) L24-27 响应 `{"error":"internal_error","request_id":"..."}`(无 GW_ 前缀,无信封)
|
||||
- **建议方案**:P2.3 任务统一修复(见 [workline.md](../worklines/api-gateway_workline.md) P2.3),所有错误码改为 `GW_*`,所有响应体改为 `{success:false,error:{code:"GW_*",message:"..."},...}`
|
||||
- **状态**:待 coord 仲裁
|
||||
|
||||
---
|
||||
|
||||
## §2 待 coord 仲裁事项汇总
|
||||
|
||||
| ISSUE | 主题 | 阻塞任务 | 状态 |
|
||||
| -------- | --------------------------------- | -------- | --------- |
|
||||
| ISSUE-001 | matrix.md gRPC 矩阵修正 | — | 待 coord |
|
||||
| ISSUE-002 | shared-go 接入方式 | P2.1 | 待 coord |
|
||||
| ISSUE-003 | API 版本化路由方案(/v1 前缀) | P2.7 | 待 coord |
|
||||
| ISSUE-004 | zap vs slog 选型 | P2.1 | 待 coord |
|
||||
| ISSUE-005 | go.mod 与 Dockerfile 版本不一致 | P2.0 | 待 coord |
|
||||
| ISSUE-007 | 01-understanding.md §6 审计表过时 | P2.0 | 待 coord |
|
||||
| ISSUE-008 | 01-understanding.md §7.1 死代码过时 | P2.0 | 待 coord |
|
||||
| ISSUE-009 | W1/W2 错误码 GW_ + ActionState | P2.3 | 待 coord |
|
||||
|
||||
> ISSUE-006 编号未使用(预留)。
|
||||
|
||||
Reference in New Issue
Block a user