Files
Edu/docs/architecture/004_architecture_impact_map.md
SpecialX 62682b9d61 docs(docs): 004 arch.db 二次校验 + 新增 v2 架构重设计 spec
004 修正 7 处与代码不符描述:

- proto 统计 / 包名 / core-edu gRPC service 数

- msg RPC 数 / data-ana RPC 数

- student-bff 模块数 / parent-bff 模块数

新增 v2 架构重设计 spec(996 行):

- Apollo Federation BFF 联邦

- DataScope @requires 运行时解析

- iam 拆分 config-service

- content CQRS / ai 无状态化

- SSE 优先 / Temporal 不引入

Spec 自审修复 6 处问题:

- apollo-router 端口冲突 4000→4011

- Kafka topic 命名一致性

- CDC/Outbox 投影器职责分工

- 改动点数字 / 服务数 / 容器数计算
2026-07-14 21:25:37 +08:00

80 KiB
Raw Blame History

架构影响地图(微服务版)

版本2.0 日期2026-07-14 状态:实施状态同步(基于代码现状 + arch.db 校准) 适用范围Edu 微服务架构DDD + EDA + CQRS 关联文档:

v2.0 变更摘要:基于代码现状(截至 2026-07-14全面校准服务清单、模块边界、依赖关系、Kafka topic、可观测性栈、BFF 实现细节;新增 §15 实施状态索引。

arch.db 二次校验2026-07-14:运行 pnpm run arch:scan 重建 arch.db22 模块 / 4715 符号 / 475 契约),据此修正 §11.1 proto 统计8 文件 / 23 service / 305 message / 139 RPC、§11.2 proto 包名(next_edu_cloud.<domain>.v1、§15.4 core-edu gRPC9 service / 43 RPC、§15.6 msg gRPC17 RPC、§15.7 data-ana gRPC18 RPC、§15.10 student-bff 模块8、§15.11 parent-bff 模块6


目录

  1. 项目概述
  2. 技术栈
  3. 分层架构
  4. 服务依赖图
  5. 认证与权限
  6. 数据访问与缓存
  7. 事件驱动架构
  8. 跨服务协作
  9. 核心业务流程
  10. 可观测性
  11. 契约与 API 架构
  12. 架构约束
  13. ADR 记录
  14. 附录6 阶段路线图
  15. 实施状态索引v2.0 新增)

1. 项目概述

1.1a 技术分层视角(系统边界)

本图展示部署分层结构(自上而下:用户 → 微前端 → 网关 → BFF → 业务服务 → 总线 → 数据)。 用户层按"使用场景域"标注BFF 层按场景域分(不是按角色分)。业务领域视角见 1.1b。 端口标注见 infra/port-allocation.md(唯一源)。

graph TB
    subgraph Users["用户层(场景域用户)"]
        Teacher["教学场景域用户<br/>(教师 / 教导主任 / 教研组长 共用)"]
        Student["学习场景域用户<br/>(学生)"]
        Parent["家长场景域用户<br/>(家长)"]
        Admin["管理场景域用户<br/>(系统管理员 / 校管理员)"]
    end

    subgraph MFE["微前端层Module Federation<br/>Next.js 15 + standalone"]
        TeacherPortal["teacher-portal :4000<br/>Shell 宿主 + 教学场景域"]
        StudentPortal["student-portal :4001<br/>Remote"]
        ParentPortal["parent-portal :4002<br/>Remote被 teacher-portal 加载)"]
        AdminPortal["admin-portal :4003<br/>Remote"]
    end

    subgraph PortalShell["Portal Shell 层(规划中)<br/>详见 [0020 Portal Shell 架构](./0020_portal_shell_architecture.md)"]
        PortalShellApp["portal-shell :4010<br/>Modular Monolith + Micro-kernel<br/>取代 MF 微前端,单服务部署"]
    end

    subgraph Gateway["网关层Go 1.25 / Gin"]
        APIGateway["api-gateway :8080<br/>JWT RS256 + JWKS + 限流 + 熔断"]
        PushGateway["push-gateway :8081<br/>WebSocket + Redis Pub/Sub<br/>gRPC 豁免HTTP /internal/*"]
    end

    subgraph BFF["BFF 聚合层NestJS / GraphQL Yoga<br/>按使用场景域分 BFF"]
        TeacherBFF["teacher-bff :3003<br/>Teacher + Admin Resolvers<br/>6 下游 gRPC 客户端"]
        StudentBFF["student-bff :3009<br/>Cache + CircuitBreaker + Event"]
        ParentBFF["parent-bff :3010<br/>Aggregation + Kafka 订阅"]
    end

    subgraph Services["业务微服务NestJS + FastAPI"]
        IAM["iam :3002 / gRPC :50052<br/>5 Controller + Outbox"]
        CoreEdu["core-edu :3004 / gRPC :50053<br/>10 模块(含合并的 classes"]
        Content["content :3005 / gRPC :50054<br/>7 模块 + Neo4j + ES sync"]
        DataAna["data-ana :3006 / gRPC :50055<br/>FastAPI + CDC consumer"]
        Msg["msg :3007 / gRPC :50056<br/>4 模块 + 4 渠道 + Kafka 16 事件"]
        AI["ai :3008 / gRPC :50058<br/>FastAPI + LLM Failover + Workflow"]
    end

    subgraph Bus["事件总线"]
        Kafka[("Kafka<br/>双 listener 29092/9092")]
        Debezium["Debezium Connect 2.7<br/>CDC MySQL → Kafka"]
    end

    subgraph Data["数据层"]
        MySQL[("MySQL 8.0<br/>每服务独占 schema")]
        Redis[("Redis 7<br/>缓存/会话/Pub/Sub")]
        ClickHouse[("ClickHouse 24.3<br/>读模型宽表")]
        Neo4j[("Neo4j 5.20<br/>知识图谱")]
        ES[("Elasticsearch 8.13<br/>题库检索")]
    end

    Teacher --> TeacherPortal
    Student --> StudentPortal
    Parent --> ParentPortal
    Admin --> AdminPortal

    TeacherPortal --> APIGateway
    StudentPortal --> APIGateway
    ParentPortal --> APIGateway
    AdminPortal --> APIGateway
    TeacherPortal -.MF Remote 加载.-> ParentPortal
    TeacherPortal -.WS 推送.-> PushGateway
    StudentPortal -.WS 推送.-> PushGateway
    ParentPortal -.WS 推送.-> PushGateway

    APIGateway --> TeacherBFF
    APIGateway --> StudentBFF
    APIGateway --> ParentBFF
    APIGateway -.admin graphql 透传.-> TeacherBFF
    PushGateway -.HTTP /internal/push.-> Msg

    TeacherBFF --> IAM
    TeacherBFF --> CoreEdu
    TeacherBFF --> Content
    TeacherBFF --> DataAna
    TeacherBFF --> AI
    TeacherBFF --> Msg
    StudentBFF --> IAM
    StudentBFF --> CoreEdu
    StudentBFF --> DataAna
    ParentBFF --> IAM
    ParentBFF --> CoreEdu
    ParentBFF --> DataAna
    ParentBFF --> Msg
    ParentBFF -.HTTP.-> PushGateway

    CoreEdu <--> Kafka
    Content <--> Kafka
    DataAna <--> Kafka
    Msg <--> Kafka
    IAM <--> Kafka
    AI <--> Kafka

    MySQL --> Debezium
    Debezium --> Kafka

    IAM --> MySQL
    CoreEdu --> MySQL
    Content --> MySQL
    Msg --> MySQL
    Content --> Neo4j
    Content --> ES
    DataAna --> ClickHouse
    AI --> ES

    IAM --> Redis
    CoreEdu --> Redis
    TeacherBFF --> Redis
    StudentBFF --> Redis
    ParentBFF --> Redis
    DataAna --> Redis
    AI --> Redis
    PushGateway --> Redis

1.1b 业务领域视角

本图按 DDD 限界上下文展示 6 个业务领域及其依赖关系。同一服务可横跨多个领域(如 core-edu 同时承载"教学组织"与"教学核心")。 技术分层视角见 1.1a

