Files
Edu/docs/architecture/004_architecture_impact_map.md
SpecialX c179af64a6 docs(docs): coord 完成 15 模块 issue 仲裁与基础设施同步
coord.md 新增 ARB-019/020/021 三章仲裁章节,修正 ARB-001。

- coord.md: 新增 ARB-019/020/021(student/parent/admin-portal 24 项)
- coord.md: 修正 ARB-001(admin P2 预留/schema 文件名/classes 数据源)
- 004 §4: 依赖图加 PBFF→DataAna+Msg
- 004 §7.2: push-gateway→Redis 软失败标注
- 004 §11.4: 错误码前缀矩阵(11 服务+i18n key)
- 004 §11.5: ActionState 信封规范(降级模式方案 B)
- matrix §1: 依赖矩阵加 PBFF 边
- matrix §2: 移除 api-gateway 为 iam gRPC 消费方
- matrix §4: admin-portal→teacher-bff
- matrix §5: 移除 /sse+鉴权头统一
- matrix §6: 错误码表补 i18n key 列
- 15 个 issue.md: 仲裁结论回写
- push-gateway_contract: 移除 /sse+鉴权头改 X-Internal-Token
- packages/contracts: 新建包 ADMIN_* 权限点常量

AI: coord
2026-07-10 16:30:51 +08:00

41 KiB
Raw Permalink Blame History

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

版本1.0 日期2026-07-07 状态:基线发布 适用范围Edu 微服务架构DDD + EDA + CQRS 关联文档:


目录

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

1. 项目概述

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

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

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

    subgraph MFE["微前端层Module Federation"]
        TeacherPortal["teacher-portal<br/>教学场景域前端"]
        StudentPortal["student-portal<br/>学习场景域前端"]
        ParentPortal["parent-portal<br/>家长场景域前端"]
        AdminPortal["admin-portal<br/>管理场景域前端"]
    end

    subgraph Gateway["网关层Go"]
        APIGateway[api-gateway<br/>Gin + JWT + 限流]
        PushGateway[push-gateway<br/>WebSocket/SSE]
    end

    subgraph BFF["BFF 聚合层NestJS<br/>按使用场景域分 BFF不是按角色分"]
        TeacherBFF["teacher-bff<br/>教学场景域聚合"]
        StudentBFF["student-bff<br/>学习场景域聚合"]
        ParentBFF["parent-bff<br/>家长场景域聚合"]
    end

    subgraph Services["业务微服务NestJS + FastAPI"]
        IAM[iam<br/>身份认证]
        CoreEdu[core-edu<br/>教学核心]
        Content[content<br/>内容资源]
        DataAna[data-ana<br/>数据分析 Python]
        Msg[msg<br/>消息通知]
        AI[ai<br/>AI 网关 Python]
    end

    subgraph Bus["事件总线"]
        Kafka[(Kafka)]
        Debezium[Debezium CDC]
    end

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

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

    TeacherPortal --> APIGateway
    StudentPortal --> APIGateway
    ParentPortal --> APIGateway
    AdminPortal --> APIGateway
    TeacherPortal -.推送.-> PushGateway
    StudentPortal -.推送.-> PushGateway

    APIGateway --> TeacherBFF
    APIGateway --> StudentBFF
    APIGateway --> ParentBFF

    TeacherBFF --> IAM
    TeacherBFF --> CoreEdu
    TeacherBFF --> Content
    TeacherBFF --> DataAna
    StudentBFF --> IAM
    StudentBFF --> CoreEdu
    ParentBFF --> IAM
    ParentBFF --> CoreEdu

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

    MySQL --> Debezium
    Debezium --> Kafka

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

    IAM --> Redis
    CoreEdu --> Redis

1.1b 业务领域视角

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

