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