graph TB
    subgraph D1["D1 身份认证领域iam 服务)"]
        IAM[iam 服务]
        IAM_M["5 Controller: Iam / Rbac / Audit / Jwks / IamGrpc<br/>users / roles / permissions / refresh_tokens / sessions<br/>totp / audit_logs / navigation_config / route_permission"]
    end

    subgraph D2["D2 教学组织领域core-edu 服务)"]
        ORG["core-edu 服务<br/>classes + scheduling + leave-requests"]
        ORG_M["classes / teacher-associations / subjects<br/>schedule / leave-requests"]
    end

    subgraph D3["D3 教学核心领域core-edu 服务)"]
        TEACH["core-edu 服务<br/>exams + homework + grades + attendance"]
        TEACH_M["exams / exam-extensions / homework / grades<br/>attendance / dashboard / admin / iam-consumer<br/>(含 state machine + datascope-injector"]
    end

    subgraph D4["D4 内容资源领域content 服务)"]
        CONTENT["content 服务"]
        CONTENT_M["7 模块: textbooks / chapters / knowledge-points<br/>questions / electives / lesson-plans / course-plans<br/>Neo4j 知识图谱 + ES 题库检索 + sync worker"]
    end

    subgraph D5["D5 沟通通知领域msg 服务)"]
        MSG["msg 服务"]
        MSG_M["4 模块: notifications / preferences / templates / announcements<br/>4 渠道: email / sms / push / in-app<br/>Kafka 消费 16 类事件 + Idempotency Guard"]
    end

    subgraph D6["D6 智能洞察领域data-ana + ai 服务)"]
        DATA["data-ana 服务"]
        AI["ai 服务"]
        DATA_M["FastAPI HTTP /analytics + gRPC 50055<br/>CDC consumer + ClickHouse 宽表<br/>analytics / dashboard / diagnostic / warnings / mastery"]
        AI_M["FastAPI HTTP /v1/ai + gRPC 50058<br/>LLM FailoverChain + Prompt Service + Quality Gate<br/>chat / question / expression / lesson-plan / report"]
    end

    IAM --> ORG
    IAM --> TEACH
    IAM --> CONTENT
    IAM --> MSG
    ORG --> TEACH
    TEACH --> CONTENT
    TEACH --> MSG
    CONTENT --> DATA
    TEACH --> DATA
    AI -.gRPC.-> CONTENT
    AI -.gRPC.-> DATA
    AI -.gRPC.-> IAM

双图并存说明

  • 1.1a 技术分层:描述部署、流量路径、网络边界,关注"如何部署与调用"
  • 1.1b 业务领域:描述 DDD 限界上下文、聚合根、领域依赖,关注"业务边界与归属"
  • 两图互补,分别服务于运维/SRE 与产品/架构视角

1.2 服务清单

端口、阶段、实施状态基于代码现状2026-07-14 = 已落地,🚧 = 部分落地, = 规划中。

类别 服务名 语言/框架 HTTP 端口 gRPC 端口 限界上下文 业务领域 阶段 状态
基础设施 api-gateway Go 1.25 (Gin) 8080 网关(路由+鉴权+限流+熔断+CORS P1
基础设施 push-gateway Go 1.25 (Gin) 8081 推送WS + Redis Pub/Sub + Kafka 消费) P5
BFF teacher-bff TS (NestJS + GraphQL Yoga) 3003 教师聚合 + Admin 命名空间聚合 教学场景域 P2
BFF student-bff TS (NestJS + GraphQL Yoga) 3009 学生聚合 学习场景域 P3
BFF parent-bff TS (NestJS + GraphQL Yoga) 3010 家长聚合 家长场景域 P4
业务 iam TS (NestJS) 3002 50052 身份认证 D1 身份认证 P2
业务 core-edu TS (NestJS) 3004 50053 教学核心(含原 classes D2 教学组织 + D3 教学核心 P3
业务 content TS (NestJS) 3005 50054 内容资源 D4 内容资源 P4
业务 data-ana Python (FastAPI) 3006 50055 数据分析 D6 智能洞察 P4
业务 msg TS (NestJS) 3007 50056 消息通知 D5 沟通通知 P5
业务 ai Python (FastAPI) 3008 50058 AI 网关 D6 智能洞察 P5
微前端 teacher-portal TS (Next.js 15) 4000 教师端MF Shell 教学场景域 P2
微前端 student-portal TS (Next.js 15) 4001 学生端MF Remote 学习场景域 P3
微前端 parent-portal TS (Next.js 15) 4002 家长端MF Remote被 teacher-portal 加载) 家长场景域 P4
微前端 admin-portal TS (Next.js 15) 4003 管理端MF Remote 管理场景域 P6
共享包 shared-proto protobuf + buf v2 跨语言契约8 proto 文件) P1
共享包 shared-ts TS TS 共享bff / outbox P1
共享包 shared-go Go Go 共享env / jwks / logger / tracer P1
共享包 shared-py Python Python 共享 P4 🚧
共享包 contracts TS 跨端权限点常量 P3 🚧
共享包 hooks TS (React) React Hooksauth / permission / viewports / graphql / trace / a11y P2
共享包 ui-components TS (shadcn 风格) UI 组件库data-table / form / modal / chart / filter-bar / status-badge P2
共享包 ui-tokens TS + CSS 设计令牌primitive / semantic-light/dark / tailwind-theme P2

历史服务classes端口 3001已合并入 core-eduC1 裁决),目录保留作历史参考,不再构建部署。

1.3 CICD → Edu 模块映射

CICD 模块(旧) Edu 服务(新) 迁移阶段
auth + users + rbac iam P2
classes + subjects + enrollment core-edu P3
courses + lessons + schedule + attendance core-edu P3
assignments + grades + exams core-edu P3
textbooks + knowledge-points content P4
questions + grading content P4
messaging + notifications msg P5
analytics + dashboard + diagnostic data-ana P4
ai + lesson-preparation ai P5
search content (ES) P4

2. 技术栈

2.1 多语言技术栈矩阵

层级 语言 框架/版本 用途
网关层 Go 1.25 Gin + otelgin + prometheus api-gateway、push-gateway
业务服务 TypeScript 5.6+ NestJS 10 + Drizzle ORM iam、core-edu、content、msg
分析/AI Python 3.12 FastAPI + structlog + prometheus-client data-ana、ai
BFF TypeScript 5.6+ NestJS 10 + GraphQL Yoga + DataLoader + opossum熔断 teacher-bff / student-bff / parent-bff
微前端 TypeScript 5.6+ Next.js 15 + Module Federation + Tailwind + shadcn 风格 4 端门户
契约 protobuf buf v2FILE 级 breaking 跨语言契约定义与生成
包管理 pnpm 11 / go.work / uv workspace 多语言 monorepo

2.2 多存储矩阵

存储 版本 用途 使用服务
MySQL 8.0 写模型主库(每服务独占 schema iam、core-edu、content、msg
Redis 7-alpine 缓存、会话、限流计数、分布式锁、Pub/Sub iam、core-edu、teacher-bff、student-bff、parent-bff、data-ana、ai、push-gateway
ClickHouse 24.3 读模型宽表、分析聚合 data-ana
Neo4j 5.20 知识图谱、前置依赖 content
Elasticsearch 8.13 题库全文检索、消息全文检索 content、msg

2.3 基础设施矩阵

组件 版本 用途
Kafka cp-kafka 7.6 事件总线,领域事件异步通信(双 listener
Zookeeper cp-zookeeper 7.6 Kafka 协调
Debezium Connect 2.7 CDCMySQL Binlog → Kafka 实时同步
OpenTelemetry SDK + OTLP 分布式追踪HTTP / gRPC 自动埋点)
Jaeger all-in-one 1.57 分布式 Trace 存储 + UIOTLP 4317/4318
Loki 3.2.1 日志聚合
Promtail 3.2.1 日志采集
Prometheus v2.51.0 指标采集(--web.enable-lifecycle15d 保留)
Alertmanager v0.27.0 告警路由与抑制
Grafana 10.4.0 可观测性可视化
node-exporter v1.8.2 主机指标
mysqld-exporter v0.15.1 MySQL 指标(命令行参数模式)
redis-exporter v1.67.0 Redis 指标
Temporal 规划中 工作流编排考试生命周期、AI 编排)
Vault P6 密钥管理

v2.0 修正Trace 存储实际使用 Jaeger all-in-oneOTLP 接收),原 v1.0 文档误写为 Tempo。当前未引入 Temporal长流程编排暂由 ai 服务内 WorkflowStateStoreRedis实现备课工作流。


3. 分层架构

3.1 六层架构

graph TB
    subgraph L1["L1 客户端层"]
        Browser[浏览器]
        Mobile[移动端]
    end

    subgraph L2["L2 微前端层"]
        MFE[Module Federation<br/>4 端门户 Next.js 15]
    end

    subgraph L3["L3 网关层Go 1.25 / Gin"]
        GW[API Gateway :8080<br/>HTTP 反向代理 + JWT RS256 + 限流 + 熔断]
        Push[Push Gateway :8081<br/>WebSocket + Redis Pub/Sub + Kafka 消费]
    end

    subgraph L4["L4 BFF 聚合层NestJS + GraphQL Yoga"]
        BFF[3 个 BFF<br/>聚合 + DataLoader + 熔断opossum]
    end

    subgraph L5["L5 业务微服务层"]
        SVC[6 业务服务<br/>NestJS + FastAPI<br/>DDD + CQRS + Outbox]
    end

    subgraph L6["L6 数据与总线层"]
        DB[(MySQL / ClickHouse / Neo4j / ES)]
        REDIS[(Redis 7)]
        KAFKA[(Kafka + Debezium CDC)]
        TEMPORAL["Temporal<br/>⏳ 规划中"]
    end

    Browser --> MFE
    Mobile --> MFE
    MFE --> GW
    MFE -.WS 推送.-> Push
    GW -- HTTP 代理 --> BFF
    GW -- HTTP 代理 --> SVC
    BFF -- gRPC --> SVC
    SVC --> DB
    SVC --> REDIS
    BFF --> REDIS
    SVC <--> KAFKA
    SVC -.规划中.-> TEMPORAL
    Push --> REDIS
    Push -.Kafka 消费.-> KAFKA

