Files
tiku-backend.net/README.md

150 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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/
```
它是功能原型壳,不是正式视觉规范。当前默认连接同源真实 API并提供平台登录、首次改密和 TOTP MFA 流程token 只保存在当前浏览器标签的 `sessionStorage`。真实模式不会回退显示 Mock 数据,目前开放概览、租户、员工和审计这组已经落地后端契约的页面,账务、公共题库等页面随对应 API 实现逐步开放。
本地首次启动先创建 `tiku` 数据库并执行迁移:
```bash
createdb -h 127.0.0.1 -U "$(whoami)" tiku
ASPNETCORE_ENVIRONMENT=Development dotnet run --project Tiku.DbMigrator
```
Development 首次迁移会通过 EF Core 官方推荐的 `UseSeeding` / `UseAsyncSeeding` 初始化平台超级管理员Migration Lock 保证并发安全,后续重复执行迁移会幂等跳过,不会重置密码或重复创建:
```text
登录地址http://localhost:5090/platform-admin/
初始账号admin@tiku.local
初始密码:由 Tiku.DbMigrator 安全随机生成,仅在首次初始化的终端输出一次
```
首次登录必须立即修改初始密码并绑定 TOTP MFA。如果丢失首次输出的临时密码应删除尚无业务数据的本地开发库后重新初始化不要把密码补写到源码、`appsettings*.json` 或 README。Production 不会自动创建默认管理员,必须使用下文的显式安全引导命令。
开发环境只隐藏 EF Core 成功 SQL 日志ORM 警告与错误仍会输出。
当前不把后端改成 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。
## 文档入口
- [本地开发快速开始](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)
## 常用命令
```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
```
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
```
该命令只允许在不存在任何平台角色用户绑定时执行。不要把临时密码写入仓库配置或命令行参数。