docs(architecture): sync runtime diagram and guidance
Some checks failed
ci / release-gate (push) Has been cancelled
Some checks failed
ci / release-gate (push) Has been cancelled
This commit is contained in:
@@ -65,7 +65,7 @@ API 不自动迁移数据库。
|
||||
|
||||
### Worker 后台处理
|
||||
|
||||
`Tiku.Worker` 独立注册六个 Hosted Service。API 不承载这些生产后台循环;仅 Development 会额外注册 `.localhost` 域名生命周期旁路,方便本地建站验收。
|
||||
`Tiku.Worker` 独立注册七个 Hosted Service。API 不承载这些生产后台循环;仅 Development 会额外注册 `.localhost` 域名生命周期旁路,方便本地建站验收。
|
||||
|
||||
| Worker | 周期 | 当前职责 |
|
||||
| --- | --- | --- |
|
||||
@@ -75,10 +75,11 @@ API 不自动迁移数据库。
|
||||
| `BackgroundJobsWorker` | 默认 2 秒、4 个分区 | 使用租约处理 PostgreSQL 中的即时、延时和待重试任务 |
|
||||
| `AuthorizationCacheInvalidationWorker` | 默认 2 秒 | 重试 PostgreSQL 中待处理的 Redis 授权缓存失效事件 |
|
||||
| `CommercialBillingWorker` | 60 秒 | 生成续费应收与催缴提醒、投递启用渠道并执行已审批退款 |
|
||||
| `PlatformApprovalWorker` | 默认 2 秒 | 异步执行已经满足审批策略的平台命令 |
|
||||
|
||||
后台任务处理器由所属 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 表为权威,不引入消息代理。
|
||||
即时任务与 `RunAfter` 延时任务统一写入 `background_jobs`。`BackgroundJobsWorker` 使用 `FOR UPDATE SKIP LOCKED` 和五分钟租约,允许多个 Worker 实例并行消费;其余六个周期处理器使用 PostgreSQL advisory lock 保持集群单例执行。商业续费、应收、退款和催缴投递仍以 PostgreSQL 表为权威,不引入消息代理。
|
||||
|
||||
## 数据与持久化
|
||||
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 认证入口
|
||||
|
||||
API 支持两组认证接口:
|
||||
API 按客户端边界提供四组认证接口:
|
||||
|
||||
- `/api/tenant/auth/**` 返回 access token 与 refresh token,适合 Bearer 客户端。
|
||||
- `/api/tenant/auth/browser/**` 把 token 写入 HttpOnly Cookie,适合同源浏览器客户端。
|
||||
- `/api/platform/auth/**`:平台授权域的 Bearer 客户端入口。
|
||||
- `/api/tenant/auth/**`:租户员工授权域的 Bearer 客户端入口。
|
||||
- `/api/student/auth/**`:学生客户端入口;与租户端共享本地账号能力,但必须使用租户授权域且匹配当前租户上下文。
|
||||
- `/api/tenant/auth/browser/**`:租户同源浏览器入口,把 token 写入 HttpOnly Cookie。
|
||||
|
||||
前三组 Bearer 路径共享认证实现,但路由与请求中的 Realm 必须一致;平台路径只接受 Platform Realm,租户端和学生端路径不接受 Platform Realm。
|
||||
|
||||
当前登录方式:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="1080" viewBox="0 0 1600 1080" role="img" aria-labelledby="title desc">
|
||||
<title id="title">TIKU Backend 当前技术架构图</title>
|
||||
<desc id="desc">TIKU Backend 是 ASP.NET Core 模块化单体。API 承载 HTTP,Worker 独立处理后台任务,DbMigrator 负责迁移,运行时依赖 PostgreSQL、Redis 和外部服务。</desc>
|
||||
<desc id="desc">TIKU Backend 是 ASP.NET Core 模块化单体。API 按平台、租户和学生客户端边界承载 HTTP,Worker 独立处理后台任务与平台审批,DbMigrator 负责迁移,运行时依赖 PostgreSQL、Redis、对象存储和外部服务。</desc>
|
||||
<defs>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
|
||||
<path d="M0 0L10 5L0 10Z" fill="#334155"/>
|
||||
@@ -47,7 +47,7 @@
|
||||
<text class="badge-text" x="96" y="211">P</text>
|
||||
<text class="node-title" x="124" y="207">平台管理端</text>
|
||||
<text class="node-text" x="84" y="239">React / Vite 管理端</text>
|
||||
<text class="node-tiny" x="84" y="258">平台账号 · SaaS 运营</text>
|
||||
<text class="node-tiny" x="84" y="258">Platform Realm · 治理审批</text>
|
||||
|
||||
<rect class="node-blue" x="66" y="307" width="178" height="92" rx="6"/>
|
||||
<circle class="badge" cx="96" cy="338" r="18"/>
|
||||
@@ -61,7 +61,7 @@
|
||||
<text class="badge-text" x="96" y="465">H5</text>
|
||||
<text class="node-title" x="124" y="461">学员端</text>
|
||||
<text class="node-text" x="84" y="493">H5 / 小程序 / App</text>
|
||||
<text class="node-tiny" x="84" y="512">学习 · 题库 · 商城</text>
|
||||
<text class="node-tiny" x="84" y="512">Student 路径 · Tenant Realm</text>
|
||||
|
||||
<rect class="node-blue" x="66" y="561" width="178" height="92" rx="6"/>
|
||||
<circle class="badge" cx="96" cy="592" r="18"/>
|
||||
@@ -91,7 +91,7 @@
|
||||
|
||||
<rect class="node-green" x="338" y="526" width="299" height="127" rx="6"/>
|
||||
<text class="node-title" x="358" y="556">Controller 边界</text>
|
||||
<text class="node-text" x="358" y="584">平台 SaaS 管理 · 租户后台</text>
|
||||
<text class="node-text" x="358" y="584">平台治理审批 · SaaS 管理 · 租户后台</text>
|
||||
<text class="node-text" x="358" y="608">题库内容学习 · 商城增长</text>
|
||||
<text class="node-text" x="358" y="632">认证运行时 · 支付回调 · 后台任务</text>
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
|
||||
<rect class="node-green" x="733" y="180" width="509" height="98" rx="6"/>
|
||||
<text class="node-title" x="755" y="210">Tiku.Application:契约与执行上下文</text>
|
||||
<text class="node-text" x="755" y="239">用例接口 / Provider 接口 · TenantContext · CurrentUser</text>
|
||||
<text class="node-text" x="755" y="239">用例 / Provider 契约 · Tenant / User / SystemScope</text>
|
||||
<text class="node-tiny" x="755" y="261">仅引用 Domain;不包含 EF Core 与第三方 SDK</text>
|
||||
|
||||
<rect class="node-amber" x="733" y="307" width="509" height="92" rx="6"/>
|
||||
@@ -123,7 +123,7 @@
|
||||
<text class="node-text" x="773" y="535">身份认证</text>
|
||||
<text class="node-text" x="773" y="558">租户 / 域名</text>
|
||||
<text class="node-text" x="773" y="581">RBAC / Feature</text>
|
||||
<text class="node-text" x="773" y="604">SaaS / 审计</text>
|
||||
<text class="node-text" x="773" y="604">SaaS / 治理审批</text>
|
||||
|
||||
<rect class="node" x="915" y="480" width="144" height="142" rx="5"/>
|
||||
<text class="node-title" x="933" y="508">教育业务</text>
|
||||
@@ -158,8 +158,8 @@
|
||||
<text class="node-text" x="1354" y="242">独立后台运行时</text>
|
||||
<text class="node-text" x="1354" y="269">域名 / 订阅 / 用量</text>
|
||||
<text class="node-text" x="1354" y="296">任务 / 授权缓存失效</text>
|
||||
<text class="node-text" x="1354" y="323">商业账务 / Worker 心跳</text>
|
||||
<text class="node-text" x="1354" y="350">PostgreSQL 锁与任务租约</text>
|
||||
<text class="node-text" x="1354" y="323">商业账务 / 平台审批</text>
|
||||
<text class="node-text" x="1354" y="350">任务租约 / Advisory Lock</text>
|
||||
|
||||
<rect class="node-amber" x="1336" y="408" width="198" height="144" rx="6"/>
|
||||
<circle class="badge" cx="1368" cy="439" r="18"/>
|
||||
@@ -185,16 +185,16 @@
|
||||
<text class="badge-text" x="105" y="859">PG</text>
|
||||
<text class="node-title" x="139" y="854">PostgreSQL</text>
|
||||
<text class="node-text" x="92" y="892">EF Core 实体 / Identity / AuthSession</text>
|
||||
<text class="node-text" x="92" y="917">业务数据 / BackgroundJob / Session</text>
|
||||
<text class="node-tiny" x="92" y="944">Query Filter · 写入拦截 · 数据库 Guard</text>
|
||||
<text class="node-text" x="92" y="917">业务 / BackgroundJob / 审批与审计</text>
|
||||
<text class="node-tiny" x="92" y="944">事实源 · Query Filter · 写入拦截 · Guard</text>
|
||||
|
||||
<rect class="node-violet" x="372" y="826" width="205" height="138" rx="6"/>
|
||||
<circle class="badge" cx="407" cy="859" r="20"/>
|
||||
<text class="badge-text" x="407" y="859">R</text>
|
||||
<text class="node-title" x="441" y="854">Redis</text>
|
||||
<text class="node-text" x="394" y="892">安全频控</text>
|
||||
<text class="node-text" x="394" y="892">安全频控 / 授权缓存</text>
|
||||
<text class="node-text" x="394" y="917">Feature / Output Cache</text>
|
||||
<text class="node-tiny" x="394" y="944">Production 必需</text>
|
||||
<text class="node-tiny" x="394" y="944">非事实源 · Production 必需</text>
|
||||
|
||||
<rect class="node-violet" x="609" y="826" width="225" height="138" rx="6"/>
|
||||
<circle class="badge" cx="644" cy="859" r="20"/>
|
||||
@@ -206,7 +206,7 @@
|
||||
|
||||
<rect class="node-blue" x="866" y="826" width="205" height="138" rx="6"/>
|
||||
<text class="node-title" x="890" y="856">对象存储</text>
|
||||
<text class="node-text" x="890" y="892">Alibaba Cloud OSS</text>
|
||||
<text class="node-text" x="890" y="892">Alibaba OSS / S3 / MinIO</text>
|
||||
<text class="node-text" x="890" y="917">预签名上传 / 资源访问</text>
|
||||
<text class="node-tiny" x="890" y="944">IObjectStorageService</text>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@@ -104,7 +104,7 @@ Redis key 使用环境前缀;配置解析会强制 `AbortOnConnectFail=false`
|
||||
|
||||
`TenantProvisioning:DefaultBaseOfferingCode` 必须指向 Active 基础套餐的有效 Published 版本。Production 启动与租户开通事务都会校验,缺失时返回 `default_offering_unavailable`。完整流程见[空数据库到租户建站验收](tenant-provisioning.md)。
|
||||
|
||||
后台任务状态和 `RunAfter` 存在 PostgreSQL。Worker 使用 `FOR UPDATE SKIP LOCKED`、五分钟租约和有限重试;周期循环使用 PostgreSQL advisory lock 防止多实例重复执行。通用任务由模块注册的 `IBackgroundJobHandler` 处理,Jobs 模块负责查找、租约、重试和失败补偿。六个循环处理域名、订阅、Feature 用量、通用任务、授权缓存失效和商业账务。`Worker:Enabled=false` 会关闭全部循环。
|
||||
后台任务状态和 `RunAfter` 存在 PostgreSQL。`BackgroundJobsWorker` 使用 `FOR UPDATE SKIP LOCKED`、五分钟租约和有限重试,允许多个 Worker 实例并行消费;其他周期处理器使用 PostgreSQL advisory lock 防止重复执行。通用任务由模块注册的 `IBackgroundJobHandler` 处理,Jobs 模块负责查找、租约、重试和失败补偿。七个循环处理域名、订阅、Feature 用量、通用任务、授权缓存失效、商业账务和平台审批执行。`Worker:Enabled=false` 会关闭全部循环。
|
||||
|
||||
API 和 Worker 必须使用同一 PostgreSQL 数据库与一致的对象存储配置。迁移必须在两者启动前由 `Tiku.DbMigrator` 单独执行。
|
||||
|
||||
@@ -119,7 +119,7 @@ API 和 Worker 应独立设置副本数与资源限制。发布顺序固定为 `
|
||||
|
||||
## 发布门禁、备份恢复和告警
|
||||
|
||||
`.github/workflows/ci.yml` 执行 restore、build、完整测试、format、EF 模型漂移、幂等 Migration SQL、平台前端检查、OpenAPI 生成漂移、API/Worker 镜像构建和 `git diff --check`。本地发布前应执行相同检查。
|
||||
`.gitea/workflows/ci.yaml` 执行 restore、build、完整测试、format、EF 模型漂移、幂等 Migration SQL、平台前端检查、OpenAPI 生成漂移、API/Worker 镜像构建和 `git diff --check`。本地发布前应执行相同检查。
|
||||
|
||||
PostgreSQL 恢复演练使用标准 `PGHOST`、`PGPORT`、`PGUSER`、`PGPASSWORD` 环境变量,并通过 `TIKU_BACKUP_SOURCE_DATABASE` 指定源数据库:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user