Files
tiku-backend.net/docs/architecture/overview.md
xiong 4751e738b1
Some checks failed
ci / release-gate (push) Has been cancelled
清理文档
2026-08-03 13:41:03 +08:00

106 lines
6.2 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.

# 系统架构与业务边界
本文描述当前仓库的实际代码结构和运行时职责。接口路径、DTO 和响应模型以运行时 OpenAPI 为准。
## 分层与依赖
```text
+------------------+ +------------------+ +-----------------+
| Tiku.Api | | Tiku.Worker | | Tiku.DbMigrator |
| HTTP API | | Background loops | | Migrate + Seed |
+--------+---------+ +--------+---------+ +--------+--------+
| | |
+---------------------+---------------------+
v
+---------------------+
| Tiku.Infrastructure |
+----------+----------+
v
+---------------------+
| Tiku.Application |
+----------+----------+
v
+---------------------+
| Tiku.Domain |
+---------------------+
```
- `Tiku.Domain` 保存领域实体、枚举和基础类型。除 Identity stores 抽象外,不依赖持久化或 Provider SDK。
- `Tiku.Application` 定义用例契约、Provider 接口、安全上下文和业务目录,依赖 Domain。
- `Tiku.Infrastructure` 实现 EF Core、PostgreSQL、Identity、外部 Provider 和后台任务,依赖 Application 与 Domain。
- `Tiku.Api``Tiku.Worker` 是独立运行时入口,`Tiku.DbMigrator` 是部署时迁移和 seed 入口。
## 运行时组件
### API
`Tiku.Api/Program.cs` 只负责组合服务、构建应用和启用请求管线。管线的关键顺序是:
```text
结构化请求日志 / 数据库请求指标 / 异常处理
-> Forwarded Headers / HTTPS / 响应压缩
-> Routing / CORS
-> Host 租户解析
-> 浏览器 CSRF
-> JWT 认证 / 认证专用限流 / 全局限流
-> 当前用户上下文 / 授权
-> SaaS Feature 校验
-> Output Cache
-> Controllers
```
OpenAPI 和 Scalar 只在 Development 映射。平台管理端位于独立的 `Tiku.PlatformAdmin.Web` React 工程,由 OpenAPI 生成接口契约Development 通过 `Tiku.Api.csproj` 的 SPA Proxy 启动 ViteProduction 仍应独立构建和部署API 不托管平台前端静态文件。
### DbMigrator
`Tiku.DbMigrator` 是唯一迁移入口,执行顺序为:
1. 解析 `ConnectionStrings:Database``DATABASE_URL`
2. 进入带审计原因的 System Scope。
3. 执行 `Database.MigrateAsync()`
4. seed 内置 SaaS Feature、PermissionModule、BackendPermission、BackendMenu 和 `starter` 套餐目录。
5. 默认 Development seed 在尚无平台角色绑定时创建平台管理员与演示数据;`--skip-development-seed` 可关闭该行为,`--bootstrap-platform-admin` 用于显式创建首个平台管理员。
API 不自动迁移数据库。
### Worker 后台处理
`Tiku.Worker` 独立注册六个 Hosted Service。API 不承载这些生产后台循环;仅 Development 会额外注册 `.localhost` 域名生命周期旁路,方便本地建站验收。
| Worker | 周期 | 当前职责 |
| --- | --- | --- |
| `TenantDomainWorker` | `TenantDomains:PollSeconds`,限制为 103600 秒 | 校验自定义域名 CNAME/TXT调用网关 TLS 接口并失效租户缓存 |
| `SaasSubscriptionWorker` | 60 秒 | 处理到期、宽限期等 SaaS 订阅生命周期 |
| `FeatureUsageWorker` | `FeatureUsageReconciliation:IntervalMinutes`,限制为 11440 分钟 | 按真实业务数据校准租户 Feature 用量 |
| `BackgroundJobsWorker` | 默认 2 秒、4 个分区 | 使用租约处理 PostgreSQL 中的即时、延时和待重试任务 |
| `AuthorizationCacheInvalidationWorker` | 默认 2 秒 | 重试 PostgreSQL 中待处理的 Redis 授权缓存失效事件 |
| `CommercialBillingWorker` | 60 秒 | 生成续费应收与催缴提醒、投递启用渠道并执行已审批退款 |
后台任务处理器由所属 Infrastructure 模块实现并注册Jobs 模块按 `JobType` 调度。当前类型包括 `content_import``content_export``asset_security_scan``tenant_export``statistics_aggregation``commerce_reconciliation``tenant_domain_recheck`;架构测试校验处理器数量、类型和模块注册。安全扫描通过 ClamAV `INSTREAM` 流式处理对象,未通过扫描或扫描不可用时不签发资源访问地址。
即时任务与 `RunAfter` 延时任务统一写入 `background_jobs`。后台任务用 `FOR UPDATE SKIP LOCKED` 和五分钟租约协调;六个周期处理器使用 PostgreSQL advisory lock允许部署多个 Worker 实例而不重复执行同一周期循环。商业续费、应收、退款和催缴投递仍以 PostgreSQL 表为权威,不引入消息代理。
## 数据与持久化
- 数据库使用标准 PostgreSQL普通 schema 由 EF Core entity、Fluent Configuration 和 Migration 管理。
- 当前模型启用 `citext``ltree``pg_trgm` 扩展,并统一映射为 `snake_case`
- Data Protection key ring 由 API 持久化到 PostgreSQL非 Development 必须使用 X509 证书保护。
- 后台任务状态、执行时间、重试和结果由 `background_jobs` 持久化。
- PostgreSQL 不启用 RLS租户隔离由应用和数据库多层共同保证详见[认证、授权与租户隔离](security-and-tenancy.md)。
## 业务入口
| Audience | 主要边界 |
| --- | --- |
| Platform | 租户开通与生命周期、员工/RBAC、治理审批、平台题库、SaaS 账务、运营与告警 |
| Tenant | 成员与 DataScope、内容题库、学习运营、学生/班级、CRM、商城增长及租户 Provider 配置 |
| Student/Public | Host 运行时配置、认证资料、学习与进度、商城权益、推荐关系和公开内容 |
具体操作、权限元数据和 DTO 以运行时 OpenAPI 为准。
## 外部服务边界
Application 通过接口表达身份、短信、对象存储、支付、通知、域名和 AI 能力Infrastructure 当前包含自托管身份、阿里云短信/OSS、微信、支付宝、站内通知、DNS JSON 查询和 HTTP 网关实现。
租户级 Provider 元数据和密钥分别存入 `TenantExternalProvider``TenantSecret`。密钥由 32 字节 master key 加密API 不应把明文、`SecretRef` 或 Provider 内部 payload 返回给客户端。