Files
gongxue-base/README.md
2026-07-12 19:26:57 +08:00

280 lines
13 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.

# tiku-supabase
面向数百租户、单租户十万级学生的 SaaS 题库工程。仓库采用 Supabase/PostgreSQL + Node.js API/Worker + Taro 4 React学生端复用 H5、微信小程序和后续 App 的业务层;租户后台与平台后台首发为响应式 H5。
当前仓库是旧 PocketBase/SQLite 题库的重构目标,不是旧项目的镜像。旧代码和旧数据只作为迁移与功能对照来源。
## 当前状态
生产地基候选已在本地冻结验证,前端可以基于 `apps/taro` 开始正式设计与实现。它还不是“可直接全量放量”的生产版本目标服务器上的真实配置、数据库迁移、Provider、首个平台超管、备份恢复、真实数据抽样、容量证据和生产上线证据仍必须完成。
2026-07-12 基线结果:
| 范围 | 结果 |
| --- | --- |
| clean-room PostgreSQL | 78/78 migrationspublic RLS 140/140tenant RLS 134/134 |
| 租户完整性 | 189/189 租户外键;单租户 100,000 学生基准通过 |
| 后端质量 | API、Worker、Importer、Taro TypeScript 通过 |
| 安全 | production runtime audit 0仓库扫描 0 findings |
| API 容器 | Node 20.20.2/Alpine 3.23 固定摘要;非 root约 53 MB |
| 三端 H5 | production 构建通过;静态烟测 25/25Chrome 交互烟测 33/33 |
| 响应式 | 桌面与 `390x844` 移动探针通过;无运行时异常和页面级横向溢出 |
| 上线门禁 | 缺少真实生产证据时 fail closed当前不会误放行 |
权威基线:
- [生产地基基线](docs/refactor/production-foundation-baseline-20260712.md)
- [clean-room 迁移审计](docs/refactor/clean-room-migration-audit-20260712.md)
- [Taro H5 浏览器 QA](docs/refactor/taro-h5-browser-qa-20260712.md)
- [Taro 供应链基线](docs/refactor/taro-supply-chain-baseline-20260712.md)
- [服务器部署手册](scripts/deploy/README.md)
## 系统边界
```text
学生 H5 / 微信小程序 / 后续 App
租户管理 H5
平台管理 H5
|
v
apps/api 统一鉴权、租户隔离和业务命令
|
+---- PostgreSQL / Supabase Auth / Storage
|
+---- apps/worker 显式队列任务和定时任务
```
- 前端业务数据默认只访问 `apps/api`,不得在页面中直写 Supabase 业务表。
- `x-tenant-id` 只提供租户上下文,不是身份凭证。
- API 与 Worker 使用独立 PostgreSQL 角色 `tiku_api``tiku_worker`
- 两个运行角色的 `BYPASSRLS` 是受控后端边界API 路由必须显式执行身份、租户和权限过滤浏览器、Taro 和 Data API 不得获得这两个凭据。
- 微信小程序只发布学生端。批量导入、复杂财务和平台运营不强行迁入小程序。
## 目录
```text
apps/api/ Node.js 业务 API
apps/taro/ Taro 4 React学生/租户/平台三端
apps/worker/ 队列消费者、平台任务、导入导出和资源复检
packages/db/ PostgreSQL 连接池与共享数据库配置
packages/domain/ 共享领域常量和类型
supabase/migrations/ schema、RLS、索引、约束和安全边界
scripts/import-pocketbase/ PocketBase 导出、dry-run、导入和校验
scripts/deploy/ 服务器脚本、systemd、Nginx 和配置模板
docs/refactor/ 架构、迁移、容量、前端交接和生产证据文档
deploy.sh 新服务器推荐的 release/symlink 发布入口
```
## 本地开发
要求:
- Node.js 20+
- Docker Desktop 或兼容 Docker 环境
- Supabase CLI
- Chrome/Chromium用于 H5 交互烟测
安装和启动:
```bash
npm ci --workspaces --include-workspace-root --include=dev
npm run supabase:start
npm run supabase:reset
npm run dev:api
```
`supabase:reset` 会清空本地数据库,只能用于本地或隔离测试库。需要集成测试数据时使用受保护命令:
```bash
npm run db:smoke-seed:test
```
脚本会同时检查数据库中的 `app_private.environment_safety` 标记和精确确认短语。不要对 staging/production 运行 `supabase:reset``db:smoke-seed:test``test:api``test:rls` 或会重建测试数据的 Worker 集成测试。
常用开发命令:
```bash
npm run dev:api
npm run dev:taro:h5
npm run dev:taro:weapp:student
```
Taro 具体页面、跨端能力和公开环境变量见 [apps/taro/README.md](apps/taro/README.md)。
## 验证
日常改动至少运行与改动范围对应的 TypeScript 和 contract 测试:
```bash
npm run check:api
npm run check:worker
npm run check:importer
npm run check:taro
npm run test:readiness
```
三端 H5 正式产物必须分别构建;根脚本 `build:taro:h5` 只等价于学生端构建:
```bash
npm run build:taro:h5:student
npm run build:taro:h5:tenant
npm run build:taro:h5:platform
npm run smoke:taro:h5
TARO_H5_INTERACTION_OUTPUT_DIR=/tmp/tiku-h5-smoke npm run smoke:taro:h5:interaction
npm run audit:taro:supply-chain
npm run guard:taro:visual
node scripts/taro-h5-release-guardrails-test.js --require-dist
npm run manifest:taro:h5 -- --require-dist
```
正式部署目录还必须放入真实的公开 `runtime-config.json`,并使用严格模式:
```bash
node scripts/taro-h5-release-guardrails-test.js --require-dist --require-runtime-config
npm run manifest:taro:h5 -- --require-dist --require-runtime-config
```
Taro 固定为 `4.2.0`。workspace postinstall 会按精确版本和源码 hash 原子应用 H5 Input/Button runtime patch不要使用 `npm ci --ignore-scripts`。Taro CLI/构建工具链尚有已审核 allowlist 内的 audit 告警,任何新增高危依赖或进入 H5/小程序 bundle 的风险都必须重新审查。
## Git 与 Gitea
远端仓库:
```text
https://git.gongxue100.com/chenhaogxjy/tiku-supabase.git
```
Gitea SSH 端口为 `2222`
```bash
git clone ssh://git@git.gongxue100.com:2222/chenhaogxjy/tiku-supabase.git
```
开发流程:
```bash
git switch main
git pull --ff-only origin main
git switch -c codex/<topic>
# 修改、验证、提交后
git push -u origin codex/<topic>
```
在 Gitea 创建 `codex/<topic> -> main` 的 PR。不要 force-push `main`。生产部署必须固定到已评审的 commit SHA而不是在验证过程中继续改动分支。
本轮 production foundation 已按最终整体状态完成验证,可以作为一个受控 baseline 合入 `main`。合并前置不是继续等待功能开发,而是确保待提交文件完整、最终 commit 与验证/证据对应,并让服务器升级按新 runbook 执行。
凭据要求:
- 已在聊天、截图、工单或日志中出现的 token 必须立即吊销。
- 开发电脑优先使用 SSH keyHTTPS token 应交给系统 credential helper不能写入 remote URL。
- 服务器只使用仓库只读 deploy key/token不得复用开发者可写凭据。
- 真实 `.env``deploy.env`、上线 evidence 和 artifacts 已由既有忽略规则保护;真实 runtime config 只放服务器受控目录,仓库仅提交 `*.example.json` 模板。
## 部署选择
| 场景 | 推荐入口 | 配置位置 | 说明 |
| --- | --- | --- | --- |
| 全新测试/预生产服务器 | 部署手册“新测试服务器”分阶段 bootstrap | 独立 `/opt/tiku-saas-staging``/srv/tiku-saas-staging``/etc/tiku-saas-staging` | 当前没有绕过生产门禁的一键 staging 发布入口 |
| 全新生产服务器 | 根目录 `deploy.sh` | `/opt/tiku-saas/shared/` | 必须通过完整生产 evidence |
| 现有云服务器升级 | `scripts/deploy/bin/deploy.sh` 安装到 `/opt/tiku-saas/bin/deploy.sh` | `/etc/tiku-saas/` | 保留原命令,但必须先升级脚本、配置和 systemd units |
服务器持续更新命令仍可以是:
```bash
sudo -u deploy /opt/tiku-saas/bin/deploy.sh
```
但这次基础升级不能直接运行服务器上的旧脚本。旧脚本会原地构建、直接覆盖 H5并重启已经废弃的 `tiku-worker.service`;新版 Worker 强制要求显式 `--job`,旧 unit 会失败。首次覆盖部署必须先按 [服务器部署手册](scripts/deploy/README.md) 完成一次性升级。
新版发布流程包含:
- 独立候选 release 构建,应用与三端 Web 原子切换。
- Taro 供应链、三端 runtime config、manifest、25 项静态与 33 项浏览器交互烟测。
- 生产 env readiness、可选 migration、迁移后的数据库 readiness。
- 与候选 commit 和 artifact SHA-256 绑定的真实 launch gate。
- API healthcheck、线上 H5 hash 校验和代码/Web 回滚。
脚本不会自动备份或回滚数据库、对象存储,也不会自动安装更新后的 systemd/Nginx 模板。涉及 migration、`.service/.timer/.target`、Nginx 或 env schema 变化时,必须先按 runbook 做人工变更和恢复演练。
## 测试服务器
推荐先部署一台生产等价的隔离测试服务器:
- 独立数据库、域名、对象存储 bucket、Auth 项目和 Provider 测试凭据。
- 数据库标记为 `staging``allow_destructive_tests=false`
- API/Worker 仍以 `NODE_ENV=production` 运行,验证生产 fail-fast而不是用 development 配置绕过。
- 不导入生产密钥,不承接真实用户流量,不复用生产数据库或 bucket。
- 可以使用脱敏数据快照,但不得运行 destructive smoke seed。
当前两套部署器都是 fail-closed 的生产发布器,在 production 模式下强制要求完整 launch evidence。仓库目前没有经过验证的“一键 staging 发布模式”,因此不能通过关闭 gate、伪造 production evidence 或套用生产 `/opt``/srv``/etc` 路径来抢跑。
测试服务器当前采用分阶段 bootstrap先在隔离目录 clone 固定 commit完成安装、构建、数据库 bootstrap/migration/readiness、三端 runtime config 和真实测试环境证据;确认系统服务与 Web 路径后,再按照部署手册激活。若只想检查候选构建,停在构建和 smoke 阶段,不切换 Web 和 systemd。后续可以增加带独立路径和独立证据模型的 staging profile但不能把它实现为生产门禁的弱化开关。
## 生产上线门禁
真实 evidence 从模板创建,但不提交 Git
```bash
cp docs/refactor/production-launch-evidence.template.json /secure/path/production-launch-evidence.json
npm run launch:gate -- --evidence /secure/path/production-launch-evidence.json
```
注意:
- evidence 的 `commit` 必须等于待发布 commit。
- 每项 artifact 必须存在且 SHA-256 匹配,默认要求在有效时间窗内。
- 相对 artifact 路径相对于 evidence 文件目录解析,必须把 evidence 与 `launch-artifacts/` 作为完整 bundle 保存。
- 本地 mock、preview、clean-room 报告不能冒充生产证据。
- 三端线上 hash/runtime config 验证通过后才能解除回滚保护。
上线前硬阻断包括:数据库/对象存储备份恢复、runtime role bootstrap、完整 migration、真实 Auth/短信/支付/存储/CORS、首个平台超管、目标规格压测、真实数据抽样、Worker 调度、告警日志和所有人工 attestation。详细顺序见 [生产地基基线](docs/refactor/production-foundation-baseline-20260712.md)。
## 首个平台超管
不要直接插入一个绕过 Auth 的管理员。先在真实 Supabase Auth 中创建或确认身份,再 dry-run
```bash
DATABASE_URL='<tiku_api connection>' \
BOOTSTRAP_PLATFORM_ADMIN_AUTH_USER_ID='<auth.users UUID>' \
BOOTSTRAP_PLATFORM_ADMIN_USERNAME='platform_owner' \
BOOTSTRAP_PLATFORM_ADMIN_NAME='平台负责人' \
npm run bootstrap:platform-admin
```
确认输出后使用精确短语应用:
```bash
DATABASE_URL='<tiku_api connection>' \
BOOTSTRAP_PLATFORM_ADMIN_AUTH_USER_ID='<auth.users UUID>' \
BOOTSTRAP_PLATFORM_ADMIN_USERNAME='platform_owner' \
BOOTSTRAP_PLATFORM_ADMIN_NAME='平台负责人' \
npm run bootstrap:platform-admin -- \
--apply --confirm BOOTSTRAP_FIRST_PLATFORM_ADMIN
```
该脚本只允许创建首个 Auth-bound active platform admin一旦存在有效绑定管理员后续 bootstrap 会永久拒绝,日常员工管理应走平台后台权限流。
## 关键文档
- [重构文档索引](docs/refactor/README.md)
- [架构](docs/refactor/architecture.md)
- [多租户鉴权安全契约](docs/refactor/multitenant-auth-security-contract.md)
- [前端交接索引](docs/refactor/frontend-handoff-index.md)
- [Taro H5 部署](docs/refactor/taro-h5-deployment.md)
- [PocketBase 真实数据迁移](docs/refactor/pocketbase-real-data-migration-runbook.md)
- [4C16G PostgreSQL 调优](docs/refactor/postgresql-4c16g-tuning.md)
- [容量压测](docs/refactor/performance-benchmark-runbook.md)
- [单租户十万学生容量](docs/refactor/tenant-student-capacity-runbook.md)
- [生产上线证据模板](docs/refactor/production-launch-evidence.template.json)
## 安全红线
- 前端只允许持有 Supabase publishable key禁止 service role、数据库密码、短信密钥、支付私钥和对象存储长期密钥。
- 生产 API/Worker 不允许 `local_dev` 存储、mock Provider、legacy auth header 或平台本地管理 key。
- migration 只使用临时注入的标准 migration roleAPI/Worker 运行角色不能执行 DDL。
- 破坏性测试只允许明确标记为 local/test/ci 且 `allow_destructive_tests=true` 的隔离数据库;绝不允许 staging/production并且必须使用精确确认短语。
- migration 是前向操作,代码/Web 回滚不会回滚数据库;先备份、演练兼容性,再迁移。
- 生产证据、访问 token、支付/短信/存储密钥和用户隐私数据不得写入 Git、README 或构建日志。