graph TB
    subgraph D1["D1 身份认证领域"]
        IAM[iam 服务]
        IAM_M[users / roles / permissions<br/>refresh_tokens / sessions]
    end

    subgraph D2["D2 教学组织领域"]
        ORG[core-edu 服务<br/>classes 模块]
        ORG_M[classes / subjects / enrollment]
    end

    subgraph D3["D3 教学核心领域"]
        TEACH[core-edu 服务<br/>exams/homework/grades]
        TEACH_M[exams / homework / grades<br/>courses / lessons / schedule / attendance]
    end

    subgraph D4["D4 内容资源领域"]
        CONTENT[content 服务]
        CONTENT_M[textbooks / knowledge-points<br/>questions / grading / search]
    end

    subgraph D5["D5 沟通通知领域"]
        MSG[msg 服务]
        MSG_M[messaging / notifications / announcements]
    end

    subgraph D6["D6 智能洞察领域"]
        DATA[data-ana 服务]
        AI[ai 服务]
        DATA_M[analytics / dashboard / diagnostic]
        AI_M[AI 备课 / 出题 / 分析 / 搜索]
    end

    IAM --> ORG
    IAM --> TEACH
    IAM --> CONTENT
    IAM --> MSG
    ORG --> TEACH
    TEACH --> CONTENT
    TEACH --> MSG
    CONTENT --> DATA
    TEACH --> DATA

双图并存说明

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

1.2 服务清单

类别 服务名 语言/框架 限界上下文 业务领域 阶段
基础设施 api-gateway Go (Gin) 网关 P1
基础设施 push-gateway Go (Gin) 推送 P5
BFF teacher-bff TS (NestJS) 教师聚合 教学场景域 P2
BFF student-bff TS (NestJS) 学生聚合 学习场景域 P3
BFF parent-bff TS (NestJS) 家长聚合 家长场景域 P4
业务 iam TS (NestJS) 身份认证 D1 身份认证 P2
业务 core-edu TS (NestJS) 教学核心 D2 教学组织 + D3 教学核心 P3
业务 content TS (NestJS) 内容资源 D4 内容资源 P4
业务 data-ana Python (FastAPI) 数据分析 D6 智能洞察 P4
业务 msg TS (NestJS) 消息通知 D5 沟通通知 P5
业务 ai Python (FastAPI) AI 网关 D6 智能洞察 P5
微前端 teacher-portal TS (Next.js) 教师端 教学场景域 P2
微前端 student-portal TS (Next.js) 学生端 学习场景域 P3
微前端 parent-portal TS (Next.js) 家长端 家长场景域 P4
微前端 admin-portal TS (Next.js) 管理端 管理场景域 P6
共享包 shared-proto TS protobuf 契约 P1
共享包 shared-ts TS TS 共享工具 P1
共享包 shared-go Go Go 共享工具 P1
共享包 shared-py Python Python 共享工具 P4

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.22+ Gin API Gateway、Push Gateway
业务服务 TypeScript 5.5+ NestJS 10 IAM、CoreEdu、Content、Msg
分析/AI Python 3.12+ FastAPI DataAna、AI 网关
BFF TypeScript 5.5+ NestJS 10 + GraphQL 教师/学生/家长聚合
微前端 TypeScript 5.5+ Next.js 15 + Module Federation 4 端门户
契约 protobuf buf 跨语言契约定义

2.2 多存储矩阵

存储 用途 使用服务
MySQL 8 写模型主库(每服务独占) IAM、CoreEdu、Content、Msg
Redis 7 缓存、会话、限流计数 全部服务
ClickHouse 读模型宽表、分析聚合 DataAna、CoreEdu读模型
Neo4j 知识图谱、前置依赖 Content
Elasticsearch 题库全文检索 Content、AI

2.3 基础设施矩阵

组件 用途
Kafka 事件总线,领域事件异步通信
Debezium CDCMySQL Binlog → Kafka 实时同步
Temporal 工作流编排考试生命周期、AI 编排)
OpenTelemetry 分布式追踪
Loki 日志聚合
Tempo 分布式 Trace 存储
Prometheus 指标采集
Grafana 可观测性可视化
Vault 密钥管理P6

3. 分层架构

3.1 六层架构

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

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

    subgraph L3["L3 网关层"]
        GW[API Gateway Go<br/>路由+鉴权+限流+熔断]
        Push[Push Gateway Go<br/>WebSocket/SSE]
    end

    subgraph L4["L4 BFF 聚合层"]
        BFF[BFF NestJS<br/>聚合+裁剪+协议转换]
    end

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

    subgraph L6["L6 数据与总线层"]
        DB[(MySQL/CH/Neo4j/ES)]
        KAFKA[(Kafka)]
        TEMPORAL[Temporal]
    end

    Browser --> MFE
    Mobile --> MFE
    MFE --> GW
    MFE -.推送.-> Push
    GW --> BFF
    BFF --> SVC
    SVC --> DB
    SVC <--> KAFKA
    SVC --> TEMPORAL

