feat(p1): complete P1 foundation stage
Some checks failed
CI Go / test (push) Has been cancelled
CI Proto / lint (push) Has been cancelled
CI Python / test (push) Has been cancelled
CI TypeScript / test (push) Has been cancelled

- monorepo: pnpm workspace + go.work + pyproject.toml + commitlint/husky
- infra: docker-compose (minimal + full profiles) + init-sql + prometheus
- arch-scan: multi-language scanner skeleton (TS/Go/Python/Proto)
- shared-proto: buf v2 + classes.proto (ClassService CRUD contract)
- api-gateway: Go/Gin + JWT HS256 auth + reverse proxy + request ID
- classes: NestJS golden template (error system + observability + middleware + CRUD + tests)
- teacher-portal: Next.js + paper-feel UI design system
- CI/CD: 4 workflows (go/ts/py/proto)
- docs: migration guide + project_rules + coding-standards + git-workflow + ui-design-system + 004 + 9 module READMEs + known-issues + spec/plan migration + roadmap
This commit is contained in:
SpecialX
2026-07-07 23:39:37 +08:00
commit 2ba4250165
100 changed files with 15242 additions and 0 deletions

81
docs/modules/README.md Normal file
View File

@@ -0,0 +1,81 @@
# 模块索引
> 版本1.0
> 日期2026-07-07
> 状态:基线发布
> 关联文档:[架构影响地图](../architecture/004_architecture_impact_map.md)
---
## 模块分类总览
本项目采用 DDD + EDA + CQRS 微服务架构,包含 6 大业务限界上下文、2 个基础设施服务、3 个 BFF 聚合层、4 个微前端和 4 个共享包。
---
## 一、基础设施服务
| 服务 | 语言/框架 | 职责 | 阶段 | README |
|------|-----------|------|------|--------|
| api-gateway | Go (Gin) | 统一入口、路由转发、JWT 鉴权、限流熔断 | P1 | [README](./api-gateway/README.md) |
| push-gateway | Go (Gin) | WebSocket/SSE 长连接、实时消息推送 | P5 | [README](./push-gateway/README.md) |
---
## 二、领域微服务
| 服务 | 语言/框架 | 限界上下文 | 主要聚合 | 阶段 | README |
|------|-----------|-----------|----------|------|--------|
| iam | TS (NestJS) | 身份认证 | User、Role、Permission | P2 | [README](./iam/README.md) |
| core-edu | TS (NestJS) | 教学核心 | Class、Course、Assignment、Exam、Grade | P3 | [README](./core-edu/README.md) |
| content | TS (NestJS) | 内容资源 | Textbook、Question、KnowledgePoint | P4 | [README](./content/README.md) |
| data-ana | Python (FastAPI) | 数据分析 | Report、Mastery、Dashboard | P4 | [README](./data-ana/README.md) |
| msg | TS (NestJS) | 消息通知 | Message、Notification、Announcement | P5 | [README](./msg/README.md) |
| ai | Python (FastAPI) | AI 网关 | LLMCall、Prompt、Generation | P5 | [README](./ai/README.md) |
---
## 三、BFF 聚合层
| BFF | 语言/框架 | 服务对象 | 阶段 | README |
|-----|-----------|----------|------|--------|
| teacher-bff | TS (NestJS + GraphQL) | 教师端 | P2 | 待创建 |
| student-bff | TS (NestJS + GraphQL) | 学生端 | P3 | 待创建 |
| parent-bff | TS (NestJS + GraphQL) | 家长端 | P4 | 待创建 |
---
## 四、微前端
| 微前端 | 语言/框架 | 服务对象 | 阶段 | README |
|--------|-----------|----------|------|--------|
| teacher-portal | TS (Next.js + Module Federation) | 教师端 | P2 | 待创建 |
| student-portal | TS (Next.js + Module Federation) | 学生端 | P3 | 待创建 |
| parent-portal | TS (Next.js + Module Federation) | 家长端 | P4 | 待创建 |
| admin-portal | TS (Next.js + Module Federation) | 管理端 | P6 | 待创建 |
---
## 五、共享包
| 包 | 语言 | 用途 | 阶段 | README |
|----|------|------|------|--------|
| shared-proto | TS | protobuf 契约定义与代码生成 | P1 | 待创建 |
| shared-ts | TS | TypeScript 共享工具类型 | P1 | 待创建 |
| shared-go | Go | Go 共享工具 | P1 | 待创建 |
| shared-py | Python | Python 共享工具 | P4 | 待创建 |
---
## 阶段交付路线
| 阶段 | 周期 | 交付模块 | 退出标准 |
|------|------|----------|----------|
| 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% 可用性 + 独立扩缩容 |
> 详细规划见 [路线图目录](../architecture/roadmap/README.md)

111
docs/modules/ai/README.md Normal file
View File

@@ -0,0 +1,111 @@
# ai AI 网关服务
> 版本0.1(骨架)
> 日期2026-07-07
> 状态P5 待交付
> 关联文档:[架构影响地图](../../architecture/004_architecture_impact_map.md)
---
## 1. 模块职责
ai 是 AI 网关限界上下文Python 实现),管理 LLMCall、Prompt、Generation 聚合。
统一封装 LLM 调用(多模型路由、重试、限流、成本控制),提供辅助出题、表达优化、分层提问等能力。
通过 gRPC 查询 content 题库与 data-ana 学情数据,结合知识图谱生成个性化内容。
---
## 2. 技术栈
| 类别 | 技术 | 版本 | 用途 |
|------|------|------|------|
| 语言 | Python | 3.12+ | AI 生态 |
| 框架 | FastAPI | 0.110+ | 异步 API |
| LLM SDK | openai / anthropic | - | 多模型调用 |
| 编排 | LangGraph | - | LLM 工作流编排 |
| 检索 | Elasticsearch | 8.x | 题库检索RAG |
| 缓存 | Redis | 7.x | Prompt 缓存、结果缓存 |
| 校验 | pydantic | 2.x | 运行时校验 |
| 追踪 | OpenTelemetry | - | LLM 调用链追踪 |
---
## 3. 架构图
```mermaid
graph TB
BFF[BFF 聚合层] -->|gRPC| AI[ai 服务]
AI --> ROUTER[ModelRouter<br/>多模型路由]
AI --> ORCH[LangGraph 编排]
AI --> RAG[RAG 检索增强]
RAG -->|gRPC| CONTENT[content 题库]
RAG -->|gRPC| ANA[data-ana 学情]
AI -->[(ES<br/>题库检索)]
AI -->[(Redis<br/>结果缓存)]
AI --> LLM[LLM API<br/>OpenAI/Claude]
```
> 待 P5 交付时补充完整的分层架构图与 LLM 编排图。
---
## 4. 核心流程图
```mermaid
sequenceDiagram
participant T as 教师
participant BFF as BFF
participant AI as ai 服务
participant CONTENT as content
participant ANA as data-ana
participant LLM as LLM API
T->>BFF: AI 辅助出题
BFF->>AI: gRPC GenerateQuestions(topic, difficulty)
AI->>CONTENT: gRPC 查询相关题目 + 知识点
AI->>ANA: gRPC 查询学情掌握度
AI->>AI: LangGraph 编排 Prompt
AI->>LLM: 调用 LLM 生成
LLM-->>AI: 生成结果
AI->>AI: 质量校验 + 缓存
AI-->>BFF: 生成的题目列表
```
> 待 P5 交付时补充:表达优化流程、分层提问流程、差异化建议流程。
---
## 5. 对外契约
- **gRPC 服务**AIServiceGenerateQuestions、OptimizeExpression、SuggestDifferentiation、GenerateLayeredQuestions待 P5 定义 protobuf
- **消费事件**:无(按需 gRPC 调用)
- **发布事件**`edu.ai.generation.completed`(可选,用于审计)
- **缓存**Redis 存储生成结果(相同 prompt 24 小时缓存)
> 待 P5 交付时补充完整 protobuf 定义与 Prompt 模板规范。
---
## 6. 依赖关系
- **上游**teacher-bffAI 辅助功能)
- **下游**LLM APIOpenAI/Claude、Elasticsearch、Redis、contentgRPC、data-anagRPC
- **跨服务**gRPC 调用 content 题库与 data-ana 学情,不消费事件
---
## 7. 架构约束
1. LLM 调用必须经 ModelRouter支持多模型故障切换
2. 生成内容必须经质量校验,禁止直接返回未校验结果
3. 调用成本必须记录,按用户/学校维度限额
4. Prompt 模板必须版本化管理,禁止硬编码
5. RAG 检索必须优先于 LLM 生成,减少幻觉
> 待 P5 交付时补充完整约束清单。
---
## 8. 架构决策
> 待 P5 交付时补充 ADR 记录预计包括Python+FastAPI 选型、LangGraph 编排选型、多模型路由策略、RAG 检索策略、成本控制策略。

