# 架构影响地图（微服务版）

> 版本：1.0
> 日期：2026-07-07
> 状态：基线发布
> 适用范围：Edu 微服务架构（DDD + EDA + CQRS）
> 关联文档：
>
> - [理想蓝图](./0010_architecture.md)
> - [项目规则](../../.trae/rules/project_rules.md)
> - [路线图](./roadmap/README.md)

---

## 目录

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

---

## 1. 项目概述

### 1.1a 技术分层视角（系统边界）

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

```mermaid
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](#11a-技术分层视角系统边界)。

```mermaid
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      | CDC，MySQL Binlog → Kafka 实时同步  |
| Temporal      | 工作流编排（考试生命周期、AI 编排） |
| OpenTelemetry | 分布式追踪                          |
| Loki          | 日志聚合                            |
| Tempo         | 分布式 Trace 存储                   |
| Prometheus    | 指标采集                            |
| Grafana       | 可观测性可视化                      |
| Vault         | 密钥管理（P6）                      |

---

## 3. 分层架构

### 3.1 六层架构

```mermaid
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. 服务依赖图

```mermaid
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 认证流程

```mermaid
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: 生成 JWT（RS256 私钥签发）
        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 + 自定义）
- 权限解析 API：getEffectivePermissions(userId) → {permissions, viewports, dataScope}

---

## 6. 数据访问与缓存

### 6.1 CQRS 读写分离

```mermaid
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 混合读策略

```mermaid
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 全链路

```mermaid
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.6，ISSUE-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 异步决策

```mermaid
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 同步聚合

```mermaid
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 异步事件闭环

```mermaid
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 工作流编排

```mermaid
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 考试生命周期

```mermaid
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 高并发提交

```mermaid
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 辅助出题

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

```mermaid
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 上下文传播

```mermaid
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 契约体系

```mermaid
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 聚合模式

```mermaid
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 扩展字段
> 设计原则：统一错误信封 + 降级模式方案 B（degraded 放 error.details 子字段）

**信封结构**：

```typescript
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; // 链路追踪 ID（X-Request-Id）
  } | null; // 成功时为 null
}
```

**降级模式（方案 B）**：

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

**示例 1：完全成功**

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

**示例 2：完全失败**

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

**示例 3：降级模式（部分聚合成功）**

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

**GraphQL errors 数组扩展**：

GraphQL 响应中，错误通过 `errors[].extensions` 携带 ActionState 字段：

```json
{
  "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 阶段总览

```mermaid
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% 可用性 + 独立扩缩容      |

> 详细规划见 [路线图目录](./roadmap/README.md)
