# Apollo Router 配置(v2.1 M2 + M3 安全加固) # # Router 作为唯一的外部 GraphQL 入口,替代 3 个 BFF 的手动聚合。 # 前端 → Router(GraphQL)→ 各子图(/graphql) # 内部调用(后端 → 后端)仍走 gRPC(ADR-037)。 # # 端口:3000(GraphQL)/ 8088(健康检查) # 镜像:ghcr.io/apollographql/router:v1.45.0 # # v2.1 M3 安全加固: # - APQ + manifest 校验(生产拒绝未知 hash) # - 深度/复杂度限制 # - 生产关闭 introspection(通过环境变量控制) # - 生产仅允许 POST(csrf.enabled 阻止 GET 查询) supergraph: listen: 0.0.0.0:3000 path: /graphql # 生产关闭 introspection(APOLLO_ROUTER_INTROSPECTION=false) # 开发默认 true 便于调试(由 docker-compose environment 注入) introspection: ${env.APOLLO_ROUTER_INTROSPECTION} # 持久化查询(v2.1 M3 安全加固) # 关联:portal-shell spec §4.3 # 注意:Apollo Router v1.45 的 persisted_queries 是 ELv2 受限特性, # 需连接 GraphOS(APOLLO_KEY + APOLLO_GRAPH_REF)才能启用。 # 自托管开发态禁用此特性;生产环境如需启用,需配置 GraphOS license。 # persisted_queries: # enabled: false # 查询限制(v2.1 M3 安全加固) # 注意:Apollo Router v1.45 的 limits.max_depth 是 ELv2 受限特性, # 需连接 GraphOS 才能启用。自托管开发态禁用; # 生产环境如需深度限制,可使用 rhai script 或 custom plugin 替代。 # limits: # max_depth: 10 # Sandbox 模式:支持开发和调试(v1.45 中 sandbox 已合并到 homepage) homepage: enabled: true # CORS:允许前端 portal 访问 cors: origins: - "http://localhost:4000" - "http://localhost:4001" - "http://localhost:4002" - "http://localhost:4003" - "http://localhost:4010" - "http://teacher-portal:4000" - "http://student-portal:4001" - "http://parent-portal:4002" - "http://admin-portal:4003" - "http://portal-shell:4010" methods: - GET - POST - OPTIONS allow_credentials: true allow_headers: - Authorization - Content-Type - X-Request-Id - X-Expected-Version - If-Match # 向所有子图注入 Router-Authorization Header(ADR-036) # 子图的 RouterAuthGuard 校验此 Header,拒绝非 Router 的直接 GraphQL 请求 # 同时透传用户身份头(x-user-id / x-user-role)与 Authorization 到子图, # 供 iam/core-edu/msg 等子图做用户级鉴权(M8:portal-shell 查询走 Router) headers: all: request: - insert: name: "router-authorization" value: "dev-router-secret" - propagate: named: "Authorization" - propagate: named: "x-user-id" - propagate: named: "x-user-role" - propagate: named: "X-Request-Id" # 健康检查 health_check: listen: 0.0.0.0:8088 # 日志(v1.45 使用 telemetry.exporters.logging) telemetry: exporters: logging: stdout: format: json instrumentation: spans: mode: spec_compliant