Files
gongxue-base/README.md
2026-07-02 09:54:01 +08:00

860 lines
73 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
这是题库项目从 PocketBase/SQLite 重构到 Supabase/PostgreSQL 的新后端仓库。
当前仓库重点承载“商用 SaaS 版本”的新架构代码,包括多租户数据库、业务 API、PocketBase 数据导入器、本地验证脚本和重构进度文档。旧 PocketBase/React 项目仍保留在原工作区作为功能参照和迁移来源,但这个 Git 仓库不打算作为旧项目全量镜像。
## 当前状态
更新时间2026-07-02
## 接管快照
截至 2026-07-02当前 `main` 已同步到 Gitea最新前端交付提交为 `f54421f test: align Taro visual guardrails with legacy UI`,其前一个核心实现提交为 `aa71251 fix: align Taro H5 with legacy question bank UI`。另一台工作机接管时,优先从 Gitea 拉取 `main`,不要从服务器的构建产物反向覆盖源码。
本轮已完成的关键变化:
- 学生 H5 已按旧题库主视觉重做浅灰网格背景、旧蓝色主色、PC 侧边栏、移动端底部导航、蓝色学习 banner、白色数据卡、彩色功能模块和紧凑列表。
- 租户后台和平台后台已按旧后台工作台风格收敛:白/灰高密度界面、侧边栏/移动导航、深色激活态、紧凑表格/表单/行布局。
- 受保护页面已补路由守卫Auth/角色校验期间不渲染业务内容;静态 H5 可以加载入口壳,但不应在未鉴权时暴露可用业务数据。
- 三端 H5 首屏入口按构建目标区分:`student``tenant-admin``platform-admin`
- 视觉守卫已从通用圆角/渐变规则调整为旧题库 UI 规则,防止后续改回营销页式大卡片风格。
本地已通过的验证命令:
```bash
npm --workspace @tiku-saas/taro run check
node scripts/taro-route-contract-test.js
npm run guard:taro:visual
node scripts/taro-visual-guardrails-test.js
npm run build:taro:h5:student
npm run build:taro:h5:tenant
npm run build:taro:h5:platform
npm run smoke:taro:h5
npm run smoke:taro:h5:interaction
node scripts/taro-h5-release-guardrails-test.js
```
云服务器当前接管点:
- 服务器仓库:`/opt/tiku-saas/repo`
- H5 发布目录:`/srv/tiku-saas/www/student``/srv/tiku-saas/www/tenant-admin``/srv/tiku-saas/www/platform-admin`
- 发布脚本:`/opt/tiku-saas/bin/deploy.sh`
- 线上 Supabase、自研 API、Nginx、runtime-config 已能基本联通;`https://api.tjszsb.com/api/tenant/resolve?host=app.tjszsb.com` 已返回 `master` 租户。
- Gitea SSH 端口是 `2222`,服务器 `deploy` 用户拉取应使用 `ssh://git@git.gongxue100.com:2222/chenhaogxjy/tiku-supabase.git` 或在 SSH config 中显式配置 `Port 2222`
- 2026-07-02 服务器手动执行 `sudo -u deploy npm run build:taro:h5:student` 时出现 Taro 构建长时间无输出、CPU 持续接近满载、`dist/h5-student` 未更新的情况。接管后建议先中止残留构建进程,清理目标目录,再用 `CI=1 NODE_OPTIONS="--max-old-space-size=4096"` 重新构建三端,详见 `scripts/deploy/README.md` 的“服务器接管和故障恢复”。
## 最新交付快照
截至 2026-07-02当前 `main` 已推送到 Gitea可进入云服务器部署和生产测试阶段。这里的“生产测试”指在真实云服务器、真实域名、真实对象存储和真实 provider 配置下做灰度/演练验证;正式对 C 端或合作商放量前,仍必须通过本文的生产上线证据门禁。
- 后端核心业务已经覆盖旧题库主链路:刷题、背单词、知识手册、分数线、错题本、收藏夹、资料下载、题目视频、会员/订单/优惠券/激活码、个人中心、站内通知、勋章、租户后台、平台 SaaS 管理、公共题库授权/采纳/同步、CRM/销售/代理/分佣、财务对账和 worker 任务。
- 多租户安全底座已经具备商用联调条件:平台/租户/学生三类身份边界、Supabase Auth JWT、迁移期 `tk_` session、RLS 测试、租户角色模板、成员权限、班级/教师/学生范围、字段脱敏、审计日志、私有资源短签名、导入/导出 job 审计均已落地。
- H5/Taro 第一版已经具备前后端联调入口:学生端、租户后台、平台后台三套 H5 构建入口、统一 API client、Supabase client 初始化、运行时公开配置、H5 静态烟测和 32 项真实浏览器交互 smoke 已接入。
- `smoke:launch-persona` 已升级为默认 `LAUNCH_SMOKE_AUTH_MODE=app_session`,可用 `--write` / `--write-md` 生成稳定上线证据文件,覆盖普通学生、租户管理员、平台管理员三类真实 API 角色旅程和越权拒绝。
- 本地真实迁移库最新规模约为 19 个租户、74,131 道题、3,722 个平台用户、3,712 个学生资料、81,160 个练习 session、327,925 条答题记录、38,207 条错题、1,501 个内容资源和 474 条权益。
- 2026-07-01 08:41 本地真实数据压测通过30 并发只读 37,520 请求、0 错误、310.34 req/s、P95 251.08ms50 并发混合读写 25,047 请求、0 错误、410.49 req/s、P95 237.41ms100 并发混合读写 24,116 请求、0 错误、393.56 req/s、P95 437.37ms150 并发混合读写 22,864 请求、0 错误、371.29 req/s、P95 633.46ms。该结果只能作为本机真实数据观察,正式容量必须在目标 4 核 16G 云服务器复跑。
目前已经完成并在本地验证通过的内容:
- Supabase/PostgreSQL 多租户数据库 schema、RLS、索引、触发器。
- `apps/api` 独立业务 API后续供 H5、Taro 小程序、管理后台统一调用;已支持 Supabase Auth JWT 和迁移期 `tk_` session 双入口。
- 租户后台能力:品牌、主题模板/草稿/发布、域名、公开设置、支付账户、登录配置、私密密钥掩码、活动内容、考试日期、题目反馈处理、用户站内通知查看、激活码、优惠券规则/核销报表、勋章管理/手动发放/签到积分反馈自动发放、成员权限、自定义角色模板、班级/教师/学生范围权限、学生批量导入、批量分班、学生备注、跟进任务、跟进效果统计、学习督导自动化预览/生成、督导规则模板、学生批量 CRM 推送、审计日志。
- 租户内容能力:可配置题库入口、任意深度分类树、考试意向标记、题目集合、顺序/随机/全真模拟蓝图、题目录入/更新、视频绑定、分数线、单词、知识手册、资料资源台账、题目/单词/知识手册/分数线/视频 JSON/CSV/Excel 批量导入。
- 学生端能力:题库入口、分类树、题目集合、顺序/随机/模考 session 组卷快照、答题、错题本、收藏夹、背单词卡片学习/发音/收藏练习、个人中心、男女默认预设头像、站内通知、勋章、考试倒计时、签到积分、积分活动任务、积分兑换、题目反馈、排行榜接口租户默认关闭、分数线、AI 择校推荐、题目视频、订单详情/状态轮询、优惠券领取/抵扣、权益、激活码预检查/兑换、资料下载;签到、积分阈值、反馈解决和积分活动可返回自动获得勋章结果,反馈处理/奖励、勋章发放和积分兑换会写入用户站内通知。学生头像不支持上传或第三方头像落库,学生激励默认以勋章自动发放为主,不默认启用排行榜。
- 平台后台能力:租户管理、租户详情、账务资料维护、平台员工创建/授权/启停、平台细粒度权限点、平台审计日志查询和 CSV/JSON 导出、平台审计告警规则/开放告警查询/确认/解决、平台审计告警外部通知渠道和发送事件、SaaS 套餐、订阅、订阅账单候选预览/dry-run/批量生成、自动计费 worker、账单、服务费收款、逾期标记、内部催缴台账、平台催缴外部通知渠道和发送事件、平台用量自动采集 worker、用量记录、SaaS 套餐额度判定、用量超额账单候选预览/dry-run/生成、自动开票 worker 和失败审计告警、公共题库授权。
- 公共题库商业化能力:租户可采纳平台授权题库为本租户副本,并可手动或由 worker 自动同步平台新增/更新题目同步会保护租户自改题目返回冲突而不覆盖后台可查询冲突明细worker 失败会生成租户 `public_question_bank_sync_failed` 通知,恢复成功自动关闭失败通知,平台可用 `/api/platform-admin/question-bank-sync-status``platform:question_bank:ops` 查看跨租户同步运营摘要。
- 题库导出能力:租户内容编辑可按题目集合、内容入口或分类节点导出 JSON、`paper_json`、打印 payload、PDF、Word 和每日一练图片 ZIP 素材包,后端强制租户隔离、答案/解析开关、复合题子题脱敏、导出 job 和审计PDF/Word/ZIP 由 exports worker 生成水印文件或运营素材并发布到 `content_assets``daily_practice` 支持每日一练九宫格 metadata、PDF/Word 版式、9 张 PNG/SVG 卡片和拼图包。
- 销售/代理/CRM 增长链路:邀请码、扫码/分享事件、首绑客资保护、销售统计、团队关系、CRM 配置、跟进分配策略、客资队列和学生批量 CRM 跟进推送。
- `apps/worker` 后台任务进程CRM webhook 队列消费、`lead.created` 客资事件、`student.crm_push` 学生跟进事件、generic/钉钉/飞书/企微机器人发送、签名、失败重试和日志student-supervision worker 可按租户督导规则模板定时生成学习跟进任务commerce worker 可补偿查询微信/支付宝支付和退款状态provider-bills worker 可下载微信/支付宝官方账单并导入资金对账platform-billing worker 可自动为即将到期且未开票的 SaaS 订阅生成服务费账单并写审计platform-usage worker 可按月从权威业务表自动采集学生数、活跃学生、题量、资源数、存储 GB、视频数、视频播放、视频次数消耗、已支付订单、GMV 和有效权益并写入用量台账和审计platform-usage-overage worker 可按上月账期自动生成 `usage_overage` 账单,执行失败会写入脱敏平台审计日志并由审计告警 worker 转为开放告警platform-dunning worker 可扫描逾期未结清服务费账单、标记 overdue、写内部催缴记录和审计platform-dunning-notifications worker 可把内部催缴记录按平台渠道推送到 generic/钉钉/飞书/企微 webhook并记录幂等发送事件platform-audit-alerts worker 可把高风险平台审计动作和自动化失败转换为内部告警并递归脱敏告警 detailsplatform-audit-notifications worker 可把开放审计告警按平台渠道推送到 generic/钉钉/飞书/企微 webhook并记录幂等发送事件assets worker 可复检托管资源元数据、执行内置安全扫描并自动下架异常资源imports worker 可执行大批量导入public-banks worker 可自动同步公共题库采纳副本exports worker 可渲染 PDF/Word 导出文件和每日一练 ZIP 图片素材包。
- 销售/代理分佣和转化看板基础闭环:租户默认比例、成员比例、激活码批次比例、订单/激活码归因、结算单生成、审核、线下打款状态、CSV/JSON 导出、打款凭证登记/复核、销售/代理转化报表、近期未成交客资、CRM 失败/跟进积压和本人/全局权限隔离。
- 订单售后基础闭环:退款请求、审核、处理状态流、微信/支付宝发起退款、微信/支付宝退款查询确认、微信/支付宝退款通知 webhook、退款金额累计、部分/全额退款订单状态、全额退款权益撤销、退款事件和审计日志。
- 资金对账、异常订单和财务凭证闭环:租户财务/运营可通过 `/api/commerce/reconciliation/*` 导入或预览支付/退款账单行,也可创建微信/支付宝官方账单下载任务;后端按租户隔离比对本地订单、支付、退款记录,识别已匹配、金额不一致、状态不一致、供应商有本地无、本地有供应商无、重复行和无效行,并写入对账批次、明细和审计日志;异常明细可创建差错工单,支持分配、开始处理、升级、解决、忽略、重开和事件留痕;`/api/commerce/operations/anomalies` 聚合异常订单风险,`/api/commerce/adjustment-vouchers*` 支持人工调整凭证、复核、事件轨迹和报表。工单和凭证只做财务审核闭环,不直接修改订单、支付、退款或权益。
- PocketBase SQLite 只读导出、JSON dry-run、标准化导入和导入后校验脚本真实旧库 248555 条业务记录已能在干净本地 Supabase 中完成全量导入。
- 本地 Supabase reset、烟测 seed、API 集成测试、完整重构检查命令。
还没有达到生产交付的部分:
- Supabase Auth/JWT、租户角色模板、班级/教师/学生范围权限已可联调;生产前还要做真实云端 Auth/JWKS 回归和 RLS 深测。
- 阿里云/腾讯云短信、微信小程序登录、微信网页登录、QQ 登录、手机号绑定/换绑、微信支付、支付宝主链路、微信/支付宝发起退款/查询确认/退款通知、支付/退款补偿 worker 已完成本地适配;本地阶段使用 mock/fake provider 和回调后业务链路验收,不要求真实平台密钥。资金对账已支持手工/API 账单导入、微信/支付宝官方账单下载任务、provider-bills worker 自动导入比对、差错工单处理、异常订单运营台和人工调整凭证复核报表;真实生产账号、真实回调域名和真实生产账单抽样验收等上线后密钥联调还没接完。
- OSS/COS/Supabase Storage 上传下载签名 provider 已接入上传后校验、PDF/图片预览、资源访问事件、动态水印上下文、锁定资源 CDN 边界、资源复检 worker、内置 `metadata_rules` 安全扫描和外部 HTTP 杀毒/内容安全 scanner 接入层已完成Taro 学生资料页已按短期签名和 `watermark.traceId` 渲染可见水印确认/预览第一版。生产还要配置真实扫描服务 endpoint/token并继续补转码/CDN 级水印、CDN 刷新和对象生命周期策略。
- Excel/CSV 导入解析已完成并复用 `content_import_jobs/items/issues` 管线;大批量异步导入 worker 基础已接入,支持 queued job 消费、重试和审计;导入后复检、模板下载、字段映射 API 和 Taro 租户内容页第一版导入操作台已完成。
- 题库导出已完成服务端结构化 payload、PDF/Word 二进制 worker、每日一练基础导出和每日一练 ZIP 图片素材包;后续还要补更精细试卷模板、多模板排版和导出操作台体验。
- 优惠券复杂规则和核销报表已可联调,包含状态启停、活动分组、最低订单金额、优惠封顶、单用户限次、首单限制、适用套餐/地区、核销明细和活动报表Taro 租户营销中心已接优惠券规则表单、筛选、核销明细和报表第一版。
- 勋章管理、手动发放、签到连续天数、积分阈值、反馈解决、积分活动任务、练习次数、单词掌握和模考成绩系统触发勋章已可联调积分活动任务、积分兑换商品、兑换订单、优惠券兑换履约、租户后台配置和用户站内通知第一版已完成Taro 学生个人中心已接积分任务/兑换/积分明细和消息中心第一版,租户营销中心已接积分任务/兑换操作台和用户通知查看第一版。学生激励默认以后台配置勋章自动发放为主排行榜默认不开启也不在学生端默认请求。CRM 死信运营第一版已完成失败池、日志脱敏、重试/忽略和审计闭环,销售/代理转化看板第一版已完成。后续还要补更细活动效果看板、外部微信订阅消息/短信推送、分佣真实打款 provider、发票、批量凭证上传、CRM 富卡片模板、外部失败告警升级、公共题库版本通知和冲突处理操作台。
- `apps/taro` 已建立 Taro 4 React 跨端前端地基,包含 H5 学生端、租户后台、平台后台三套构建入口、租户解析、统一 API client 和 Supabase Auth client 初始化学生端第一批页面已接入登录、首页、题库、练习、背单词、知识手册、分数线、AI 择校推荐、资料、独立消息中心和个人中心,已新增 `RichContent` 安全渲染组件用于题干、选项、解析、知识手册和逐题复盘H5 端已用 KaTeX 渲染 `$...$``$$...$$``\(...\)``\[...\]` 公式,私有题图可用 `asset:<uuid>`/`content_asset:<uuid>` 资源引用走短期预览签名,已升级背单词为今日计划/单元学习/收藏练习、学习概览、掌握率、收藏数、计划拆分、卡片翻转、发音、美/英音切换和本地位置恢复第一版,知识手册已接章节内搜索、安全文本摘要高亮和目录定位第一版,分数线已接目标地区默认筛选、院校/专业/年份 chip、租户动态字段筛选、结果字段 chip 和趋势摘要第一版AI 择校已接报告生成、历史报告和 Markdown/HTML 导出第一版,资料页已补齐预览/下载的短签名、水印 traceId 和强制水印容器第一版个人中心已接学习报告、14 天趋势、题型表现、最近练习、男女预设头像选择、积分任务/兑换/积分明细和消息中心摘要第一版,独立消息中心已接状态/类型筛选、批量已读、归档/忽略和站内安全跳转第一版;学生端不默认请求排行榜,仅在租户显式开启 `enableLeaderboard` 并完成压测后进入独立排行榜页或活动页;租户后台第一批页面已接入工作台、数据看板、学生/班级、题库内容、营销中心、财务运营和租户设置,学生运营页已接跟进看板、学习督导自动化、督导规则保存和批量 CRM 推送第一版,营销中心已接 CRM 配置、队列筛选、死信失败池、日志查看、重试/忽略、分佣结算、优惠券规则/核销报表、积分任务/兑换操作台和用户通知查看第一版,财务运营已接退款状态机、官方账单任务、对账异常、差错工单和调整凭证第一版,设置页已接主题模板、草稿预览/发布、角色模板和成员绑定第一版;平台后台已接入工作台、租户管理、账务中心、公共题库授权、平台员工管理,以及创建租户、租户详情、状态变更、账务资料维护、平台员工创建/编辑/禁用恢复、权限点勾选、平台审计查询/CSV 导出、开放审计告警确认/解决、审计告警外部通知渠道/事件状态摘要、订阅、订阅账单候选/dry-run/批量生成、自动计费 worker 生成结果查看、收款、逾期预览/催缴记录、催缴外部通知渠道/事件摘要、用量和题库授权第一版写操作。
- 根目录已清理为新 Supabase SaaS monorepo 编排层;旧 PocketBase/React 项目和旧构建产物仅保留在 `参考/` 目录作为迁移参考,不进入 Git 提交。
## 商用功能完成度总览
| 模块 | 当前状态 | 说明 |
| --- | --- | --- |
| 多租户 SaaS 底座 | √ 可联调 | PostgreSQL schema、RLS、租户、品牌、域名、主题、成员权限、平台/租户/学生三类身份边界已建立 |
| 学生刷题主链路 | √ 可联调 | 入口、分类、集合、顺序/随机/模考、答题、错题、收藏、报告、视频、资料、个人中心、勋章、站内通知已接 API |
| 背单词/知识手册/分数线 | √ 可联调 | 列表、学习/阅读、动态筛选、JSON/CSV/Excel 导入和 Taro 第一版页面已具备 |
| 会员/订单/优惠券/激活码 | √ 可联调 | 下单、订单详情/状态轮询、优惠券规则/核销、激活码、权益、退款状态机和对账地基已完成 |
| 国内登录/支付 provider | √ 本地可跑,待真实密钥 | 阿里云/腾讯云短信、微信小程序/网页、QQ、微信支付、支付宝均有 adapter/fake 测试;生产 readiness 已阻断不支持 provider、非 HTTPS/localhost 回调、缺少支付回调和公开配置混入密钥;生产账号和回调域名上云后联调 |
| 租户后台运营 | √ 可联调 | 学生/班级、内容导入导出、营销、优惠券、积分、勋章、CRM、分佣、销售/代理转化、财务运营、主题和角色模板已具备第一版 |
| 平台 SaaS 账务 | √ 可联调 | 套餐、订阅、订阅账单、自动计费、用量采集、超额账单 API/worker、收款、逾期催缴、外部通知和审计已具备 |
| 公共题库商业化 | √ 可联调 | 平台题库授权、单地区/全国 SaaS 范围、租户采纳、手动/自动同步、冲突处理和通知已完成基础闭环 |
| 对象存储/资料安全 | √ 可联调,待生产 AV/CDN | OSS/COS/Supabase Storage 签名、上传确认、短签名预览下载、水印 traceId、复检和安全扫描地基已完成生产配置会拒绝 local_dev、非 HTTPS 公开 URL、非官方阿里云 OSS endpoint、阿里云 OSS 内网直签和未接外部扫描服务 |
| PocketBase 真实数据迁移 | √ 本地跑通,待人工复核 blocker | SQLite 导出、标准化导入、校验和抽样脚本已跑通;正式切换前处理缺用户订单和缺归属手册章节 |
| Taro H5 三端前端 | √ 第一版可构建 | 学生端、租户后台、平台后台均有真实 API 页面;已补 H5 `index.html` 模板和发布产物守卫;后续继续补小程序兼容、视觉精修、状态管理、包体优化和端到端测试 |
| 生产安全/压测交付 | △ 本地真实数据压测已跑,云端待复测 | 2026-07-01 08:41 本地真实迁移库 API 进程压测30 并发只读 0 错误、310.34 req/s、P95 251.08ms50 并发混合读写 0 错误、410.49 req/s、P95 237.41ms100 并发混合读写 0 错误、393.56 req/s、P95 437.37ms150 并发混合读写 0 错误、371.29 req/s、P95 633.46ms。Docker API 2C/4G 受限复核和 DB 2C/8G 未调参悲观复核已留档。上云后必须执行生产 readiness、PostgreSQL shared-host 调优、远程 Auth/RLS、4C16G 复测、`security:repo`、真实 `@codex-security` 扫描和上线证据门禁。 |
更完整的进度看这些文档:
- `docs/refactor/implementation-status.md`
- `docs/refactor/backend-progress.md`
- `docs/refactor/backend-handoff-roadmap.md`
- `docs/refactor/ai-development-guardrails.md`
- `docs/refactor/content-import-contract.md`
- `docs/refactor/object-storage.md`
- `docs/refactor/object-storage-production-runbook.md`
- `docs/refactor/project-structure.md`
- `docs/refactor/frontend-handoff-index.md`
- `docs/refactor/backend-capability-status.md`
- `docs/refactor/legacy-feature-gap-matrix.md`
- `docs/refactor/supabase-frontend-access-strategy.md`
- `docs/refactor/taro-frontend-integration.md`
- `docs/refactor/taro-visual-language.md`
- `docs/refactor/taro-production-integration-checklist.md`
- `docs/refactor/multitenant-auth-security-contract.md`
- `docs/refactor/next-development-todo.md`
- `docs/refactor/blueprint-coverage.md`
- `docs/refactor/api-structure.md`
- `docs/refactor/web-launch-acceptance-checklist.md`
- `docs/refactor/backend-open-items-and-capacity-20260701.md`
## 目录结构
```text
apps/api/ Node.js 业务 API
apps/taro/ Taro 4 React 跨端前端H5 三入口,后续扩展小程序
apps/worker/ 后台异步任务CRM webhook、支付/退款补偿、官方账单下载、平台计费/用量/催缴、平台审计告警/外部通知、资源复检、导入执行、公共题库同步、题库导出渲染等
packages/config/ 共享配置
packages/db/ PostgreSQL 连接池和查询封装
packages/domain/ 领域常量和共享类型
supabase/migrations/ 数据库迁移schema、RLS、索引、触发器
supabase/seed.sql 最小租户 seed
scripts/import-pocketbase/ PocketBase schema/数据导入器和校验器
scripts/smoke-seed.js 本地集成测试 seed 数据
scripts/api-integration-test.js
scripts/deploy/ 云服务器部署模板Nginx、systemd、环境变量示例、发布脚本
docs/refactor/ 重构架构、进度、治理文档
docker-compose.api.yml API 容器化运行配置
```
旧项目参考文件在本机 `F:\project\参考\旧题库项目`,旧前端构建产物在 `F:\project\参考\旧构建产物`。这两个目录都只用于对照和迁移,不作为当前新项目源码。
## 本地开发
前置要求:
- Node.js 20+
- Docker Desktop
- Supabase CLI
启动本地 Supabase 和 API
```bash
npm install
npm run supabase:start
npm run supabase:reset
npm run db:smoke-seed
npm run dev:api
```
Taro H5 本地开发:
```bash
npm run dev:taro:h5
```
三套 H5 构建:
```bash
npm run build:taro:h5:student
npm run build:taro:h5:tenant
npm run build:taro:h5:platform
```
对应产物:
```text
apps/taro/dist/h5-student
apps/taro/dist/h5-tenant-admin
apps/taro/dist/h5-platform-admin
```
推荐分别部署到学生端域名、租户后台域名、平台后台域名;三者共用 `apps/taro/src/services/api.ts` 请求层,业务数据默认调用 `apps/api`,不要在页面里直写 Supabase 表。
构建后可以先跑静态启动烟测,确认三套 H5 产物能被普通静态服务器托管、`runtime-config.json` 只含公开字段、JS/CSS 资源不 404并用 mock 后端验证 `/api/tenant/resolve` 契约:
```bash
node scripts/taro-route-contract-test.js
node scripts/taro-api-contract-test.js
node scripts/taro-persona-contract-test.js
node scripts/product-scope-guardrails-test.js
npm run smoke:taro:h5
npm run smoke:taro:h5:interaction
```
`taro-route-contract-test` 会校验 `apps/taro/src/app.config.ts`、真实 `pages/**/index.tsx`、启动页三端跳转、H5 静态烟测入口和前端交接文档中的页面引用保持一致。新增或删除页面时必须同步路由和文档,避免 H5/小程序构建后才发现入口漂移。
`taro-api-contract-test` 会比对 `apps/taro/src` 中所有 `apiRequest('/api/...')` 调用与 `apps/api/src/features/*/index.ts` 注册路由,阻断前端调用不存在 API、method 写错或绕过统一 `/api` 命名空间的漂移;动态导入和少量 server alias 需要在脚本 allowlist 中显式声明。
`taro-persona-contract-test` 会从学生、租户管理员、平台管理员三类前端视角检查关键页面、路由和服务调用,阻断刷题、会员订单、错题收藏、学生运营、内容导入、营销财务、租户设置、平台租户账务和公共题库授权入口被误删或漂移。
`smoke:taro:h5:interaction` 会启动三套 H5 发布产物、本地 mock API 和本机 Chrome/Edge在真实浏览器里点击学生首页、题库、答题、收藏、错题/收藏复习、背单词、知识手册、资料短签名和水印、视频播放授权、分数线、AI 择校、消息中心、会员收银台下单/支付参数/订单状态,租户后台内容导入、公共题库采纳/同步/冲突处理、学生运营、营销/CRM/分佣、主题/角色/成员写操作,以及平台后台租户、账务、公共题库授权和员工写操作,用来补足静态烟测无法发现的 H5 运行时空白页、history 路由和点击事件问题。
H5 线上推荐每个静态目录放独立 `runtime-config.json` 覆盖公开配置,避免 API/Auth 域名变化时重打包:
```text
apps/taro/deploy/h5-student.runtime-config.example.json
apps/taro/deploy/h5-tenant-admin.runtime-config.example.json
apps/taro/deploy/h5-platform-admin.runtime-config.example.json
```
部署时把示例复制为对应 Web 根目录的 `runtime-config.json`,只填写 `portal``apiBaseUrl``supabaseUrl``supabasePublishableKey``tenantCode` 这类公开字段。完整 Nginx、CSP、缓存、CORS 和三域名部署说明见:
```text
docs/refactor/taro-h5-deployment.md
scripts/deploy/README.md
```
学生端当前页面:
```text
apps/taro/src/pages/student/login
apps/taro/src/pages/student/home
apps/taro/src/pages/student/catalog
apps/taro/src/pages/student/practice
apps/taro/src/pages/student/vocabulary
apps/taro/src/pages/student/handbook
apps/taro/src/pages/student/scoreline
apps/taro/src/pages/student/ai-school
apps/taro/src/pages/student/assets
apps/taro/src/pages/student/profile
```
租户后台当前页面:
```text
apps/taro/src/pages/tenant-admin/workbench
apps/taro/src/pages/tenant-admin/dashboard
apps/taro/src/pages/tenant-admin/students
apps/taro/src/pages/tenant-admin/content
apps/taro/src/pages/tenant-admin/marketing
apps/taro/src/pages/tenant-admin/finance
apps/taro/src/pages/tenant-admin/settings
```
平台后台当前页面:
```text
apps/taro/src/pages/platform-admin/workbench
apps/taro/src/pages/platform-admin/tenants
apps/taro/src/pages/platform-admin/billing
apps/taro/src/pages/platform-admin/question-banks
apps/taro/src/pages/platform-admin/staff
```
单次运行 CRM worker
```bash
npm --workspace @tiku-saas/worker run crm:once
```
单次运行支付/退款补偿 worker
```bash
npm --workspace @tiku-saas/worker run commerce:once
```
单次运行微信/支付宝官方账单下载 worker
```bash
npm --workspace @tiku-saas/worker run provider-bills:once
```
单次运行平台 SaaS 订阅自动计费 worker
```bash
npm --workspace @tiku-saas/worker run platform-billing:once
```
生产定时任务建议每天低峰运行一次 `node dist/apps/worker/src/index.js --once --job platform-billing`。可用环境变量控制批量大小和提前开票窗口:
```text
WORKER_PLATFORM_BILLING_BATCH_SIZE=50
WORKER_PLATFORM_BILLING_DAYS_AHEAD=45
WORKER_PLATFORM_BILLING_DUE_DAYS=15
WORKER_PLATFORM_BILLING_ID=platform-billing-prod-1
```
单次运行平台 SaaS 用量超额自动开票 worker
```bash
npm --workspace @tiku-saas/worker run platform-usage-overage:once
```
生产定时任务建议每月 1 日低峰先用 `WORKER_PLATFORM_USAGE_MONTH=上月 YYYY-MM` 运行 `platform-usage` 采集完整用量快照,再运行 `node dist/apps/worker/src/index.js --once --job platform-usage-overage` 自动生成上一个自然月的 `usage_overage` 账单。该 worker 复用后端统一超额计算服务,只读取 `tenant_usage_records`、SaaS 套餐 `included_quotas/overage_prices` 和订阅 metadata 覆盖,使用唯一索引和账单查重防重复开票;账期月份必须是 `YYYY-MM` 且月份在 `01..12`。worker 执行失败会写入 `platform.invoice.usage_overage_worker_failed` 脱敏平台审计日志,后续由 `platform-audit-alerts` 转为高优先级开放告警,并可继续通过 `platform-audit-notifications` 推送到钉钉/飞书/企微。
```text
WORKER_PLATFORM_USAGE_OVERAGE_BATCH_SIZE=100
WORKER_PLATFORM_USAGE_OVERAGE_MONTH=
WORKER_PLATFORM_USAGE_OVERAGE_DUE_DAYS=15
WORKER_PLATFORM_USAGE_OVERAGE_ID=platform-usage-overage-prod-1
```
单次运行平台 SaaS 逾期催缴 worker
```bash
npm --workspace @tiku-saas/worker run platform-dunning:once
```
生产定时任务建议每天在自动计费之后运行一次 `node dist/apps/worker/src/index.js --once --job platform-dunning`。它只处理已过 `due_date` 且未结清的服务费账单:把账单标记为 `overdue`、将租户 `billing_status` 推为 `past_due`、写入 `tenant_invoice_reminders` 内部催缴台账和审计,不会自动停用租户。
```text
WORKER_PLATFORM_DUNNING_BATCH_SIZE=100
WORKER_PLATFORM_DUNNING_ID=platform-dunning-prod-1
```
单次运行平台 SaaS 逾期催缴外部通知 worker
```bash
npm --workspace @tiku-saas/worker run platform-dunning-notifications:once
```
生产定时任务建议在 `platform-dunning` 之后每 5 到 15 分钟运行一次 `node dist/apps/worker/src/index.js --once --job platform-dunning-notifications`。它会把 `tenant_invoice_reminders` 中待发送或失败的内部催缴记录按 `platform_dunning_notification_channels` 配置入队到 `platform_dunning_notification_events`,支持 generic、钉钉、飞书和企业微信 webhook发送成功后会把对应催缴记录标记为 `sent`,发送失败会按退避策略重试并在终止失败时标记 `failed`。渠道密钥必须写入 `app_private.platform_secrets`API 只返回 `secretRef` 和 webhook host/path事件查询会递归脱敏 request payload。
```text
WORKER_PLATFORM_DUNNING_NOTIFICATION_BATCH_SIZE=50
WORKER_PLATFORM_DUNNING_NOTIFICATION_MAX_ATTEMPTS=5
WORKER_PLATFORM_DUNNING_NOTIFICATION_BACKOFF_SECONDS=10,60,300,900,1800
WORKER_PLATFORM_DUNNING_NOTIFICATION_REQUEST_TIMEOUT_MS=10000
WORKER_PLATFORM_DUNNING_NOTIFICATION_ALLOW_INSECURE_LOCALHOST=false
```
单次运行平台审计告警 worker
```bash
npm --workspace @tiku-saas/worker run platform-audit-alerts:once
```
生产定时任务建议每 5 到 15 分钟运行一次 `node dist/apps/worker/src/index.js --once --job platform-audit-alerts`。它只扫描 `platform.%` 审计日志,把命中启用规则的高风险动作写入 `platform_audit_alerts`;告警 details 会递归脱敏 token、secret、password、key、authorization、cookie、session、cert、signature 等敏感字段。
```text
WORKER_PLATFORM_AUDIT_ALERT_BATCH_SIZE=200
WORKER_PLATFORM_AUDIT_ALERT_LOOKBACK_DAYS=14
WORKER_PLATFORM_AUDIT_ALERT_ID=platform-audit-alerts-prod-1
```
单次运行平台审计告警外部通知 worker
```bash
npm --workspace @tiku-saas/worker run platform-audit-notifications:once
```
生产定时任务建议在 `platform-audit-alerts` 后每 5 到 15 分钟运行一次 `node dist/apps/worker/src/index.js --once --job platform-audit-notifications`。它会把开放告警按 `platform_audit_notification_channels` 配置入队到 `platform_audit_notification_events`,支持 generic、钉钉、飞书和企业微信 webhook发送请求和事件台账都会递归脱敏敏感字段。钉钉/飞书签名密钥必须存入 `app_private.platform_secrets`API 只返回 `secretRef` 和 webhook host/path。
```text
WORKER_PLATFORM_AUDIT_NOTIFICATION_BATCH_SIZE=50
WORKER_PLATFORM_AUDIT_NOTIFICATION_MAX_ATTEMPTS=5
WORKER_PLATFORM_AUDIT_NOTIFICATION_BACKOFF_SECONDS=10,60,300,900,1800
WORKER_PLATFORM_AUDIT_NOTIFICATION_REQUEST_TIMEOUT_MS=10000
WORKER_PLATFORM_AUDIT_NOTIFICATION_ALLOW_INSECURE_LOCALHOST=false
```
单次运行内容资源复检 worker
```bash
npm --workspace @tiku-saas/worker run assets:once
```
单次运行内容导入 worker
```bash
npm --workspace @tiku-saas/worker run imports:once
```
单次运行公共题库自动同步 worker
```bash
npm --workspace @tiku-saas/worker run public-banks:once
```
单次运行学习督导规则 worker
```bash
npm run build:worker
node apps/worker/dist/apps/worker/src/index.js --once --job student-supervision
```
生产定时任务建议每 15 到 60 分钟运行一次 `node dist/apps/worker/src/index.js --once --job student-supervision`。它只处理启用状态的租户学习督导规则,按规则阈值扫描未学习、错题积压、低正确率、单词待复习和超期未完成练习的学生,并幂等生成 `learning` 跟进任务;教师/班主任范围规则必须绑定班级,生成结果、失败原因和 worker 信息会写入规则 `last_result/metadata` 与审计。
```text
WORKER_STUDENT_SUPERVISION_BATCH_SIZE=20
WORKER_STUDENT_SUPERVISION_ID=student-supervision-prod-1
WORKER_STUDENT_SUPERVISION_CLAIM_STALE_SECONDS=900
```
单次运行题库 PDF/Word/每日一练 ZIP 导出 worker
```bash
npm --workspace @tiku-saas/worker run exports:once
```
默认本地数据库:
```text
postgresql://postgres:postgres@127.0.0.1:54322/postgres
```
默认 API 地址:
```text
http://127.0.0.1:8787
```
## 验证命令
完整后端重构检查:
```bash
npm run check:refactor
```
这个命令会依次执行:
- API TypeScript 检查
- PocketBase importer TypeScript 检查
- PocketBase 导入后校验
- 本地 smoke seed
- API 构建
- 本地 API 集成测试
常用单项命令:
```bash
npm run check:api
npm run check:worker
npm run check:importer
npm run check:taro
npm run test:readiness
npm run test:auth:remote-smoke
npm run test:launch-gate
npm run smoke:auth:remote
npm run audit:runtime
npm run security:repo
npm run pb:import:dry-run
npm run pb:import:validate
npm run test:pb:dry-run
npm run test:api
npm run test:worker:crm
npm run test:worker:commerce
npm run test:worker:platform-billing
npm run test:worker:platform-usage
npm run test:worker:platform-dunning
npm run test:worker:platform-dunning-notifications
npm run test:worker:platform-audit-alerts
npm run test:worker:platform-audit-notifications
npm run test:worker:assets
npm run test:worker:exports
npm run test:worker:imports
npm run test:worker:public-banks
npm run test:worker:student-supervision
npm run test:rls
```
## 云服务器部署与生产测试顺序
接下来在新云服务器上建议按下面顺序推进。不要跳过证据门禁;它是后续给合作商交付 SaaS 时的安全底线。
当前 `tjszsb.com` 已建议按 6 个生产入口使用:`api.tjszsb.com` 反代业务 API`app.tjszsb.com` 承载学生 H5`admin.tjszsb.com` 承载租户后台,`console.tjszsb.com` 承载平台后台,`supabase.tjszsb.com` 反代 Supabase gateway/Auth/Storage/PostgREST`studio.tjszsb.com` 仅限固定 IP/VPN 访问 Supabase Studio。可提交到仓库的部署模板在 `scripts/deploy/`;真实服务器文件建议放在 `/opt/tiku-saas/repo``/srv/tiku-saas/www/*``/etc/tiku-saas/*.env`。Gitea token、数据库密码、支付私钥、短信密钥、对象存储密钥都只允许放服务器本地不允许写入 Git、前端运行时配置或部署脚本。
当前云服务器是 Alibaba Cloud Linux 3 + 宝塔面板环境,宝塔 Nginx 配置在 `/www/server/nginx``/www/server/panel/vhost/nginx`,不是 `/etc/nginx`。H5 静态产物仍发布到 `/srv/tiku-saas/www/*`,宝塔站点根目录通过 `/www/wwwroot/tiku-saas/*` 软链接接入。完整服务器落地记录见 `scripts/deploy/README.md`
1. 准备服务器基础环境:安装 Docker、Node.js 20+、Supabase CLI、Nginx/Caddy、进程管理或容器编排工具拉取本仓库 `main`,以 Gitea 最新提交为准。
2. 启动 Supabase/PostgreSQL执行全部 migrations 和最小 seed确认 `DATABASE_URL` 指向云端数据库。
3.`docs/refactor/postgresql-4c16g-tuning.md` 应用 4 核 16G `shared-host` 起步参数,启用 `pg_stat_statements`,重启 PostgreSQL 后跑 `PG_TUNING_PROFILE=shared-host npm run perf:postgres:evidence -- --strict --json`
4. 配置生产 `.env`:关闭 legacy 身份头和平台本地 key配置 HTTPS CORS 白名单、强随机 session/JWT secret、对象存储 provider、短信/OAuth/支付 provider、worker provider 和 webhook 域名。生产环境禁止 `CORS=*`、mock/未知短信 provider、local_dev 存储、localhost webhook、非 HTTPS 回调。
5. 导入旧 PocketBase 数据:先跑 production dry-run 和 sample确认 7 个已支付缺用户订单、22 个缺所属手册章节等旧数据人工复核项有明确处理结论,再执行正式导入演练。
6. 构建并部署 API/workerAPI 对外只开放 HTTPSworker 按本文的计费、用量、催缴、审计、资源复检、导入、导出、公共题库同步等任务设置 cron 或队列。
7. 构建三套 H5`build:taro:h5:student``build:taro:h5:tenant``build:taro:h5:platform`,分别部署到学生端、租户后台、平台后台域名。每个发布目录根部放置真实公开 `runtime-config.json`,只允许公开字段。
8. 执行生产验收:`readiness:production``readiness:production:db``smoke:auth:remote``test:rls``smoke:launch-persona -- --write ...`、Taro H5 静态/交互 smoke、API/worker 构建检查、`security:repo`、真实 `@codex-security` 扫描。
9. 执行云端真实数据压测:按 runbook 跑 6/30/50/100 阶梯,只读和混合读写各一组;把摘要写入 `production-launch-evidence.json`,不要把原始压测报告提交 Git。
10. 通过 `npm run launch:gate -- --evidence docs/refactor/production-launch-evidence.json` 后,再进入灰度生产测试。灰度期间继续观察 CPU、内存、慢 SQL、连接数、错误率、P95/P99、对象存储签名、支付回调、短信/OAuth 登录、订单权益开通和 worker 失败告警。
当前可上线生产测试的边界:后端主链路和 H5 第一版已具备联调条件;真实生产账号、真实支付/短信/OAuth 回调、对象存储 AV/CDN、水印策略、4C16G 云端容量和真实迁移数据人工复核仍是上线前必须验收项。学生头像只支持男女预设,不做上传;排行榜默认不开启,只有租户明确购买/开启活动并完成专项压测后再进入独立功能。
## 生产就绪检查
填好生产 `.env` 后,先跑环境变量级检查:
```bash
npm run readiness:production
```
确认 `DATABASE_URL` 指向生产 Supabase/PostgreSQL 后,再跑数据库配置检查:
```bash
npm run readiness:production:db
```
这个检查会阻断默认弱密钥、`CORS=*`、不支持或 mock 短信 provider、legacy 身份头、local_dev 存储、非 HTTPS 对象存储公开 URL、非官方阿里云 OSS endpoint、阿里云 OSS 内网直签、对象存储未配置、CRM insecure localhost、平台审计/催缴通知 localhost 等生产风险;带 `:db` 的版本还会检查租户 provider 公开配置是否混入密钥、活跃短信/OAuth/支付 provider 是否缺少 `app_private.tenant_secrets`、短信/OAuth/支付公开配置是否缺少生产必填字段、OAuth redirectUri 和支付 notifyUrl 是否为生产 HTTPS、平台通知 webhook 是否为生产 HTTPS、钉钉/飞书平台通知是否缺少 `app_private.platform_secrets`、域名是否未验证。
Supabase Auth/JWKS 上云后需要用真实 access token 跑远程验收:
```bash
AUTH_SMOKE_API_BASE_URL=https://api.example.com \
AUTH_SMOKE_TENANT_ID=<tenant-uuid> \
AUTH_SMOKE_STUDENT_ACCESS_TOKEN=<student-supabase-access-token> \
AUTH_SMOKE_TENANT_ADMIN_ACCESS_TOKEN=<tenant-admin-supabase-access-token> \
AUTH_SMOKE_PLATFORM_ADMIN_ACCESS_TOKEN=<platform-admin-supabase-access-token> \
AUTH_SMOKE_WRONG_TENANT_ID=<another-tenant-uuid> \
AUTH_SMOKE_REQUIRE_ADMIN_TOKENS=true \
npm run smoke:auth:remote
```
这个命令会验证真实 Supabase JWT 能访问 `/api/auth/me``/api/profile/me`,学生不能访问租户后台/平台后台,租户管理员不能访问平台后台,平台管理员能访问平台后台,坏 token 和错租户上下文会被拒绝。真实 access token 只允许在验收命令行临时提供,不要写入仓库、前端 `runtime-config.json` 或长期 `.env`
RLS 需要同时跑动态隔离验收:
```bash
npm run test:rls
```
这个命令会先执行本地 smoke seed再在事务内模拟 Supabase `authenticated/anon/platform_admin` JWT claims验证主租户和合作商租户的品牌、设置、域名、成员、题库、订单、资源、SaaS 账单等代表性表不会跨租户泄露;同时验证无 `tenant_id` claim 不能读取租户数据,普通租户上下文不能跨租户写入。脚本里的临时 grant 会随事务回滚,不会改变实际 schema 权限。
## 生产上线证据门禁
正式切换前不要只看“口头跑过测试”。把真实生产/预生产验收结果整理成证据文件,再运行上线门禁:
```bash
cp docs/refactor/production-launch-evidence.template.json docs/refactor/production-launch-evidence.json
npm run launch:gate -- --evidence docs/refactor/production-launch-evidence.json
```
`production-launch-evidence.json` 不入 Git里面只记录验收摘要、artifact 路径、审批人和时间,不保存真实 access token、支付密钥、对象存储密钥或用户隐私明细。门禁会要求以下证据全部齐备并通过
- `readiness:production``readiness:production:db`、严格 `perf:postgres:evidence -- --strict`
- 真实 `smoke:auth:remote``test:rls`
- PocketBase production dry-run、`pb:import:validate``pb:import:sample`
- 真实数据 API 读路径压测、API/worker/Taro 构建。
- `smoke:launch-persona` 真实 API 角色旅程:普通学生 SVIP 后刷题、收藏、错题/收藏复习入口,租户管理员看板/主题/学生/销售转化入口,平台管理员租户/套餐/审计入口,以及越权拒绝。
- `smoke:taro:h5``smoke:taro:h5:interaction`、严格 `taro-h5-release-guardrails-test --require-runtime-config`
- `audit:runtime``security:repo`、真实 `@codex-security` 扫描。
- 备份、回滚、真实数据抽样、生产 provider、对象存储控制、支付对账和三套 H5 `runtime-config.json` 人工确认。
补充说明:当前 Codex 环境如果没有暴露 `@codex-security` 可调用工具,不能把插件扫描写成已完成;只能先用 `npm run audit:runtime``npm run security:repo``npm run test:readiness``npm run test:rls` 和代码审查作为临时安全证据,并在上线证据里保留插件扫描待补项。
模板文件:
```text
docs/refactor/production-launch-evidence.template.json
```
## PocketBase 迁移 Dry-Run
如果旧数据源是 SQLite先从旧 PocketBase 数据目录只读导出业务 collection。默认读取 `F:\project\参考\旧题库数据库文件`,输出到已被 `.gitignore` 覆盖的 `pb_export/`
```powershell
$env:PB_SQLITE_DIR="F:\project\参考\旧题库数据库文件"
$env:PB_EXPORT_DIR="F:\project\pb_export"
npm run pb:export:sqlite
```
导出会生成:
```text
pb_export/*.json 各 PocketBase collection 的普通业务 JSON
pb_export/sqlite-export-manifest.json
pb_export/storage-manifest.json
pb_export/pb_schema.sqlite.json
```
默认导出会移除 `password/token/secret/sessionKey/openid/unionid` 等敏感身份或密钥字段,只在 manifest 中记录脱敏字段数量;手机号等迁移必需字段会保留。不要把 `pb_export/`、manifest 或真实迁移报告提交到 Git。
把旧 PocketBase 导出的集合 JSON 放到仓库根目录 `pb_export/` 后,执行不写数据库的静态 dry-run
```bash
npm run pb:import:dry-run
```
需要给 CI 或脚本读取时:
```bash
npm run pb:import:dry-run -- --json
```
dry-run 会检查导出目录、JSON 形态、核心集合缺失、重复/缺失旧 ID、敏感字段、旧 schema 关系断裂和未映射集合。存在 blocker 时命令返回非 0所有 blocker 处理完后,再执行 `npm run pb:import:json``npm run pb:import:validate`
默认 dry-run 使用 `development` profile正式迁移、预生产验收和 CI 应使用 `production` profile。生产 profile 会额外输出 `migrationReadiness`,检查用户、题目、科目、分类、订单、套餐、激活码、单词和知识手册等必需集合,以及用户手机号、题目归属、订单套餐、激活码、单词和手册归属等关键字段覆盖率。`--profile` 只接受 `development``production`,拼写错误会按 blocker 失败。
当前真实 SQLite 基线已经跑通只读导出和干净库全量导入58 个业务 collection、248555 条记录、9 个 storage 原始资源文件;本地 `npx supabase db reset` 后执行 `npm run pb:import:json` 最近用时约 10 分 11 秒,`npm run pb:import:validate` 结果为 0 failures、3 warnings。`user_answer_records``mock_exam_configs``referral_qrcodes``commission_settings` 已进入标准化导入,导入后核心计数包括 3670 用户、74102 题目、85199 条旧答题记录、38205 条错题、636 订单、447 权益、79 个推广码和 1 条租户分佣设置。导入器现在还会从旧 `region_modules/module_nodes/subjects/categories/questions.nodeId` 生成新架构 `content_entries/content_nodes/question_collections/practice_blueprints`,最新导入计数为 11 个题库入口、2830 个内容节点、1597 个题目合集、82106 条合集题目关系、3102 个顺序/随机练习蓝图;所有已发布旧题都会写入 `entry_id/content_node_id/primary_collection_id`,供 Taro 前端按新模型直接消费。
导入结构校验后,还要运行真实业务抽样:
```powershell
$env:DATABASE_URL="postgresql://postgres:postgres@127.0.0.1:54322/postgres"
npm run pb:import:sample
```
`pb:import:sample` 是只读脚本,用来证明迁移数据能被新 SaaS 业务模型消费:题库入口、分类节点、题目合集、顺序/随机/全真模拟蓝图、题目当前版本、答题记录、错题、收藏、单词、知识手册、分数线、订单、支付、权益、激活码、资源台账和敏感字段泄露都会被抽样检查。当前真实迁移库最近结果为 `0 failures, 6 warnings, 1 skipped, 39 passed`warning 均为旧数据人工复核项或上线前留档项,详见 runbook。
如需生成本地报告:
```powershell
$env:PB_SAMPLE_WRITE_REPORT="true"
npm run pb:import:sample
Remove-Item Env:\PB_SAMPLE_WRITE_REPORT
```
报告输出到已忽略的 `docs/refactor/migration-reports/`,不要提交真实用户、订单或学习数据样本。
production dry-run 目前仍有 2 个真实数据 blocker30 个订单缺用户、22 个知识手册章节缺所属手册;导入器会把它们隔离到财务复核/迁移待复核手册并写入 `pb_import_issues`,其中最新导入 run 的 critical issue 剩余 29 个7 个已支付订单缺用户、22 个手册章节缺所属手册。正式切换前仍必须人工确认,详见:
```text
docs/refactor/pocketbase-real-data-migration-runbook.md
docs/refactor/next-development-todo.md
```
真实生产数据迁移不要只看命令是否能跑完,需要按迁移验收 runbook 执行 dry-run、正式导入演练、导入后校验、业务抽样、Taro 联调、冻结切换和回滚准备:
```text
docs/refactor/pocketbase-real-data-migration-runbook.md
```
### API 压测和 4 核 16G 评估
默认本地烟测会构建 API 并自动启动临时端口,使用当前 `DATABASE_URL` 的真实数据做只读混合请求:
```powershell
$env:DATABASE_URL="postgresql://postgres:postgres@127.0.0.1:54322/postgres"
npm run perf:api:local
```
报告输出到已忽略的 `docs/refactor/performance-reports/`。可以用 `npm run perf:summary -- --input <api-benchmark.json> --json` 自动提取 `launch:gate` 需要的错误率、P95/P99、并发和时长摘要。4 核 16G 云服务器应按压测 runbook 跑 6/30/50/100 阶梯并发,并结合 PostgreSQL 调参文档观察慢 SQL、连接数、锁等待和 P95/P99
```text
docs/refactor/postgresql-4c16g-tuning.md
docs/refactor/performance-benchmark-runbook.md
```
本地 Docker Desktop 可用时,可以先用受限 API 容器做 4 核 16G shared-host 风格的预演。该入口默认把 API 容器限制为 2 CPU/4G、关闭 legacy `x-user-id`,并用 `Authorization: Bearer <tk_session>` 跑 30 只读、50/100 混合读写矩阵:
```powershell
$env:DATABASE_URL="postgresql://postgres:postgres@127.0.0.1:54322/postgres"
npm run perf:api:docker-4c16g
```
注意:这个入口默认只限制 API 容器资源,并会生成 `docker-4c16g-resource-evidence-*.json/md` 记录 Docker Desktop、API 容器和 Supabase DB 容器的资源上下文;本地 Supabase/PostgreSQL 仍受 Docker Desktop 全局资源影响。需要更贴近本地 4C16G 模拟时,可以显式设置 `BENCHMARK_LIMIT_DB_RESOURCES=true``BENCHMARK_DB_CPUS``BENCHMARK_DB_MEMORY`,脚本默认会在结束后恢复 DB 容器限制。正式容量承诺仍要在目标 4 核 16G 云服务器复跑。
PostgreSQL 调参与运行证据采集:
```powershell
$env:DATABASE_URL="postgresql://postgres:postgres@127.0.0.1:54322/postgres"
npm run perf:postgres:evidence
```
生产上线前必须用严格模式生成门禁摘要:
```powershell
$env:PG_TUNING_PROFILE="shared-host"
npm run perf:postgres:evidence -- --strict --json
Remove-Item Env:\PG_TUNING_PROFILE
```
严格模式会检查 4 核 16G profile、`pending_restart=0``pg_stat_statements` 可用、`jit=off`,以及 API 请求相关超时不为 0。需要生成可人工复核的 `ALTER SYSTEM` SQL 时运行:
```powershell
npm run perf:postgres:sql -- --profile=shared-host
```
上线前角色旅程烟测:
```powershell
$env:DATABASE_URL="postgresql://postgres:postgres@127.0.0.1:54322/postgres"
$env:LAUNCH_SMOKE_AUTH_MODE="app_session"
npm run smoke:launch-persona -- --write docs/refactor/launch-artifacts/launch-persona-smoke.json --write-md docs/refactor/launch-artifacts/launch-persona-smoke.md
Remove-Item Env:\LAUNCH_SMOKE_AUTH_MODE
```
`smoke:launch-persona` 会从普通学生、租户管理员、平台管理员三个视角调用真实 API默认使用 `LAUNCH_SMOKE_AUTH_MODE=app_session` 的 Bearer `tk_` session不依赖旧 `x-user-id` 或平台本地 key覆盖 SVIP 后刷题、收藏、错题复习入口、租户数据看板/主题/学生/销售转化、平台租户/套餐/审计入口和越权拒绝。它会写入少量 `launch_persona_smoke` 测试记录,生产只建议在灰度或演练租户运行。脚本始终保留带时间戳的 JSON/Markdown 报告;写生产证据时用 `--write``--write-md` 同步生成 `production-launch-evidence.json` 里引用的稳定 artifact。
Taro H5 发布产物守卫:
```powershell
npm run build:taro:h5:student
npm run build:taro:h5:tenant
npm run build:taro:h5:platform
npm run smoke:taro:h5
npm run smoke:taro:h5:interaction
npm run manifest:taro:h5
node scripts\taro-h5-release-guardrails-test.js --require-dist
```
`smoke:taro:h5` 会启动临时静态服务器和 mock API验证三套 H5 的 `index.html`、静态资源、history fallback、公开 runtime config 和租户解析契约。`smoke:taro:h5:interaction` 会再拉起真实 Chrome/Edge打开三套 H5 产物并点击 32 项关键入口,覆盖学生首页、题库、答题、收藏、错题/收藏复习、背单词、知识手册、资料短签名和水印、视频播放授权、分数线、AI 择校、消息中心、会员收银台下单/支付参数/订单状态,租户后台内容导入、公共题库采纳/同步/冲突处理、学生运营、营销/CRM/分佣、主题/角色/成员写操作,以及平台后台租户、账务、公共题库授权和员工写操作,确认页面 JS 执行、路由跳转、关键 API 和后台入口点击没有空白页或运行时异常。`manifest:taro:h5` 会生成三套 H5 的部署清单,记录构建命令、发布目录、入口路由、`index.html` hash、资源数量、runtime-config 状态和租户解析模式,方便前端/运维核对实际上传目录。`taro-h5-release-guardrails-test` 会确认三套 H5 目录存在 `index.html`,并扫描源码/产物是否混入旧 PocketBase、`x-user-id`、平台本地 key、数据库连接串或服务端密钥形态。正式部署时还必须在每个 H5 目录根部放置对应的 `runtime-config.json`
写入生产上线证据时使用严格模式,确保三套正式发布目录已经放好真实公开 `runtime-config.json`,且 warning 为 0
```powershell
npm --silent run smoke:taro:h5 -- --json > docs/refactor/launch-artifacts/taro-h5-static-smoke.json
npm --silent run smoke:taro:h5:interaction -- --json > docs/refactor/launch-artifacts/taro-h5-interaction-smoke.json
node scripts\taro-h5-release-guardrails-test.js --require-dist --require-runtime-config --json > docs/refactor/launch-artifacts/taro-h5-release-guardrails.json
npm --silent run manifest:taro:h5 -- --require-dist --require-runtime-config --json --write docs/refactor/launch-artifacts/taro-h5-release-manifest.json > docs/refactor/launch-artifacts/taro-h5-release-manifest.stdout.json
```
最近一次本地真实迁移库已包含前期压测写入记录,当前规模约为 19 个租户、74,131 道题、1,631 个题目合集、3,120 个练习蓝图、3,519 个单词、2,692 条知识手册、3,722 个平台用户、3,712 个学生资料、81,160 个练习 session、327,925 条答题记录、38,207 条错题、1,501 个内容资源和 474 条权益。压测 worker 是无停顿请求流,不能直接等同于真实在线学生数;前端完成后需要用真实页面埋点估算单个学生平均 RPS再折算在线容量。
README 只保留最新本地真实数据压测摘要。更早的 Docker API 受限资源复核、高资源 Docker Desktop 历史结果和每轮说明见 `docs/refactor/performance-benchmark-summary-20260630.md``docs/refactor/backend-open-items-and-capacity-20260701.md`
| 并发 worker | 时长 | 刷题写入比例 | 请求数 | 错误率 | 吞吐 | P95 | P99 |
| ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| API 进程 / 30 | 120s | 0% | 37,520 | 0.00% | 310.34 req/s | 251.08 ms | 388.49 ms |
| API 进程 / 50 | 60s | 10% | 25,047 | 0.00% | 410.49 req/s | 237.41 ms | 344.51 ms |
| API 进程 / 100 | 60s | 8% | 24,116 | 0.00% | 393.56 req/s | 437.37 ms | 533.63 ms |
| API 进程 / 150 | 60s | 6% | 22,864 | 0.00% | 371.29 req/s | 633.46 ms | 759.62 ms |
| Docker API 2c4g / 30 | 120s | 0% | 36,800 | 0.00% | 305.59 req/s | 241.46 ms | 351.17 ms |
| Docker API 2c4g / 50 | 60s | 10% | 24,120 | 0.00% | 398.79 req/s | 231.28 ms | 325.94 ms |
| Docker API 2c4g / 100 | 60s | 8% | 22,462 | 0.00% | 370.86 req/s | 445.26 ms | 532.32 ms |
| Docker API 2c4g / 150 | 60s | 6% | 20,708 | 0.00% | 340.74 req/s | 689.67 ms | 833.08 ms |
| Docker API 2c4g + DB 2c8g / 30 | 120s | 0% | 8,397 | 0.00% | 69.48 req/s | 1183.29 ms | 1697.59 ms |
| Docker API 2c4g + DB 2c8g / 50 | 60s | 10% | 6,640 | 0.00% | 109.61 req/s | 996.01 ms | 1303.45 ms |
| Docker API 2c4g + DB 2c8g / 100 | 60s | 8% | 6,381 | 0.00% | 104.13 req/s | 1705.51 ms | 2098.41 ms |
| Docker API 2c4g + DB 2c8g / 150 | 60s | 6% | 5,211 | 0.00% | 83.23 req/s | 3006.71 ms | 3699.64 ms |
只读上线门禁继续要求 `includeWrites=false`;混合读写报告需要显式使用 `--allow-writes` 做人工容量观察,例如:
```powershell
npm run perf:summary -- --input docs/refactor/performance-reports/api-benchmark-20260701-075709.json --json --allow-writes --min-duration-seconds=60 --min-concurrency=50 --max-p95-ms=500 --max-p99-ms=1200
```
使用 `--allow-writes` 时会输出 `capacityObservation`,不输出 `launchGateCheck`,不能把写入场景误填成生产上线门禁的只读证据。
本地结论:当前 Docker Desktop 分配 20 CPU、约 63GB 内存,高于常见 4 核 16G 云服务器,不能直接作为生产 SLA。2026-07-01 08:41 本地 API 进程压测中50 worker 混合读写为 25,047 请求、0 错误、410.49 req/s、P95 237.41ms,这是当前真实迁移库的舒适观察;按 0.05 到 0.2 req/s/人的页面节奏粗略折算,约对应 2,052 到 8,210 名活跃在线学生请求吞吐。100 worker 为 393.56 req/s、P95 437.37ms,约对应 1,968 到 7,871 名可作为本机可用上沿150 worker 进入压力区,为 371.29 req/s、P95 633.46ms,约对应 1,856 到 7,426 名。2026-07-01 06:53 同时限制 API 2C/4G 和 DB 2C/8G 时30 worker 只读和 50 worker 混合读写仍 0 错误,但 P95 分别升至 1183.29ms 和 996.01ms未通过上线延迟门禁这是“DB 受限但未调 PostgreSQL 参数”的悲观观察50 worker 109.61 req/s 只可粗略折算约 548 到 2,192 名活跃在线学生的下限吞吐,不能作为可售 SLA。正式对外容量承诺必须在目标 4 核 16G 云服务器、生产 PostgreSQL shared-host 参数、`pg_stat_statements`、生产对象存储/CDN 和真实前端请求节奏下复跑。脱敏摘要和剩余功能清单见:
```text
docs/refactor/performance-benchmark-summary-20260630.md
docs/refactor/backend-open-items-and-capacity-20260701.md
```
正式切换前建议使用 production 严格模式:
```bash
npm run pb:import:dry-run -- --profile=production --json --fail-on-warnings
```
导入后校验建议在预生产/生产切换前把 warning 也作为阻断:
```powershell
$env:FAIL_ON_WARNINGS="true"
npm run pb:import:validate
Remove-Item Env:\FAIL_ON_WARNINGS
```
## API 模块
当前 API 目录:
```text
apps/api/src/features/
auth/ 短信登录、迁移期 session、微信小程序登录、微信网页登录、QQ 登录
catalog/ 学生端目录、内容入口、分类树、题目集合、资料、商城只读接口
commerce/ 订单、支付确认、退款、激活码、优惠券规则/核销、权益、资金对账和差错工单
health/ 健康检查
learning/ 练习 session 组卷、答题、错题、收藏、学习进度、排行榜
platform-admin/ 平台方权限、租户、SaaS 套餐、订阅、订阅账单候选/批量生成、账单、用量
profile/ 学生个人中心、勋章
referral/ 销售/代理客资追踪、CRM 队列
referral/commission.ts
分佣设置、汇总、来源明细、结算单、审核/打款、导出和凭证复核
scoreline/ 分数线
tenant/ 租户解析
tenant-admin/ 租户后台配置、主题、成员权限、班级学生、活动、勋章和审计
tenant-content/ 租户内容导航、题库维护、资源管理、批量导入和题库导出
video/ 题目视频讲解
```
API 身份上下文:
- 推荐:`Authorization: Bearer <supabase_access_token>`,可配合 `x-tenant-id` 提供当前租户上下文。
- 本地/迁移期:`Authorization: Bearer <tk_session>`
- 兼容旧测试:`x-user-id``x-platform-admin-key` 仅允许在 `ALLOW_LEGACY_AUTH_HEADERS=true``ALLOW_PLATFORM_ADMIN_KEY=true` 的非生产环境使用。
生产环境必须设置 `ALLOW_LEGACY_AUTH_HEADERS=false``ALLOW_PLATFORM_ADMIN_KEY=false`,前端不能再传 `x-user-id` 代表当前用户。
平台后台权限:
- 平台账号以后端 `platform_users.primary_role='platform_admin'` 为准,不只信 JWT claim。
- 平台账号通过 `platform_users.platform_permissions` 控制细粒度能力,`{"*":true}` 表示超级管理员。
- 平台员工通过 `GET/PUT/PATCH /api/platform-admin/staff` 管理,必须绑定 Supabase Auth 用户 ID禁用员工会使 `status='disabled'`,后续 Supabase JWT 映射和迁移期 session 都会被拒绝。
- 平台后台启动后可调用 `GET /api/platform-admin/permissions` 获取 `catalog/effective`,用于隐藏不可见菜单和按钮。
- 后端接口继续按 `platform:staff:read/write/status``platform:tenant:read/write/status/billing_profile``platform:billing:read/write/payment/dunning/notification``platform:audit:read/export/alert/notification``platform:question_bank:read/grant/ops` 等权限点强制校验。
- `x-platform-admin-key` 只允许本地兼容,生产必须关闭。
## 重要安全约定
- 租户公开配置和主题配置不能存放密钥;主题 token 只能是后端允许的颜色、半径、安全 CSS 变量、图标 token 和公开素材引用。
- 商户密钥、短信密钥、OAuth app secret 等必须进入 `app_private.tenant_secrets`,或后续生产 KMS/Vault。
- 资料、PDF、视频等资源必须先进入 `content_assets` 台账,再由 API 校验权限并下发签名 URL学生端预览、锁定资料和视频会使用短 TTL并返回带 `traceId``watermark` 上下文供前端渲染可见水印。`members/svip/private` 外部 CDN URL 默认拒绝,除非显式登记 provider-managed 访问;所有上传签名、上传确认、下载/预览 granted/denied 都写入 `content_asset_access_events`。托管对象必须 `uploadStatus=verified``securityScanStatus=passed` 后才能发布、下载、预览或播放;生产环境应定时运行 assets worker 复检对象元数据,执行 `metadata_rules` 和外部 HTTP scanner异常资源会被标记 failed/skipped 并退回 draft。
- `NODE_ENV=production` 下 API 和 worker 都会拒绝 `STORAGE_DEFAULT_PROVIDER=local_dev`、空 bucket 或关闭 `STORAGE_REQUIRE_TENANT_PREFIX`worker 还会拒绝未接入外部 HTTP 安全扫描或开启 fail-open 的生产配置。
- 题库入口和分类使用 `content_entries/content_nodes`;题目列表和练习规则使用 `question_collections/practice_blueprints`,前端不要再把旧树字段当成唯一业务结构。
- 批量导入必须先写 `content_import_jobs/items/issues`,保留原始 payload、规范化 payload、逐行问题和审计记录。题目、单词、知识手册、分数线和视频 JSON/CSV/Excel 导入已走这套后台校验管线;大批量任务可提交 `executionMode=async`,由 imports worker 消费,前端只轮询 job 状态和展示 issues。学生端题干/解析/手册内容统一走 `apps/taro/src/components/RichContent.tsx` 做受控渲染,不执行导入内容中的任意 HTML/JS公式只渲染解析出的 LaTeX token私有题图只接受资源 ID 引用并走后端短签名。
- 题库导出必须由后端按权限生成,不允许前端直接读取数据库拼导出文件;不开启答案/解析时顶层题目和复合题子题都必须脱敏PDF/Word/每日一练 ZIP 只通过 exports worker 写入 `content_assets` 后再签名下载/预览。
- 支付 webhook 必须先设计幂等键和验签流程,再进入生产使用;生产环境还应定时运行 commerce worker 兜底供应商漏通知和处理中退款,并定时运行 provider-bills worker 下载官方账单核对本地订单。官方账单下载任务只保存下载域名、hash 和对账批次 ID不向前端暴露下载 URL 或商户密钥。优惠券状态、最低金额、封顶、单用户限次、首单、适用套餐/地区和订单抵扣都由后端重新校验,前端只能展示后端返回金额。对账差错工单和人工调整凭证只允许记录财务处理结论、附件引用和审计事件,不允许前端、工单接口或凭证审批接口直接篡改订单、支付、退款或权益状态。
## 最近一次验证
最近本地验证命令:
```text
node --check scripts/launch-persona-smoke.js
npm run test:readiness
npm run security:repo
npm run check:taro
LAUNCH_SMOKE_AUTH_MODE=app_session npm run smoke:launch-persona -- --write docs/refactor/launch-artifacts/launch-persona-smoke.json --write-md docs/refactor/launch-artifacts/launch-persona-smoke.md
PERF_AUTH_MODE=app_session PERF_DURATION_SECONDS=120 PERF_CONCURRENCY=30 PERF_RAMP_SECONDS=15 PERF_INCLUDE_WRITES=false npm run perf:api:local
PERF_AUTH_MODE=app_session PERF_DURATION_SECONDS=60 PERF_CONCURRENCY=50 PERF_RAMP_SECONDS=10 PERF_INCLUDE_WRITES=true PERF_PRACTICE_FLOW_RATIO=0.1 npm run perf:api:local
PERF_AUTH_MODE=app_session PERF_DURATION_SECONDS=60 PERF_CONCURRENCY=100 PERF_RAMP_SECONDS=10 PERF_INCLUDE_WRITES=true PERF_PRACTICE_FLOW_RATIO=0.08 npm run perf:api:local
PERF_AUTH_MODE=app_session PERF_DURATION_SECONDS=60 PERF_CONCURRENCY=150 PERF_RAMP_SECONDS=10 PERF_INCLUDE_WRITES=true PERF_PRACTICE_FLOW_RATIO=0.06 npm run perf:api:local
npx supabase db reset
npm run check:api
npm run check:worker
npm run test:worker:commerce
npm run test:worker:platform-billing
npm run test:worker:platform-usage
npm run test:worker:platform-usage-overage
npm run test:worker:platform-dunning
npm run test:worker:platform-dunning-notifications
npm run test:worker:platform-audit-alerts
npm run test:worker:platform-audit-notifications
npm run test:worker:assets
npm run test:worker:exports
npm run test:auth:remote-smoke
npm run test:rls
npm run test:api
npm run check:refactor
npm run audit:runtime
git diff --check
```
结果:通过。最近一轮上线前本地复核已通过 `npm run test:readiness``npm run security:repo``npm run check:taro``node --check scripts/launch-persona-smoke.js``node scripts/production-launch-gate-test.js``git diff --check``security:repo` 为 0 finding`test:readiness` 已包含生产配置 fail-fast、Taro runtime/API/persona/route contract、H5 发布守卫、自动勋章并发、PostgreSQL 调参证据 helper、Docker 压测资源证据、远程 Auth smoke 脚本、launch persona 稳定证据 CLI 和上线门禁测试。`LAUNCH_SMOKE_AUTH_MODE=app_session npm run smoke:launch-persona -- --write ...` 已通过,生成带时间戳报告和稳定 `launch-persona-smoke.json/md`,覆盖普通学生 SVIP 后刷题、收藏、错题/收藏复习入口,租户管理员 dashboard/主题/学生/销售转化入口,平台管理员租户/套餐/审计入口,以及学生越权后台和跨租户访问拒绝。
真实迁移库本地 API 压测已跑 30/50/100/150 阶梯,均 0 错误50 并发混合读写为 410.49 req/s、P95 237.41ms100 并发混合读写为 393.56 req/s、P95 437.37ms150 并发进入压力观察区。该结果用于证明当前后端代码和索引在本机真实数据下可跑通高并发刷题读写链路,不作为云服务器 SLA。
最近一轮真实迁移专项验证已通过 `npx supabase db reset``npm run pb:import:json``npm run pb:import:validate``npm run pb:import:sample``npm run check:importer``pb:import:sample` 当前为 0 failures、6 warnings、1 skipped、39 passedproduction dry-run 仍按预期返回非 0因为旧数据本身还剩订单缺用户和手册章节缺归属两个 blocker。`npm run test:auth:remote-smoke` 覆盖远程 Auth/JWKS 验收脚本自身。`npm run test:rls` 覆盖 75 条运行时 RLS 断言,包含主租户、合作商租户、无租户 claim、平台管理员旁路和跨租户写入拒绝。`npm run test:api` 覆盖平台细粒度权限、公共题库跨租户同步运营状态、资源访问事件、锁定 CDN 资源拒绝、provider-managed CDN 显式放行、学生短 TTL 下载/预览、访问记录查询、安全扫描门禁、官方账单下载任务权限和脱敏响应、异常订单运营台、人工调整凭证提交/复核/事件/报表、销售/代理转化报表本人/全局权限、平台账单逾期 dry-run/催缴记录、平台审计告警查询/状态更新/越权拒绝/敏感 details 脱敏、平台审计告警通知渠道/事件查询和密钥不回显、平台催缴通知渠道/事件查询和密钥不回显、租户隔离,以及凭证审批不修改订单/支付/权益。`npm run test:worker:commerce` 覆盖支付/退款补偿、微信/支付宝官方账单下载、账单 hash 校验、导入 `provider_download` 对账批次和密钥不泄露。`npm run test:worker:platform-billing` 覆盖平台 SaaS 订阅自动计费、重复开票保护、账单明细和审计。`npm run test:worker:platform-usage` 覆盖平台 SaaS 月度用量自动采集、11 类指标、手工调整记录不覆盖和重复运行幂等。`npm run test:worker:platform-usage-overage` 覆盖平台 SaaS 超额账单明细、重复开票保护、非法账期失败审计、审计告警生成和敏感错误信息脱敏。`npm run test:worker:platform-dunning` 覆盖平台 SaaS 逾期账单标记、内部催缴记录、租户 `past_due` 状态和每日催缴幂等。`npm run test:worker:platform-dunning-notifications` 覆盖平台 SaaS 催缴外部通知入队、generic webhook 发送、幂等、防重复、联系方式掩码、签名密钥不泄露和请求 payload 脱敏。`npm run test:worker:platform-audit-alerts` 覆盖平台审计告警生成、规则匹配、幂等、防重复和告警 details 脱敏。`npm run test:worker:platform-audit-notifications` 覆盖平台审计告警外部通知入队、generic webhook 发送、幂等、防重复、签名密钥不泄露和请求 payload 脱敏。`npm run test:worker:assets` 覆盖托管资源复检、内置安全扫描、外部 HTTP scanner 通过/失败/不可用 fail-closed、扫描失败/跳过事件和异常资源自动下架。`npm run test:worker:public-banks` 覆盖公共题库自动同步、失败通知和恢复自动关闭。`npm run test:worker:exports` 覆盖导出 worker 生成可信资源并标记 `securityScanStatus=passed``npm run audit:runtime` 当前为 0 vulnerabilitiesExcel 解析已从 `exceljs` 切换为 `read-excel-file`,避免生产运行时携带 `exceljs -> uuid` 的已知中危依赖。
注意:`apps/taro` 是静态构建工程,线上发布 `apps/taro/dist/**`,不发布 `node_modules`。Taro 4.2.0 当前构建工具链仍会触发 `npm run audit:taro:toolchain` 的上游 high/critical 提示,不能用 `npm audit fix --force` 降级到 Taro 3 破坏构建;上线验收时以 `audit:runtime`、构建产物、前端密钥检查和静态服务器配置为准,并持续跟进 Taro 官方修复。
## 下一步建议
优先继续补:
1. 真实云端 Auth/JWKS 回归、RLS 深测和生产环境配置验收;生产 `.env` 和数据库 provider 配置必须先通过 `readiness:production``readiness:production:db`,再开放前端联调域名。
2. 继续补 Taro 前端:学生端小程序公式真机验收、题图资源后台字段化、小程序支付与分享,租户后台更细导入体验/数据范围 UI/主题素材库/财务复核细节,平台后台在线收款、审计报表增强、审计告警通知升级策略、催缴通知操作台细节和小程序兼容验证。
3. 对象存储真实 AV/内容安全扫描服务联调、CDN 防盗链、转码/CDN 级水印和生命周期策略。
4. 题库导出模板精排、导出操作台、导入字段映射 UI 和复检结果操作台;继续对真实迁移数据做题目、订单、权益、错题、资料和视频抽样验收。
5. 上云后接真实 OAuth/短信/支付生产账号、回调域名和真实生产账单抽样验收;本地阶段继续用 mock/fake provider 验证回调后业务链路、幂等、审计、密钥不泄露和权益开通/撤销。后续还要补真实打款 provider、发票、公共题库版本通知/冲突处理操作台、积分活动风控、连续签到奖励深化、销售/代理转化预聚合和更细团队数据范围。排行榜不是默认主线功能,仅在租户显式购买/开启活动并完成压测后,才进入防刷、日/周榜预聚合和运营看板开发。
旧原生小程序前端位于 `F:\project\参考\旧题库小程序前端文件`,后续 Taro H5/小程序补体验时只作为页面状态、微信平台能力和交互参考,不继承旧 PocketBase 直连和旧鉴权逻辑。