Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# USTSACMLand 开发路线图

最后更新:2026-08-11(Asia/Shanghai)
最后更新:2026-08-13(Asia/Shanghai)

本路线图只保留仍需执行的工作和当前生产基线,不再把已经完成的每次迁移、测试数量和历史烟测逐条堆在主文档中。详细实现记录放在 `README.md`、`docs/evidence/`、`docs/operations-runbook.md` 和 GitHub Pull Request 中。

Expand Down Expand Up @@ -40,7 +40,7 @@ USTSACMLand 的定位是苏州科技大学 ACM 集训队官网,当前产品范
## 2. 当前生产基线

- [x] GitHub Pages 已发布 React SPA,支持子路径资源、深链刷新和生产榜单审计。
- [x] Supabase Auth、Postgres、RLS、12 个 Edge Function 和 75 个生产 migration 已部署;除公开头像代理 `member-avatar` 按设计关闭 JWT 验证外,其余函数均启用 JWT 验证,12 个函数的 import map、浏览器 CORS/后台拒绝边界及同步调度已通过生产只读检查。推荐计划与 WebChat 成员入口继续关闭,遗留图片数据库与函数安全基础保留。证据见 [`docs/evidence/supabase-ten-function-readiness-2026-07-26.md`](./docs/evidence/supabase-ten-function-readiness-2026-07-26.md) 与 [`docs/evidence/agent-cold-start-handoff-audit-2026-08-09.md`](./docs/evidence/agent-cold-start-handoff-audit-2026-08-09.md)。
- [x] Supabase Auth、Postgres、RLS、12 个 Edge Function 和 76 个生产 migration 已部署;除公开头像代理 `member-avatar` 按设计关闭 JWT 验证外,其余函数均启用 JWT 验证,12 个函数的 import map、浏览器 CORS/后台拒绝边界及同步调度已通过生产只读检查。推荐计划与 WebChat 成员入口继续关闭,遗留图片数据库与函数安全基础保留。2026-08-12 已应用 `202608090001_retire_webchat_mutations.sql` 并部署 `webchat-config` v14;证据见 [`docs/evidence/webchat-retirement-production-2026-08-12.md`](./docs/evidence/webchat-retirement-production-2026-08-12.md)。
- [x] 邮箱注册、密码登录、真实邮箱找回密码、修改密码和会话恢复流程可用。
- [x] 成员资料、年级、专业联想、QQ、六个平台绑定和 XCPC ELO 姓名自动匹配已上线。
- [x] Rating 榜、刷题榜、周榜、月榜和自定义时间范围增量榜已上线。
Expand All @@ -50,7 +50,7 @@ USTSACMLand 的定位是苏州科技大学 ACM 集训队官网,当前产品范
- [x] 每日一题、完成/撤销、讨论、审核和后台题目生命周期已上线。
- [x] WebChat 的历史实现曾完成当前模型、累计成员限额、私有历史、刷新恢复和“思考中”等能力;现已作为遗留模块停止产品开发并保持生产关闭,代码与安全边界继续保留。
- [x] 个人数据导出已上线,并通过真实成员归属和敏感字段生产烟测;证据见 `docs/evidence/personal-data-export-production-2026-07-20.md`。
- [x] 加密数据库备份与隔离恢复演练已完成;证据见 `docs/evidence/database-restore-drill-2026-07-19.md`。
- [x] 加密数据库备份与隔离恢复演练已完成;2026-08-13 使用当前 `main` 的 76-migration Schema v2 生产快照完成备份、Storage 清单/哈希、单事务隔离恢复、Auth/RLS、匿名拒绝和明文清理核对;证据见 [`docs/evidence/database-restore-drill-2026-08-13.md`](./docs/evidence/database-restore-drill-2026-08-13.md)

## 3. v1.0.0 发布前必须完成

Expand Down Expand Up @@ -86,7 +86,7 @@ USTSACMLand 的定位是苏州科技大学 ACM 集训队官网,当前产品范