3.2 依赖方向

L1 客户端 → L2 微前端 → L3 网关 → L4 BFF → L5 业务服务 → L6 数据/总线

严格规则

  1. L3 网关层只做路由、鉴权、限流、熔断,不写业务逻辑;只做 HTTP 反向代理,不做协议转换
  2. L4 BFF 层只做聚合、裁剪、协议转换GraphQL → gRPC不持有业务状态
  3. L5 业务服务之间通过 gRPC同步或 Kafka 事件(异步)通信,不直接访问对方数据库
  4. L6 数据层每个微服务独占自身数据库,禁止跨库联表

4. 服务依赖图

graph TB
    subgraph Gateway["网关层"]
        APIGW[api-gateway :8080]
        PushGW[push-gateway :8081]
    end

    subgraph BFF["BFF 层"]
        TBFF[teacher-bff :3003]
        SBFF[student-bff :3009]
        PBFF[parent-bff :3010]
    end

    subgraph Services["业务服务"]
        IAM[iam :3002]
        CoreEdu[core-edu :3004]
        Content[content :3005]
        DataAna[data-ana :3006]
        Msg[msg :3007]
        AI[ai :3008]
    end

    subgraph Shared["共享包"]
        Proto[shared-proto<br/>8 proto]
        SharedTS[shared-ts<br/>bff/outbox]
        SharedGo[shared-go<br/>env/jwks/logger/tracer]
        SharedPy[shared-py]
        Contracts[contracts<br/>权限点]
        Hooks[hooks<br/>React Hooks]
        UIComps[ui-components]
        UITokens[ui-tokens]
    end

    %% Gateway → BFFHTTP 反向代理 + 路径重写)
    APIGW -- HTTP 代理 --> TBFF
    APIGW -- HTTP 代理 --> SBFF
    APIGW -- HTTP 代理 --> PBFF
    APIGW -. /api/admin/graphql 透传 .-> TBFF
    APIGW -- HTTP 代理 --> IAM
    APIGW -- HTTP 代理 --> CoreEdu
    APIGW -- HTTP 代理 --> Content
    APIGW -- HTTP 代理 --> Msg
    APIGW -- HTTP 代理 --> AI
    APIGW -- HTTP 代理 --> DataAna
    PushGW -. HTTP /internal/push .-> Msg
    PushGW -. Kafka edu.notify.notification.sent .-> Msg

    %% BFF → 业务服务gRPC
    TBFF -- gRPC --> IAM
    TBFF -- gRPC --> CoreEdu
    TBFF -- gRPC --> Content
    TBFF -- gRPC --> DataAna
    TBFF -- gRPC --> AI
    TBFF -- gRPC --> Msg

    SBFF -- gRPC --> IAM
    SBFF -- gRPC --> CoreEdu
    SBFF -- gRPC --> DataAna
    SBFF -. Kafka 事件 .-> PushGW

    PBFF -- gRPC --> IAM
    PBFF -- gRPC --> CoreEdu
    PBFF -- gRPC --> DataAna
    PBFF -- gRPC --> Msg
    PBFF -. HTTP .-> PushGW
    PBFF -. Kafka 订阅 .-> CoreEdu
    PBFF -. Kafka 订阅 .-> IAM

    %% 业务服务间事件
    CoreEdu -. Kafka 事件 .-> Content
    CoreEdu -. Kafka 事件 .-> DataAna
    CoreEdu -. Kafka 事件 .-> Msg
    Content -. Kafka 事件 .-> DataAna
    IAM -. Kafka 事件 .-> CoreEdu
    IAM -. Kafka 事件 .-> Msg
    AI -. gRPC .-> Content
    AI -. gRPC .-> DataAna
    AI -. gRPC .-> IAM
    DataAna -. Kafka 事件 .-> CoreEdu
    DataAna -. Kafka 事件 .-> Msg

    %% 共享包依赖
    IAM --> Proto
    CoreEdu --> Proto
    Content --> Proto
    DataAna --> Proto
    Msg --> Proto
    AI --> Proto
    APIGW --> SharedGo
    PushGW --> SharedGo
    IAM --> SharedTS
    CoreEdu --> SharedTS
    Content --> SharedTS
    Msg --> SharedTS
    TBFF --> SharedTS
    SBFF --> SharedTS
    PBFF --> SharedTS

4.1 服务间通信矩阵

