130 lines
5.7 KiB
Markdown
130 lines
5.7 KiB
Markdown
# TIKU Backend
|
||
|
||
题库 SaaS 的正式后端。项目已收敛到 ASP.NET Core + EF Core + PostgreSQL,本仓库是后续开发的唯一目标后端。架构决策见 [ADR 0001](docs/adr/0001-authoritative-dotnet-backend.md)。
|
||
|
||
## 架构边界
|
||
|
||
- 旧 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 伪造切换租户。
|
||
- 公共题库由唯一平台主体拥有;订阅有效租户可访问公共题,租户私题只属于本租户。
|
||
|
||
## 技术栈与目录
|
||
|
||
- 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、架构说明和迁移路线
|
||
```
|
||
|
||
## 平台端静态原型
|
||
|
||
平台端 demo 已作为静态文件挂到 API 项目:
|
||
|
||
```text
|
||
GET /platform-admin/
|
||
```
|
||
|
||
它是功能原型壳,不是正式视觉规范。默认 mock 模式;联调时通过 `runtime-config.js` 注入同源 `/api`、平台 access token provider 和 API 模式。
|
||
|
||
当前不把后端改成 MVC/Razor,也不为这个静态 demo 单独维护 Node 服务。后续平台端产品化时,建议迁为独立 React/Vite/Next 工程,.NET 继续提供 API。
|
||
|
||
## 数据库与 ORM 分工
|
||
|
||
EF Core code-first migration 负责:
|
||
|
||
- 表、列、索引、普通外键;
|
||
- 普通 unique/check constraint;
|
||
- 模型快照和迁移历史;
|
||
- 通过 `Tiku.DbMigrator` 显式执行迁移。
|
||
|
||
PostgreSQL guard 负责 EF 无法表达的跨表租户不变量:
|
||
|
||
- `TenantQuestionReference` 只能引用平台公共题或当前租户私题;
|
||
- `TaxonomyNode` 父节点只能属于平台主体或当前租户;
|
||
- 需要读取 `tenants.mode` 或比较 owner 关系的条件约束。
|
||
|
||
维护规则:
|
||
|
||
1. SQL 只放在 `Tiku.Infrastructure/Persistence/PostgreSqlTenantConstraintSql.cs`。
|
||
2. Migration 只调用 `migrationBuilder.EnsureTenantIsolationGuards()` / `DropTenantIsolationGuards()`。
|
||
3. 重建 `InitialSchema` 后,`Up()` 末尾必须调用 `EnsureTenantIsolationGuards()`,`Down()` 开头必须调用 `DropTenantIsolationGuards()`。
|
||
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。
|
||
|
||
## 文档入口
|
||
|
||
- [当前认证、授权与 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)
|
||
|
||
## 常用命令
|
||
|
||
```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
|
||
git diff --check
|
||
```
|
||
|
||
生成迁移 SQL:
|
||
|
||
```bash
|
||
dotnet ef migrations script \
|
||
--project Tiku.Infrastructure \
|
||
--startup-project Tiku.DbMigrator
|
||
```
|
||
|
||
检查模型是否有未生成 migration 的变更:
|
||
|
||
```bash
|
||
dotnet ef migrations has-pending-model-changes \
|
||
--project Tiku.Infrastructure \
|
||
--startup-project Tiku.DbMigrator
|
||
```
|
||
|
||
首次部署可在迁移完成后创建平台超级管理员:
|
||
|
||
```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
|
||
```
|
||
|
||
该命令只允许在不存在任何平台角色用户绑定时执行。不要把临时密码写入仓库配置或命令行参数。
|