3.2 依赖方向

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

严格规则

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

4. 服务依赖图

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

    subgraph BFF["BFF 层"]
        TBFF[teacher-bff]
        SBFF[student-bff]
        PBFF[parent-bff]
    end

    subgraph Services["业务服务"]
        IAM[iam]
        CoreEdu[core-edu]
        Content[content]
        DataAna[data-ana]
        Msg[msg]
        AI[ai]
    end

    subgraph Shared["共享包"]
        Proto[shared-proto]
        SharedTS[shared-ts]
    end

    APIGW --> TBFF
    APIGW --> SBFF
    APIGW --> PBFF
    PushGW --> Msg

    TBFF --> IAM
    TBFF --> CoreEdu
    TBFF --> Content
    TBFF --> DataAna
    TBFF --> AI

    SBFF --> IAM
    SBFF --> CoreEdu
    SBFF --> Content
    SBFF --> DataAna

    PBFF --> IAM
    PBFF --> CoreEdu
    PBFF --> DataAna
    PBFF --> Msg

    CoreEdu -.事件.-> Content
    CoreEdu -.事件.-> DataAna
    CoreEdu -.事件.-> Msg
    Content -.事件.-> DataAna
    IAM -.事件.-> CoreEdu
    IAM -.事件.-> Msg
    AI -.gRPC.-> Content
    AI -.gRPC.-> DataAna

    IAM --> Proto
    CoreEdu --> Proto
    Content --> Proto
    DataAna --> Proto
    Msg --> Proto
    AI --> Proto

    IAM --> SharedTS
    CoreEdu --> SharedTS
    Content --> SharedTS
    Msg --> SharedTS

4.1 服务间通信矩阵

调用方 → 被调用方 协议 场景
api-gateway → BFF gRPC 请求路由
BFF → 业务服务 gRPC 同步查询聚合
CoreEdu → Content Kafka 事件 教学内容变更通知
CoreEdu → DataAna Kafka 事件 学情数据投递
CoreEdu → Msg Kafka 事件 通知触发
IAM → CoreEdu Kafka 事件 用户变更同步
AI → Content gRPC 题库查询
AI → DataAna gRPC 学情数据查询
push-gateway → Msg gRPC 推送通道建立

5. 认证与权限

5.1 JWT RS256 认证流程

sequenceDiagram
    participant U as 用户
    participant GW as API Gateway
    participant IAM as IAM 服务
    participant SVC as 业务服务

    rect rgb(240, 248, 255)
        Note over U,IAM: 阶段 1: 登录签发
        U->>GW: POST /auth/login {username, password}
        GW->>IAM: gRPC Login(username, password)
        IAM->>IAM: 校验密码 + 查询权限
        IAM->>IAM: 生成 JWTRS256 私钥签发)
        IAM-->>GW: {accessToken, refreshToken, userInfo}
        GW-->>U: 200 {accessToken, refreshToken}
    end

    rect rgb(240, 255, 240)
        Note over U,SVC: 阶段 2: 请求鉴权
        U->>GW: GET /api/classes + Authorization: Bearer <token>
        GW->>GW: RS256 公钥校验签名
        GW->>GW: 校验 exp/iss/aud
        GW->>GW: 提取 userId/role/dataScope
        GW->>SVC: gRPC 请求 + 透传 userId/role/dataScope metadata
        SVC->>SVC: 权限校验requirePermission
        SVC-->>GW: 响应数据
        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 分类

Topic 模式 示例 生产者 消费者
edu.identity.user.created 用户创建 IAM CoreEdu、Msg
edu.identity.user.updated 用户更新 IAM CoreEdu、Msg
edu.org.class.created 班级创建 CoreEdu DataAna
edu.teaching.assignment.submitted 作业提交 CoreEdu DataAna、Msg
edu.teaching.exam.published 考试发布 CoreEdu Msg
edu.teaching.grade.recorded 成绩录入 CoreEdu DataAna、Msg
edu.content.question.published 题目发布 Content AI、ES
edu.insight.mastery.updated 掌握度更新 DataAna CoreEdu、Msg

必需依赖软失败标注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 投递通知到多渠道

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 三支柱可观测性