调用方 → 被调用方 协议 场景
api-gateway → BFF HTTP 反向代理 路由分发 + 剥离 /api/v1/{bff} 前缀
api-gateway → 业务服务 HTTP 反向代理 剥离 /api 前缀,保留 /v1/{domain}/*
api-gateway → teacher-bff HTTP 透传 /api/admin/graphql/graphqladmin
BFF → 业务服务 gRPC 同步查询聚合 + DataLoader 批量去重
push-gateway → msg HTTP /internal/* msg 主动推送X-Internal-Key 鉴权)
push-gateway → msg Kafka 消费 消费 edu.notify.notification.sent
parent-bff → push-gateway HTTP 触发家长端推送
CoreEdu → Content Kafka 事件 教学内容变更通知
CoreEdu → DataAna Kafka 事件 学情数据投递9 类事件)
CoreEdu → Msg Kafka 事件 通知触发(考试/作业/成绩/考勤)
IAM → CoreEdu Kafka 事件 用户变更同步6 类事件)
IAM → Msg Kafka 事件 用户/角色变更通知6 类事件)
Content → DataAna Kafka 事件 内容发布同步
DataAna → CoreEdu Kafka 事件 掌握度更新 → 推荐练习
DataAna → Msg Kafka 事件 掌握度预警触发
AI → Content gRPC 题库查询 / 知识点查询
AI → DataAna gRPC 学情数据查询
AI → IAM gRPC 用户信息查询
AI → Kafka Kafka 生产 AI 用量事件发布(edu.ai.usage.*

4.2 BFF 下游客户端矩阵

所有 BFF 下游客户端统一抽象B8 裁决):每个客户端有 gRPC + mock 两个实现,未配置 gRPC target 时自动降级为 mock。

BFF 下游客户端gRPC :port
teacher-bff iam (:50052) / core-edu (:50053) / content (:50054) / data-ana (:50055) / msg (:50056) / ai (:50058)
student-bff iam / core-edu / data-ana
parent-bff iam / core-edu / data-ana / msg / push-gateway (HTTP)

5. 认证与权限

5.1 JWT RS256 认证流程

实施细节api-gateway 通过 JWKS Fetchershared-go/jwks缓存 RS256 公钥校验 JWT 校验通过后注入 x-user-id / x-user-roles / x-user-data-scope / x-request-id 头部HTTP 反向代理到下游服务; 下游服务NestJS通过 AuthMiddleware 解析头部、PermissionGuardAPP_GUARD做权限校验。 DEV_MODE=true 时跳过 JWT 校验,接受 dev-token

sequenceDiagram
    participant U as 用户
    participant GW as API Gateway (Go)
    participant IAM as iam 服务
    participant SVC as 下游服务 (NestJS / FastAPI)

    rect rgb(240, 248, 255)
        Note over U,IAM: 阶段 1: 登录签发
        U->>GW: POST /api/v1/iam/login {username, password}
        GW->>IAM: HTTP 反向代理(无鉴权路由)
        IAM->>IAM: bcrypt 校验 + 查询权限 (PermissionCacheService)
        IAM->>IAM: 生成 JWTRS256 私钥签发)+ refresh_token
        IAM->>IAM: 写 iam_outboxUSER_EVENTS
        IAM-->>GW: {accessToken, refreshToken, userInfo}
        GW-->>U: 200 Set-Cookie httpOnly + ActionState 信封
    end

    rect rgb(240, 255, 240)
        Note over U,SVC: 阶段 2: 请求鉴权
        U->>GW: GET /api/v1/classes + Authorization: Bearer <token>
        GW->>GW: JWKS Fetcher 取 RS256 公钥
        GW->>GW: 校验签名 + exp/iss/aud
        GW->>GW: 提取 userId/roles/dataScope
        GW->>SVC: HTTP 代理 + 注入 x-user-* 头部
        SVC->>SVC: AuthMiddleware 解析头部
        SVC->>SVC: PermissionGuard (APP_GUARD) 校验权限
        SVC->>SVC: DataScopeInjector 注入 WHERE 条件
        SVC-->>GW: ActionState 响应
        GW-->>U: 200 响应
    end

5.2 三层角色模型

层级 来源 示例 优先级
系统角色 系统预设 admin、teacher、student、parent 最高
组织角色 学校/班级分配 年级组长、班主任、学科组长
临时角色 临时授权 代课教师、临时代理 最低

规则:权限取三层角色权限的并集,拒绝权限取交集(任一层拒绝则拒绝)。

5.3 DataScope 6 级数据范围

级别 名称 数据范围 典型角色
L0 SELF 仅本人数据 学生、家长
L1 CLASS 本班数据 班主任、学生
L2 GRADE 本年级数据 年级组长
L3 SCHOOL 本校数据 校管理员
L4 DISTRICT 本区数据 区教研员
L5 ALL 全部数据 系统管理员

实现:业务服务在 Repository 层根据 dataScope 级别动态注入 WHERE 条件。

5.4 视口四层模型

视口Viewport是用户在特定场景域下的可见范围。视口既可独立配置RoleViewport 表), 也可由权限推导permission → viewport 默认映射)。新角色只需配置权限集,视口自动推导; 需要差异化时再显式配置视口。

层级 含义 配置载体 示例
L1 导航 侧边栏菜单项 navigation_config 表 教导主任看到"全校成绩分析"菜单
L2 路由 可访问路由 route_permission 表 + Gateway 校验 教导主任可访问 /admin/grade-analysis
L3 组件 页面内组件可见性 usePermission().hasPermission() 教导主任看到"导出全校报表"按钮
L4 数据 数据行级过滤 DataScope 枚举 教导主任 DataScope=grade_managed管辖年级

场景域 BFF 复用策略

按"使用场景域"分 BFF而非按角色分。新角色复用现有 BFF通过视口差异化。

BFF 场景域 复用角色
Teacher BFF 教学场景 教师、教导主任、教研组长
Student BFF 学习场景 学生
Parent BFF 家长场景 家长
Admin BFF 管理场景 系统管理员、校管理员

实现:教导主任归入 Teacher BFF + 额外管理视口L1 导航增加管理菜单项L4 数据范围扩大到年级)。

iam 服务职责

  • 认证:登录/登出/JWT/2FA
  • RBAC角色/权限/角色-权限映射 CRUD
  • 视口配置:导航/路由/组件级视口配置 CRUD
  • DataScope数据范围解析all/grade_managed/class_taught/children/owned + 自定义)
  • 权限解析 APIgetEffectivePermissions(userId) → {permissions, viewports, dataScope}

6. 数据访问与缓存

6.1 CQRS 读写分离

graph LR
    subgraph Write["写路径"]
        Cmd[Command 命令] --> App[Application Service]
        App --> Domain[Domain 领域模型]
        Domain --> Repo[Repository 写模型]
        Repo --> mysql_w[(MySQL 主库)]
        App --> Outbox[(Outbox 表<br/>同事务)]
    end

    subgraph Sync["同步链路"]
        Outbox --> Relay[Relay Worker]
        Relay --> kafka_sync[(Kafka)]
        kafka_sync --> Proj[Projection]
        Proj --> ch_sync[(ClickHouse 宽表)]
        Proj --> redis_sync[(Redis 缓存)]
        Proj --> es_sync[(ES 索引)]
    end

    subgraph Read["读路径"]
        Query[Query 查询] --> ReadModel[Read Model]
        ReadModel --> ch_read[(ClickHouse 宽表)]
        ReadModel --> redis_read[(Redis 缓存)]
        ReadModel --> es_read[(ES 索引)]
    end

6.2 BFF 混合读策略

flowchart TD
    Q[BFF 收到查询请求] --> C1{Redis 命中?}
    C1 -- 是 --> R1[返回缓存]
    C1 -- 否 --> C2{需要聚合多服务?}
    C2 -- 否 --> C3[直接 gRPC 调用单一服务]
    C3 --> C4[写入 Redis]
    C4 --> R2[返回]
    C2 -- 是 --> C5[并行 gRPC 调用多服务]
    C5 --> C6[内存聚合裁剪]
    C6 --> C7[写入 Redis 5-30s 短缓存]
    C7 --> R3[返回聚合结果]

6.3 缓存策略矩阵

数据类型 存储 TTL 失效策略
用户会话 Redis 30 分钟 滑动过期
权限列表 Redis 5 分钟 事件驱动失效
班级/年级列表 Redis 5 分钟 事件驱动失效
教学资源详情 Redis 30 秒 短 TTL
BFF 聚合结果 Redis 5-30 秒 短 TTL
学情宽表 ClickHouse 实时 CDC 同步
题库检索 ES 实时 CDC 同步

7. 事件驱动架构

7.1 Outbox + Kafka + CDC 全链路

graph LR
    subgraph Service["业务服务"]
        Cmd[Command 处理]
        Domain[Domain 聚合]
        Repo[Repository]
        Outbox[(Outbox 表)]
    end

    subgraph MySQL["MySQL 主库"]
        BizTable[(业务表)]
        OutboxTable[(outbox 表)]
    end

    subgraph Relay["Relay Worker"]
        Poll[轮询 outbox<br/>每 100ms]
        Publish[发布到 Kafka]
        Mark[标记 processed]
    end

    subgraph Bus["事件总线"]
        kafka_bus[(Kafka topic)]
    end

    subgraph Consumers["消费者"]
        Proj[Projection<br/>更新读模型]
        OtherSvc[其他服务<br/>业务订阅]
    end

    Cmd --> Domain
    Domain --> Repo
    Repo --> BizTable
    Repo --> OutboxTable
    OutboxTable --> Poll
    Poll --> Publish
    Publish --> kafka_bus
    kafka_bus --> Proj
    kafka_bus --> OtherSvc
    Proj --> read_stores[(ClickHouse / Redis / ES)]

7.2 事件 Topic 分类

实际命名(基于 services/*/src/shared/kafka/topic-map.tsservices/iam/src/config/kafka.ts 模式 edu.<domain>.<aggregate>.<action>。msg 服务统一使用 edu.notify.notification.* 发布ARB-013

Topic 生产者 消费者 说明
edu.identity.user.created iam core-edu (iam-consumer)、msg 用户创建
edu.identity.user.updated iam core-edu、msg 用户更新
edu.identity.user.deleted iam msg 用户删除
edu.identity.user.role_changed iam core-edu、msg 用户角色变更
edu.identity.role.created iam msg 角色创建
edu.identity.role.updated iam msg 角色更新
edu.teaching.exam.published core-edu msg 考试发布
edu.teaching.exam.extended core-edu msg 考试延时(实时)
edu.teaching.exam.force_submitted core-edu msg 考试强制交卷(实时)
edu.teaching.exam.question_reordered core-edu msg 题序打乱(实时)
edu.teaching.homework.assigned core-edu msg 作业布置
edu.teaching.assignment.submitted core-edu data-ana、msg 作业提交
edu.teaching.assignment.graded core-edu msg 作业批改完成
edu.teaching.grade.recorded core-edu data-ana、msg 成绩录入
edu.teaching.attendance.recorded core-edu msg 考勤记录
edu.content.question.published content ai、ES sync worker 题目发布
edu.content.textbook.updated content data-ana 教材更新
edu.insight.mastery.updated data-ana core-edu、msg 掌握度更新
edu.notify.notification.sent msg push-gateway 通知投递(驱动推送)
edu.notify.notification.read msg 通知已读
edu.notify.notification.recalled msg 通知撤回
edu.notify.notification.failed msg 通知投递失败
edu.notify.notification.events msg 兜底 topic
edu.ai.usage.* ai data-ana 规划中) AI 用量事件

Outbox 表命名:每服务独立 outbox 表iam_outbox / core_edu_outbox / content_outbox / msg_outbox由 shared-ts/outbox 模块统一管理。

必需依赖软失败标注ARB-015 §17.6ISSUE-058 覆盖 ISSUE-055

  • push-gateway → Redis软失败Redis 故障仅告警 + degraded: true + /readyz 返 200不返 503、不触发 Pod 重启)
  • 理由Redis 故障时单实例仍能服务本地连接(仅跨实例广播失效);重启会丢失本地连接表,加剧雪崩风险
  • ISSUE-055 必需依赖列表应排除 push-gateway → Redis

7.3 核心领域事件

事件 触发场景 消费者动作
UserRegistered 新用户注册 CoreEdu 初始化默认班级关联Msg 发送欢迎通知
ExamPublished 考试发布 Msg 推送考试通知给学生DataAna 创建考试分析骨架
HomeworkSubmitted 学生提交作业 DataAna 记录提交行为Msg 通知教师
HomeworkGraded 教师批改完成 DataAna 更新掌握度Msg 通知学生
MasteryUpdated 掌握度计算完成 CoreEdu 推荐个性化练习Msg 触发预警
NotificationRequested 通知请求 Msg 投递通知到 4 渠道email/sms/push/in-app
NotificationSent 通知投递完成 push-gateway 通过 Kafka 消费触发 WebSocket 推送

8. 跨服务协作

8.1 同步 vs 异步决策

flowchart TD
    Req[跨服务协作需求] --> C1{需要强一致性?}
    C1 -- 是 --> C2{调用方需要立即结果?}
    C2 -- 是 --> Sync[同步 gRPC 调用]
    C2 -- 否 --> Saga[Saga 编排<br/>Temporal]
    C1 -- 否 --> C3{需要事件最终一致?}
    C3 -- 是 --> Async[异步 Kafka 事件]
    C3 -- 否 --> C4{仅查询读取?}
    C4 -- 是 --> Read[读模型冗余]
    C4 -- 否 --> Sync

