forked from xiongyuxing/tiku-backend.net
4.5 KiB
4.5 KiB
第二阶段:.NET 工程底座
完成日期:2026-07-27。
本阶段按 greenfield 项目建设,不承担旧 Supabase / NestJS 数据兼容。数据库结构以 EF Core 实体、Fluent Configuration 和 Migration 为唯一权威来源;API 运行时不自动修改数据库。
数据库开发与发布边界
- 开发采用 code first:修改实体或 Fluent Configuration 后生成 EF Core Migration。
- Migration 统一保存在
Tiku.Infrastructure/Persistence/Migrations/。 Tiku.DbMigrator是执行 Migration 的独立入口。Tiku.Api和Tiku.Worker不调用Database.Migrate(),避免多实例启动时争抢 DDL,也避免应用进程持有结构变更权限。- 发布前生成并审查 SQL;生产环境由部署流程显式执行 DbMigrator 或审核后的 SQL。
- Development 未配置连接串时默认连接本机
tiku数据库,并使用当前系统用户名,不内置密码。 - 非 Development 环境必须显式配置
ConnectionStrings:Database或DATABASE_URL,缺失时启动失败。
常用命令:
dotnet ef migrations add <MigrationName> \
--project Tiku.Infrastructure \
--startup-project Tiku.DbMigrator
dotnet ef migrations script \
--project Tiku.Infrastructure \
--startup-project Tiku.DbMigrator
dotnet run --project Tiku.DbMigrator
真实 PostgreSQL 测试基线
Tiku.IntegrationTests 已移除 EF Core InMemory provider,全部集成测试连接真实 PostgreSQL:
- 管理连接可通过
TIKU_TEST_POSTGRES_ADMIN覆盖。 - 默认管理连接为
Host=localhost;Database=postgres;Username=<当前系统用户>。 - 测试进程创建一次已执行完整 Migration 的模板数据库。
- 每个
ApiTestFactory从模板克隆独立tiku_it_*数据库,测试之间不共享业务数据。 - Factory 释放时终止连接并删除克隆库;进程退出时删除模板库。
- 测试只允许管理
tiku_it_*命名空间,不访问或清理已有tiku业务数据库。
真实关系型测试暴露并修正了以下 InMemory 无法可靠验证的问题:
- 测试夹具缺失的 Region、School、Subject、Category、Question 等外键实体。
Question与QuestionVersion当前版本引用形成的插入循环,改为事务内分阶段保存。ReferralLead.FirstTrackId与ReferralTrack.LeadId形成的插入循环,改为事务内分阶段保存。- PostgreSQL JSON 映射不能将未定义的
default(JsonElement)生成为 SQL literal,缺省数组改为有效的[]。 - 徽章发放不再伪造超长 legacy ID;通知使用新记录 ID 生成独立、稳定的去重键。
配置与密钥安全
- 根配置不再提交可用于生产的 JWT signing key。
- Development 只使用明确标识的开发 JWT key;Production 拒绝该 key。
- 租户第三方凭据使用 AES-256-GCM envelope 保存。
- 每条密文使用 12-byte nonce、16-byte authentication tag。
- AAD 绑定
tenantId、secretRef和keyId,密文不能跨租户或跨引用替换。 - 主密钥必须是 Base64 编码的 32 字节值;Production 拒绝仓库内的开发测试 key。
- 运行时配置键为
Security:TenantSecrets:KeyId和Security:TenantSecrets:MasterKey;环境变量可使用TIKU_TENANT_SECRET_KEY_ID与TIKU_TENANT_SECRET_MASTER_KEY。 - 新 schema 只保留
encryption_key_id、encrypted_payload、encryption_nonce、encryption_tag,不保留明文字段或明文回退读取路径。
本阶段的 EncryptTenantSecretPayloads Migration 会直接删除旧 secret_payload 字段。这是 greenfield 决策,不提供旧数据转换或兼容窗口。
验证结果
2026-07-27 在本机 PostgreSQL 18.4、.NET SDK 10.0.301 上完成:
dotnet build:通过,0 warning / 0 error
dotnet test:通过,265/265
UnitTests:16/16
IntegrationTests(真实 PostgreSQL):249/249
dotnet format --verify-no-changes:通过
git diff --check:通过
EF Core migration script:通过,生成 4184 行 SQL
测试数据库清理:通过,无 tiku_it_* 残留
第二阶段退出条件
- EF Core Migration 成为 code-first schema 的唯一版本历史。
- API 与 Worker 不在启动时自动执行 Migration。
- 生产数据库、JWT 和租户密钥配置缺失时 fail fast。
- 租户第三方凭据只保存 AES-GCM 密文 envelope。
- 集成测试完全切换到隔离的真实 PostgreSQL 数据库。
- 修复真实数据库暴露的外键、循环依赖、JSON 和字段长度问题。
- 全量构建、测试、格式与 Migration SQL 验证通过。