docs: rewrite documentation from current implementation

This commit is contained in:
2026-07-30 13:30:24 +08:00
parent 5100854795
commit d895e1da63
23 changed files with 553 additions and 1612 deletions

172
README.md
View File

@@ -1,155 +1,89 @@
# TIKU Backend
题库 SaaS 的正式后端。项目已收敛到 ASP.NET Core + EF Core + PostgreSQL,本仓库是后续开发的唯一目标后端。架构决策见 [ADR 0001](docs/adr/0001-authoritative-dotnet-backend.md)
TIKU Backend 是题库 SaaS 的 ASP.NET Core 后端,使用 EF Core 管理 PostgreSQL 数据,提供平台端、租户端和学生端 API并由独立 Worker 处理后台任务
![TIKU Backend 技术架构图](docs/assets/tiku-backend-architecture.svg)
## 架构边界
## 当前技术栈
- 旧 NestJS / Supabase 仓库只作为业务行为和接口清单参考,不作为运行时依赖。
- 不兼容旧 Supabase 数据库、RLS、Storage bucket、Refresh Token 或旧题单 JSON。
- PostgreSQL 按标准 PostgreSQL 使用,不绑定 Supabase 托管能力。
- 普通 schema 由 EF Core entity、Fluent Configuration 和 Migration 管理;`Tiku.DbMigrator` 是迁移入口。
- 多租户隔离不使用 PostgreSQL RLS由 Host 租户解析、EF Query Filter、写入拦截器、PostgreSQL 约束和真实 PostgreSQL 测试共同保证。
- 身份、短信、对象存储、支付、通知和 AI 都通过 Application 层接口表达业务意图;第三方 SDK、密钥读取和 provider 细节只允许出现在 Infrastructure。
- 租户自定义域名由可信 Host 解析,不接受 query/header 伪造切换租户。
- 公共题库由唯一平台主体拥有;订阅有效租户可访问公共题,租户私题只属于本租户。
- .NET 10 / ASP.NET Core Controller API
- Entity Framework Core 10 + Npgsql 10 + PostgreSQL
- ASP.NET Core Identity + RSA JWT + 数据库存储的 Session
- Scalar + OpenAPI仅 Development 暴露)
- Redis分布式安全频控和生产输出缓存
- MassTransit 8 + RabbitMQ 4 + EF Core Outbox
- Serilog + OpenTelemetry
- xUnit 单元测试和真实 PostgreSQL 集成测试
## 技术栈与目录
- ASP.NET Core Controller API
- Entity Framework Core + Npgsql
- PostgreSQL
- Serilog
- ZLinq
- AlibabaCloud OSS / SMS SDK
- Senparc.Weixin.*
- AlipaySDKNet.Standard
- Microsoft Semantic Kernel仅 Infrastructure AI 边界)
- xUnit
## 解决方案结构
```text
Tiku.Api # HTTP API、认证授权、OpenAPI/Scalar、静态原型入口
Tiku.Application # 应用服务、用例编排、接口抽象
Tiku.Domain # 领域实体、枚举、基础类型
Tiku.Infrastructure # EF Core、PostgreSQL、外部服务实现
Tiku.DbMigrator # 数据库迁移启动项目
Tiku.Worker # 后台任务入口
Tiku.UnitTests # 单元测试
Tiku.IntegrationTests # API / EF / PostgreSQL 集成测试
docs # ADR、架构说明和迁移路线
Tiku.Api HTTP API、中间件、认证授权、OpenAPI/Scalar、静态管理端
Tiku.Application 用例契约、应用服务接口和安全上下文
Tiku.Domain 领域实体、枚举和值对象
Tiku.Infrastructure EF Core、PostgreSQL、认证、消息和外部服务实现
Tiku.Contracts API 与 Worker 之间的版本化消息契约
Tiku.DbMigrator 数据库迁移、内置目录 seed 和平台管理员引导
Tiku.Worker 域名、订阅、用量和后台任务处理
Tiku.UnitTests 单元测试
Tiku.IntegrationTests API、授权、EF 模型、迁移和真实 PostgreSQL 测试
```
## 平台端静态原型
依赖方向固定为:`Domain <- Application <- Infrastructure``Api``Worker``DbMigrator` 是组合根;第三方 SDK、数据库访问和密钥处理只放在 Infrastructure。
平台端 demo 已作为静态文件挂到 API 项目:
## 快速启动
```text
GET /platform-admin/
```
它是功能原型壳,不是正式视觉规范。当前默认连接同源真实 API并提供平台账号密码登录和首次改密流程token 只保存在当前浏览器标签的 `sessionStorage`。真实模式不会回退显示 Mock 数据,目前开放概览、租户、员工和审计这组已经落地后端契约的页面,账务、公共题库等页面随对应 API 实现逐步开放。
本地首次启动先创建 `tiku` 数据库并执行迁移:
需要 .NET 10 SDK 和 PostgreSQL。Development 默认连接本机 `tiku` 数据库,也可以通过 `DATABASE_URL` 覆盖。
```bash
createdb -h 127.0.0.1 -U "$(whoami)" tiku
dotnet restore TIKU-BACKEND.slnx
dotnet build TIKU-BACKEND.slnx --no-restore
ASPNETCORE_ENVIRONMENT=Development dotnet run --project Tiku.DbMigrator
dotnet run --project Tiku.Api
```
Development 首次迁移会通过 EF Core 官方推荐的 `UseSeeding` / `UseAsyncSeeding` 初始化平台超级管理员Migration Lock 保证并发安全,后续重复执行迁移会幂等跳过,不会重置密码或重复创建:
Development 首次迁移会创建平台管理员 `admin@tiku.local`,随机临时密码只在 DbMigrator 首次运行的终端输出。完整步骤见[本地开发与运行](docs/quickstart.md)。
```text
登录地址http://localhost:5090/platform-admin/
初始账号admin@tiku.local
初始密码:由 Tiku.DbMigrator 安全随机生成,仅在首次初始化的终端输出一次
```
默认开发入口:
首次登录必须立即修改初始密码;正式密码至少 8 位,并同时包含字母和数字。如果丢失首次输出的临时密码,应删除尚无业务数据的本地开发库后重新初始化,不要把密码补写到源码、`appsettings*.json` 或 README。Production 不会自动创建默认管理员,必须使用下文的显式安全引导命令。
- 平台管理端:<http://localhost:5090/platform-admin/>
- Scalar<http://localhost:5090/scalar/v1>
- OpenAPI<http://localhost:5090/openapi/v1.json>
- Liveness<http://localhost:5090/api/health>
- Readiness<http://localhost:5090/api/health/ready>
开发环境只隐藏 EF Core 成功 SQL 日志ORM 警告与错误仍会输出。
## 运行时边界
当前不把后端改成 MVC/Razor也不为这个静态 demo 单独维护 Node 服务。后续平台端产品化时,建议迁为独立 React/Vite/Next 工程,.NET 继续提供 API
- API 不自动执行数据库迁移;部署和本地初始化都使用 `Tiku.DbMigrator`
- Development 可不配置 Redis 和 RabbitMQProduction 缺少任一依赖时 API 与 Worker 会拒绝启动。
- 租户由可信 Host 解析;平台 Host 上只有允许的路径可通过 `x-tenant-code``tenantCode` 指定租户。
- 租户数据由 EF Query Filter、写入拦截器、租户限定外键/唯一索引和 PostgreSQL guard 共同隔离。
- 普通请求默认要求认证;匿名接口必须显式声明 `[AllowAnonymous]`
- API 只在 Development 映射 OpenAPI 和 Scalar不应把文档端点作为生产依赖。
## 数据库与 ORM 分工
EF Core code-first migration 负责:
- 表、列、索引、普通外键;
- 普通 unique/check constraint
- 模型快照和迁移历史;
- 通过 `Tiku.DbMigrator` 显式执行迁移。
PostgreSQL guard 负责 EF 无法表达的跨表租户不变量:
- `TenantQuestionReference` 只能引用平台公共题或当前租户私题;
- `TaxonomyNode` 父节点只能属于平台主体或当前租户;
- 需要读取 `tenants.mode` 或比较 owner 关系的条件约束。
- 已发布套餐版本及其模块、额度清单不可修改;订阅套餐类型与订单快照必须一致。
- 套餐控制 Feature角色控制 Permission菜单仅按有效权限生成导航内容后台按题库、词汇、手册、视频、分数线和站点内容分模块授权。
- 员工、学生、私有题、存储、导入、导出和短信额度在业务写入时原子消费Worker 定期按真实数据校准当前量。
维护规则:
1. 租户 SQL 放在 `PostgreSqlTenantConstraintSql.cs`SaaS 商品 SQL 放在 `PostgreSqlSaasCatalogConstraintSql.cs`
2. Migration 只调用集中 helper不复制 trigger SQL。
3. 重建 `InitialSchema` 后,`Up()` 末尾必须调用 `EnsureTenantIsolationGuards()``EnsureSaasCatalogGuards()``Down()` 先调用对应 Drop helper。
4. 新增 guard 前先判断能否用 EF FK / unique / check 表达;表达不了才加 PostgreSQL guard。
5. 每个 guard 必须有 migration script 断言和真实 PostgreSQL 越权测试。
## 开发约束
- 新增租户实体必须实现租户 marker并通过模型测试确认 Query Filter、租户唯一索引和组合外键。
- 普通 Controller / Service 不接受可写 `tenantId`、任意 owner tenant GUID、任意 bucket 或 provider 密钥。
- 题目写接口使用 `QuestionLocator`;答题接口使用 `sessionQuestionId`;不得恢复裸 `QuestionId` 练习写入。
- 自定义域名请求不得通过 `tenantCode``host` query 或客户端转发头切换租户。
- 业务层不得直接引用第三方 SDK namespace、拼 OSS bucket、读取微信/支付/短信/AI 密钥。
- 不新增 Supabase provider、Supabase URL 拼接、Supabase Storage 或 Supabase Auth 兼容层。
- AI 面向租户教师后台和题目反馈审核;租户 API Key 存 `TenantSecret`SK 类型不得进入 Domain/Application/API。
## 文档入口
- [本地开发快速开始](docs/quickstart.md)
- [当前认证、授权与 Host 安全策略](docs/architecture/authentication-authorization-security.md)
- [认证与授权待补强清单](docs/architecture/authentication-authorization-hardening-plan.md)
- [迁移路线与剩余范围](docs/migration-roadmap.md)
- [API 契约基线说明](docs/migration/contracts/README.md)
- [AI 底座设计](docs/migration/phase-8-ai-foundation.md)
- [第九阶段SaaS 模块商城与租户交付闭环](docs/migration/phase-9-saas-marketplace-and-onboarding.md)
## 常用命令
## 常用验证
```bash
dotnet restore TIKU-BACKEND.slnx
dotnet build TIKU-BACKEND.slnx --no-restore
dotnet test TIKU-BACKEND.slnx --no-build
dotnet format TIKU-BACKEND.slnx --verify-no-changes --no-restore
dotnet ef migrations has-pending-model-changes \
--project Tiku.Infrastructure \
--startup-project Tiku.DbMigrator \
--no-build
git diff --check
```
生成迁移 SQL
PostgreSQL 特有的迁移、事务、约束和跨租户不变量必须由 `Tiku.IntegrationTests` 在真实 PostgreSQL 上验证,不能只依赖 EF InMemory。
```bash
dotnet ef migrations script \
--project Tiku.Infrastructure \
--startup-project Tiku.DbMigrator
```
## 文档
检查模型是否有未生成 migration 的变更
当前文档统一从[文档总览](docs/README.md)进入
```bash
dotnet ef migrations has-pending-model-changes \
--project Tiku.Infrastructure \
--startup-project Tiku.DbMigrator
```
- [系统架构与业务边界](docs/architecture/overview.md)
- [认证、授权与租户隔离](docs/architecture/security-and-tenancy.md)
- [配置与后台任务](docs/operations.md)
- [本地开发与运行](docs/quickstart.md)
Production 首次部署可在迁移完成后显式创建平台超级管理员:
```bash
export TIKU_BOOTSTRAP_PLATFORM_ADMIN_EMAIL='admin@example.com'
export TIKU_BOOTSTRAP_PLATFORM_ADMIN_PASSWORD='replace-with-a-strong-temporary-password'
export TIKU_BOOTSTRAP_PLATFORM_ADMIN_NAME='Platform Administrator'
dotnet run --project Tiku.DbMigrator -- --bootstrap-platform-admin
```
该命令只允许在不存在任何平台角色用户绑定时执行。不要把临时密码写入仓库配置或命令行参数。
接口、DTO、请求参数和响应模型以运行时 OpenAPI/Scalar 为准;文档不再维护手写接口清单或迁移过程记录。