8.2 BFF 同步聚合

sequenceDiagram
    participant U as 教师端
    participant BFF as teacher-bff
    participant IAM as iam
    participant CoreEdu as core-edu
    participant DataAna as data-ana

    U->>BFF: 查询班级仪表盘
    BFF->>BFF: 解析 token 获取 userId
    par 并行查询
        BFF->>IAM: gRPC GetUser(userId)
        IAM-->>BFF: 用户信息
    and
        BFF->>CoreEdu: gRPC GetClassesByTeacher(userId)
        CoreEdu-->>BFF: 班级列表
    and
        BFF->>DataAna: gRPC GetTeacherDashboardStats(userId)
        DataAna-->>BFF: 统计数据
    end
    BFF->>BFF: 内存聚合裁剪
    BFF-->>U: 仪表盘聚合数据

8.3 异步事件闭环

flowchart LR
    A[教师录入成绩] --> B[CoreEdu 写入 MySQL + Outbox]
    B --> C[Outbox Relay 发布事件]
    C --> D[teaching.grade.recorded]
    D --> E[DataAna 消费更新掌握度]
    D --> F[Msg 消费通知学生]
    E --> G[insight.mastery.updated]
    G --> H[CoreEdu 消费推荐练习]
    G --> I[Msg 消费掌握度预警]

8.4 Temporal 工作流编排

flowchart TD
    Start[考试发布] --> A1[Activity: 创建考试实例]
    A1 --> A2[Activity: 通知学生]
    A2 --> A3[Activity: 等待作答窗口]
    A3 --> A4[Activity: 收集提交]
    A4 --> C1{是否全部提交?}
    C1 -- 否 --> A5[Activity: 自动提交未答]
    C1 -- 是 --> A6[Activity: 批改]
    A5 --> A6
    A6 --> A7[Activity: 发布成绩]
    A7 --> A8[Activity: 生成分析]
    A8 --> End[工作流完成]

9. 核心业务流程

9.1 考试生命周期

sequenceDiagram
    participant T as 教师
    participant BFF as teacher-bff
    participant Core as core-edu
    participant Msg as msg
    participant DA as data-ana
    participant S as 学生

    rect rgb(240, 248, 255)
        Note over T,Core: 阶段 1: 创建发布
        T->>BFF: 创建考试
        BFF->>Core: gRPC CreateExam
        Core->>Core: 写入 MySQL + Outbox
        Core-->>BFF: examId
        BFF-->>T: 创建成功
        Core->>Msg: ExamPublished 事件
        Msg->>S: 推送考试通知
    end

    rect rgb(240, 255, 240)
        Note over S,Core: 阶段 2: 作答提交
        S->>BFF: 提交答卷
        BFF->>Core: gRPC SubmitExam
        Core->>Core: 写入答卷 + Outbox
        Core-->>BFF: 提交成功
        Core->>DA: ExamSubmitted 事件
        DA->>DA: 记录提交行为
    end

    rect rgb(255, 240, 245)
        Note over T,DA: 阶段 3: 批改出分
        T->>BFF: 批改答卷
        BFF->>Core: gRPC GradeExam
        Core->>Core: 写入成绩 + Outbox
        Core-->>BFF: 批改完成
        Core->>DA: GradeRecorded 事件
        DA->>DA: 更新掌握度
        Core->>Msg: GradeRecorded 事件
        Msg->>S: 推送成绩通知
    end

9.2 高并发提交

flowchart TD
    S[学生提交] --> GW[API Gateway]
    GW --> GW1{限流检查}
    GW1 -- 通过 --> BFF[BFF]
    GW1 -- 拒绝 --> R1[429 限流响应]
    BFF --> Core[CoreEdu]
    Core --> C1{Redis 分布式锁}
    C1 -- 获取锁 --> C2[写入答卷]
    C2 --> C3[Outbox 事件]
    C3 --> C4[释放锁]
    C4 --> R2[成功]
    C1 -- 锁竞争 --> C5[排队等待 500ms]
    C5 --> C1
    C5 --> C6{超时?}
    C6 -- 是 --> R3[排队中,请稍后]

9.3 AI 辅助出题

sequenceDiagram
    participant T as 教师
    participant BFF as teacher-bff
    participant AI as ai 网关
    participant Content as content
    participant DA as data-ana

    T->>BFF: 请求 AI 出题
    BFF->>AI: gRPC GenerateQuestions
    AI->>Content: gRPC 查询知识点
    Content-->>AI: 知识点列表
    AI->>DA: gRPC 查询班级学情
    DA-->>AI: 学情数据
    AI->>AI: LLM 调用生成题目
    AI-->>BFF: 生成的题目列表
    BFF-->>T: 返回题目供教师审核
    T->>BFF: 确认入库
    BFF->>Content: gRPC CreateQuestions
    Content-->>BFF: 入库成功

10. 可观测性

10.1 三支柱可观测性

实际落地Jaeger all-in-one 接收 OTLPHTTP 4318 / gRPC 4317Loki + Promtail 采集容器日志Prometheus 抓取 /metrics 端点。 所有 NestJS 服务通过 shared/observability/{logger,metrics,tracer}.ts 注册Go 网关通过 shared-go/{logger,tracer} + otelginPython 服务通过 structlog + opentelemetry-instrumentation-fastapi + prometheus-client

graph TB
    subgraph App["应用层"]
        NESTJS[NestJS 服务<br/>pino + prom-client + OTLP]
        GO[Go 网关<br/>slog + prometheus + otelgin]
        PY[Python 服务<br/>structlog + prometheus-client + OTLP]
        PORTAL[Next.js portal<br/>OTel Web + Sentry]
    end

    subgraph Collect["采集层"]
        OTEL[OpenTelemetry SDK<br/>OTLP exporter]
        PROM[Prometheus 抓取<br/>/metrics]
        PROMTAIL[Promtail<br/>容器日志]
    end

    subgraph Storage["存储层"]
        LOKI[(Loki 3.2.1<br/>日志)]
        JAEGER[(Jaeger 1.57<br/>TraceOTLP 4317/4318)]
        PROMDB[(Prometheus v2.51<br/>指标 15d 保留)]
    end

    subgraph Exporters["Exporters"]
        NODE[node-exporter :9100<br/>host.docker.internal]
        MYSQL[mysqld-exporter :9104]
        REDIS[redis-exporter :9121]
    end

    subgraph Vis["可视化层"]
        GRAFANA[Grafana 10.4<br/>统一面板 :3030]
        ALERT[Alertmanager v0.27<br/>告警路由]
    end

    NESTJS --> OTEL
    GO --> OTEL
    PY --> OTEL
    PORTAL -.OTLP HTTP.-> OTEL
    OTEL --> JAEGER
    NESTJS --> PROM
    GO --> PROM
    PY --> PROM
    PROM --> PROMDB
    PROMTAIL --> LOKI
    NODE --> PROM
    MYSQL --> PROM
    REDIS --> PROM
    LOKI --> GRAFANA
    JAEGER --> GRAFANA
    PROMDB --> GRAFANA
    PROMDB --> ALERT

10.2 Trace 上下文传播

flowchart LR
    A[客户端请求] --> B[API Gateway<br/>otelgin 生成 traceId]
    B --> C[BFF<br/>继承 W3C traceparent]
    C --> D[业务服务 gRPC<br/>继承 metadata]
    D --> E[Kafka 事件<br/>traceId 写入 header]
    E --> F[消费者服务<br/>继承 traceId]
    F --> G[下游存储<br/>span 记录]
    G --> H[Jaeger UI<br/>查询链路]

规则

  • 所有跨服务调用必须透传 W3C Trace ContextHTTP traceparent 头 / gRPC metadata
  • Kafka 事件必须将 traceId 写入消息 header
  • 日志必须包含 traceId / requestId 用于关联查询
  • 关键业务操作必须创建 span创建考试、提交作业、批改、AI 生成、通知投递等)
  • 每服务暴露 /metricsPrometheus 抓取)+ /healthzliveness+ /readyzreadiness

10.3 健康检查与降级