- [x] 项目负责人已选择 Apache License 2.0(SPDX 标识符:`Apache-2.0`),维护 Agent 已加入根目录 `LICENSE`。该许可证覆盖项目原创源代码,以及未附带其他授权声明的原创文档和配置;学校、集训队、赛事标识、第三方素材、成员数据和平台数据仍保持独立授权边界。
- [x] 确认同步巡检、数据库备份、凭据轮换、回滚和管理员操作可以由全新上下文 Agent 仅根据仓库文档冷启动执行。2026-08-09 全新上下文 Agent 完整阅读根契约与专项手册,在不触发生产写操作的前提下完成 GitHub/Supabase 冷启动核对、同步队列巡检、备份连续性检查及前端、Edge Function、数据库和 Cloudflare 回滚桌面推演;同时识别并修复仓库级 Secret 与 `production-operations` Environment Secret 的检查口径偏差。证据见 [`docs/evidence/agent-cold-start-handoff-audit-2026-08-09.md`](./docs/evidence/agent-cold-start-handoff-audit-2026-08-09.md)。
- [ ] 按 `docs/release-checklist.md` 完成最终检查并创建 `v1.0.0` 标签。2026-07-29 已通过仓库就绪检查、全仓库 ESLint、七项工作流结构门禁、93 个 Vitest 文件共 596 项测试、10 个函数入口 Deno 类型检查、136 个文件 Deno Lint、462 项 Edge Function 测试、生产构建和 Cloudflare 指纹资源长期缓存门禁;Supabase 已关闭邮箱自动确认并启用服务端 Turnstile CAPTCHA,preflight 与严格就绪检查均通过。全新真实邮箱的有效 token 注册、确认邮件、确认前登录拒绝、重复确认安全性、确认后密码登录和带独立 Turnstile 的自助注销已经完成;注销后的 Auth、Profile 及 19 类关联数据均为 0,再次登录返回标准凭据拒绝。两组各不超过 30 次的生产限流检查均安全停止但未触发 `429`。2026-08-04 又将登录/注册限额临时从 `30` 降至 `2`,等待 30 秒并严格限制为三次请求后仍只得到 `400 / invalid_credentials`;这表明动态降阈值没有立即收缩当前 IP 的旧令牌桶余额,配置已恢复为 `30`,不能把结果记作恢复通过。冷启动交接验收已于 2026-08-09 完成;仍缺维护窗口内可复现的受控 `429` 窗口恢复、当前 `main` Schema v2 备份恢复演练,以及 Supabase 日志与 Firecrawl 保留窗口核验,因此暂不创建标签。证据见 [`docs/evidence/release-gates-2026-07-28.md`](./docs/evidence/release-gates-2026-07-28.md)、[`docs/evidence/registration-abuse-production-gap-2026-07-28.md`](./docs/evidence/registration-abuse-production-gap-2026-07-28.md)、[`docs/evidence/auth-rate-limit-recovery-production-2026-08-04.md`](./docs/evidence/auth-rate-limit-recovery-production-2026-08-04.md) 与 [`docs/evidence/agent-cold-start-handoff-audit-2026-08-09.md`](./docs/evidence/agent-cold-start-handoff-audit-2026-08-09.md)。
- [ ] 按 `docs/release-checklist.md` 完成最终检查并创建 `v1.0.0` 标签。2026-08-13 已补齐当前 `main` Schema v2 备份恢复演练;仍缺维护窗口内可复现的受控 `429` 窗口恢复、Supabase 日志与 Firecrawl 保留窗口核验,因此暂不创建标签。证据见 [`docs/evidence/release-gates-2026-07-28.md`](./docs/evidence/release-gates-2026-07-28.md)、[`docs/evidence/registration-abuse-production-gap-2026-07-28.md`](./docs/evidence/registration-abuse-production-gap-2026-07-28.md)、[`docs/evidence/auth-rate-limit-recovery-production-2026-08-04.md`](./docs/evidence/auth-rate-limit-recovery-production-2026-08-04.md)、[`docs/evidence/agent-cold-start-handoff-audit-2026-08-09.md`](./docs/evidence/agent-cold-start-handoff-audit-2026-08-09.md) 与 [`docs/evidence/database-restore-drill-2026-08-13.md`](./docs/evidence/database-restore-drill-2026-08-13.md)。

