diff --git a/AGENTS.md b/AGENTS.md
index 0e99e5f..097dc7c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -2,7 +2,7 @@
## Project Structure & Module Organization
-`TIKU-BACKEND.slnx` is a .NET 10 modular monolith. `Tiku.Domain` holds entities; `Tiku.Application` defines use-case contracts; `Tiku.Infrastructure` contains EF Core, PostgreSQL, Redis, authentication, jobs, and external integrations. `Tiku.Api` and `Tiku.Worker` are independent runtimes; `Tiku.DbMigrator` owns migration and bootstrap work. Tests live in `Tiku.UnitTests` and `Tiku.IntegrationTests`. The React/TypeScript admin UI is in `Tiku.PlatformAdmin.Web`; documentation and deployment assets live under `docs/` and `deploy/`.
+`TIKU-BACKEND.slnx` is a .NET 10 modular monolith. `Tiku.Domain` holds entities; `Tiku.Application` defines use-case contracts; `Tiku.Infrastructure` contains EF Core, PostgreSQL, Redis, jobs, and external integrations. `Tiku.Api` and `Tiku.Worker` are independent runtimes; `Tiku.DbMigrator` owns migration and bootstrap work. Tests live in `Tiku.UnitTests` and `Tiku.IntegrationTests`. The React/TypeScript UI is in `Tiku.PlatformAdmin.Web`; documentation and deployment assets live under `docs/` and `deploy/`.
Keep dependencies flowing `Domain <- Application <- Infrastructure`. Database access, SDK integrations, and secret handling belong in Infrastructure, not controllers or domain types.
diff --git a/README.md b/README.md
index e1d0c47..add2f1b 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ dotnet run --project Tiku.Api
dotnet run --project Tiku.Worker
```
-Development 首次迁移会创建平台管理员 `admin@tiku.local`,随机临时密码只在 DbMigrator 首次运行的终端输出。完整步骤见[本地开发与运行](docs/quickstart.md)。
+默认 Development seed 会在尚无平台角色绑定时创建平台管理员 `admin@tiku.local` 和演示数据;随机临时密码只在首次创建时输出。日常步骤见[本地开发快速上手](docs/quickstart.md),不含演示数据的完整 SaaS 验收见[空数据库到租户建站验收](docs/tenant-provisioning.md)。
默认开发入口:
@@ -86,6 +86,7 @@ PostgreSQL 特有的迁移、事务、约束和跨租户不变量必须由 `Tiku
- [系统架构与业务边界](docs/architecture/overview.md)
- [认证、授权与租户隔离](docs/architecture/security-and-tenancy.md)
- [配置与后台任务](docs/operations.md)
-- [本地开发与运行](docs/quickstart.md)
+- [本地开发快速上手](docs/quickstart.md)
+- [空数据库到租户建站验收](docs/tenant-provisioning.md)
接口、DTO、请求参数和响应模型以运行时 OpenAPI/Scalar 为准;文档不再维护手写接口清单或迁移过程记录。
diff --git a/docs/README.md b/docs/README.md
index ba07da3..9180dbc 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -2,14 +2,25 @@
这里仅记录当前代码已经实现的架构、运行方式和维护约束。接口细节以 Development 环境的 OpenAPI/Scalar 为准,数据库结构以 EF Core Migration 和模型快照为准。
-## 阅读入口
+## 从这里开始
-| 文档 | 内容 | 适合谁 |
-| --- | --- | --- |
-| [本地开发与运行](quickstart.md) | PostgreSQL 初始化、启动 API、验证命令、常见问题 | 新开发者 |
-| [系统架构与业务边界](architecture/overview.md) | 项目依赖、运行时组件、当前业务模块和后台任务链路 | 开发与评审人员 |
-| [认证、授权与租户隔离](architecture/security-and-tenancy.md) | 登录、Session、JWT、Cookie/CSRF、Realm、RBAC、Capability、DataScope、租户隔离 | API 与安全开发者 |
-| [配置与后台任务](operations.md) | 环境配置、Production 启动门禁、Redis、Worker、ClamAV 和健康检查 | 开发与运维人员 |
+| 目标 | 文档 |
+| --- | --- |
+| 首次拉取代码,启动本地开发环境 | [本地开发快速上手](quickstart.md) |
+| 从空库验收租户创建、Owner 激活和站点发布 | [空数据库到租户建站验收](tenant-provisioning.md) |
+| 理解项目分层、运行时和业务边界 | [系统架构与业务边界](architecture/overview.md) |
+| 修改认证、权限或租户数据 | [认证、授权与租户隔离](architecture/security-and-tenancy.md) |
+| 部署 API/Worker、配置依赖或排查任务 | [配置与后台任务](operations.md) |
+
+## 文档边界
+
+- `README.md`:项目定位、最短启动入口和仓库地图。
+- `docs/quickstart.md`:非破坏性的日常开发路径。
+- `docs/tenant-provisioning.md`:会创建或清理本地数据库的完整 SaaS 验收路径。
+- `docs/architecture/**`:当前代码的稳定设计与安全边界。
+- `docs/operations.md`:部署配置、后台处理、健康检查和恢复演练。
+
+路线图、阶段计划、代码评审快照和历史迁移过程不放在当前实现文档中;需要保留时应进入 Issue、项目管理系统或明确标记的历史归档。
## 权威来源
@@ -25,4 +36,5 @@
2. 新增租户实体时,同时验证 Query Filter、租户唯一索引、组合外键和写入拦截器。
3. 数据库结构变更必须生成 EF Core Migration,并检查 migration script 和 pending model changes。
4. 不在文档中保存连接密码、JWT 私钥、证书密码、Provider 密钥或平台管理员临时密码。
-5. 不再维护阶段路线图、旧后端接口对比、评审快照或开发过程记录。
+5. 代码行为变化时更新对应主题,不新增内容重叠的临时说明文件。
+6. 不维护阶段路线图、旧后端接口对比、评审快照或开发过程记录。
diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md
index c1315cc..8a6f4ec 100644
--- a/docs/architecture/overview.md
+++ b/docs/architecture/overview.md
@@ -37,8 +37,8 @@
`Tiku.Api/Program.cs` 只负责组合服务、构建应用和启用请求管线。管线的关键顺序是:
```text
-Forwarded Headers
- -> HTTPS / 压缩 / 静态文件
+结构化请求日志 / 数据库请求指标 / 异常处理
+ -> Forwarded Headers / HTTPS / 响应压缩
-> Routing / CORS
-> Host 租户解析
-> 浏览器 CSRF
@@ -49,7 +49,7 @@ Forwarded Headers
-> Controllers
```
-OpenAPI 和 Scalar 只在 Development 映射。平台管理端位于独立的 `Tiku.PlatformAdmin.Web` React 工程,由 OpenAPI 生成接口契约并单独构建、部署;`Tiku.Api` 不再托管平台前端静态文件。
+OpenAPI 和 Scalar 只在 Development 映射。平台管理端位于独立的 `Tiku.PlatformAdmin.Web` React 工程,由 OpenAPI 生成接口契约;Development 通过 `Tiku.Api.csproj` 的 SPA Proxy 启动 Vite,Production 仍应独立构建和部署,API 不托管平台前端静态文件。
### DbMigrator
@@ -58,14 +58,14 @@ OpenAPI 和 Scalar 只在 Development 映射。平台管理端位于独立的 `T
1. 解析 `ConnectionStrings:Database` 或 `DATABASE_URL`。
2. 进入带审计原因的 System Scope。
3. 执行 `Database.MigrateAsync()`。
-4. seed 内置 SaaS Feature、PermissionModule、BackendPermission 和 BackendMenu 目录。
-5. Development 全新数据库自动 seed 平台管理员;非 Development 仅在显式传入 `--bootstrap-platform-admin` 时创建管理员。
+4. seed 内置 SaaS Feature、PermissionModule、BackendPermission、BackendMenu 和 `starter` 套餐目录。
+5. 默认 Development seed 在尚无平台角色绑定时创建平台管理员与演示数据;`--skip-development-seed` 可关闭该行为,`--bootstrap-platform-admin` 用于显式创建首个平台管理员。
API 不自动迁移数据库。
### Worker 后台处理
-`Tiku.Worker` 独立注册六个 Hosted Service,API 进程不注册后台循环:
+`Tiku.Worker` 独立注册六个 Hosted Service。API 不承载这些生产后台循环;仅 Development 会额外注册 `.localhost` 域名生命周期旁路,方便本地建站验收。
| Worker | 周期 | 当前职责 |
| --- | --- | --- |
diff --git a/docs/architecture/security-and-tenancy.md b/docs/architecture/security-and-tenancy.md
index 864de44..3e4b3ff 100644
--- a/docs/architecture/security-and-tenancy.md
+++ b/docs/architecture/security-and-tenancy.md
@@ -83,7 +83,7 @@ Development 默认平台 Host 是 `localhost` 和 `127.0.0.1`。Production 启
新租户创建时必须提供主域名。域名统一转换为小写 ASCII/IDN Host,并使用随机 32 字节 Base64Url TXT 值验证所有权;只有 DNS 与 TLS 都成功后才进入 `Active`。平台领取 Owner 激活链接前还会校验租户、Active 主域名和试用/订阅状态。
-激活链接格式固定为 `https://{primaryHost}/activate/{activationId}#token={token}`。Token 位于 fragment,不进入 HTTP 请求、服务器访问日志或 Referer;PostgreSQL 只保存 SHA-256 哈希。Grant 绑定签发时的 `DomainId`,浏览器激活要求请求 Host、已解析 Tenant、Grant 和 Active 主域名完全一致。并发签发由事务 advisory lock 和部分唯一索引收敛为一个有效 Grant;幂等重放只返回 Grant ID 与过期时间,不能恢复明文。
+Production 默认激活链接为 `https://{primaryHost}/activate/{activationId}#token={token}`;Development 可通过专用 localhost 模板指向租户前端端口。Token 位于 fragment,不进入 HTTP 请求、服务器访问日志或 Referer;PostgreSQL 只保存 SHA-256 哈希。Grant 绑定签发时的 `DomainId`,浏览器激活要求请求 Host、已解析 Tenant、Grant 和 Active 主域名完全一致。并发签发由事务 advisory lock 和部分唯一索引收敛为一个有效 Grant;幂等重放只返回 Grant ID 与过期时间,不能恢复明文。
浏览器激活在受审计事务中消费 Grant、设置密码、清除强制改密状态并创建数据库 Session。成功响应仅写入 HttpOnly access/refresh Cookie 与可读 CSRF Cookie,不向 JavaScript 返回 Token Pair;密码策略失败会整体回滚,Grant 不会提前消费。
@@ -124,6 +124,18 @@ Development 默认平台 Host 是 `localhost` 和 `127.0.0.1`。Production 启
- 租户、套餐和 Feature 变更在数据库提交后直接失效当前 API 进程与 Redis 中的相关缓存。
- 后台任务在业务事务提交后持久化到 PostgreSQL,独立 Worker 使用租约执行;延时和重试由 `RunAfter` 控制。
+## Redis 授权缓存模式
+
+`Security:AuthorizationCache:Mode` 支持三种当前实现模式:
+
+- `Disabled`:直接以 PostgreSQL 完成安全状态和权限读取。
+- `Shadow`:PostgreSQL 决策仍为准,同时读取、回填并比较 Redis 结果。
+- `Active`:优先读取 Redis 安全状态与权限快照;缓存缺失或 Redis 不可用时回退 PostgreSQL。
+
+缓存键按环境、realm、租户、用户和 Session 隔离,不保存 JWT、Refresh Token、手机号或邮箱。权限快照键包含持久化授权版本;用户、成员、租户、Session 或角色权限变化会推进版本并触发缓存失效。提交后若 Redis 失效失败,事件保留在 PostgreSQL,由 `AuthorizationCacheInvalidationWorker` 重试;旧版本不会覆盖新版本。
+
+Redis 不是授权事实源。Redis 与 PostgreSQL 同时无法完成安全校验时返回 503 `auth_security_unavailable`,不能使用本地旧快照放行。
+
## 安全配置门禁
Production 还会在启动时验证 Redis、Data Protection 证书、租户 Secret master key、短信 pepper、CORS 和外部服务配置。完整配置入口见[配置与后台任务](../operations.md)。
diff --git a/docs/assets/tiku-backend-architecture.svg b/docs/assets/tiku-backend-architecture.svg
index 5beb9e1..a5b9313 100644
--- a/docs/assets/tiku-backend-architecture.svg
+++ b/docs/assets/tiku-backend-architecture.svg
@@ -1,6 +1,6 @@
diff --git a/docs/development-plan.md b/docs/development-plan.md
deleted file mode 100644
index 3b3cd0e..0000000
--- a/docs/development-plan.md
+++ /dev/null
@@ -1,335 +0,0 @@
-# TIKU Backend 后续开发计划
-
-## 1. 计划目标
-
-后续开发围绕教育业务闭环、SaaS 产品化、可靠性、性能和可运营性推进。每个阶段必须形成可独立验收的业务结果,不以接口数量或数据表数量作为完成标准。
-
-总体目标:
-
-- 建立服务端可信的练习、评分、报告和学习分析链路。
-- 完成内容生产、教学组织、学生学习和教师干预闭环。
-- 打通套餐、权益、商品、订单、支付和教育资源访问。
-- 提供平台端、租户端、教师端和学生端可实际使用的工作流。
-- 建立真实 PostgreSQL、Redis 和对象存储路径下的质量与性能门禁。
-- 保持模块化单体边界,在明确出现独立扩缩容需求前不拆分微服务。
-
-## 2. 实施原则
-
-- PostgreSQL 是业务状态、权限、权益、余额、订单和任务状态的权威来源。
-- Redis 只用于缓存、限流和可重建的加速数据,不作为授权或交易事实来源。
-- 客户端提交的用户、租户、角色、正确性、价格、权益和状态均不可信,必须由服务端解析或计算。
-- 所有可能被网络重试的写操作必须具备幂等语义。
-- 所有状态转换必须定义合法前置状态,并通过事务或比较并交换更新保证并发安全。
-- 所有租户数据访问必须同时满足租户隔离、操作权限、DataScope、套餐权益和资源可见性规则。
-- 导入、导出、聚合、提醒、扫描等长任务统一进入 `background_jobs`。
-- 前端接口以实时 OpenAPI 为唯一契约来源,不维护第二套手写接口模型。
-- 每个行为变更都要有回归测试;PostgreSQL 特有约束必须使用真实 PostgreSQL 验证。
-
-## 3. 阶段总览
-
-| 阶段 | 主题 | 建议周期 | 主要结果 |
-| --- | --- | ---: | --- |
-| P0 | 学习核心链路可信化 | 2 个迭代 | 服务端判分、幂等答题、并发安全交卷、不可变报告 |
-| P1 | 内容生产与练习编排 | 2 个迭代 | 题目生命周期、题集、练习蓝图、导入发布闭环 |
-| P2 | 教学组织与教师运营 | 2~3 个迭代 | 班级、任务、提醒、学情和学生干预 |
-| P3 | 学生学习与个性化 | 2~3 个迭代 | 错题复习、间隔学习、自适应练习和成长激励 |
-| P4 | SaaS 权益与商业闭环 | 2 个迭代 | 套餐权益、教育商品、支付、退款和激活码联动 |
-| P5 | 产品界面与契约交付 | 持续并行 | 四类用户拥有完整可操作工作流 |
-| P6 | 性能、扩展与可观测性 | 持续并行 | 业务压测、聚合读模型、多实例安全和 SLO 告警 |
-
-周期用于安排依赖关系,不作为压缩验收范围的依据。阶段可以并行准备,但不得越过前置发布门禁。
-
-## 4. P0:学习核心链路可信化
-
-### 4.1 题目与评分快照
-
-- 为练习会话题目保存题目 ID、版本 ID、题型、题干、选项、标准答案、解析、分值和评分规则快照。
-- 会话创建后不得因题库后续编辑而改变本次练习的评分结果。
-- 学生会话详情只能返回安全投影,不返回标准答案、解析或选项正确标记。
-- 为单选、多选、判断、填空建立独立服务端评分器。
-- 主观题支持 `PendingReview`、`TeacherReviewed` 和 `SelfPractice` 等明确状态。
-- 自评结果只能用于练习反馈,不计入权威成绩、积分和排行榜。
-
-### 4.2 答题幂等与并发控制
-
-- 答题 DTO 增加 `IdempotencyKey`、`ExpectedSessionVersion` 和 `ClientSequence`。
-- 建立答题幂等记录,保存操作类型、请求哈希、响应快照和完成状态。
-- 相同幂等键与相同请求体必须重放原响应。
-- 相同幂等键与不同请求体必须返回明确冲突。
-- 练习会话增加并发版本和最后客户端序列。
-- 使用数据库唯一约束和比较并交换更新阻止重复答案、乱序写入和多设备并发覆盖。
-- 明确答案修改策略:允许覆盖时保留版本历史;不允许覆盖时返回稳定错误码。
-
-### 4.3 交卷与报告状态机
-
-- 定义 `Active → Scoring → Submitted`、`Active → Expired`、`Active → Cancelled` 状态转换。
-- 交卷请求增加幂等键,并保证同一会话只能生成一份权威报告。
-- 评分、错题更新、积分事件和报告生成在同一事务边界内提交,或通过同事务创建的后台任务可靠续办。
-- 报告发布后保持不可变;重新评分必须生成新版本并记录原因、操作者和审计事件。
-- 处理评分中断、任务重试和超时租约回收。
-
-### 4.4 P0 测试与发布门禁
-
-- 覆盖重复答题、幂等冲突、旧版本、乱序序列、双设备并发和重复交卷。
-- 覆盖跨租户、非本人会话、过期会话、已提交会话和未授权题目。
-- 覆盖学生响应不泄露答案及解析。
-- 覆盖各客观题型的服务端判分和边界输入。
-- 使用真实 PostgreSQL 验证唯一约束、事务竞争和失败回滚。
-- 完成迁移首次执行及幂等第二次执行验证。
-
-完成标准:客户端无法伪造成绩;网络重试不会产生重复答案、重复报告、重复积分或重复错题计数。
-
-## 5. P1:内容生产与练习编排
-
-### 5.1 内容生命周期
-
-- 统一题目、目录节点、题集和练习蓝图的 `Draft → Review → Published → Archived` 生命周期。
-- 增加乐观版本、状态前置校验、发布审计和归档恢复规则。
-- 支持题目版本对比、引用关系查看和安全回滚。
-- 发布前校验题干、选项、答案、解析、分类、资源和题型结构完整性。
-- 已被历史练习引用的版本不得物理删除。
-
-### 5.2 题集与练习蓝图
-
-- 支持人工题集、动态规则题集和固定快照题集。
-- 练习蓝图支持知识点、题型、难度、题量、分值、随机种子和去重规则。
-- 创建练习时记录蓝图版本、抽题结果和随机种子,确保结果可重放。
-- 增加题量不足、资源不可见、跨租户引用和已归档内容的失败关闭规则。
-
-### 5.3 导入与批量运营
-
-- 导入流程拆分为上传、解析、预检、确认、执行和结果下载。
-- 预检结果精确到行、字段和错误代码。
-- 导入支持幂等键、来源哈希和重复内容策略。
-- 批量发布、归档和分类必须提供影响范围预览。
-- 大批量任务进入后台任务系统,并支持进度、取消、重试和结果资产。
-
-### 5.4 内容质量指标
-
-- 记录题目使用次数、作答人数、正确率、平均耗时、跳过率和争议率。
-- 为低质量、异常高正确率、异常低正确率和长期未使用题目提供运营筛选。
-- 质量指标采用异步增量聚合,不在学生提交请求中执行大范围统计。
-
-完成标准:运营人员可以从草稿创建到发布、组卷、导入和质量复盘完成完整工作流。
-
-## 6. P2:教学组织与教师运营
-
-### 6.1 班级与成员
-
-- 完善班级、教师、助教、学生和分组模型。
-- 支持邀请、批量导入、转班、退班、冻结和历史成员查询。
-- 所有成员变更记录操作者、原因、时间和前后状态。
-- DataScope 支持按校区、部门、班级和本人范围过滤。
-
-### 6.2 学习任务
-
-- 支持练习、每日一练、作业和考试任务。
-- 支持目标班级、分组、指定学生、发布时间、截止时间、补交和重做策略。
-- 发布任务时固定内容或蓝图版本,避免后续编辑改变已发布任务。
-- 学生任务列表明确返回未开始、进行中、已提交、已逾期和已批改状态。
-
-### 6.3 提醒与通知
-
-- 支持任务发布、即将截止、逾期、批改完成和权益到期提醒。
-- 提醒任务使用幂等键和领取租约,防止多实例重复发送。
-- 通知记录渠道、模板版本、发送状态、失败原因和重试次数。
-- 支持租户级通知策略、免打扰时段和渠道开关。
-
-### 6.4 学情与干预
-
-- 建立学生、班级、知识点和任务维度的学习统计。
-- 支持未完成、连续退步、薄弱知识点和异常作答行为规则。
-- 风险命中后生成教师待办,可记录联系、备注、处理结果和下次跟进时间。
-- 教师只能查看 DataScope 允许的学生和班级。
-
-完成标准:教师能够发布任务、查看进度、完成批改、识别风险并记录干预结果。
-
-## 7. P3:学生学习与个性化
-
-### 7.1 错题复习
-
-- 错题记录包含知识点、错误次数、最近错误、最近复习、掌握状态和下一次复习时间。
-- 区分未掌握、学习中、待巩固和已掌握状态。
-- 复习结果更新间隔,不以单次答对立即永久解决。
-- 错题复习生成稳定会话,并记录生成规则版本。
-
-### 7.2 词汇与间隔学习
-
-- 定义明确的间隔重复算法、等级、下次复习时间和遗忘重置规则。
-- 复习计划按到期时间、掌握程度和每日上限生成。
-- 算法版本和关键输入写入学习事件,保证结果可解释。
-
-### 7.3 自适应练习
-
-- 建立用户知识点掌握度读模型。
-- 根据最近表现、题目难度、重复间隔和任务目标选择题目。
-- 推荐结果保存输入快照、算法版本、候选集合和最终选择。
-- 提供固定规则回退,推荐服务异常时仍可生成可用练习。
-
-### 7.4 成长与激励
-
-- 徽章、连续学习、积分和阶段目标使用可配置规则。
-- 奖励发放必须幂等,并记录触发事件和规则版本。
-- 排行榜支持租户、班级、时间范围和隐私开关。
-- 防止通过重复提交、回放请求或自评结果刷取奖励。
-
-完成标准:学生可以获得稳定、可解释且不会重复奖励的个性化学习计划。
-
-## 8. P4:SaaS 权益与商业闭环
-
-### 8.1 统一权益判定
-
-- 建立统一权益服务,组合操作权限、DataScope、套餐 Feature、额度、区域策略和灰度状态。
-- 统一返回拒绝原因和可观测诊断信息。
-- 前端 bootstrap 只展示最终可用能力,但后端仍独立执行完整判定。
-- 权益变更后可靠失效本地缓存和 Redis 缓存。
-
-### 8.2 教育商品与权益发放
-
-- 商品可绑定课程、题库、练习次数、有效期和会员等级。
-- 支付成功后幂等发放权益。
-- 退款、撤销、订单关闭和订阅到期执行明确的权益回收或冻结策略。
-- 保留每次权益变更的来源订单、规则、操作者和审计记录。
-
-### 8.3 激活码
-
-- 支持批次、渠道、数量、有效期、领取限制和适用租户。
-- 激活过程使用事务和唯一约束,防止重复核销。
-- 激活结果与权益服务联动,并支持撤销审计。
-- 提供批次使用率、渠道效果和异常核销报表。
-
-### 8.4 租户自助运营
-
-- onboarding 使用可恢复状态机覆盖租户、Owner、域名、品牌、套餐和支付配置。
-- 域名验证、证书和网关配置进入后台任务并保留诊断信息。
-- 主题、导航和模块配置支持草稿、预览、发布、版本和回滚。
-- 平台支持面向指定租户查看能力、用量、账务、任务和配置异常。
-
-完成标准:租户能够完成开通、配置、购买、使用、续费和故障诊断,不依赖人工修改数据库。
-
-## 9. P5:产品界面与契约交付
-
-### 9.1 平台端
-
-- 完成租户 onboarding、域名、套餐、账务、用量、题库和运营任务工作台。
-- 所有长任务显示进度、失败原因、重试和结果下载入口。
-- 提供租户能力诊断和配置版本回滚入口。
-
-### 9.2 租户管理端与教师端
-
-- 完成员工、角色、学生、班级、内容、任务、学情、商品和订单工作流。
-- 页面操作权限与后端权限清单保持一致。
-- 批量操作必须先展示影响范围和失败明细。
-
-### 9.3 学生端
-
-- 完成运行时 bootstrap、登录、任务、练习、错题、词汇、视频、权益和订单闭环。
-- 网络重试统一携带幂等键和客户端序列。
-- 明确处理会话过期、版本冲突、权益不足和任务已结束状态。
-
-### 9.4 契约门禁
-
-- 每次 Controller 变更后重新生成 OpenAPI 和前端类型。
-- CI 检查 OpenAPI operation、DTO 和前端生成产物是否同步。
-- 禁止前端手写后端枚举值、权限代码和请求模型。
-
-完成标准:每类用户都可以在界面中完成对应业务闭环,且不存在仅有 API、没有可操作入口的已发布能力。
-
-## 10. P6:性能、扩展与可观测性
-
-### 10.1 查询与读模型
-
-- 将学习统计的多次顺序查询改为条件聚合或专用汇总读模型。
-- 将趋势按日期、知识点和班级的聚合下推 PostgreSQL。
-- 为高频筛选建立与实际查询匹配的复合索引,并使用真实执行计划验证。
-- 控制分页上限,避免无界列表和大对象图加载。
-- 为核心端点建立单请求数据库命令数预算。
-
-### 10.2 缓存策略
-
-- 缓存目录、运行时配置、Feature 快照、公共内容和稳定聚合结果。
-- 缓存键必须包含租户、资源版本和影响结果的策略版本。
-- 写操作提交成功后再执行缓存失效;失效失败必须可重试。
-- 记录缓存命中率、回源率、失效延迟和热键。
-
-### 10.3 后台处理与多实例
-
-- 所有任务领取继续使用 PostgreSQL 租约和 `FOR UPDATE SKIP LOCKED`。
-- 生命周期扫描和周期性调度增加跨实例互斥或唯一调度记录。
-- 任务处理器必须幂等,并区分可重试和永久失败。
-- 记录任务排队时间、执行时间、重试次数、租约过期和死任务数量。
-
-### 10.4 业务性能测试
-
-- 保留公共缓存读和依赖就绪场景。
-- 增加带 JWT、权限、租户解析和 DataScope 的认证分页读。
-- 增加创建练习、并发答题、交卷、报告和排行榜场景。
-- 增加下单、支付回调、退款和权益发放场景。
-- 增加导入、导出和提醒后台任务积压恢复场景。
-- 结果必须报告目标速率、实际 QPS、状态分布、错误率、p95、p99、丢弃迭代和依赖指标。
-- 稳态容量测试至少持续 30 分钟,并使用接近生产的数据量和独立发压端。
-
-### 10.5 可观测性与 SLO
-
-- 建立 API 延迟、错误率、数据库命令数、连接池等待和慢 SQL 指标。
-- 建立 Redis 延迟、命中率、连接失败和缓存失效指标。
-- 建立答题冲突、重复交卷、评分失败、支付回调失败和权益补偿指标。
-- 日志统一包含请求 ID、租户 ID、用户 ID、操作、任务 ID 和业务对象 ID,敏感值必须脱敏。
-- 为认证、练习、支付、后台任务和数据库连接池设置发布告警门槛。
-
-完成标准:核心业务拥有可重复的容量基线,扩容不会导致重复任务、重复发放或状态竞争。
-
-## 11. 每阶段统一交付物
-
-每个阶段合并前必须同时交付:
-
-- Domain、Application、Infrastructure 和 API 边界清晰的实现。
-- 可审查的 EF Core Migration;特殊 PostgreSQL 约束使用手写 SQL。
-- DTO、OpenAPI operation、错误码和生成的前端类型。
-- 单元测试、API 集成测试和真实 PostgreSQL 集成测试。
-- 跨租户、越权、重复请求、并发竞争和失败回滚负向测试。
-- 必要的指标、结构化日志和运维配置。
-- 对应平台端、租户端、教师端或学生端工作流。
-- 发布、回滚、数据兼容和缓存失效说明。
-
-## 12. 统一发布门禁
-
-发布候选必须满足:
-
-```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
-dotnet ef migrations script --project Tiku.Infrastructure --startup-project Tiku.DbMigrator
-git diff --check
-```
-
-涉及数据库或种子数据时还必须:
-
-- 在 Development 环境运行真实 `Tiku.DbMigrator`。
-- 再运行一次迁移器验证幂等性。
-- 验证迁移前后关键数据兼容性。
-- 验证真实 PostgreSQL 下的租户隔离、约束和并发行为。
-
-涉及性能敏感路径时还必须:
-
-- 运行对应业务场景压测。
-- 对照最近一次有效基线检查吞吐、p95、p99、错误率和数据库命令数。
-- 性能退化未解释或超过阶段门槛时不得发布。
-
-## 13. 建议执行顺序
-
-严格按以下顺序启动开发:
-
-1. 服务端评分与题目快照。
-2. 答题幂等、会话版本和客户端序列。
-3. 并发安全交卷与不可变报告。
-4. 内容生命周期、题集和练习蓝图。
-5. 班级、任务、提醒、学情和教师干预。
-6. 错题间隔复习、词汇学习和自适应练习。
-7. 套餐权益、教育商品、支付和激活码联动。
-8. 完成各角色产品界面及 OpenAPI 契约门禁。
-9. 聚合读模型、业务压测、多实例安全和 SLO 告警。
-
-P0 未通过发布门禁前,不应上线积分奖励、排行榜或基于正确率的推荐;这些能力依赖可信评分结果。
diff --git a/docs/operations.md b/docs/operations.md
index a743cb8..cd9febb 100644
--- a/docs/operations.md
+++ b/docs/operations.md
@@ -55,6 +55,8 @@ dotnet run --project Tiku.DbMigrator -- --bootstrap-platform-admin
Redis key 使用环境前缀;配置解析会强制 `AbortOnConnectFail=false`。Redis 不是用户、Session、权限、套餐或用量的权威数据源。
+授权缓存由 `Security:AuthorizationCache` 配置,默认 `Mode` 为 `Disabled`。切换为 `Shadow` 或 `Active` 前,应先确认 API 与 Worker 使用同一 Redis 和 PostgreSQL,并观察 `Tiku.Security.AuthorizationCache` 的 mismatch、fallback 与 Redis 延迟指标。回滚只需切回 `Disabled`,不应回退授权版本或失效事件相关数据库结构。详细故障语义见[认证、授权与租户隔离](architecture/security-and-tenancy.md#redis-授权缓存模式)。
+
## Worker 与后台处理配置
```json
diff --git a/docs/quickstart.md b/docs/quickstart.md
index 2623598..9afabe9 100644
--- a/docs/quickstart.md
+++ b/docs/quickstart.md
@@ -1,47 +1,61 @@
-# 空数据库到租户建站
+# 本地开发快速上手
-本页记录 Development 环境从全新 PostgreSQL 数据库完成平台管理员、租户、Owner 激活、网站发布和学生端访问的真实流程。数据库迁移只由 `Tiku.DbMigrator` 执行,API 不会自动更新 Schema。
+本页用于日常开发:初始化依赖、迁移数据库、启动 API/Worker/平台前端并完成基础验证。若要从空数据库验收“创建租户 → Owner 激活 → 发布站点”的完整流程,请改看[空数据库到租户建站验收](tenant-provisioning.md)。
-## 1. 准备环境
+## 前置依赖
-需要 .NET 10、Node.js 24+、npm 11+、PostgreSQL、Redis,以及 `psql`、`createdb`、`dropdb`。
+- .NET 10 SDK
+- Node.js 24+、npm 11+
+- PostgreSQL
+- Redis(Development 可不配置;涉及分布式缓存、频控或完整验收时应启动)
```bash
dotnet --version
node --version
npm --version
pg_isready -h 127.0.0.1 -p 5432
-redis-cli -h 127.0.0.1 -p 6379 ping
```
-首次拉取代码后安装依赖:
+首次拉取代码后恢复依赖:
```bash
dotnet restore TIKU-BACKEND.slnx
npm --prefix Tiku.PlatformAdmin.Web install
-npm --prefix /path/to/tiku-saas-web install
```
-## 2. 创建空数据库
+## 配置数据库
-以下操作只针对本地数据库 `tiku`。如果它已经包含需要保留的数据,请先备份,不要执行清理命令。
+Development 未配置连接串时,默认使用当前系统用户连接本机 `tiku` 数据库:
+
+```text
+Host=localhost;Database=tiku;Username=<当前系统用户>
+```
+
+首次使用可创建数据库:
```bash
-dropdb --if-exists -h 127.0.0.1 -U <数据库用户> tiku
createdb -h 127.0.0.1 -U <数据库用户> tiku
```
-Development 未配置连接串时默认使用当前系统用户连接本机 `tiku`。其他用户或端口应显式设置:
+使用其他地址、端口或账号时,通过环境变量覆盖:
```bash
export ConnectionStrings__Database='Host=127.0.0.1;Port=5432;Database=tiku;Username=<数据库用户>;Password=<本地密码>'
```
-不要把连接串、密码或 Token 写入 `appsettings*.json`、README 或 Git。
+不要把连接串、密码、Token 或私钥写入仓库。
-## 3. 初始化目录、starter 套餐和首个平台账号
+## 迁移与初始化
-先设置一次性 Bootstrap 参数,再执行生产式空库初始化:
+API 不执行 Migration。数据库结构、内置权限/菜单目录和 `starter` 套餐统一由 `Tiku.DbMigrator` 初始化:
+
+```bash
+ASPNETCORE_ENVIRONMENT=Development dotnet run --project Tiku.DbMigrator
+```
+
+默认 Development seed 会在尚无平台角色绑定时创建 `admin@tiku.local`、演示租户和演示运营数据;随机临时密码只在首次创建时输出,首次登录必须改密。
+
+若需要不含演示数据的空库,使用显式 Bootstrap 流程,不要运行默认 Development seed:
```bash
export ASPNETCORE_ENVIRONMENT=Development
@@ -54,157 +68,69 @@ dotnet run --project Tiku.DbMigrator -- \
--bootstrap-platform-admin
```
-该命令按固定顺序执行:
+完整空库验收步骤见[空数据库到租户建站验收](tenant-provisioning.md)。
-1. EF Core Migration;
-2. Feature、Permission、菜单和额度目录;
-3. 内置 `starter` 套餐及其已发布版本;
-4. 可选的平台超级管理员 Bootstrap。
+## 启动运行时
-`starter` 是零元、CNY、已发布的建站基础套餐,包含 `core.backoffice` 和 `marketing.site_content`。首个平台账号使用临时密码,首次登录必须改密。
-
-清除 Bootstrap 密码并再运行一次 Migrator,确认日常重复执行不会创建演示租户或重复目录:
+启动 API:
```bash
-unset TIKU_BOOTSTRAP_PLATFORM_ADMIN_PASSWORD
-unset TIKU_BOOTSTRAP_PLATFORM_ADMIN_EMAIL
-unset TIKU_BOOTSTRAP_PLATFORM_ADMIN_NAME
-
-dotnet run --project Tiku.DbMigrator -- --skip-development-seed
+ASPNETCORE_ENVIRONMENT=Development dotnet run --project Tiku.Api --launch-profile http
```
-Migration 需要 `citext`、`ltree` 和 `pg_trgm` 扩展。执行用户必须可以创建这些扩展,或由数据库管理员预先安装。
-
-## 4. 启动真实服务
-
-确保 Redis 已运行,然后从后端仓库启动 API:
-
-```bash
-export ASPNETCORE_ENVIRONMENT=Development
-export ConnectionStrings__Redis='localhost:6379,abortConnect=false'
-dotnet run --project Tiku.Api --launch-profile http
-```
-
-API 在 Development 会同时拉起平台管理端 Vite 服务:
+`Tiku.Api.csproj` 的 SPA Proxy 会在 Development 启动 `Tiku.PlatformAdmin.Web` 的 Vite 服务。默认入口:
- 平台管理端:
- API:
- Scalar:
- OpenAPI:
+- Liveness:
- Readiness:
-不要使用 `http://localhost:5090/platform-admin/` 作为开发入口;该路径受 API 授权保护,未登录访问返回 401。
-
-在 `tiku-saas-web` 仓库另开终端,使用真实 API 模式启动租户前端:
+后台循环不在 API 内运行。需要处理域名、订阅、任务队列、授权缓存失效或商业账务时,另开终端启动 Worker:
```bash
-VITE_DATA_MODE=api \
-VITE_DEV_API_TARGET='http://localhost:5090' \
-npm run dev -- --host 0.0.0.0 --port 5180
+ASPNETCORE_ENVIRONMENT=Development dotnet run --project Tiku.Worker
```
-浏览器始终请求同源 `/api`,Vite 只在服务端把它代理到 `VITE_DEV_API_TARGET`。代理保留原始 Host,因此 `school.localhost` 能由后端解析到正确租户。
-
-## 5. 浏览器建站流程
-
-### 5.1 平台首次登录
-
-1. 打开 ;
-2. 使用 Bootstrap 邮箱和临时密码登录;
-3. 按页面要求设置新密码;
-4. 进入“租户管理”。
-
-### 5.2 创建租户和本地域名
-
-点击“新建租户”,至少填写:
-
-- 租户短编码,例如 `school`;
-- 租户名称;
-- 主域名 `school.localhost`;
-- Owner 姓名;
-- Owner 邮箱或手机号。
-
-不选择套餐时,后端自动使用 `starter` 和默认试用天数。Development 配置只对精确的 `localhost` 或 `*.localhost` 启用 DNS/TLS 旁路,通常数秒内显示“DNS 与 TLS 已激活”。其他域名仍走真实 DNS 和网关流程。
-
-### 5.3 签发并消费 Owner 链接
-
-1. 域名 Active 后点击“领取激活链接”;
-2. 填写审计原因并确认;
-3. 立即保存弹窗中的一次性链接;
-4. 用完整链接打开 `http://school.localhost:5180/activate/...#token=...`;
-5. Owner 设置密码后自动进入 `/manage/onboarding`。
-
-Token 只在签发成功弹窗显示一次。租户前端读入 Fragment 后立即清除地址栏;后端消费后不能重放。平台管理员看不到 Owner 密码,也不需要审批 Owner 激活。
-
-### 5.4 配置并发布
-
-向导依次完成:品牌信息、模板、主题样式、页面模块、桌面/移动预览、发布上线。保存草稿不会影响学生端;发布成功后 Runtime 读取已发布配置。
-
-打开或刷新 ,应看到新的品牌、导航、主题和首页模块。退出租户后台后,可在 使用 Owner 账号重新登录。
-
-## 6. 预期状态
-
-| 阶段 | 预期状态 |
-| --- | --- |
-| 刚创建域名 | `pending` |
-| Development 后台任务处理完成 | 域名 `active` |
-| Owner 尚未领取链接 | `ready_to_issue` |
-| 链接签发 | `issued` |
-| Owner 激活并登录 | 进入 `/manage/onboarding` |
-| 草稿完成但未发布 | `ready_to_launch` |
-| 发布完成 | 学生端显示已发布配置 |
-
-## 7. 常见问题
-
-### `.localhost` 一直 Pending
-
-确认 API 使用 `ASPNETCORE_ENVIRONMENT=Development`,并加载:
-
-```json
-{
- "TenantDomains": {
- "PollSeconds": 2,
- "EnableDevelopmentLocalhostBypass": true
- }
-}
-```
-
-API 日志应出现 `Processed ... pending Development tenant domains`。非 Development 环境启用该旁路会在启动时失败。
-
-### 激活页只出现 OPTIONS,没有 POST
-
-不要把 API 地址配置为浏览器请求 Base URL。租户前端真实模式必须使用同源 `/api`,开发代理目标使用:
+如需 Redis,API 与 Worker 应使用同一实例:
```bash
-VITE_DEV_API_TARGET=http://localhost:5090
+export ConnectionStrings__Redis='localhost:6379,abortConnect=false'
```
-确保旧的 `VITE_API_BASE_URL` 未注入进程,并重启 Vite。
+## 验证修改
-### 激活失败后地址栏已没有 Token
+```bash
+dotnet build TIKU-BACKEND.slnx --no-restore
+dotnet test TIKU-BACKEND.slnx --no-build
+dotnet format TIKU-BACKEND.slnx --verify-no-changes --no-restore
+npm --prefix Tiku.PlatformAdmin.Web run check
+dotnet ef migrations has-pending-model-changes \
+ --project Tiku.Infrastructure \
+ --startup-project Tiku.DbMigrator \
+ --no-build
+git diff --check
+```
-如果后端尚未消费 Token,可重新打开平台最初交付的完整链接。已经消费、过期或丢失明文时,必须由平台撤销并重新签发,不能从数据库或日志恢复。
+PostgreSQL 特有的 Migration、事务、约束和租户隔离行为必须由真实 PostgreSQL 集成测试验证,EF InMemory 不能替代。接口、DTO 和错误响应以当前运行时 OpenAPI/Scalar 为准。
-### 发布后旧标签仍显示筹备页
+## 常见问题
-草稿与已发布配置相互隔离。确认向导显示发布成功后,刷新学生端标签,让它重新请求 Runtime Bootstrap。
+### API 报数据库不可用
-### Cookie 没有建立
+确认 PostgreSQL 已启动、数据库存在,并核对 `ConnectionStrings__Database` 或 `DATABASE_URL`。非 Development 环境没有本地默认连接串。
-必须通过 `school.localhost:5180` 访问激活和后台,不能改用 `localhost:5180` 或把 `tenantId` 填进请求。浏览器 Session 使用 Secure/HttpOnly Cookie,写请求使用 CSRF 双提交 Token,前端不得降级保存 JWT。
+### 找不到平台管理员临时密码
+
+默认 Development seed 和显式 Bootstrap 都只在创建账号时输出一次临时密码,后续运行不会重放。不要从日志或数据库恢复明文;应通过受控流程重置,或在确认无需保留本地数据后重建开发数据库。
### Readiness 返回 503
-确认 PostgreSQL 和 Redis 均可访问。匿名 readiness 只返回总体状态;依赖详情需要具有 `platform:operations:view` 权限的平台账号。
+`/api/health/ready` 会检查 PostgreSQL 和已配置的 Redis。先验证数据库连接;配置 Redis 后还需确认 Redis 可访问。匿名响应不会暴露依赖详情。
-## 8. 清理
+### API 启动了但后台任务不执行
-先停止 API、平台 Vite 和租户 Vite,再只删除明确的本地数据库:
+Production 和常规 Development 都需要独立运行 `Tiku.Worker`。Development 仅额外在 API 中注册本地域名生命周期旁路,不代表 API 承载全部 Worker 循环。
-```bash
-dropdb -h 127.0.0.1 -U <数据库用户> tiku
-```
-
-该操作不可恢复,会删除本轮创建的平台账号、租户、Session、草稿和发布配置。
-
-更多配置见[配置与后台任务](operations.md),安全边界见[认证、授权与租户隔离](architecture/security-and-tenancy.md)。
+下一步可阅读[系统架构与业务边界](architecture/overview.md)、[认证、授权与租户隔离](architecture/security-and-tenancy.md)和[配置与后台任务](operations.md)。
diff --git a/docs/redis-authorization-cache.md b/docs/redis-authorization-cache.md
deleted file mode 100644
index c490b75..0000000
--- a/docs/redis-authorization-cache.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# Redis 认证授权缓存
-
-## 请求链路
-
-受保护请求先在本地完成 JWT 验签,再通过一次 Redis MGET 校验 Session、用户、租户、成员资格和持久化授权版本。权限快照使用 60 秒进程内缓存和 5 分钟 Redis 缓存;本地快照键包含授权版本,因此撤权后的下一请求不会继续使用旧权限。PostgreSQL 始终是事实源,Redis 读取失败时绕过本地快照并回退数据库。
-
-缓存不保存 JWT、Refresh Token、手机号或邮箱。Redis key 使用环境隔离前缀,并区分 platform/tenant realm、tenant、user 和 session。
-
-## 配置与故障语义
-
-```json
-{
- "Security": {
- "AuthorizationCache": {
- "Mode": "Disabled",
- "LocalSnapshotSeconds": 60,
- "DistributedStateSeconds": 60,
- "DistributedSnapshotSeconds": 300,
- "JitterPercent": 20
- }
- }
-}
-```
-
-- `Disabled`:保持 PostgreSQL 权威读取,仅维护持久化授权版本。
-- `Shadow`:PostgreSQL 决策仍为准,同时读取、回填和比较 Redis 结果。
-- `Active`:Redis 为主要读取路径,缓存缺失或不可用时回退 PostgreSQL。
-- Redis 与 PostgreSQL 同时不可用时返回 `503`,错误码为 `auth_security_unavailable`。
-
-生产环境的 API 和 Worker 都必须配置 `ConnectionStrings:Redis` 或 `REDIS_URL`。Worker 重试 `authorization_cache_invalidations` 中未完成的失效事件;Redis 版本写入是单调的,旧事件不会覆盖新版本。
-
-## 发布与回滚
-
-1. 先部署迁移,保持 `Disabled`。
-2. 切换 `Shadow`,观察 `Tiku.Security.AuthorizationCache` 指标中的 mismatch、fallback 和 Redis 延迟。
-3. 确认无非并发不一致后,对单实例启用 `Active`,再逐步扩容。
-4. 回滚时只把模式切回 `Disabled`,不回退数据库迁移。
-
-RBAC 表和权限目录由 PostgreSQL 触发器在业务事务内推进授权版本并写入失效事件。任何新增的用户、成员、租户、Session 或角色权限写路径,也必须调用 `IAuthorizationStateInvalidator` 完成同步 Redis 失效。
diff --git a/docs/tenant-provisioning.md b/docs/tenant-provisioning.md
new file mode 100644
index 0000000..3123f02
--- /dev/null
+++ b/docs/tenant-provisioning.md
@@ -0,0 +1,210 @@
+# 空数据库到租户建站验收
+
+本页记录 Development 环境从全新 PostgreSQL 数据库完成平台管理员、租户、Owner 激活、网站发布和学生端访问的真实流程。数据库迁移只由 `Tiku.DbMigrator` 执行,API 不会自动更新 Schema。
+
+## 1. 准备环境
+
+需要 .NET 10、Node.js 24+、npm 11+、PostgreSQL、Redis,以及 `psql`、`createdb`、`dropdb`。
+
+```bash
+dotnet --version
+node --version
+npm --version
+pg_isready -h 127.0.0.1 -p 5432
+redis-cli -h 127.0.0.1 -p 6379 ping
+```
+
+首次拉取代码后安装依赖:
+
+```bash
+dotnet restore TIKU-BACKEND.slnx
+npm --prefix Tiku.PlatformAdmin.Web install
+npm --prefix /path/to/tiku-saas-web install
+```
+
+## 2. 创建空数据库
+
+以下操作只针对本地数据库 `tiku`。如果它已经包含需要保留的数据,请先备份,不要执行清理命令。
+
+```bash
+dropdb --if-exists -h 127.0.0.1 -U <数据库用户> tiku
+createdb -h 127.0.0.1 -U <数据库用户> tiku
+```
+
+Development 未配置连接串时默认使用当前系统用户连接本机 `tiku`。其他用户或端口应显式设置:
+
+```bash
+export ConnectionStrings__Database='Host=127.0.0.1;Port=5432;Database=tiku;Username=<数据库用户>;Password=<本地密码>'
+```
+
+不要把连接串、密码或 Token 写入 `appsettings*.json`、README 或 Git。
+
+## 3. 初始化目录、starter 套餐和首个平台账号
+
+先设置一次性 Bootstrap 参数,再执行生产式空库初始化:
+
+```bash
+export ASPNETCORE_ENVIRONMENT=Development
+export TIKU_BOOTSTRAP_PLATFORM_ADMIN_EMAIL='<平台管理员邮箱>'
+export TIKU_BOOTSTRAP_PLATFORM_ADMIN_PASSWORD='<临时密码>'
+export TIKU_BOOTSTRAP_PLATFORM_ADMIN_NAME='<显示名称>'
+
+dotnet run --project Tiku.DbMigrator -- \
+ --skip-development-seed \
+ --bootstrap-platform-admin
+```
+
+该命令按固定顺序执行:
+
+1. EF Core Migration;
+2. Feature、Permission、菜单和额度目录;
+3. 内置 `starter` 套餐及其已发布版本;
+4. 可选的平台超级管理员 Bootstrap。
+
+`starter` 是零元、CNY、已发布的建站基础套餐,包含 `core.backoffice` 和 `marketing.site_content`。首个平台账号使用临时密码,首次登录必须改密。
+
+清除 Bootstrap 密码并再运行一次 Migrator,确认日常重复执行不会创建演示租户或重复目录:
+
+```bash
+unset TIKU_BOOTSTRAP_PLATFORM_ADMIN_PASSWORD
+unset TIKU_BOOTSTRAP_PLATFORM_ADMIN_EMAIL
+unset TIKU_BOOTSTRAP_PLATFORM_ADMIN_NAME
+
+dotnet run --project Tiku.DbMigrator -- --skip-development-seed
+```
+
+Migration 需要 `citext`、`ltree` 和 `pg_trgm` 扩展。执行用户必须可以创建这些扩展,或由数据库管理员预先安装。
+
+## 4. 启动真实服务
+
+确保 Redis 已运行,然后从后端仓库启动 API:
+
+```bash
+export ASPNETCORE_ENVIRONMENT=Development
+export ConnectionStrings__Redis='localhost:6379,abortConnect=false'
+dotnet run --project Tiku.Api --launch-profile http
+```
+
+API 在 Development 会同时拉起平台管理端 Vite 服务:
+
+- 平台管理端:
+- API:
+- Scalar:
+- OpenAPI:
+- Readiness:
+
+不要使用 `http://localhost:5090/platform-admin/` 作为开发入口;该路径受 API 授权保护,未登录访问返回 401。
+
+在 `tiku-saas-web` 仓库另开终端,使用真实 API 模式启动租户前端:
+
+```bash
+VITE_DATA_MODE=api \
+VITE_DEV_API_TARGET='http://localhost:5090' \
+npm run dev -- --host 0.0.0.0 --port 5180
+```
+
+浏览器始终请求同源 `/api`,Vite 只在服务端把它代理到 `VITE_DEV_API_TARGET`。代理保留原始 Host,因此 `school.localhost` 能由后端解析到正确租户。
+
+## 5. 浏览器建站流程
+
+### 5.1 平台首次登录
+
+1. 打开 ;
+2. 使用 Bootstrap 邮箱和临时密码登录;
+3. 按页面要求设置新密码;
+4. 进入“租户管理”。
+
+### 5.2 创建租户和本地域名
+
+点击“新建租户”,至少填写:
+
+- 租户短编码,例如 `school`;
+- 租户名称;
+- 主域名 `school.localhost`;
+- Owner 姓名;
+- Owner 邮箱或手机号。
+
+不选择套餐时,后端自动使用 `starter` 和默认试用天数。Development 配置只对精确的 `localhost` 或 `*.localhost` 启用 DNS/TLS 旁路,通常数秒内显示“DNS 与 TLS 已激活”。其他域名仍走真实 DNS 和网关流程。
+
+### 5.3 签发并消费 Owner 链接
+
+1. 域名 Active 后点击“领取激活链接”;
+2. 填写审计原因并确认;
+3. 立即保存弹窗中的一次性链接;
+4. 用完整链接打开 `http://school.localhost:5180/activate/...#token=...`;
+5. Owner 设置密码后自动进入 `/manage/onboarding`。
+
+Token 只在签发成功弹窗显示一次。租户前端读入 Fragment 后立即清除地址栏;后端消费后不能重放。平台管理员看不到 Owner 密码,也不需要审批 Owner 激活。
+
+### 5.4 配置并发布
+
+向导依次完成:品牌信息、模板、主题样式、页面模块、桌面/移动预览、发布上线。保存草稿不会影响学生端;发布成功后 Runtime 读取已发布配置。
+
+打开或刷新 ,应看到新的品牌、导航、主题和首页模块。退出租户后台后,可在 使用 Owner 账号重新登录。
+
+## 6. 预期状态
+
+| 阶段 | 预期状态 |
+| --- | --- |
+| 刚创建域名 | `pending` |
+| Development 后台任务处理完成 | 域名 `active` |
+| Owner 尚未领取链接 | `ready_to_issue` |
+| 链接签发 | `issued` |
+| Owner 激活并登录 | 进入 `/manage/onboarding` |
+| 草稿完成但未发布 | `ready_to_launch` |
+| 发布完成 | 学生端显示已发布配置 |
+
+## 7. 常见问题
+
+### `.localhost` 一直 Pending
+
+确认 API 使用 `ASPNETCORE_ENVIRONMENT=Development`,并加载:
+
+```json
+{
+ "TenantDomains": {
+ "PollSeconds": 2,
+ "EnableDevelopmentLocalhostBypass": true
+ }
+}
+```
+
+API 日志应出现 `Processed ... pending Development tenant domains`。非 Development 环境启用该旁路会在启动时失败。
+
+### 激活页只出现 OPTIONS,没有 POST
+
+不要把 API 地址配置为浏览器请求 Base URL。租户前端真实模式必须使用同源 `/api`,开发代理目标使用:
+
+```bash
+VITE_DEV_API_TARGET=http://localhost:5090
+```
+
+确保旧的 `VITE_API_BASE_URL` 未注入进程,并重启 Vite。
+
+### 激活失败后地址栏已没有 Token
+
+如果后端尚未消费 Token,可重新打开平台最初交付的完整链接。已经消费、过期或丢失明文时,必须由平台撤销并重新签发,不能从数据库或日志恢复。
+
+### 发布后旧标签仍显示筹备页
+
+草稿与已发布配置相互隔离。确认向导显示发布成功后,刷新学生端标签,让它重新请求 Runtime Bootstrap。
+
+### Cookie 没有建立
+
+必须通过 `school.localhost:5180` 访问激活和后台,不能改用 `localhost:5180` 或把 `tenantId` 填进请求。浏览器 Session 使用 Secure/HttpOnly Cookie,写请求使用 CSRF 双提交 Token,前端不得降级保存 JWT。
+
+### Readiness 返回 503
+
+确认 PostgreSQL 和 Redis 均可访问。匿名 readiness 只返回总体状态;依赖详情需要具有 `platform:operations:view` 权限的平台账号。
+
+## 8. 清理
+
+先停止 API、平台 Vite 和租户 Vite,再只删除明确的本地数据库:
+
+```bash
+dropdb -h 127.0.0.1 -U <数据库用户> tiku
+```
+
+该操作不可恢复,会删除本轮创建的平台账号、租户、Session、草稿和发布配置。
+
+日常开发启动见[本地开发快速上手](quickstart.md),更多配置见[配置与后台任务](operations.md),安全边界见[认证、授权与租户隔离](architecture/security-and-tenancy.md)。