服务类型 /healthz 行为 /readyz 行为
网关层 进程存活即 ok 检查下游可达性soft-failure
BFF 进程存活即 ok 检查 Redis + 下游 gRPC probe6 个 probe
业务服务 进程存活即 ok 检查 DB + Redis + Kafka + gRPC server
push-gateway 进程存活即 ok Redis 软失败(不返 503+ Kafka consumer 状态
data-ana 进程存活即 ok ClickHouse 1s 超时 + CDC lag < 1000 + Redis + iam

11. 契约与 API 架构

11.1 Protobuf 契约体系

实际 proto 文件位于 packages/shared-proto/proto/,共 8 个:ai.proto / analytics.proto / classes.proto / content.proto / core_edu.proto / events.proto / iam.proto / msg.proto。 arch.db 统计2026-07-148 proto 文件 / 23 service / 305 message / 139 RPC。 buf v2 配置:lint STANDARD(含 5 项 except 豁免)+ breaking FILE 级别。 buf.gen.yaml 生成 6 套代码protocolbuffers {go/js/python} + grpc {go/node/python},输出到 shared-{go,ts,py}/gen/proto/

graph TB
    subgraph Proto["shared-proto/proto/ (8 文件)"]
        IamProto[iam.proto<br/>IamService]
        CoreEduProto[core_edu.proto<br/>9 Service: Exam/Homework/Grade/<br/>Attendance/Class/Schedule/<br/>LeaveRequest/Dashboard/Admin]
        ClassesProto[classes.proto<br/>ClassService历史保留]
        ContentProto[content.proto<br/>Textbook/Chapter/<br/>KnowledgeGraph/Question/<br/>Elective/LessonPlan/CoursePlan]
        MsgProto[msg.proto<br/>Notification/Preference/<br/>Template Service]
        DataAnaProto[analytics.proto<br/>AnalyticsService]
        AiProto[ai.proto<br/>AiService]
        EventsProto[events.proto<br/>领域事件 schema]
    end

    subgraph Gen["buf generate (buf v2)"]
        BufGen[buf generate]
        TSGen[shared-ts/gen/proto<br/>@bufbuild/protobuf + grpc-node]
        GoGen[shared-go/gen/proto<br/>protobuf-go + grpc-go]
        PyGen[shared-py/gen/proto<br/>protobuf + grpc-python]
    end

    subgraph Services["消费服务"]
        SvcTS[NestJS 服务<br/>iam/core-edu/content/msg<br/>teacher-bff/student-bff/parent-bff]
        SvcGo[Go 网关<br/>api-gateway/push-gateway]
        SvcPy[Python 服务<br/>data-ana/ai]
    end

    IamProto --> BufGen
    CoreEduProto --> BufGen
    ClassesProto --> BufGen
    ContentProto --> BufGen
    MsgProto --> BufGen
    DataAnaProto --> BufGen
    AiProto --> BufGen
    EventsProto --> BufGen

    BufGen --> TSGen
    BufGen --> GoGen
    BufGen --> PyGen

    TSGen --> SvcTS
    GoGen --> SvcGo
    PyGen --> SvcPy

11.2 契约规则

规则 说明
包命名 proto 包名采用 next_edu_cloud.<domain>.v1 格式(如 next_edu_cloud.iam.v1next_edu_cloud.core_edu.v1
Topic 命名 Kafka topic 采用 edu.<domain>.<aggregate>.<action> 格式(如 edu.identity.user.created
版本化 破坏性变更必须升版本v1 → v2buf breaking FILE 级别 CI 强制
字段编号 禁止复用已删除字段编号,使用 reserved
消息命名 PascalCase
字段命名 snake_case
注释 每个 message 和字段必须注释
CI 强制 buf lint + buf breaking 必须通过
代码生成 buf generate 生成 6 套代码go/js/python × protobuf/grpc

11.3 BFF 聚合模式

graph LR
    subgraph Client["客户端"]
        Q[GraphQL 查询]
    end

    subgraph BFF["BFF 层"]
        Resolver[GraphQL Resolver]
        DataLoader[DataLoader 批量去重]
        Cache[Redis 短缓存]
    end

    subgraph Services["业务服务"]
        S1[服务 A]
        S2[服务 B]
        S3[服务 C]
    end

    Q --> Resolver
    Resolver --> Cache
    Cache --> DataLoader
    DataLoader --> S1
    DataLoader --> S2
    DataLoader --> S3

11.4 错误码前缀矩阵

来源coord 仲裁 ARB-017 §19.6 / ARB-014 / ARB-015 / ARB-018 / G14 / F4 规则:服务名大写 + 下划线分隔,禁止子前缀(如 EXAMS_/HOMEWORK_/GRADES_ 已移除)

层级 服务 前缀 示例 仲裁依据
网关 api-gateway GW_ GW_UNAUTHORIZED / GW_RATE_LIMITED ARB-014
网关 push-gateway PUSH_ PUSH_DEVICE_NOT_FOUND / PUSH_CHANNEL_FAILED ARB-015
BFF teacher-bff BFF_TEACHER_ BFF_TEACHER_UNAUTHORIZED / BFF_TEACHER_BAD_GATEWAY ARB-016
BFF student-bff BFF_STUDENT_ BFF_STUDENT_UNAUTHORIZED / BFF_STUDENT_VALIDATION_ERROR ARB-017
BFF parent-bff BFF_PARENT_ BFF_PARENT_CHILD_NOT_BOUND / BFF_PARENT_BAD_GATEWAY ARB-018
业务 iam IAM_ IAM_USER_NOT_FOUND / IAM_INVALID_CREDENTIALS ARB-003
业务 core-edu CORE_EDU_ CORE_EDU_EXAM_NOT_FOUND / CORE_EDU_GRADE_NOT_FOUND ARB-004
业务 content CONTENT_ CONTENT_QUESTION_NOT_FOUND / CONTENT_TEXTBOOK_NOT_FOUND ARB-005
业务 msg MSG_ MSG_NOTIFICATION_NOT_FOUND / MSG_TEMPLATE_NOT_FOUND ARB-008
业务 data-ana DATA_ANA_ DATA_ANA_DASHBOARD_UNAVAILABLE / DATA_ANA_ANALYTICS_NOT_READY ARB-009
业务 ai AI_ AI_GENERATION_FAILED / AI_QUOTA_EXCEEDED ARB-010

前端 i18n key 映射规则F4 裁决):

服务 i18n key 模式 示例
api-gateway error.gateway.<code_snake> error.gateway.unauthorized
push-gateway error.push.<code_snake> error.push.device_not_found
teacher-bff error.bffTeacher.<code_snake> error.bffTeacher.unauthorized
student-bff error.bffStudent.<code_snake> error.bffStudent.validation_error
parent-bff error.bffParent.<code_snake> error.bffParent.child_not_bound
iam error.iam.<code_snake> error.iam.user_not_found
core-edu error.core_edu.<code_snake> error.core_edu.exam_not_found
content error.content.<code_snake> error.content.question_not_found
msg error.msg.<code_snake> error.msg.notification_not_found
data-ana error.data_ana.<code_snake> error.data_ana.dashboard_unavailable
ai error.ai.<code_snake> error.ai.generation_failed

11.5 ActionState 信封规范

来源coord 仲裁 ARB-017 §19.6 适用范围:所有 BFF / Gateway HTTP 响应、GraphQL response 的 errors 扩展字段 设计原则:统一错误信封 + 降级模式方案 Bdegraded 放 error.details 子字段)

信封结构

interface ActionState<T = unknown> {
  success: boolean; // 整体成功/失败
  data: T | null; // 成功时返回数据,失败时为 null
  error: {
    code: string; // 错误码(见 §11.4 前缀矩阵)
    message: string; // 人类可读错误消息i18n key 解析后)
    details?: Record<string, unknown>; // 附加详情(含 degraded 字段)
    traceId: string; // 链路追踪 IDX-Request-Id
  } | null; // 成功时为 null
}

降级模式(方案 B

  • success = true(整体成功)
  • data 内含 extensions.degraded: true 子字段
  • error 仍为 null非错误
  • 用于部分聚合失败场景(如 teacher-bff 聚合 iam 成功但 core-edu 失败)

示例 1完全成功

{
  "success": true,
  "data": { "userId": "u001", "name": "张老师" },
  "error": null
}

示例 2完全失败

{
  "success": false,
  "data": null,
  "error": {
    "code": "BFF_TEACHER_BAD_GATEWAY",
    "message": "下游服务不可用",
    "details": { "downstream": "core-edu", "reason": "timeout" },
    "traceId": "req-abc123"
  }
}

示例 3降级模式部分聚合成功

{
  "success": true,
  "data": {
    "user": { "userId": "u001", "name": "张老师" },
    "classes": null,
    "extensions": { "degraded": true, "failedServices": ["core-edu"] }
  },
  "error": null
}

GraphQL errors 数组扩展

GraphQL 响应中,错误通过 errors[].extensions 携带 ActionState 字段:

{
  "errors": [
    {
      "message": "下游服务不可用",
      "extensions": {
        "code": "BFF_TEACHER_BAD_GATEWAY",
        "details": { "downstream": "core-edu" },
        "traceId": "req-abc123"
      }
    }
  ]
}

12. 架构约束

12.1 服务独立性约束

约束 说明
数据库独占 每个微服务独占自身数据库,禁止跨库联表
契约先行 所有跨服务通信必须先定义 protobuf 契约
Outbox 强制 所有领域事件必须通过 Outbox 模式发布
幂等消费 所有事件消费者必须实现幂等性
单一职责 每个服务只负责一个限界上下文
无状态服务 业务服务不持有会话状态Redis 承载)

12.2 通信约束

场景 允许 禁止
客户端 → Gateway REST + WebSocket 直连业务服务
Gateway → BFF HTTP 反向代理(路径重写剥离前缀) gRPC 转换、REST 业务逻辑
Gateway → 业务服务 HTTP 反向代理(剥离 /api 前缀) gRPC 转换
BFF → 业务服务 gRPC + DataLoader 批量去重 直接访问 DB
push-gateway → msg HTTP /internal/* + Kafka 消费 gRPC豁免ARB-015
业务服务之间(同步) gRPC REST、直接 DB
业务服务之间(异步) Kafka 事件Outbox 模式) 直接 producer 调用
事件发布 Outbox 模式 直接 Kafka producer

12.3 数据一致性约束

场景 一致性级别 实现
聚合内 强一致 单事务
聚合间 最终一致 Kafka 事件
服务间 最终一致 Kafka 事件 / Saga
读模型 最终一致 Projection 异步更新
缓存 最终一致 事件驱动失效 + 短 TTL

13. ADR 记录

编号 决策 原因 状态
ADR-001 采用 DDD 限界上下文划分服务 业务边界清晰,独立演进 已采纳
ADR-002 采用 NestJS 作为业务服务框架 TS 生态成熟,装饰器 + DI 适合 DDD 已采纳
ADR-003 采用 Go 作为网关语言 高并发、低内存、适合网关场景 已采纳
ADR-004 采用 Python 作为分析/AI 语言 数据科学/AI 生态丰富 已采纳
ADR-005 采用 CQRS 读写分离 读多写少,读模型可独立优化 已采纳
ADR-006 采用 Outbox 模式发布事件 保证事务与事件最终一致 已采纳
ADR-007 采用 Kafka 作为事件总线 高吞吐、持久化、成熟生态 已采纳
ADR-008 采用 Debezium CDC 解耦 Outbox Relay减少业务侵入 已采纳
ADR-009 采用 protobuf + buf 契约先行 多语言契约统一、版本化、CI 强制 已采纳
ADR-010 采用 JWT RS256 非对称签名 网关公钥校验无需共享私钥 已采纳
ADR-011 采用 DataScope 6 级数据范围 满足 K12 多层级数据隔离 已采纳
ADR-012 采用 Module Federation 微前端 独立部署、技术栈无关、渐进迁移 已采纳
ADR-013 采用 Temporal 工作流编排 长流程编排、可观测、可回滚 规划中(当前由 ai 内 WorkflowStateStore 临时实现)
ADR-014 采用 ClickHouse 读模型宽表 分析查询亚秒级响应 已采纳
ADR-015 api-gateway 采用 HTTP 反向代理(非 gRPC 转换) Go 网关只做 HTTP简化部署下游 HTTP/gRPC 双协议 已采纳
ADR-016 push-gateway 豁免 gRPC 基础设施层无流式推送场景msg/student-bff/parent-bff 改用 HTTP /internal/* 已采纳
ADR-017 classes 服务合并入 core-edu 教学组织与教学核心共享聚合根边界 已采纳
ADR-018 BFF 统一 GraphQL Yoga + DataLoader + opossum 熔断 协议统一、批量去重、降级模式 Bdegraded 子字段) 已采纳
ADR-019 admin-portal GraphQL 经 teacher-bff 命名空间 复用 teacher-bff resolveradmin role 中间件强制隔离 已采纳
ADR-020 parent-portal 作为 MF Remote 被 teacher-portal 加载 家长入口可由教师端嵌入,统一 Shell 宿主 已采纳
ADR-021 Trace 存储 Jaeger 替代 Tempo all-in-one 镜像部署简单OTLP 原生支持 已采纳
ADR-022 共享包 ui-tokens 替代原 shared-tokens 命名 三层令牌primitive/semantic/tailwind-theme实际落地 已采纳

14. 附录6 阶段路线图

14.1 阶段总览

graph LR
    P1[P1 地基<br/>M1-M3] --> P2[P2 身份<br/>M4-M6]
    P2 --> P3[P3 核心教学<br/>M7-M10]
    P3 --> P4[P4 内容分析<br/>M11-M13]
    P4 --> P5[P5 沟通AI<br/>M14-M16]
    P5 --> P6[P6 硬化<br/>M17-M18]

14.2 服务与阶段映射

状态基于代码现状2026-07-14 已落地 / 🚧 部分落地 / 规划中。

阶段 周期 交付服务 退出标准 实际状态
P1 地基 M1-M3 api-gateway、classes黄金模板、shared-proto classes 域 CRUD 端到端跑通 完成classes 已合并入 core-edu
P2 身份 M4-M6 iam、teacher-bff、teacher-portal 骨架 教师可登录并看到空白 Dashboard 完成
P3 核心教学 M7-M10 core-edu合并 classes、student-bff、student-portal 考试→作答→批改→成绩全链路 完成(含 LeaveRequests/Dashboard/Admin/IamConsumer 扩展)
P4 内容分析 M11-M13 content、data-ana、parent-bff、parent-portal 知识图谱查询 + 学情宽表 5s 完成(含 7 模块 + Neo4j + ES sync + CDC consumer + 11 analytics 端点)
P5 沟通AI M14-M16 msg、push-gateway、ai 全校广播 + AI 辅助出题 完成msg 4 模块 4 渠道 + push-gateway WS + Kafka + ai 11 端点 + 备课工作流)
P6 硬化 M17-M18 admin-portal、Service Mesh 99.9% 可用性 + 独立扩缩容 🚧 admin-portal 已落地Service Mesh / Vault / 99.9% SLO 待硬化

详细规划见 路线图目录tech-debtpending-features


15. 实施状态索引v2.0 新增)

本节按服务/包罗列实际落地的模块、Controller、关键组件作为代码现状的快速索引。 详细模块设计见各服务 README.mddocs/01-understanding.md

15.1 api-gatewayGo :8080

  • 中间件链Recovery → otelgin → RequestID → CORS → SecurityHeaders → RequestBodyLimit(10MB) → RateLimit(100rps+20burst) → CircuitBreaker → AuthMiddleware(JWKS RS256) → Metrics
  • 路由组
    • /healthz/readyz/metrics(公开)
    • /api/v1/{classes,iam,exams,homework,grades,textbooks,chapters,knowledge-points,questions,notifications,messages,announcements,ai,analytics,dashboard}/* → HTTP 反向代理
    • /api/v1/{teacher,student,parent}/* → BFF 反向代理(剥离 /api/v1/{bff} 前缀)
    • /api/admin/graphql → teacher-bff /graphqlAdminRoleMiddleware 强制)
  • 关键依赖shared-go/jwks(公钥缓存)、shared-go/envshared-go/loggershared-go/tracer

15.2 push-gatewayGo :8081

  • WebSocket 端点/wsJWT RS256 via query ?token= 或 Authorization 头)
  • 内部 HTTP API/internal/push/internal/broadcast/internal/online/:userIDX-Internal-Key 鉴权)
  • 跨实例广播Redis Pub/SubSubscribeAll + RebuildPresenceOnStartup
  • Kafka 消费edu.notify.notification.sentARB-013
  • 健康检查/healthzliveness/readyzRedis 软失败 + Kafka consumer 状态)
  • 依赖hubin-memory connection registryredisclientkafkaconsumerwsobservability

15.3 iamNestJS :3002 / gRPC :50052

  • ControllersIamController、RbacController、AuditController、JwksController、IamGrpcController
  • ServicesIamService、JwksService、PermissionCacheServiceRedis、TokenBlacklistService
  • Outboxiam_outbox 表,发布到 edu.identity.user.* topic
  • APP_GUARDPermissionGuardDB 驱动 + Redis 缓存I3 裁决)
  • AuthMiddleware 应用范围:v1/iam/melogoutchange-passwordviewportspermissions/effectivechildrenrolespermissionsusersaudittotp

15.4 core-eduNestJS :3004 / gRPC :50053

  • 业务模块10
    • exams含 exam-extensions、exam-state-machine
    • homework含 homework-state-machine
    • grades含 grade-calculator
    • attendance
    • classes含 teacher-associationsC1 合并自原 classes 服务)
    • scheduling含 schedule-conflict 检测)
    • leave-requestsP3.13
    • dashboard
    • admin
    • iam-consumer消费 IAM 6 类事件)
  • 共享组件datascope-injectorRepository 层 WHERE 注入、outboxcore_edu_outbox、global-error.filter
  • gRPC 服务943 RPCExamService / HomeworkService / GradeService / AttendanceService / ClassService / ScheduleService / LeaveRequestService / DashboardService / AdminService

15.5 contentNestJS :3005 / gRPC :50054

  • 业务模块7textbooks、chapters、knowledge-points、questions、electives、lesson-plans、course-plans
  • gRPC controllers7Textbook / Chapter / KnowledgeGraph / Question / Elective / LessonPlan / CoursePlan
  • 同步 workeres-sync.worker题库 ES 索引、neo4j-sync.worker知识图谱节点
  • Outboxcontent_outbox发布 edu.content.* 事件
  • 存储MySQL业务表+ Neo4j知识图谱+ Elasticsearch题库检索

15.6 msgNestJS :3007 / gRPC :50056

  • 业务模块4notifications、preferences、templates、announcements
  • gRPC controllers317 RPCNotificationService9 RPC/ NotificationPreferenceService2 RPC/ NotificationTemplateService6 RPCARB-008 裁剪)
  • 渠道4email、sms、push、in-appchannel-dispatcher 路由)
  • Kafka 消费16 类事件iam 6 + core-edu 9 + data-ana 1shared/kafka/topic-map.ts
  • Kafka 生产4 类 edu.notify.notification.* 事件 + 1 兜底 topic
  • 辅助组件push-gateway.clientHTTP 调用 /internal/push、idempotency.guardRedis SETNX 去重、Outboxmsg_outbox
  • 存储MySQL + Elasticsearch消息全文检索+ Redis幂等性

15.7 data-anaFastAPI :3006 / gRPC :50055

  • HTTP 端点3 基础 + 11 业务 = 14
    • 基础://healthz/readyz
    • 业务(全部 ActionState 信封):
      • /analytics/class/{class_id}/performance
      • /analytics/student/{student_id}/{weakness,trend,errorbook,mastery}
      • /analytics/{teacher,student,parent,admin}/dashboard
      • /analytics/warnings + /analytics/warnings/trigger
      • /analytics/class/{class_id}/mastery-distribution
  • gRPC 服务AnalyticsService18 RPC
  • CDC 消费者:手动 commitlag 阈值 1000超过 readyz 返 503
  • /readyz 4 依赖ClickHouse1s+ CDC consumerlag<1000+ Redis200ms+ iam gRPC2s
  • 存储ClickHouse宽表+ Redis缓存+ iam gRPC用户信息

15.8 aiFastAPI :3008 / gRPC :50058

  • HTTP 端点11
    • /healthz/readyz
    • /v1/ai/chat(非流式)+ /v1/ai/chat/streamSSE
    • /v1/ai/generate/question + /v1/ai/generate/question/streamSSE
    • /v1/ai/optimize/expression
    • /v1/ai/lesson-plan/generate + /v1/ai/lesson-plan/status/{workflow_id} + /v1/ai/lesson-plan/confirm/{workflow_id}
    • /v1/ai/generate/reportclass_summary / student_detail / exam_analysis
  • gRPC 服务AiService9 RPC
  • 核心组件LLM FailoverChain4 适配器 + 熔断 + 故障切换、PromptTemplateServiceJinja2 + YAML、QualityGateRuleValidator + LLMJudge
  • 用量与配额UsageRecorderRedis+ QuotaEnforcer + KafkaProduceredu.ai.usage.*
  • 限流RateLimiterRedis 三维度令牌桶user/ip/school
  • 安全PII redactor + 输入清洗 + 输出审核
  • 备课工作流4 步编排 + WorkflowStateStoreRedis TTL
  • 下游 gRPC 客户端ContentClientGrpc / DataAnaClientGrpc / IamClientGrpc连接失败降级不阻断启动

15.9 teacher-bffNestJS :3003 / GraphQL Yoga

  • 模块GraphQLModuleTeacher + Admin ResolversARB-001 扁平合并)+ HealthModule + MiddlewareModule
  • 下游客户端6iam / core-edu / content / data-ana / msg / aiB8 裁决统一抽象gRPC + mock 双实现)
  • GraphQL 端点/graphql(同时承载 teacher 与 admin 命名空间)
  • SSE 控制器ai-chat-sse.controller.ts(透传 ai 服务流式响应)
  • Health probes6iam-grpc / core-edu-grpc / content-grpc / data-ana-grpc / ai-grpc / msg-grpc + redis probe

15.10 student-bffNestJS :3009 / GraphQL Yoga

  • 模块8CacheModuleGlobal Redis+ DownstreamModuleGlobal gRPC+ CircuitBreakerModuleGlobal opossum+ HealthModule + DataLoaderModule + StudentModuleGraphQL Yoga + Resolver+ PushGatewayModuleHTTP /internal/push+ EventModuleKafka 事件订阅 + push-gateway 推送)
  • 下游客户端iam / core-edu / data-ana

15.11 parent-bffNestJS :3010 / GraphQL Yoga

  • 模块6HealthModule + GraphqlModuleYoga /v1/graphql+ ClientsModuleiam + core-edu + data-ana + msg + push-http+ KafkaModulecache-invalidation + notification-push handler+ AggregationModuleorchestrator + fallback-strategy + child-guard + response-mapper+ DataLoaderModuledataloader.factory + loaders 批量去重)
  • 缓存Redis + LRU cache + cache-key.builder

15.12 teacher-portalNext.js 15 :4000MF Shell

  • 路由组25+ 业务页面dashboard、classes、schedule、exams、homework、grades、attendance、analytics、knowledge-graph、lesson-plans、course-plans、textbooks、questions、notifications、students、ai-assist、ai-lesson-plan、ai-report、diagnostic、error-book、practice、leave、elective、schedule-changes、settings
  • MF Remote 加载ParentPortalRemote在 teacher-portal 内嵌入家长端视图)
  • GraphQL 客户端文件graphql.tsbase+ graphql-p4.ts / p5.ts / p7-admin.ts / p7-advanced.ts / p7-exams.ts / p7-grades.ts / p7-insights.ts按阶段渐进扩展
  • 可观测性observability-providerOTel Web + Sentry + web-vitals + performance-dashboard
  • 国际化messages/{en,zh-CN}.json
  • 认证lib/auth.tscookie 迁移 + token 刷新 + cross-tab sync

15.13 student-portal / parent-portal / admin-portalNext.js 15 :4001/:4002/:4003MF Remote

  • student-portal:路由组 leave + 主页exam-types 类型mocks/handlers + server
  • parent-portallogin + 主页 + providerschild-storeZustandmiddleware.tsPWAmanifest + sw.js
  • admin-portallogin + admin layouthooksuse-classes/files/roles/school/students/teachers/users/graphqllib/{auth,i18n,permissions,web-vitals}

15.14 共享包实施状态

关键导出 状态
shared-proto 8 proto 文件 + buf.yaml + buf.gen.yaml生成 6 套代码)
shared-ts bff/loggeroutbox/OutboxModule + publisher + schema + types被 iam/core-edu/content/msg/BFF 共享)
shared-go env/config.Loadjwks/FetcherRS256 公钥缓存)、logger/slog JSONtracer/OTLP init
shared-py pyproject.tomluv workspace member 🚧
contracts STUDENT_PERMISSIONS 常量12 权限点) 🚧
hooks use-auth / use-permission / use-viewports / use-graphql-client / use-trace-id / use-a11y-id / use-aria-live / use-api / use-toast
ui-components data-table / filter-bar / form / modal / chart / calendar / status-badge / empty / loading + utils/cn
ui-tokens primitive.css / semantic-light.css / semantic-dark.css / tailwind-theme.css / all.css + colors/shadows/spacing/typography (.ts)

15.15 部署与运维实施状态

  • 本地开发infra/docker-compose.yml(基础设施)+ pnpm dev / go run / uv run
  • 最小化部署infra/docker-compose.minimal.yml
  • 生产部署infra/docker-compose.deploy.ymlbuild: 替代 image:
  • 测试部署infra/docker-compose.test.yml
  • 监控栈infra/docker-compose.monitoring.ymlobservability profile
  • K8s Helm chartinfra/k8s/helm/edu-platform umbrella + 各子 chart
  • CI/CD.github/workflows/ci.ymlquality-ts / quality-go / quality-proto / deployno-push 本地构建模式)
  • 备份infra/backup/backup-mysql.sh(每服务独立,保留 7 天)
  • 混沌工程infra/chaos/experiments.yaml
  • WAFinfra/security/waf-rules.conf
  • 端口分配infra/port-allocation.md(唯一源)

15.16 文档体系实施状态

路径 用途
docs/architecture/004_architecture_impact_map.md 本文件(架构影响地图,设计意图唯一源)
docs/architecture/0010_architecture.md 理想蓝图(目标态)
docs/architecture/004-p6-addendum.md P6 硬化附录
docs/architecture/roadmap/ tech-debt / pending-features / integration-test-phase
docs/architecture/runbooks/ p6-hardening / post-p6-followup / incident-response
docs/architecture/issues/ 协调记录coord / matrix / workline+ contracts/ + objections/ + worklines/
docs/architecture/ai-allocation.md AI 模块分配
docs/architecture/ai-work-orchestration.md AI 工作编排
docs/architecture/coord-cross-review.md coord 交叉审查
docs/architecture/coord-final-decisions.md coord 最终裁决ARB-001~022+
docs/architecture/president-final-rulings.md president 最终裁决batch 0.9+
docs/modules/<service>/README.md 各服务模块文档iam/core-edu/content/msg/data-ana/ai/api-gateway/push-gateway/classes
docs/standards/ coding-standards / cicd-runbook / full-stack-runbook / git-workflow / local-dev-runbook / multi-ai-collaboration / ui-design-system
docs/troubleshooting/known-issues.md 已知问题速查(索引式场景→技术映射)

本文件 v2.0 已基于代码现状2026-07-14全面校准。后续代码变更须按 项目规则 §1 同步更新本文件 + 运行 pnpm run arch:scan