@@ -1,158 +1,210 @@
# 本地开发与运行
# 空数据库到租户建站
本页用于从全新开发环境启动当前 TIKU Backend 。数据库迁移由 DbMigrator 执行, API 不会自动创建或 更新 s chema。
本页记录 Development 环境从全新 PostgreSQL 数据库完成平台管理员、租户、Owner 激活、网站发布和学生端访问的真实流程 。数据库迁移只 由 `Tiku. DbMigrator` 执行, API 不会自动更新 S chema。
## 1. 准备环境
必需:
- .NET 10 SDK;
- PostgreSQL;
- `psql` 、`createdb` 等 PostgreSQL 命令行工具。
可选:
- Redis 7;
- ClamAV( 验证资源安全扫描时需要) 。
需要 .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
psql --version
redis-cli -h 127.0.0.1 -p 6379 ping
```
## 2. 还原并构建
首次拉取代码后安装依赖:
```bash
git clone <repository-url> TIKU-BACKEND
cd TIKU-BACKEND
dotnet restore TIKU-BACKEND.slnx
dotnet build TIKU-BACKEND.slnx --no-restore
npm --prefix Tiku.PlatformAdmin.Web install
npm --prefix /path/to/tiku-saas-web install
```
## 3 . 创建 PostgreSQL 数据库
## 2 . 创建空 数据库
当前系统用户能本地登录 PostgreSQL 时:
以下操作只针对本地数据库 `tiku` 。如果它已经包含需要保留的数据,请先备份,不要执行清理命令。
```bash
createdb -h 127.0.0.1 -U " $( whoami) " tiku
dropdb --if-exists -h 127.0.0.1 -U <数据库用户> tiku
createdb -h 127.0.0.1 -U <数据库用户> tiku
```
Development 未显式 配置连接串时, API、DbMigrator 和设计时 EF 工具默认使用:
```text
Host=localhost;Database=tiku;Username=<当前系统用户>
```
其他用户、端口或认证方式使用环境变量:
Development 未配置连接串时默认使用当前系统用户连接本机 `tiku` 。其他用户或端口应显式设置 :
```bash
export DATABASE_URL = 'Host=127.0.0.1;Port=5432;Database=tiku;Username=<数据库用户>;Password=<本地密码>'
export ConnectionStrings__Database = 'Host=127.0.0.1;Port=5432;Database=tiku;Username=<数据库用户>;Password=<本地密码>'
```
不要把含密码的 连接串写入 `appsettings*.json` 、README 或 Git。
不要把连接串、密码或 Token 写入 `appsettings*.json` 、README 或 Git。
## 4 . 执行迁移和 seed
## 3 . 初始化目录、starter 套餐和首个平台账号
先设置一次性 Bootstrap 参数,再执行生产式空库初始化:
```bash
ASPNETCORE_ENVIRONMENT = Development dotnet run --project Tiku.DbMigrator
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
```
DbMigrator 会 :
该命令按固定顺序执行 :
1. 执行所有 EF Core Migration;
2. seed 内置 Feature、Permission、菜单和额度目录;
3. 在全新 Development 数据库创建平台超级管理员。
1. EF Core Migration;
2. Feature、Permission、菜单和额度目录;
3. 内置 `starter` 套餐及其已发布版本;
4. 可选的平台超级管理员 Bootstrap。
```text
账号: admin@tiku.local
密码:首次创建时随机生成,只在当前终端输出一次
```
`starter` 是零元、CNY、已发布的建站基础套餐, 包含 `core.backoffice` 和 `marketing.site_content` 。首个平台账号使用临时密码,首次登录必须改密。
重复运行是幂等的,不会重置密码或再次显示临时密码。首次登录必须改密;不要为了找回密码删除已有业务数据的数据库。
Migration 需要 `citext` 、`ltree` 和 `pg_trgm` 扩展。执行迁移的 PostgreSQL 用户必须有创建扩展的权限,或由管理员预先安装。
## 5. 启动 API
清除 Bootstrap 密码并再运行一次 Migrator, 确认日常重复执行不会创建演示租户或重复目录:
```bash
dotnet run --project Tiku.Api
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
```
默认 Development 入口:
Migration 需要 `citext` 、`ltree` 和 `pg_trgm` 扩展。执行用户必须可以创建这些扩展,或由数据库管理员预先安装。
- 平台管理端:首次在 `Tiku.PlatformAdmin.Web` 执行 `npm install` ;之后启动 `Tiku.Api` 时会在 Development 自动启动前端,访问 < http: // localhost:5173 >
## 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 服务:
- 平台管理端:< http: // localhost:5173 >
- API: < http: // localhost:5090 >
- Scalar: < http: // localhost:5090 / scalar / v1 >
- OpenAPI JSON : < http: // localhost:5090 / openapi / v1 . json >
- Liveness: < http: // localhost:5090 / api / health >
- OpenAPI: < http: // localhost:5090 / openapi / v1 . json >
- Readiness: < http: // localhost:5090 / api / health / ready >
OpenAPI 和 Scalar 仅在 Development 映射。接口路径、输入字段、响应模型和授权要求以这里生成的文档为准 。
不要使用 `http://localhost:5090/platform-admin/` 作为开发入口;该路径受 API 授权保护,未登录访问返回 401 。
## 6. 可选:启动 Redis
本地单实例开发可以不配置 Redis。需要验证安全频控、Feature 缓存和 Output Cache 时,先启动本地服务,再设置:
在 `tiku-saas-web` 仓库另开终端,使用真实 API 模式启动租户前端:
```bash
export ConnectionStrings__Redis = 'localhost:6379,abortConnect=false'
VITE_DATA_MODE = api \
VITE_DEV_API_TARGET = 'http://localhost:5090' \
npm run dev -- --host 0.0.0.0 --port 5180
```
Production 必须配置 Redis; PostgreSQL 仍是用户、Session、权限、套餐和用量的权威数据源 。
浏览器始终请求同源 `/api` , Vite 只在服务端把它代理到 `VITE_DEV_API_TARGET` 。代理保留原始 Host, 因此 `school.localhost` 能由后端解析到正确租户 。
## 7 . 启动 Worker 与 ClamAV
## 5 . 浏览器建站流程
API 不处理后台循环。另开终端启动 Worker:
### 5.1 平台首次登录
1. 打开 < http: // localhost:5173 > ;
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 读取已发布配置。
打开或刷新 < http: // school . localhost:5180 /> ,应看到新的品牌、导航、主题和首页模块。退出租户后台后,可在 < http: // school . localhost:5180 / manage / login > 使用 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
dotnet run --project Tiku.Worker
VITE_DEV_API_TARGET = http://localhost:5090
```
`Worker__Enabled=false` 仅用于测试或维护。后台任务状态、租约、重试和 `RunAfter` 存在 PostgreSQL; 多个 Worker 通过 advisory lock 和任务租约协调。域名 DNS/TLS 流程只有在 `TenantDomains` 的 CNAME target 和 Gateway 配置完整后才能激活自定义域名 。
确保旧的 `VITE_API_BASE_URL` 未注入进程,并重启 Vite 。
上传确认会创建 `asset_security_scan` 任务。Worker 通过 TCP 3310 连接 ClamAV, 且 ClamAV `StreamMaxLength` 必须不小于 `Storage:MaxUploadBytes` (当前默认均为 500 MiB) 。本地可以使用容器启动 ClamAV, 并确保该限制已配置; ClamAV 不可用时任务会重试,资源保持不可访问。
### 激活失败后地址栏已没有 Token
## 8. 开发验证
如果后端尚未消费 Token, 可重新打开平台最初交付的完整链接。已经消费、过期或丢失明文时, 必须由平台撤销并重新签发, 不能从数据库或日志恢复。
```bash
curl --fail http://localhost:5090/api/health
curl --fail http://localhost:5090/api/health/ready
### 发布后旧标签仍显示筹备页
dotnet test TIKU-BACKEND.slnx --no-build
dotnet format TIKU-BACKEND.slnx --verify-no-changes --no-restore
dotnet ef migrations has-pending-model-changes \
--project Tiku.Infrastructure \
--startup-project Tiku.DbMigrator \
--no-build
git diff --check
```
草稿与已发布配置相互隔离。确认向导显示发布成功后,刷新学生端标签,让它重新请求 Runtime Bootstrap。
`Tiku.IntegrationTests` 会创建临时 PostgreSQL 数据库,验证 API、授权、迁移和租户隔离。测试账户和测试数据库只用于自动化验证。
### Cookie 没有建立
## 常见问题
### 连接 PostgreSQL 失败
```bash
pg_isready -h 127.0.0.1 -p 5432
psql -h 127.0.0.1 -U <数据库用户> -d postgres -c 'select current_user;'
```
确认当前终端的 `DATABASE_URL` 指向真实存在的数据库,并且 API 与 DbMigrator 使用同一连接配置。
### 无法创建 PostgreSQL 扩展
请让数据库管理员安装 `citext` 、`ltree` 、`pg_trgm` ,或授予迁移用户创建这些扩展所需的权限。
### 没看到管理员临时密码
临时密码只在全新 Development 数据库第一次创建管理员时显示。已有管理员时 DbMigrator 会跳过;应使用正常密码恢复流程。
必须通过 `school.localhost:5180` 访问激活和后台,不能改用 `localhost:5180` 或把 `tenantId` 填进请求。浏览器 Session 使用 Secure/HttpOnly Cookie, 写请求使用 CSRF 双提交 Token, 前端不得降级保存 JWT。
### Readiness 返回 503
匿名 readiness 只返回总体 `status` 与 `checkedAt` 。配置了 Redis 连接串但服务未启动时会返回 503; 依赖细节需要使用具有 `platform:operations:view` 权限的平台账号访问 `/api/platform-admin/operations/health` 。
确认 PostgreSQL 和 Redis 均可访问。匿名 readiness 只返回总体状态;依赖详情需要具有 `platform:operations:view` 权限的平台账号 。
### API 出现 HTTPS 重定向警告
## 8. 清理
仅使用 HTTP launch profile 时可能无法确定 HTTPS 端口,不影响 `http://localhost:5090` 的本地访问。需要验证 HTTPS 时使用项目的 `https` profile。
先停止 API、平台 Vite 和租户 Vite, 再只删除明确的本地数据库:
```bash
dropdb -h 127.0.0.1 -U <数据库用户> tiku
```
该操作不可恢复, 会删除本轮创建的平台账号、租户、Session、草稿和发布配置。
更多配置见[配置与后台任务 ](operations.md ),安全边界见[认证、授权与租户隔离 ](architecture/security-and-tenancy.md )。