View File

@@ -0,0 +1,281 @@
# api-gateway 网关服务
> 版本1.0
> 日期2026-07-07
> 状态P1 已交付
> 关联文档:[架构影响地图](../../architecture/004_architecture_impact_map.md)
---
## 1. 模块职责
api-gateway 是整个 Edu 平台的统一入口网关,承担以下核心职责:
- **路由转发**:将外部 HTTP/REST 请求按路径前缀转发到对应 BFF 或业务服务
- **JWT 鉴权**:使用 RS256 公钥校验 JWT 签名,提取 userId/role/dataScope 注入下游 metadata
- **限流熔断**:基于 Redis 令牌桶限流,基于错误率的滑动窗口熔断
- **CORS 跨域**:处理浏览器跨域预检请求
- **访问日志**结构化访问日志zap含 traceId/userId/latency/statusCode
- **健康检查**`/healthz``/readyz` 端点供 Kubernetes 探针使用
**不做的事**:不写业务逻辑、不访问数据库、不持有业务状态。
---
## 2. 技术栈
| 类别 | 技术 | 版本 | 用途 |
|------|------|------|------|
| 语言 | Go | 1.22+ | 高性能网关 |
| Web 框架 | Gin | 1.10+ | HTTP 路由与中间件链 |
| JWT | golang-jwt/v5 | 5.2+ | RS256 签名校验 |
| 缓存/限流 | Redis | 7.x | 令牌桶计数、会话缓存 |
| 配置 | viper | 1.18+ | 多源配置env/yaml/configmap |
| 日志 | zap | 1.27+ | 结构化高性能日志 |
| 链路追踪 | OpenTelemetry | 1.24+ | 分布式追踪上下文注入 |
| 指标 | prometheus/client_golang | 1.19+ | RED 指标暴露 |
| 容器化 | Docker | - | 多阶段构建 |
| 编排 | Kubernetes | 1.28+ | 生产部署 |
---
## 3. 架构图
```mermaid
graph TB
subgraph Client["客户端"]
MFE[微前端 4 端]
end
subgraph Gateway["api-gateway"]
subgraph Middleware["中间件链"]
CORS[CORS 中间件]
LOG[访问日志 zap]
TRACE[OpenTelemetry trace]
AUTH[JWT RS256 鉴权]
RATE[限流 Redis 令牌桶]
CB[熔断器 滑动窗口]
end
ROUTER[Gin Router]
PROXY[gRPC 反向代理]
end
subgraph Downstream["下游服务"]
TBFF[teacher-bff]
SBFF[student-bff]
PBFF[parent-bff]
IAM[iam 登录特殊路由]
end
subgraph Infra["基础设施"]
REDIS[(Redis<br/>限流计数)]
JWKSIAM[(IAM JWKS 公钥)]
OTEL[OTLP Collector]
end
MFE -->|HTTP/REST| CORS
CORS --> LOG --> TRACE --> AUTH --> RATE --> CB --> ROUTER
ROUTER --> PROXY
PROXY -->|gRPC| TBFF
PROXY -->|gRPC| SBFF
PROXY -->|gRPC| PBFF
ROUTER -.特殊路由.-> IAM
RATE --> REDIS
AUTH --> JWKSIAM
LOG --> OTEL
TRACE --> OTEL
```
---
## 4. 核心流程图
### 4.1 鉴权与路由流程
```mermaid
sequenceDiagram
participant U as 微前端
participant GW as API Gateway
participant R as Redis
participant SVC as 下游服务
U->>GW: GET /api/classes + Bearer token
GW->>GW: CORS 校验
GW->>GW: 记录访问日志traceId 生成)
GW->>GW: OpenTelemetry span 创建
GW->>GW: 提取 Authorization header
GW->>GW: RS256 公钥校验签名
GW->>GW: 校验 exp/iss/aud
GW->>GW: 提取 userId/role/dataScope
GW->>R: 令牌桶限流检查userId 维度)
R-->>GW: 通过
GW->>GW: 熔断器状态检查
GW->>SVC: gRPC 请求 + metadata 透传
SVC-->>GW: gRPC 响应
GW-->>U: HTTP 响应 + traceId header
```
### 4.2 限流流程
```mermaid
flowchart TD
REQ[请求到达] --> Q1{Redis 令牌桶<br/>剩余令牌 >= 1?}
Q1 -- 是 --> DEC[扣减令牌<br/>INCR + EXPIRE]
DEC --> PASS[放行]
Q1 -- 否 --> Q2{是否超量请求?}
Q2 -- 是 --> REJ1[429 Too Many Requests<br/>Retry-After header]
Q2 -- 否 --> WAIT[排队等待<br/>短超时]
WAIT --> Q1
```
### 4.3 登录特殊处理流程
```mermaid
sequenceDiagram
participant U as 用户
participant GW as API Gateway
participant IAM as IAM 服务
Note over GW: /auth/* 路径跳过 JWT 鉴权
U->>GW: POST /auth/login {username, password}
GW->>GW: 限流检查IP 维度)
GW->>IAM: gRPC Login(username, password)
IAM->>IAM: 校验密码
IAM->>IAM: 生成 JWTRS256 私钥签发)
IAM-->>GW: {accessToken, refreshToken, userInfo}
GW-->>U: 200 Set-Cookie httpOnly + JSON body
```
---
## 5. 对外契约
### 5.1 REST API 路由表
| 方法 | 路径 | 鉴权 | 转发目标 | 说明 |
|------|------|------|----------|------|
| POST | /auth/login | 否 | iam | 登录签发 JWT |
| POST | /auth/refresh | 否 | iam | 刷新令牌 |
| POST | /auth/logout | 是 | iam | 登出 |
| GET | /api/classes/* | 是 | teacher-bff/student-bff | 班级相关 |
| GET | /api/courses/* | 是 | teacher-bff/student-bff | 课程相关 |
| GET | /api/assignments/* | 是 | teacher-bff/student-bff | 作业相关 |
| GET | /api/grades/* | 是 | teacher-bff/student-bff | 成绩相关 |
| GET | /api/exams/* | 是 | teacher-bff/student-bff | 考试相关 |
| GET | /api/messages/* | 是 | teacher-bff/student-bff | 消息相关 |
| GET | /api/insights/* | 是 | teacher-bff/student-bff | 学情分析 |
| GET | /healthz | 否 | 本地 | 存活探针 |
| GET | /readyz | 否 | 本地 | 就绪探针 |
| GET | /metrics | 否 | 本地 | Prometheus 指标 |
### 5.2 gRPC 服务契约
api-gateway 不对外暴露 gRPC 服务,仅作为 gRPC 客户端调用下游。
### 5.3 事件契约
api-gateway 不发布也不消费任何 Kafka 事件。
---
## 6. 依赖关系
### 6.1 上游依赖(调用方)
| 上游 | 协议 | 说明 |
|------|------|------|
| teacher-portal | HTTP/REST | 教师端微前端 |
| student-portal | HTTP/REST | 学生端微前端 |
| parent-portal | HTTP/REST | 家长端微前端 |
| admin-portal | HTTP/REST | 管理端微前端 |
### 6.2 下游依赖(被调用方)
| 下游 | 协议 | 说明 |
|------|------|------|
| teacher-bff | gRPC | 教师聚合层 |
| student-bff | gRPC | 学生聚合层 |
| parent-bff | gRPC | 家长聚合层 |
| iam | gRPC | 登录/刷新令牌特殊路由 |
| Redis | TCP | 限流计数、JWKS 缓存 |
| IAM JWKS | HTTP | RS256 公钥拉取5 分钟缓存) |
### 6.3 共享包依赖
| 包 | 用途 |
|----|------|
| shared-proto | gRPC stub 与 protobuf 类型 |
| shared-go | Go 通用工具(错误码、日志字段约定) |
---
## 7. 架构约束
1. **无业务逻辑**:网关只做路由、鉴权、限流、熔断,禁止写任何业务规则
2. **无状态**:不持有业务状态,会话状态由 Redis 管理,支持水平扩缩容
3. **无数据库**:禁止直连任何业务数据库
4. **单一职责**所有横切关注点以中间件形式实现顺序明确CORS → 日志 → 追踪 → 鉴权 → 限流 → 熔断)
5. **配置驱动**:路由表、限流阈值、熔断阈值通过 viper 配置注入,支持热更新
6. **可观测性强制**:每个请求必须生成 traceId记录 userId/latency/statusCode
7. **优雅停机**:收到 SIGTERM 后停止接受新请求,等待已有请求完成(最长 30s
---
## 8. 架构决策
### ADR-001选用 Go + Gin 而非 Node.js
**决策**:网关层使用 Go 1.22 + Gin 框架。
**理由**
- 网关是 IO 密集型场景Go 的 goroutine 模型在高并发下内存占用极低
- 单实例可承载 10k+ QPS是 Node.js 的 3-5 倍
- 编译为单二进制,容器镜像 < 20MB启动 < 1s
**替代方案**Node.js (Fastify) - 内存占用高、GC 压力大,不适合作纯转发层。
### ADR-002JWT 签名算法从 HS256 迁移到 RS256
**决策**P1 阶段使用 HS256共享密钥快速验证P2 阶段迁移到 RS256非对称签名
**理由**
- RS256 允许 IAM 私钥签发、网关/服务公钥校验,密钥不需共享
- 公钥可通过 JWKS endpoint 分发,轮换密钥无需重启服务
- HS256 适合 P1 单体调试,但生产环境密钥分发风险高
### ADR-003限流使用 Redis 令牌桶而非本地内存
**决策**:限流计数器存储在 Redis使用令牌桶算法。
**理由**
- 多副本部署下,本地内存限流无法保证全局配额
- Redis 原子操作INCR + EXPIRE保证计数准确性
- 令牌桶支持突发流量,优于漏桶的严格匀速
### ADR-004路由配置通过 viper 静态注入而非服务发现
**决策**P1 阶段路由表通过 yaml/env 静态配置,不引入服务发现。
**理由**
- P1 服务数量少api-gateway + classes静态配置足够
- 服务发现Consul/Nacos增加运维复杂度留待 P6 引入
- viper 支持热重载,路由变更无需重启
### ADR-005gRPC 转发而非 HTTP 代理
**决策**:网关到下游 BFF/服务使用 gRPC 而非 HTTP 反向代理。
**理由**
- gRPC 基于 HTTP/2 多路复用,连接复用率高
- protobuf 二进制编码比 JSON 节省 30%+ 带宽
- 强类型契约,编译期发现接口变更
- Connect-RPC 兼容 HTTP/JSON 客户端,前端仍可用 REST
### ADR-006熔断器使用滑动窗口而非简单计数
**决策**:熔断器基于滑动窗口错误率,而非固定窗口计数。
**理由**
- 滑动窗口对突发错误更敏感,避免边界效应
- 半开状态可逐步放量,避免雪崩后全量恢复冲击
- Go 生态有成熟实现sony/gobreaker

View File

@@ -0,0 +1,352 @@
# classes 班级服务P1 黄金模板)
> 版本1.0
> 日期2026-07-07
> 状态P1 已交付P3 合并入 core-edu
> 关联文档:[架构影响地图](../../architecture/004_architecture_impact_map.md)
---
## 1. 模块职责
classes 服务是 P1 阶段的**黄金模板服务**,承担以下双重职责:
### 1.1 业务职责
- **班级 CRUD**创建、查询、更新、删除班级Class 聚合根)
- **班级成员管理**:学生加入/退出班级、教师分配
- **班级查询**:按年级/学校/教师维度查询班级列表
### 1.2 模板职责(供后续服务复制)
- **横切关注点验证**JWT 鉴权、权限校验、DataScope 过滤、OpenTelemetry 追踪、结构化日志、错误处理、参数校验、限流降级
- **CQRS 模式验证**Command 写 MySQL + OutboxQuery 读 Redis 缓存
- **契约验证**protobuf 定义 + buf 生成 + gRPC + Connect-RPC
- **测试范式验证**单元测试vitest+ 集成测试 + 契约测试 + E2E 测试
**P3 阶段**classes 域将合并入 core-edu 服务,作为 core-edu 的一个聚合模块。
---
## 2. 技术栈
| 类别 | 技术 | 版本 | 用途 |
|------|------|------|------|
| 语言 | TypeScript | 5.5+ | 类型安全 |
| 框架 | NestJS | 10.x | 依赖注入、模块化、装饰器 |
| ORM | Drizzle ORM | 0.31+ | 类型安全 SQL 构建器 |
| 数据库 | MySQL | 8.x | 写模型主库 |
| 缓存 | Redis | 7.x | 读模型缓存、会话 |
| 校验 | Zod | 3.23+ | 运行时类型校验 |
| 链路追踪 | OpenTelemetry | 1.24+ | 分布式追踪 |
| 日志 | pino | 9.x | 结构化高性能日志 |
| 测试 | vitest | 2.x | 单元/集成测试 |
| 契约测试 | buf | 1.40+ | protobuf 契约与生成 |
| E2E | Playwright | 1.45+ | 端到端测试 |
| 容器化 | Docker | - | 多阶段构建 |
---
## 3. 架构图
```mermaid
graph TB
subgraph Client["调用方"]
BFF[BFF 聚合层]
end
subgraph Classes["classes 服务"]
subgraph API["API 层"]
CTRL[ClassController<br/>gRPC + Connect-RPC]
GUARD[AuthGuard<br/>JWT metadata 校验]
PERM[PermissionGuard<br/>requirePermission]
SCOPE[DataScopeInterceptor<br/>6 级数据范围]
end
subgraph App["Application 层"]
CMD[CommandHandler<br/>CreateClass/UpdateClass/DeleteClass]
QRY[QueryHandler<br/>ListClasses/GetClass]
OUTBOX[OutboxWriter<br/>同事务写 outbox]
end
subgraph Domain["Domain 层"]
AGG[ClassAggregate<br/>聚合根 + 不变量]
EVT[DomainEvent<br/>ClassCreated/Updated/Deleted]
end
subgraph Infra["Infrastructure 层"]
REPO[ClassRepository<br/>Drizzle ORM]
CACHE[ClassCache<br/>Redis 读模型]
PROJ[Projection<br/>outbox → Redis]
end
end
subgraph Store["存储"]
MYSQL[(MySQL<br/>classes + outbox)]
REDIS[(Redis<br/>班级缓存)]
KAFKA[(Kafka<br/>领域事件)]
end
BFF -->|gRPC| GUARD
GUARD --> PERM
PERM --> SCOPE
SCOPE --> CTRL
CTRL --> CMD
CTRL --> QRY
CMD --> AGG
AGG --> EVT
CMD --> OUTBOX
CMD --> REPO
QRY --> CACHE
REPO --> MYSQL
OUTBOX --> MYSQL
CACHE --> REDIS
PROJ --> MYSQL
PROJ --> REDIS
PROJ -->|Relay Worker| KAFKA
```
---
## 4. 核心流程图
### 4.1 CreateClass 命令流程(写路径)
```mermaid
sequenceDiagram
participant BFF as BFF
participant CTRL as ClassController
participant CMD as CreateClassHandler
participant AGG as ClassAggregate
participant REPO as ClassRepository
participant OUTBOX as OutboxWriter
participant DB as MySQL
participant PROJ as Projection
participant K as Kafka
BFF->>CTRL: gRPC CreateClass(req)
CTRL->>CTRL: AuthGuard 校验 JWT metadata
CTRL->>CTRL: PermissionGuard 校验 class:create
CTRL->>CTRL: DataScopeInterceptor 注入 schoolId
CTRL->>CMD: execute(CreateClassCommand)
CMD->>AGG: ClassAggregate.create(name, gradeId, schoolId)
AGG->>AGG: 校验不变量(名称非空、年级存在)
AGG-->>CMD: ClassCreatedEvent
CMD->>REPO: save(classAggregate)
REPO->>DB: INSERT INTO classes ...
CMD->>OUTBOX: append(ClassCreatedEvent)
OUTBOX->>DB: INSERT INTO outbox (同事务)
DB-->>CMD: 事务提交成功
CMD-->>CTRL: ClassDTO
CTRL-->>BFF: gRPC 响应
Note over PROJ,K: 异步投影
PROJ->>DB: 轮询 outbox (100ms)
PROJ->>K: 发布 edu.org.class.created
PROJ->>DB: 标记 outbox processed
```
### 4.2 ListClasses 查询流程(读路径)
```mermaid
sequenceDiagram
participant BFF as BFF
participant CTRL as ClassController
participant QRY as ListClassesHandler
participant CACHE as ClassCache
participant REPO as ClassRepository
participant DB as MySQL
BFF->>CTRL: gRPC ListClasses(filter)
CTRL->>CTRL: AuthGuard + PermissionGuard(class:read)
CTRL->>CTRL: DataScopeInterceptor 注入 dataScope=L2/gradeId
CTRL->>QRY: execute(ListClassesQuery)
QRY->>CACHE: getClassesByGrade(gradeId)
alt 缓存命中
CACHE-->>QRY: ClassDTO[]
else 缓存未命中
CACHE-->>QRY: null
QRY->>REPO: findByGrade(gradeId, dataScope)
REPO->>DB: SELECT * FROM classes WHERE grade_id=? AND ...
DB-->>REPO: 行数据
REPO-->>QRY: ClassAggregate[]
QRY->>CACHE: setClassesByGrade(gradeId, dtos, TTL=5min)
end
QRY-->>CTRL: ClassDTO[]
CTRL-->>BFF: gRPC 响应
```
### 4.3 事件发布与投影流程
```mermaid
flowchart TD
CMD[Command 处理完成] --> TX[MySQL 事务提交<br/>classes 表 + outbox 表]
TX --> SUCC{提交成功?}
SUCC -- 是 --> RELAY[Relay Worker 轮询<br/>每 100ms]
SUCC -- 否 --> ROLL[回滚<br/>无事件产生]
RELAY --> READ[读取 outbox 未处理记录]
READ --> PUB[发布到 Kafka<br/>edu.org.class.created]
PUB --> MARK[标记 outbox processed=true]
MARK --> CONSUME[消费者处理]
CONSUME --> PROJ1[Projection 更新<br/>Redis 读模型]
CONSUME --> PROJ2[DataAna 投影<br/>ClickHouse 宽表]
CONSUME --> PROJ3[Msg 服务<br/>通知触发]
```
---
## 5. 对外契约
### 5.1 gRPC 服务契约protobuf
```protobuf
service ClassService {
rpc CreateClass(CreateClassRequest) returns (Class);
rpc GetClass(GetClassRequest) returns (Class);
rpc ListClasses(ListClassesRequest) returns (ListClassesResponse);
rpc UpdateClass(UpdateClassRequest) returns (Class);
rpc DeleteClass(DeleteClassRequest) returns (Empty);
}
message Class {
string id = 1;
string name = 2;
string grade_id = 3;
string school_id = 4;
int32 student_count = 5;
string homeroom_teacher_id = 6;
int64 created_at = 7;
int64 updated_at = 8;
}
```
### 5.2 领域事件契约
| 事件 | Topic | 生产者 | 消费者 | 字段 |
|------|-------|--------|--------|------|
| ClassCreated | `edu.org.class.created` | classes | DataAna、Msg | classId, name, gradeId, schoolId |
| ClassUpdated | `edu.org.class.updated` | classes | DataAna、Msg | classId, changes, updatedAt |
| ClassDeleted | `edu.org.class.deleted` | classes | DataAna、Msg | classId, deletedAt |
### 5.3 数据库表
| 表 | 用途 | 关键字段 |
|----|------|----------|
| classes | 班级写模型主表 | id, name, grade_id, school_id, homeroom_teacher_id, student_count, created_at, updated_at |
| outbox | 事件 Outbox 表 | id, aggregate_id, event_type, payload, processed, created_at |
---
## 6. 依赖关系
### 6.1 上游依赖(调用方)
| 上游 | 协议 | 说明 |
|------|------|------|
| teacher-bff | gRPC | 教师端班级管理 |
| student-bff | gRPC | 学生端班级查询 |
| parent-bff | gRPC | 家长端子女班级查询 |
### 6.2 下游依赖(被调用方)
| 下游 | 协议 | 说明 |
|------|------|------|
| MySQL | TCP | 写模型主库classes + outbox |
| Redis | TCP | 读模型缓存5 分钟 TTL |
| Kafka | TCP | 领域事件发布 |
### 6.3 共享包依赖
| 包 | 用途 |
|----|------|
| shared-proto | ClassService protobuf 定义与生成代码 |
| shared-ts | 通用类型、错误码、日志字段约定 |
---
## 7. 架构约束
1. **黄金模板强制**本服务的横切关注点实现必须可复制后续服务iam/core-edu/content 等)以本服务为模板
2. **CQRS 强制**:写路径必须经 Command → Aggregate → Repository + Outbox读路径必须先查缓存再查库
3. **Outbox 强制**:所有写操作必须同事务写入 outbox 表,禁止直接发布 Kafka 消息
4. **权限校验强制**:每个 RPC 方法必须经 PermissionGuard 校验 `class:create`/`class:read`/`class:update`/`class:delete`
5. **DataScope 强制**:查询必须经 DataScopeInterceptor 注入数据范围,禁止全表查询
6. **不变量保护**ClassAggregate 必须在创建/更新时校验业务不变量(名称非空、学生数 ≤ 上限)
7. **事务边界**:单聚合事务,禁止跨聚合事务
8. **P3 合并约束**:合并入 core-edu 时protobuf 契约保持不变,仅内部模块迁移
---
## 8. 架构决策
### ADR-001选用 NestJS 而非 Express/Fastify
**决策**:业务服务统一使用 NestJS 10 框架。
**理由**
- 依赖注入容器便于横切关注点组合Guard/Interceptor/Pipe
- 模块化系统天然匹配 DDD 限界上下文
- 装饰器声明式编程,代码可读性高
- 原生支持 gRPC、Microservices、OpenTelemetry
**替代方案**Express + 手工组合中间件 - 缺乏依赖注入,横切关注点难以复用。
### ADR-002选用 Drizzle ORM 而非 Prisma/TypeORM
**决策**:数据访问层使用 Drizzle ORM。
**理由**
- SQL-first 设计,生成的 SQL 可预测、可优化
- 类型安全且零运行时开销(不像 Prisma 有查询引擎)
- 支持 MySQL 事务、Outbox 模式所需的同事务多表写入
- Schema 即代码,迁移文件可读性强
**替代方案**Prisma - 查询引擎二进制大、事务控制弱TypeORM - 装饰器模型过重。
### ADR-003CQRS 读写分离
**决策**:写路径操作 MySQL 主库,读路径优先读 Redis 缓存。
**理由**
- 班级列表读多写少,缓存可承接 90%+ 读流量
- 写路径与读路径分离,可独立扩展
- Outbox 保证缓存最终一致(事件触发缓存失效)
**替代方案**:直接读 MySQL - 高并发下主库压力大;双写 - 一致性难保证。
### ADR-004Outbox 模式保证事件可靠发布
**决策**:所有领域事件通过 Outbox 表同事务写入Relay Worker 异步发布。
**理由**
- 业务表与 outbox 表同事务,保证"要么都成功要么都失败"
- Relay Worker 轮询 outbox 发布到 Kafka至少一次语义
- 避免业务提交成功但事件丢失的问题
**替代方案**:直接发 Kafka - 事务提交失败但消息已发导致幻读CDC - 增加运维复杂度P4 引入。
### ADR-005Zod 运行时校验
**决策**:所有 RPC 请求参数使用 Zod schema 校验。
**理由**
- protobuf 提供编译期类型检查,但运行时仍需业务规则校验
- Zod schema 可复用为 TypeScript 类型,单一数据源
- NestJS Pipe 集成,校验失败返回结构化错误
### ADR-006pino 结构化日志
**决策**:使用 pino 而非 winston 或 NestJS 默认 Logger。
**理由**
- pino 性能是 winston 的 3-5 倍,异步写入不阻塞事件循环
- JSON 结构化输出,便于 Loki 采集与查询
- 支持 traceId/userId 上下文注入,与 OpenTelemetry 对齐
### ADR-007P3 阶段合并入 core-edu
**决策**classes 服务在 P3 阶段合并入 core-edu 服务,作为 core-edu 的一个模块。
**理由**
- classes 域与课程、作业、考试域强耦合,跨服务调用频繁
- P1 独立服务用于验证黄金模板P3 合并以减少网络开销
- 合并后 protobuf 契约保持不变,仅内部代码迁移
- 合并后 outbox 共享 core-edu 事务,简化一致性保证

View File

@@ -0,0 +1,104 @@
# content 内容资源服务
> 版本0.1(骨架)
> 日期2026-07-07
> 状态P4 待交付
> 关联文档:[架构影响地图](../../architecture/004_architecture_impact_map.md)
---
## 1. 模块职责
content 是内容资源限界上下文,管理 Textbook、Question、KnowledgePoint 三大聚合。
负责教材管理、题库管理(含 Elasticsearch 全文检索、知识图谱构建Neo4j 存储前置依赖关系)。
为 core-edu 提供题目来源,为 ai 服务提供出题素材与知识图谱查询。
---
## 2. 技术栈
| 类别 | 技术 | 版本 | 用途 |
|------|------|------|------|
| 语言 | TypeScript | 5.5+ | 类型安全 |
| 框架 | NestJS | 10.x | 依赖注入、模块化 |
| ORM | Drizzle ORM | 0.31+ | 关系数据访问 |
| 关系库 | MySQL | 8.x | 教材/题目写模型 |
| 图数据库 | Neo4j | 5.x | 知识图谱、前置依赖 |
| 搜索 | Elasticsearch | 8.x | 题库全文检索 |
| 校验 | Zod | 3.23+ | 运行时校验 |
---
## 3. 架构图
```mermaid
graph TB
BFF[BFF 聚合层] -->|gRPC| CONTENT[content 服务]
AI[ai 服务] -->|gRPC| CONTENT
CONTENT --> TB[Textbook 模块]
CONTENT --> Q[Question 模块]
CONTENT --> KP[KnowledgePoint 模块]
CONTENT -->[(MySQL<br/>教材/题目)]
CONTENT -->[(Neo4j<br/>知识图谱)]
CONTENT -->[(ES<br/>题库索引)]
CONTENT -.事件.-> K[(Kafka<br/>edu.content.*)]
```
> 待 P4 交付时补充完整的分层架构图与多存储协同图。
---
## 4. 核心流程图
```mermaid
sequenceDiagram
participant T as 教师
participant BFF as BFF
participant CONTENT as content
participant ES as Elasticsearch
participant N as Neo4j
T->>BFF: 创建题目
BFF->>CONTENT: gRPC CreateQuestion
CONTENT->>CONTENT: 写 MySQL + Outbox
CONTENT->>ES: 异步索引题目
CONTENT->>N: 异步更新知识点关联
CONTENT-->>BFF: 成功
```
> 待 P4 交付时补充:知识图谱查询流程、题库检索流程、教材发布流程。
---
## 5. 对外契约
- **gRPC 服务**TextbookService、QuestionService、KnowledgePointService待 P4 定义 protobuf
- **领域事件**`edu.content.question.published``edu.content.textbook.updated``edu.content.knowledge.linked`
- **存储表**textbooks、questions、knowledge_points、knowledge_edges、outbox
> 待 P4 交付时补充完整 protobuf 定义与多存储 schema。
---
## 6. 依赖关系
- **上游**teacher-bff、student-bff、aigRPC 查询题库与知识图谱)
- **下游**MySQL、Neo4j、Elasticsearch、Kafka
- **跨服务**:消费 core-edu 的教学事件触发内容关联;被 data-ana 消费内容发布事件
---
## 7. 架构约束
1. 题库检索必须走 Elasticsearch禁止 MySQL LIKE 全表扫描
2. 知识图谱前置依赖查询必须走 Neo4j禁止关系库递归查询
3. MySQL 写入后必须异步同步 ES 索引与 Neo4j 关系
4. Outbox 模式强制
> 待 P4 交付时补充完整约束清单。
---
## 8. 架构决策
> 待 P4 交付时补充 ADR 记录预计包括Neo4j 选型、ES 索引策略、多存储一致性保证、CDC 引入决策。

View File

@@ -0,0 +1,105 @@
# core-edu 教学核心服务
> 版本0.1(骨架)
> 日期2026-07-07
> 状态P3 待交付
> 关联文档:[架构影响地图](../../architecture/004_architecture_impact_map.md)
---
## 1. 模块职责
core-edu 是教学核心限界上下文,合并 P1 的 classes 域,管理 Class、Course、Assignment、Exam、Grade 等聚合。
覆盖教学全链路:班级管理、课程编排、作业布置与提交、考试发布与批改、成绩录入与查询。
是整个平台最大的业务服务,承载考试→作答→批改→成绩核心链路。
---
## 2. 技术栈
| 类别 | 技术 | 版本 | 用途 |
|------|------|------|------|
| 语言 | TypeScript | 5.5+ | 类型安全 |
| 框架 | NestJS | 10.x | 依赖注入、模块化 |
| ORM | Drizzle ORM | 0.31+ | 数据访问 |
| 数据库 | MySQL | 8.x | 写模型主库 |
| 缓存 | Redis | 7.x | 读模型缓存 |
| 读模型 | ClickHouse | - | 学情宽表P4 接入) |
| 校验 | Zod | 3.23+ | 运行时校验 |
| 编排 | Temporal | - | 考试生命周期编排 |
---
## 3. 架构图
```mermaid
graph TB
BFF[BFF 聚合层] -->|gRPC| CORE[core-edu 服务]
CORE --> CLASS[Class 模块<br/>P3 合并]
CORE --> COURSE[Course 模块]
CORE --> ASSIGN[Assignment 模块]
CORE --> EXAM[Exam 模块]
CORE --> GRADE[Grade 模块]
CORE -->[(MySQL)]
CORE -->[(Redis)]
CORE -->[(ClickHouse<br/>读模型)]
CORE -.事件.-> K[(Kafka<br/>edu.teaching.*)]
```
> 待 P3 交付时补充完整的分层架构图与 CQRS 读写分离图。
---
## 4. 核心流程图
```mermaid
sequenceDiagram
participant T as 教师
participant BFF as BFF
participant CORE as core-edu
participant K as Kafka
T->>BFF: 发布考试
BFF->>CORE: gRPC PublishExam
CORE->>CORE: 校验 + Outbox 写入
CORE-->>BFF: 成功
CORE->>K: edu.teaching.exam.published
K->>K: Msg 通知学生 / DataAna 创建分析骨架
```
> 待 P3 交付时补充:作业提交流程、批改流程、成绩录入流程、考试生命周期 Saga。
---
## 5. 对外契约
- **gRPC 服务**ClassServiceP1 迁移、CourseService、AssignmentService、ExamService、GradeService待 P3 定义 protobuf
- **领域事件**`edu.teaching.assignment.submitted``edu.teaching.exam.published``edu.teaching.grade.recorded``edu.org.class.created`
- **数据库表**classes、courses、assignments、submissions、exams、exam_responses、grades、outbox
> 待 P3 交付时补充完整 protobuf 定义与表结构。
---
## 6. 依赖关系
- **上游**teacher-bff、student-bff、parent-bff
- **下游**MySQL、Redis、ClickHouse读模型、Kafka、Temporal
- **跨服务**:消费 iam 的 `edu.identity.user.*` 事件初始化关联;被 data-ana 消费学情事件
---
## 7. 架构约束
1. P3 合并 classes 服务后protobuf 契约保持不变
2. 考试生命周期使用 Temporal Saga 编排,禁止单体事务
3. 成绩录入后必须发布事件触发 DataAna 掌握度更新
4. Outbox 模式强制,所有写操作同事务写 outbox
> 待 P3 交付时补充完整约束清单。
---
## 8. 架构决策
> 待 P3 交付时补充 ADR 记录预计包括classes 合并决策、Temporal 编排选型、CQRS 读模型 ClickHouse 选型、考试并发策略。

View File

@@ -0,0 +1,104 @@
# data-ana 数据分析服务
> 版本0.1(骨架)
> 日期2026-07-07
> 状态P4 待交付
> 关联文档:[架构影响地图](../../architecture/004_architecture_impact_map.md)
---
## 1. 模块职责
data-ana 是数据分析限界上下文Python 实现),管理 Report、Mastery、Dashboard 聚合。
消费 core-edu 与 content 的领域事件,构建 ClickHouse 学情宽表,计算知识点掌握度。
对外提供学情仪表盘查询、班级/年级/学校维度报表、个性化推荐数据支撑。
---
## 2. 技术栈
| 类别 | 技术 | 版本 | 用途 |
|------|------|------|------|
| 语言 | Python | 3.12+ | 数据分析 |
| 框架 | FastAPI | 0.110+ | 异步 API |
| ORM | SQLAlchemy | 2.x | ClickHouse 查询 |
| 分析库 | ClickHouse | - | 学情宽表、实时聚合 |
| 任务 | Celery | 5.x | 异步计算任务 |
| 校验 | pydantic | 2.x | 运行时校验 |
| 追踪 | OpenTelemetry | - | 分布式追踪 |
---
## 3. 架构图
```mermaid
graph TB
BFF[BFF 聚合层] -->|gRPC| ANA[data-ana 服务]
K[(Kafka)] -->|消费事件| ANA
ANA --> PROJ[Projection<br/>事件 → ClickHouse]
ANA --> CALC[MasteryCalculator<br/>掌握度计算]
ANA --> RPT[ReportGenerator<br/>报表生成]
ANA -->[(ClickHouse<br/>学情宽表)]
ANA -.事件.-> K2[(Kafka<br/>edu.insight.mastery.updated)]
```
> 待 P4 交付时补充完整的分层架构图与事件消费管线图。
---
## 4. 核心流程图
```mermaid
sequenceDiagram
participant K as Kafka
participant ANA as data-ana
participant CH as ClickHouse
participant BFF as BFF
K->>ANA: edu.teaching.grade.recorded
ANA->>ANA: Projection 写入宽表
ANA->>ANA: 触发掌握度计算Celery
ANA->>CH: 更新 mastery 表
ANA->>K: 发布 edu.insight.mastery.updated
BFF->>ANA: gRPC GetDashboard(studentId)
ANA->>CH: 查询宽表聚合
ANA-->>BFF: DashboardDTO
```
> 待 P4 交付时补充报表生成流程、掌握度算法流程、CDC 同步流程。
---
## 5. 对外契约
- **gRPC 服务**DashboardService、MasteryService、ReportService待 P4 定义 protobuf
- **消费事件**`edu.teaching.*``edu.content.*`
- **发布事件**`edu.insight.mastery.updated`
- **ClickHouse 宽表**student_wide_table、mastery_table、exam_analysis_table
> 待 P4 交付时补充完整 protobuf 定义与宽表 schema。
---
## 6. 依赖关系
- **上游**teacher-bff、student-bff、parent-bff、aigRPC 查询学情)
- **下游**ClickHouse、Kafka消费与发布、Celery异步任务
- **跨服务**:消费 core-edu/content 事件;发布掌握度事件被 core-edu 消费触发推荐
---
## 7. 架构约束
1. 查询必须走 ClickHouse 宽表,禁止实时计算
2. 事件消费必须幂等,基于 event_id 去重
3. 掌握度计算必须异步Celery不阻塞事件消费
4. 宽表查询响应时间 ≤ 5 秒
> 待 P4 交付时补充完整约束清单。
---
## 8. 架构决策
> 待 P4 交付时补充 ADR 记录预计包括Python+FastAPI 选型、ClickHouse 选型、Celery 异步框架选型、掌握度算法选型。

102
docs/modules/iam/README.md Normal file
View File

@@ -0,0 +1,102 @@
# iam 身份认证服务
> 版本0.1(骨架)
> 日期2026-07-07
> 状态P2 待交付
> 关联文档:[架构影响地图](../../architecture/004_architecture_impact_map.md)
---
## 1. 模块职责
iam 是身份认证限界上下文,管理 User、Role、Permission 三大聚合。
负责用户注册/登录/登出、JWT RS256 签发与刷新、三层角色模型(系统/组织/临时)分配与校验。
同时对外提供权限列表查询(供 api-gateway 与业务服务缓存)。
---
## 2. 技术栈
| 类别 | 技术 | 版本 | 用途 |
|------|------|------|------|
| 语言 | TypeScript | 5.5+ | 类型安全 |
| 框架 | NestJS | 10.x | 依赖注入、模块化 |
| ORM | Drizzle ORM | 0.31+ | 数据访问 |
| 数据库 | MySQL | 8.x | 用户/角色/权限主库 |
| 缓存 | Redis | 7.x | 权限列表缓存、会话 |
| 密码 | bcrypt | 5.x | 密码哈希 |
| 校验 | Zod | 3.23+ | 运行时校验 |
| JWT | jose | 5.x | RS256 签发与公钥暴露 |
---
## 3. 架构图
```mermaid
graph TB
BFF[BFF/网关] -->|gRPC| IAM[iam 服务]
IAM --> USER[UserAggregate]
IAM --> ROLE[RoleAggregate]
IAM --> PERM[PermissionAggregate]
IAM -->[(MySQL)]
IAM -->[(Redis<br/>权限缓存)]
IAM -->|JWKS| GW[api-gateway 公钥拉取]
IAM -.事件.-> K[(Kafka<br/>edu.identity.user.*)]
```
> 待 P2 交付时补充完整的分层架构图Controller/Application/Domain/Infrastructure
---
## 4. 核心流程图
```mermaid
sequenceDiagram
participant GW as API Gateway
participant IAM as iam
participant DB as MySQL
participant K as Kafka
GW->>IAM: gRPC Login(username, password)
IAM->>DB: 查询用户 + bcrypt 校验
IAM->>IAM: 生成 JWT RS256
IAM-->>GW: {accessToken, refreshToken}
IAM->>K: 发布 edu.identity.user.logged_in
```
> 待 P2 交付时补充:刷新令牌流程、权限校验流程、角色分配流程。
---
## 5. 对外契约
- **gRPC 服务**UserServiceLogin/Refresh/Logout/Register/GetUserProfile、RoleService、PermissionService待 P2 定义 protobuf
- **HTTP 端点**`/.well-known/jwks.json` 暴露 RS256 公钥
- **领域事件**`edu.identity.user.created``edu.identity.user.updated``edu.identity.role.assigned`
> 待 P2 交付时补充完整 protobuf 定义与事件 schema。
---
## 6. 依赖关系
- **上游**teacher-bff、student-bff、parent-bff、api-gatewayJWKS 拉取)
- **下游**MySQL用户/角色/权限表、Redis权限缓存、Kafka领域事件
- **共享包**shared-proto、shared-ts
---
## 7. 架构约束
1. JWT 必须使用 RS256 非对称签名,私钥仅 iam 持有
2. 密码必须 bcrypt 哈希,禁止明文存储
3. 权限列表缓存 TTL 5 分钟,事件驱动失效
4. 三层角色权限取并集,拒绝权限取交集
> 待 P2 交付时补充完整约束清单。
---
## 8. 架构决策
> 待 P2 交付时补充 ADR 记录预计包括RS256 选型、bcrypt 参数、会话管理策略、权限缓存策略。

105
docs/modules/msg/README.md Normal file
View File

@@ -0,0 +1,105 @@
# msg 消息通知服务
> 版本0.1(骨架)
> 日期2026-07-07
> 状态P5 待交付
> 关联文档:[架构影响地图](../../architecture/004_architecture_impact_map.md)
---
## 1. 模块职责
msg 是消息通知限界上下文,管理 Message、Notification、Announcement 聚合。
消费各服务领域事件触发多渠道通知投递站内信、邮件、短信、App 推送)。
与 push-gateway 协作建立 WebSocket/SSE 长连接,实现实时消息推送。
---
## 2. 技术栈
| 类别 | 技术 | 版本 | 用途 |
|------|------|------|------|
| 语言 | TypeScript | 5.5+ | 类型安全 |
| 框架 | NestJS | 10.x | 依赖注入、模块化 |
| ORM | Drizzle ORM | 0.31+ | 数据访问 |
| 数据库 | MySQL | 8.x | 消息持久化 |
| 缓存 | Redis | 7.x | 未读计数、会话 |
| 队列 | Kafka | - | 事件消费 |
| 模板 | Handlebars | - | 通知模板渲染 |
| 校验 | Zod | 3.23+ | 运行时校验 |
---
## 3. 架构图
```mermaid
graph TB
K[(Kafka)] -->|消费事件| MSG[msg 服务]
MSG --> DISP[Dispatcher<br/>渠道分发]
MSG -->[(MySQL<br/>消息持久化)]
MSG -->[(Redis<br/>未读计数)]
DISP --> INAPP[站内信]
DISP --> EMAIL[邮件]
DISP --> SMS[短信]
DISP --> PUSH[push-gateway<br/>实时推送]
MSG -.事件.-> K2[(Kafka<br/>edu.msg.*)]
```
> 待 P5 交付时补充完整的分层架构图与多渠道分发图。
---
## 4. 核心流程图
```mermaid
sequenceDiagram
participant K as Kafka
participant MSG as msg
participant PG as push-gateway
participant U as 用户
K->>MSG: edu.teaching.exam.published
MSG->>MSG: 创建 Notification 记录
MSG->>MSG: Dispatcher 渠道分发
MSG->>PG: gRPC Push(userId, payload)
PG->>U: WebSocket 实时推送
MSG->>MSG: 更新未读计数Redis
```
> 待 P5 交付时补充:广播通知流程、通知模板渲染流程、未读计数同步流程。
---
## 5. 对外契约
- **gRPC 服务**MessageService、NotificationService、AnnouncementService待 P5 定义 protobuf
- **消费事件**`edu.identity.user.*``edu.teaching.*``edu.insight.*`
- **发布事件**`edu.msg.notification.sent``edu.msg.announcement.published`
- **数据库表**messages、notifications、announcements、notification_templates、outbox
> 待 P5 交付时补充完整 protobuf 定义与表结构。
---
## 6. 依赖关系
- **上游**teacher-bff、student-bff、parent-bff、push-gatewaygRPC 推送调用)
- **下游**MySQL、Redis、Kafka、外部邮件/短信网关
- **跨服务**:消费所有业务事件触发通知;与 push-gateway 协作实时推送
---
## 7. 架构约束
1. 通知投递必须至少一次语义,失败重试 3 次
2. 通知模板必须使用 Handlebars 渲染,禁止字符串拼接
3. 未读计数必须 Redis 实时维护,异步同步 MySQL
4. 广播通知必须分批投递,避免瞬时流量冲击
> 待 P5 交付时补充完整约束清单。
---
## 8. 架构决策
> 待 P5 交付时补充 ADR 记录,预计包括:多渠道分发策略、模板引擎选型、推送可靠性保证、广播限流策略。

View File

@@ -0,0 +1,114 @@
# push-gateway 推送网关服务
> 版本0.1(骨架)
> 日期2026-07-07
> 状态P5 待交付
> 关联文档:[架构影响地图](../../architecture/004_architecture_impact_map.md)
---
## 1. 模块职责
push-gateway 是实时推送基础设施服务Go 实现),管理 WebSocket/SSE 长连接。
接收 msg 服务的推送请求,维护用户在线连接池,将消息实时投递到浏览器/移动端。
支持连接鉴权、心跳保活、断线重连、多设备同步、连接数监控。
---
## 2. 技术栈
| 类别 | 技术 | 版本 | 用途 |
|------|------|------|------|
| 语言 | Go | 1.22+ | 高并发长连接 |
| Web 框架 | Gin | 1.10+ | HTTP 升级 WebSocket |
| WebSocket | gorilla/websocket | 1.5+ | WebSocket 协议 |
| 缓存 | Redis | 7.x | 在线连接表、pub/sub |
| 配置 | viper | 1.18+ | 配置注入 |
| 日志 | zap | 1.27+ | 结构化日志 |
| 追踪 | OpenTelemetry | 1.24+ | 分布式追踪 |
| 编排 | Kubernetes | 1.28+ | 生产部署 |
---
## 3. 架构图
```mermaid
graph TB
MSG[msg 服务] -->|gRPC Push| PG[push-gateway]
PG --> HUB[ConnectionHub<br/>连接池管理]
HUB --> C1[用户 1 连接]
HUB --> C2[用户 2 连接]
HUB --> CN[用户 N 连接]
PG -->[(Redis<br/>在线连接表 + pub/sub)]
MFE[微前端] -.WebSocket.-> PG
PG --> HEART[心跳保活<br/>30s ping/pong]
```
> 待 P5 交付时补充完整的分层架构图与多副本连接同步图。
---
## 4. 核心流程图
```mermaid
sequenceDiagram
participant U as 用户
participant PG as push-gateway
participant R as Redis
participant MSG as msg 服务
U->>PG: WebSocket 连接 + JWT 鉴权
PG->>R: 注册在线连接userId → nodeId
PG-->>U: 连接建立
Note over PG: 心跳保活 30s ping/pong
MSG->>PG: gRPC Push(userId, payload)
PG->>R: 查询 userId 在线 nodeId
alt 本节点在线
PG->>U: WebSocket 推送消息
else 跨节点在线
PG->>R: pub/sub 转发到目标节点
R->>PG: 目标节点订阅收到
PG->>U: 推送消息
end
```
> 待 P5 交付时补充:断线重连流程、多设备同步流程、连接数监控流程。
---
## 5. 对外契约
- **gRPC 服务**PushServicePush、Broadcast、GetOnlineStatus待 P5 定义 protobuf
- **HTTP 端点**`/ws`WebSocket 升级)、`/healthz``/readyz``/metrics`
- **事件**:不发布也不消费 Kafka 事件,仅接收 msg 的 gRPC 推送调用
- **Redis 协议**在线连接表HASH、跨节点推送pub/sub channel `push:{nodeId}`
> 待 P5 交付时补充完整 protobuf 定义与 WebSocket 消息协议。
---
## 6. 依赖关系
- **上游**msg 服务gRPC Push 调用)
- **下游**Redis在线连接表、pub/sub 跨节点同步)
- **客户端**teacher-portal、student-portal、parent-portalWebSocket 连接)
- **共享包**shared-proto、shared-go
---
## 7. 架构约束
1. 无业务逻辑,仅做连接管理与消息转发
2. 多副本部署下,通过 Redis pub/sub 同步跨节点推送
3. 连接鉴权必须校验 JWT禁止未认证连接
4. 心跳超时 60s 无响应则断开连接
5. 单节点最大连接数 50k超出时拒绝新连接
> 待 P5 交付时补充完整约束清单。
---
## 8. 架构决策
> 待 P5 交付时补充 ADR 记录预计包括Go+gorilla/websocket 选型、Redis pub/sub 跨节点方案、连接数上限策略、心跳间隔选型。