### PR #146 合并前审查整改

Expand All @@ -99,8 +99,8 @@ USTSACMLand 的定位是苏州科技大学 ACM 集训队官网,当前产品范
- 仓库已完成:移除 `use-composed-ref@1.4.0` 许可补充材料中从其他包推断的版权归属;现仅记录该精确 npm 包与源码 tag 的 MIT 声明、标准许可条款,以及上游未提供 LICENSE 文件或版权声明的事实,不再制造未经上游确认的版权行。
- 仓库已完成:修复仓库就绪检查的组织级 Actions Secret 分页漏检,并让缺少 `production-operations` Environment 时返回可操作的失败信息;已补齐分页、缺失 Environment 和失败信息回归测试,readiness 专项 14 项通过。
- 仓库已完成:统一公开隐私页与关闭态产品行为,不再承诺当前没有成员入口的单会话删除操作,明确 180 天自动清理、个人数据导出和永久注销边界;隐私页与默认关闭路由共 21 项测试通过。
- 仓库已完成:阻止普通成员绕过已隐藏的 WebChat 界面直接调用 own-history 写 RPC 创建或修改遗留会话;新增 migration 撤销 `public`、`anon`、`authenticated` 与 `service_role` 对创建、重命名、归档和消息 upsert 的执行权限,同时将 relay 请求开关与图片上传全局暂停状态持久化为关闭,保留本人历史读取/删除、个人导出、180 天清理和注销级联边界。当前 51pgTAP 文件、1249 项断言通过;生产 migration 尚未应用,仍须项目负责人单独批准后部署
- 仓库已完成:将管理员 WebChat 配置与成员 AI 权限界面收紧为只读关闭态,禁止通过站内后台修改中转站、模型、Key、预算、请求开关、成员授权或额度;`webchat-config` 的合法更新请求固定返回 `410 feature_retired`,同时保留关闭状态和历史用量诊断。管理员界面专项 20 项、Edge Function 专项 15 项、全量 Deno 477 项测试通过,并已完成桌面、390px 与宽屏 Chrome 验收;Pages 与 Edge Function 生产部署仍须另行授权
- 仓库与生产已完成:阻止普通成员绕过已隐藏的 WebChat 界面直接调用 own-history 写 RPC 创建或修改遗留会话;`202608090001_retire_webchat_mutations.sql` 已应用,撤销 `public`、`anon`、`authenticated` 与 `service_role` 对创建、重命名、归档和消息 upsert,以及两个管理员写 RPC 的执行权限,同时将 relay 请求开关与图片上传全局暂停状态持久化为关闭,保留本人历史读取/删除、个人导出、180 天清理和注销级联边界。生产共 76migration,六个 writer 对三类应用角色全部撤权;部署后没有新增 WebChat 请求或额度账目。证据见 [`docs/evidence/webchat-retirement-production-2026-08-12.md`](./docs/evidence/webchat-retirement-production-2026-08-12.md)
- 仓库与生产已完成:将管理员 WebChat 配置与成员 AI 权限界面收紧为只读关闭态,禁止通过站内后台修改中转站、模型、Key、预算、请求开关、成员授权或额度;`webchat-config` v14 的合法更新请求固定返回 `410 feature_retired`,同时保留关闭状态和历史用量诊断。管理员界面专项 20 项、Edge Function 专项 15 项、严格 Supabase readiness 通过,并已完成桌面、390px 与宽屏 Chrome 验收;本次仅部署 `webchat-config`,未修改 Secret/Vault、其他函数或 Pages。证据见 [`docs/evidence/webchat-retirement-production-2026-08-12.md`](./docs/evidence/webchat-retirement-production-2026-08-12.md)
- 仓库已完成:同步 CI 回归到 WebChat 只读关闭态断言,并修复 WebKit 移动学习章节导航与邀请码注册页的异步时序;移动端锚点即时定位、当前章节导航同步收回,E2E 轮询最终可见几何状态并为低速路由加载保留充分等待,相关 WebKit 重复测试 20/20 通过。