graph TB
    subgraph App["应用层"]
        SVC[业务服务]
        GW[网关]
        BFF[BFF]
    end

    subgraph Collect["采集层"]
        OTEL[OpenTelemetry SDK]
        PROM[Prometheus Exporter]
    end

    subgraph Storage["存储层"]
        LOKI[(Loki<br/>日志)]
        TEMPO[(Tempo<br/>Trace)]
        PROMDB[(Prometheus<br/>指标)]
    end

    subgraph Vis["可视化层"]
        GRAFANA[Grafana<br/>统一面板]
        ALERT[AlertManager<br/>告警]
    end

    SVC --> OTEL
    GW --> OTEL
    BFF --> OTEL
    OTEL --> LOKI
    OTEL --> TEMPO
    SVC --> PROM
    GW --> PROM
    PROM --> PROMDB
    LOKI --> GRAFANA
    TEMPO --> GRAFANA
    PROMDB --> GRAFANA
    PROMDB --> ALERT

10.2 Trace 上下文传播

flowchart LR
    A[客户端请求] --> B[API Gateway<br/>生成 traceId]
    B --> C[BFF<br/>继承 traceId]
    C --> D[业务服务<br/>继承 traceId]
    D --> E[Kafka 事件<br/>traceId 写入 header]
    E --> F[消费者服务<br/>继承 traceId]
    F --> G[数据存储<br/>span 记录]

规则

  • 所有跨服务调用必须透传 W3C Trace Context
  • Kafka 事件必须将 traceId 写入消息 header
  • 日志必须包含 traceId 用于关联查询
  • 关键业务操作必须创建 span创建考试、提交作业、批改等

11. 契约与 API 架构

11.1 Protobuf 契约体系

graph TB
    subgraph Proto["protobuf 契约仓库"]
        Identity[identity/v1<br/>user/role/permission]
        Org[org/v1<br/>class/subject/enrollment]
        Teaching[teaching/v1<br/>course/assignment/exam]
        Content[content/v1<br/>textbook/question]
        Comm[comm/v1<br/>message/notification]
        Insight[insight/v1<br/>report/mastery]
    end

    subgraph Gen["代码生成"]
        Buf[buf generate]
        TS[TS 生成代码<br/>@bufbuild/protobuf]
        Go[Go 生成代码<br/>protobuf-go]
        Py[Python 生成代码<br/>betterproto]
    end

    subgraph Services["消费服务"]
        SvcTS[NestJS 服务]
        SvcGo[Go 网关]
        SvcPy[Python 服务]
    end

    Identity --> Buf
    Org --> Buf
    Teaching --> Buf
    Content --> Buf
    Comm --> Buf
    Insight --> Buf

    Buf --> TS
    Buf --> Go
    Buf --> Py

    TS --> SvcTS
    Go --> SvcGo
    Py --> SvcPy

11.2 契约规则

规则 说明
包命名 edu.[context].[aggregate].v[version]
版本化 破坏性变更必须升版本v1 → v2
字段编号 禁止复用已删除字段编号,使用 reserved
消息命名 PascalCase
字段命名 snake_case
注释 每个 message 和字段必须注释
CI 强制 buf lint + buf breaking 必须通过

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 gRPC REST
BFF → 业务服务 gRPC 直接访问 DB
业务服务之间(同步) gRPC + 必要时 REST、直接 DB
业务服务之间(异步) Kafka 事件 直接 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 工作流编排 长流程编排、可观测、可回滚 已采纳
ADR-014 采用 ClickHouse 读模型宽表 分析查询亚秒级响应 已采纳

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 服务与阶段映射

阶段 周期 交付服务 退出标准
P1 地基 M1-M3 api-gateway、classes黄金模板、shared-proto classes 域 CRUD 端到端跑通
P2 身份 M4-M6 iam、teacher-bff、teacher-portal 骨架 教师可登录并看到空白 Dashboard
P3 核心教学 M7-M10 core-edu合并 classes、student-bff、student-portal 考试→作答→批改→成绩全链路
P4 内容分析 M11-M13 content、data-ana、parent-bff、parent-portal 知识图谱查询 + 学情宽表 5s
P5 沟通AI M14-M16 msg、push-gateway、ai 全校广播 + AI 辅助出题
P6 硬化 M17-M18 admin-portal、Service Mesh 99.9% 可用性 + 独立扩缩容

详细规划见 路线图目录