Files
tiku-backend.net/README.md

7.1 KiB
Raw Blame History

TIKU Backend

题库 SaaS 的正式后端。项目已收敛到 ASP.NET Core + EF Core + PostgreSQL本仓库是后续开发的唯一目标后端。架构决策见 ADR 0001

架构边界

  • 旧 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
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 项目:

GET /platform-admin/

它是功能原型壳,不是正式视觉规范。当前默认连接同源真实 API并提供平台账号密码登录和首次改密流程token 只保存在当前浏览器标签的 sessionStorage。真实模式不会回退显示 Mock 数据,目前开放概览、租户、员工和审计这组已经落地后端契约的页面,账务、公共题库等页面随对应 API 实现逐步开放。

本地首次启动先创建 tiku 数据库并执行迁移:

createdb -h 127.0.0.1 -U "$(whoami)" tiku
ASPNETCORE_ENVIRONMENT=Development dotnet run --project Tiku.DbMigrator

Development 首次迁移会通过 EF Core 官方推荐的 UseSeeding / UseAsyncSeeding 初始化平台超级管理员Migration Lock 保证并发安全,后续重复执行迁移会幂等跳过,不会重置密码或重复创建:

登录地址http://localhost:5090/platform-admin/
初始账号admin@tiku.local
初始密码:由 Tiku.DbMigrator 安全随机生成,仅在首次初始化的终端输出一次

首次登录必须立即修改初始密码;正式密码至少 8 位,并同时包含字母和数字。如果丢失首次输出的临时密码,应删除尚无业务数据的本地开发库后重新初始化,不要把密码补写到源码、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 练习写入。
  • 自定义域名请求不得通过 tenantCodehost query 或客户端转发头切换租户。
  • 业务层不得直接引用第三方 SDK namespace、拼 OSS bucket、读取微信/支付/短信/AI 密钥。
  • 不新增 Supabase provider、Supabase URL 拼接、Supabase Storage 或 Supabase Auth 兼容层。
  • AI 面向租户教师后台和题目反馈审核;租户 API Key 存 TenantSecretSK 类型不得进入 Domain/Application/API。

文档入口

常用命令

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

dotnet ef migrations script \
  --project Tiku.Infrastructure \
  --startup-project Tiku.DbMigrator

检查模型是否有未生成 migration 的变更:

dotnet ef migrations has-pending-model-changes \
  --project Tiku.Infrastructure \
  --startup-project Tiku.DbMigrator

Production 首次部署可在迁移完成后显式创建平台超级管理员:

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

该命令只允许在不存在任何平台角色用户绑定时执行。不要把临时密码写入仓库配置或命令行参数。