## 4. v1.0.0 发布后接入 Cloudflare
Expand Down
53 changes: 53 additions & 0 deletions docs/evidence/database-restore-drill-2026-08-13.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# 当前 main Schema v2 加密备份与隔离恢复演练

日期:2026-08-13(Asia/Shanghai)

## 范围

- 生产项目:`qzggoqdmsvktrtnjislw` / `USTSACMLand`
- 备份提交:`29709004dca0d69b3778f512f13c5c8200018042`
- 加密备份运行:[31622577243](https://github.com/greenthree/USTSACMLand/actions/runs/31622577243)
- 隔离恢复运行:[31622919641](https://github.com/greenthree/USTSACMLand/actions/runs/31622919641)
- Supabase CLI:`2.109.1`

本次由项目负责人批准执行。备份只读取生产数据库和私有 Storage 元数据/对象;恢复工作流不使用生产 Supabase 凭据,不连接远端数据库,只在一次性 GitHub Runner 的本地 Supabase/PostgreSQL 17 中恢复。除下述 GitHub 仓库级 `SUPABASE_ACCESS_TOKEN` 轮换外,未修改生产数据库、Supabase Function Secret/Vault、函数或 Pages,也未触发模型、图片或 WebChat 请求。

## 凭据轮换

首次备份 run `31619244319` 与唯一受控重试 `31619567558` 均在配置检查通过后,于首个 `supabase link` 返回 `Unauthorized`。两次运行都没有开始数据库 dump、Storage 下载、加密或 Artifact 上传。项目负责人随后批准轮换仓库级 `SUPABASE_ACCESS_TOKEN`;新令牌由负责人直接写入 GitHub Secret,Agent 未读取、复制或记录令牌值。GitHub Secret 元数据确认更新时间为 2026-08-13 01:24(Asia/Shanghai),之后的正式备份成功。

新 Supabase PAT 于 2026-09-12 到期。维护 Agent 必须在到期前重新生成短期令牌、更新同名 GitHub Secret,并用一次成功备份确认轮换完成;不得等待定时备份因过期失败后再处理。

## 备份结果

备份工作流的配置检查、数据库与 Auth 导出、Schema v2 Storage 快照、动态白名单、AES-256-CBC/PBKDF2 加密、自解密校验、明文清理和密文 Artifact 上传全部通过。Artifact 仅包含加密文件及其校验和,按工作流保留 14 天。

## 隔离恢复结果

脱敏报告确认:

| 项目 | 结果 |
| ---------------------- | ---: |
| `profiles` | 8 |
| 平台账号 | 41 |
| 当前平台统计 | 40 |
| 统计快照 | 1411 |
| 同步运行 | 1828 |
| Auth 用户 | 8 |
| migration 历史 | 76 |
| WebChat 图片附件 | 0 |
| WebChat Storage 对象 | 0 |
| WebChat Storage 总字节 | 0 |
| 隔离恢复阶段耗时 | 3 秒 |

Storage 功能状态为 `installed`,Bucket `webchat-images` 保持私有;空清单 SHA-256 为标准空值。数据库引用与 Storage 对账、对象哈希校验和匿名访问拒绝均通过。

7 类孤儿关系全部为 `0`:Profile/Auth 双向、平台账号/Profile、统计/Profile、统计/平台账号、图片/Profile、图片/会话。

三个 `auth.users` 应用触发器已恢复;隔离临时账号的注册建档、密码登录、本人 Profile RLS、其他 Profile 隐藏、匿名公开视图、匿名私表保护、受控注销和 canary 清理全部通过。Runner、解密文件、临时凭据、Storage 对象和探针均在报告上传前清理。

## 结论与边界

本次演练证明当前 `main` 对应的 76-migration 生产快照可以在干净的 Supabase 平台基线中完成 Schema v2 解密、单事务恢复、Auth/RLS 验证、关闭态空 Storage 对账和清理。自动化恢复 RTO 基线为约 3 分钟;不包含新建远端项目、Secrets/Auth 回调、Edge Functions、DNS、第三方凭据和业务复核。

本证据不记录成员姓名、邮箱、QQ、平台账号、密码哈希、消息正文、SQL、连接信息、Token 或加密口令。
44 changes: 44 additions & 0 deletions docs/evidence/webchat-retirement-production-2026-08-12.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# WebChat 退役关闭态生产部署

日期:2026-08-12(Asia/Shanghai)

项目:`qzggoqdmsvktrtnjislw` / `USTSACMLand`

基线提交:`29709004dca0d69b3778f512f13c5c8200018042`

执行范围:项目负责人批准的 `202608090001_retire_webchat_mutations.sql` 与 `webchat-config` 单函数部署。

## 执行结果

- 生产 migration 已由 Supabase CLI `2.109.1` 应用。
- dry-run 仅包含 `202608090001_retire_webchat_mutations.sql`。
- migration list 已对账为本地/远端一致,共 76 个 migration,0 个待部署。
- 仅部署 `webchat-config`,版本从 13 更新为 14;其他 11 个 Edge Function 未部署。
- 未修改 Secret/Vault,未读取或回显任何 Secret 值,未部署 Pages,未发起模型、图片或 WebChat 消息请求。

## 关闭态对账

部署后通过 Supabase linked database 只读查询确认:

| 检查项 | 结果 |
| --------------------------------------------------------- | -------- |
| `202608090001` 已应用 | `true` |
| `private.webchat_relay_config.requests_enabled` | `false` |
| `private.webchat_global_quota_state.image_uploads_paused` | `true` |
| 6 个退役 writer 对 `anon` | 全部撤销 |
| 6 个退役 writer 对 `authenticated` | 全部撤销 |
| 6 个退役 writer 对 `service_role` | 全部撤销 |
| 部署后新增 `webchat_requests` | `0` |
| 部署后新增全局 request usage | `0` |

`npm run check:supabase-readiness` 通过,报告 76 个 migration、12 个 Edge Function、23 个 Function Secret 名称(缺失 0)、0 个 schema lint finding、Auth/REST/Edge Function/CORS/队列调度就绪。报告同时提示生产未启用 PITR 且物理备份为 0;项目继续依赖并演练仓库加密逻辑备份,该提示不是本次 WebChat 关闭变更引入的故障。

`webchat-config` 的本地专项测试通过:15/15。测试覆盖管理员认证、正式 Origin CORS、只读脱敏配置、更新请求固定返回 `410 feature_retired`、不读取用量、不调用 writer,以及异常响应脱敏。

未运行完整 `npm run check:production-security`,因为该脚本包含临时解除图片暂停、上传真实夹具和完整图片生命周期流程,与本次明确的“不得触发图片请求”批准范围冲突。已用上述不触发图片、模型或真实成员写入的最小关闭态验证替代,并保留完整脚本作为后续独立安全复核工具。

公开生产页面验证已完成:首页桌面、390px 和 1440px 宽屏无横向溢出且 Chrome 控制台无 warning/error;未登录 `/assistant` 回到首页,普通导航无 AI 助手入口;未登录 `/admin/webchat` 进入登录页。

## 回滚边界

数据库 migration 不回写、不删除、不重新授予退役 writer;如发现问题,只能新增前向 corrective migration。函数故障时只部署与当前 Schema 兼容的最小关闭态修复,保持所有产品开关关闭;不得回退为可写版本。
Loading
Loading