feat(p1): complete P1 foundation stage
- 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:
81
docs/modules/README.md
Normal file
81
docs/modules/README.md
Normal 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
111
docs/modules/ai/README.md
Normal 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 服务**:AIService(GenerateQuestions、OptimizeExpression、SuggestDifferentiation、GenerateLayeredQuestions)(待 P5 定义 protobuf)
|
||||
- **消费事件**:无(按需 gRPC 调用)
|
||||
- **发布事件**:`edu.ai.generation.completed`(可选,用于审计)
|
||||
- **缓存**:Redis 存储生成结果(相同 prompt 24 小时缓存)
|
||||
|
||||
> 待 P5 交付时补充完整 protobuf 定义与 Prompt 模板规范。
|
||||
|
||||
---
|
||||
|
||||
## 6. 依赖关系
|
||||
|
||||
- **上游**:teacher-bff(AI 辅助功能)
|
||||
- **下游**:LLM API(OpenAI/Claude)、Elasticsearch、Redis、content(gRPC)、data-ana(gRPC)
|
||||
- **跨服务**:gRPC 调用 content 题库与 data-ana 学情,不消费事件
|
||||
|
||||
---
|
||||
|
||||
## 7. 架构约束
|
||||
|
||||
1. LLM 调用必须经 ModelRouter,支持多模型故障切换
|
||||
2. 生成内容必须经质量校验,禁止直接返回未校验结果
|
||||
3. 调用成本必须记录,按用户/学校维度限额
|
||||
4. Prompt 模板必须版本化管理,禁止硬编码
|
||||
5. RAG 检索必须优先于 LLM 生成,减少幻觉
|
||||
|
||||
> 待 P5 交付时补充完整约束清单。
|
||||
|
||||
---
|
||||
|
||||
## 8. 架构决策
|
||||
|
||||
> 待 P5 交付时补充 ADR 记录,预计包括:Python+FastAPI 选型、LangGraph 编排选型、多模型路由策略、RAG 检索策略、成本控制策略。
|
||||
281
docs/modules/api-gateway/README.md
Normal file
281
docs/modules/api-gateway/README.md
Normal 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: 生成 JWT(RS256 私钥签发)
|
||||
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-002:JWT 签名算法从 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-005:gRPC 转发而非 HTTP 代理
|
||||
|
||||
**决策**:网关到下游 BFF/服务使用 gRPC 而非 HTTP 反向代理。
|
||||
|
||||
**理由**:
|
||||
- gRPC 基于 HTTP/2 多路复用,连接复用率高
|
||||
- protobuf 二进制编码比 JSON 节省 30%+ 带宽
|
||||
- 强类型契约,编译期发现接口变更
|
||||
- Connect-RPC 兼容 HTTP/JSON 客户端,前端仍可用 REST
|
||||
|
||||
### ADR-006:熔断器使用滑动窗口而非简单计数
|
||||
|
||||
**决策**:熔断器基于滑动窗口错误率,而非固定窗口计数。
|
||||
|
||||
**理由**:
|
||||
- 滑动窗口对突发错误更敏感,避免边界效应
|
||||
- 半开状态可逐步放量,避免雪崩后全量恢复冲击
|
||||
- Go 生态有成熟实现(sony/gobreaker)
|
||||
352
docs/modules/classes/README.md
Normal file
352
docs/modules/classes/README.md
Normal 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 + Outbox,Query 读 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-003:CQRS 读写分离
|
||||
|
||||
**决策**:写路径操作 MySQL 主库,读路径优先读 Redis 缓存。
|
||||
|
||||
**理由**:
|
||||
- 班级列表读多写少,缓存可承接 90%+ 读流量
|
||||
- 写路径与读路径分离,可独立扩展
|
||||
- Outbox 保证缓存最终一致(事件触发缓存失效)
|
||||
|
||||
**替代方案**:直接读 MySQL - 高并发下主库压力大;双写 - 一致性难保证。
|
||||
|
||||
### ADR-004:Outbox 模式保证事件可靠发布
|
||||
|
||||
**决策**:所有领域事件通过 Outbox 表同事务写入,Relay Worker 异步发布。
|
||||
|
||||
**理由**:
|
||||
- 业务表与 outbox 表同事务,保证"要么都成功要么都失败"
|
||||
- Relay Worker 轮询 outbox 发布到 Kafka,至少一次语义
|
||||
- 避免业务提交成功但事件丢失的问题
|
||||
|
||||
**替代方案**:直接发 Kafka - 事务提交失败但消息已发,导致幻读;CDC - 增加运维复杂度,P4 引入。
|
||||
|
||||
### ADR-005:Zod 运行时校验
|
||||
|
||||
**决策**:所有 RPC 请求参数使用 Zod schema 校验。
|
||||
|
||||
**理由**:
|
||||
- protobuf 提供编译期类型检查,但运行时仍需业务规则校验
|
||||
- Zod schema 可复用为 TypeScript 类型,单一数据源
|
||||
- NestJS Pipe 集成,校验失败返回结构化错误
|
||||
|
||||
### ADR-006:pino 结构化日志
|
||||
|
||||
**决策**:使用 pino 而非 winston 或 NestJS 默认 Logger。
|
||||
|
||||
**理由**:
|
||||
- pino 性能是 winston 的 3-5 倍,异步写入不阻塞事件循环
|
||||
- JSON 结构化输出,便于 Loki 采集与查询
|
||||
- 支持 traceId/userId 上下文注入,与 OpenTelemetry 对齐
|
||||
|
||||
### ADR-007:P3 阶段合并入 core-edu
|
||||
|
||||
**决策**:classes 服务在 P3 阶段合并入 core-edu 服务,作为 core-edu 的一个模块。
|
||||
|
||||
**理由**:
|
||||
- classes 域与课程、作业、考试域强耦合,跨服务调用频繁
|
||||
- P1 独立服务用于验证黄金模板,P3 合并以减少网络开销
|
||||
- 合并后 protobuf 契约保持不变,仅内部代码迁移
|
||||
- 合并后 outbox 共享 core-edu 事务,简化一致性保证
|
||||
104
docs/modules/content/README.md
Normal file
104
docs/modules/content/README.md
Normal 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、ai(gRPC 查询题库与知识图谱)
|
||||
- **下游**: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 引入决策。
|
||||
105
docs/modules/core-edu/README.md
Normal file
105
docs/modules/core-edu/README.md
Normal 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 服务**:ClassService(P1 迁移)、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 选型、考试并发策略。
|
||||
104
docs/modules/data-ana/README.md
Normal file
104
docs/modules/data-ana/README.md
Normal 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、ai(gRPC 查询学情)
|
||||
- **下游**: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
102
docs/modules/iam/README.md
Normal 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 服务**:UserService(Login/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-gateway(JWKS 拉取)
|
||||
- **下游**: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
105
docs/modules/msg/README.md
Normal 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-gateway(gRPC 推送调用)
|
||||
- **下游**:MySQL、Redis、Kafka、外部邮件/短信网关
|
||||
- **跨服务**:消费所有业务事件触发通知;与 push-gateway 协作实时推送
|
||||
|
||||
---
|
||||
|
||||
## 7. 架构约束
|
||||
|
||||
1. 通知投递必须至少一次语义,失败重试 3 次
|
||||
2. 通知模板必须使用 Handlebars 渲染,禁止字符串拼接
|
||||
3. 未读计数必须 Redis 实时维护,异步同步 MySQL
|
||||
4. 广播通知必须分批投递,避免瞬时流量冲击
|
||||
|
||||
> 待 P5 交付时补充完整约束清单。
|
||||
|
||||
---
|
||||
|
||||
## 8. 架构决策
|
||||
|
||||
> 待 P5 交付时补充 ADR 记录,预计包括:多渠道分发策略、模板引擎选型、推送可靠性保证、广播限流策略。
|
||||
114
docs/modules/push-gateway/README.md
Normal file
114
docs/modules/push-gateway/README.md
Normal 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 服务**:PushService(Push、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-portal(WebSocket 连接)
|
||||
- **共享包**: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 跨节点方案、连接数上限策略、心跳间隔选型。
|
||||
Reference in New Issue
Block a user