|
|
516929461f
|
docs: 拿阶段 0 的权威清单核对交付,110/110 零缺口
之前那个正则脚本只能说"没发现缺口",证明不了"没有缺口"。这次拿阶段 0 人工裁决过的
端点清单来对 —— 那 110 条 KEEP 是「必须搬」的权威名单,逐条对到新后端。
**结果 110/110 全部有对应实现,零缺口。**
87 条词元化后自动匹配上;剩下 23 条是 API 重新设计导致路径本来就对不上的,
逐条人工落实,没有一条是真的漏了。一度以为 /api/register 没实现,
查下去是改叫 POST /api/users 了。
把其中**猜不到的那 10 条改名**记进了清单(problemset → problem-sets 这类
一眼能猜的没列)。日后排查「这个功能以前的接口现在在哪」,看这张表就够了:
/api/register → POST /api/users
/api/logout → DELETE /api/auth/session
/api/hitokoto → GET /api/quotes/random
/api/pickone → GET /api/problems/random
/api/user_activity_rank → GET /api/rankings/activity
/api/profile/fresh_display_id → POST /api/me/problem-display-ids/refresh
……
最后一条 /api/judge_server_heartbeat/ → /api/judge-server/heartbeat 单独标了:
判题沙箱镜像是原样复用的,靠 compose 的 BACKEND_URL 找后端,改这条要同步改
compose,否则判题机静默离线。已核对三套 compose 都是新路径。
也写明了方法的局限:词元匹配只能提示「这两条像是同一个」,证明不了行为一致 ——
行为一致靠的是两轮独立评审和阶段 5 的实跑演练,不是这张表。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-08 04:11:39 -06:00 |
|
|
|
a47e051a49
|
docs(阶段5): 补验 WebSocket 经 Caddy 与机房那套 compose
演练报告里原来有两块是没验过的,补上:
## WebSocket 经 Caddy
学生盯着「判题中…」变成结果就靠这条路,而它经过 Caddy 的 handle /ws/*,
是配置最容易写错、又只在生产才暴露的一段。实测 upgrade 成功,301ms 内
收到两条推送:judging → finished(AC)。
## 机房那套 compose.school.yml
和服务器那套差别不小(没有 postgres、连远程库、端口 81、COOKIE_SECURE=false),
之前一次都没跑过。留下 oj-postgres 当「远程库」、其余换成 school 栈跑了一遍:
连库、首页、题目列表、登录、WS、完整判题全通。
其中特意验了 **Cookie 没带 Secure** —— 带了的话机房(http 直连 IP)会出现
「登录成功但立刻又变未登录」,是那种看起来毫无头绪的故障。
顺带确认机房的拓扑是「本地 Redis + 本地判题沙箱 + 远程库」,
判题不跨公网,只有数据库查询走公网。
演练用的是 docs/specs/schema.sql 只灌结构,盘上不留学生数据;跑完已清干净。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-08 03:33:00 -06:00 |
|
|
|
c59ecd6dbb
|
fix(SQL 沙箱 Minor): 让题目的 memoryLimit 对学生真正生效
## M-1
题目写 64MB 也没意义 —— 唯一的硬顶是子进程那个固定 512MB 的 ulimit -d,
学生实际能吃到 8 倍。旧实现是 setlimit(SQLITE_LIMIT_LENGTH, memoryLimit)
把单值长度贴着题目内存限,但 sql.js 的 wasm 没导出 sqlite3_limit(已核对导出表),
复刻不了。
改成引擎侧按字节记账(ByteBudget):取行时累加,单值超限或结果集累计超限都按 MLE 拒。
max_page_count 管的是库文件页数,管不住「一个 SELECT 拼出一个巨大的值」,所以两者
不重复。查询题和增删改题(dumpTables)两条路都记账,受信脚本不记。
实测 6 条,关键是**同一句 SQL 在 4MB 的题上被拦、在 64MB 的题上放行**,
证明限制跟着题目走而不是一刀切。
第一版测试用的是 100MB 的值,结论是错的:wasm 堆触顶时的兜底和我的记账器报的是
同一句「单个数据值超出内存限制」,大值根本分不清是谁拦的。换成 8MB 才测得准。
这个教训写进注释了。
M-1 的第二半(max_page_count 学生可自行调大)在 I-1 拦 PRAGMA 时已一并修掉。
## M-3
阶段 5 的分阶段兜底超时顺带解决:出题人预览死循环从 25s 降到 13005ms 实测。
## M-2 不修
「强制两个测试点期望结果不同」会把合法出题也挡掉(刻意用两组数据验证同一边界、
结果恰好相同),代价是老师被一条看不懂的错误拦住。评审也确认与旧实现一致、非回归。
更合适的是提示而非拒绝,但要动契约和后台前端。理由写进评审文档,免得下次又当新发现。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-08 02:27:35 -06:00 |
|
|
|
fb22b7d49f
|
docs(阶段5): 用生产快照跑完整切换演练
演练用 compose.debian.yml **本身**在本机 Docker 里跑,不是简化版。
数据是 2026-08-07 的 pg_dumpall 快照:1710 用户 / 956 题 / 123140 提交。
## 出口标准达成
停旧栈 11s,起新栈 34s(镜像预先构建好),全链路验证约 2 分钟 ——
**停机不到 1 分钟**,远在 30 分钟内。真正的时间风险在构建镜像(首次约 5 分钟),
所以手册里第一条就是「镜像必须在停机窗口之前构建好」。
验证到位的:首页、站点配置、题目列表、标签、公告、登录(argon2 新哈希和
Django pbkdf2 旧哈希都支持)、个人页、排行榜、后台四个接口、判题机自动注册,
以及**完整判题**(提交 Python A+B → AC,1.2 秒,两个测试点全过)。
## 两件原以为要做、实测不用做的事
- **不需要任何 DDL**:生产 dump 和新后端在用的库逐列对比,两边都是 278 列,
零差异。新后端直接跑在现有结构上。
- **不需要重置序列**:我在 phase3-coverage.md 里记的那条「切换必做:重置序列」
**是错的**,来自我手工按显式 id 导入、又没补 setval 的本地库。真实的
pg_dumpall 带 30 条 setval,且把快照里所有序列和 max(id) 逐个对过,错位 0 个。
已在原文档上标注更正,没有删掉原文 —— 错误结论本身也是信息。
## 回滚保证已实测
新栈跑完登录、提交、判题之后,再和生产 dump 比一次结构:逐列一致,零差异。
加上数据目录布局照抄旧后端,回滚 = 停新栈 + 起旧栈,约 20 秒,不动任何数据。
(未实测的部分也写明了:本机没构建旧 Django 镜像,「起旧栈」这一步没跑过。)
## 演练抓到的真问题
**pg_dumpall 备份会覆盖数据库口令。** 恢复完快照,新后端立刻报
`password authentication failed` —— 因为 dump 里带
`ALTER ROLE onlinejudge ... PASSWORD 'md5…'`,把角色口令覆盖成了备份时生产的那个。
正常切换不受影响(根本不恢复备份),但灾难恢复时这一条不写下来,
现场会被一个看起来毫不相干的报错卡住。
**恢复备份前必须先停应用**,否则 dump 里的 DROP DATABASE 失败。演练时因为
目标库是空的,数据照样进去了 —— 那是运气,目标库有数据就是满屏主键冲突。
## 镜像体积没达标,写明了原因
api 镜像 487MB,设计文档写的是「数十 MB」。一半以上(269MB)是 clang-format
拖进来的 LLVM,光 libLLVM.so 就 124MB。旧 Python 镜像同样装了 clang-format,
所以新镜像仍明显更小,但当初估「数十 MB」时没把它算进去。
瘦身路径也记了(换静态 clang-format 可砍 265MB),暂不做。
## 清理
演练在 data/postgres 留下了一份完整的生产数据副本,含 1710 名学生的
raw_password 明文列,已删除。手册里留了提醒 —— 那不是测试数据。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-08 02:13:59 -06:00 |
|
|
|
0f94e7ecbd
|
fix(阶段4): 两份独立安全评审的 Critical/Important 全部修掉
## 权限边界评审(后台 86 个 handler)
守卫本身一个没漏,问题全在对象级归属校验:
- C1 跨题单删奖章:先按 (id, problemsetId) 校验奖章归属再删,
否则拿自己的题单 id + 别人的奖章 id 就能把别人的 user_badge 删掉
- C2 make-public 无归属校验:补 canEdit,越权者拿不到题面
- I1 两个分析端点被 `/problems/:id` 遮蔽 —— Hono 按注册顺序匹配,
不是静态优先。挪到 `/problem-analytics/*`
- I2 from-public 只校验目标比赛归属:源题也必须是公开题库题
- I3 克隆比赛回传原比赛明文密码:克隆一律 password: null
- I4 upload-image 守卫比旧后端严,教师写题面会 403:收回 requireAdmin
两个互不可见的教师账号实跑复验,六条全部拦住。
## SQL 判题沙箱评审
- I-1 查询题只读被一句 `PRAGMA query_only=0` 关掉,实测 DML 拿到 AC。
query_only 自己就是个 PRAGMA,旧实现靠 authorizer 把 SQLITE_PRAGMA
一律拒了才没这个洞。现在 runStudent 逐语句拦 PRAGMA(用
sqlite3_normalized_sql 判关键字,注释和大小写由 SQLite 抹平),
并在每条语句前重放 query_only 和 max_page_count 兜底。
顺带修掉 M-1 里 max_page_count 学生可自行调大的部分。
- I-2 单条语句进了 step() 就打断不了,只能等父进程 SIGKILL,
而兜底时限是整个作业一口价 25s —— 1s 限的题要 26s 才判 TLE,
判题池只有 2 个槽,几发死循环就能把所有人堵住。
改成分阶段:子进程用 stderr 报 prepare/student/display,
父进程边读边换表,一进学生 SQL 就把兜底收到「题目时限 + 2s」。
实测 26s → 3.06s。
归因也跟着修了:卡在受信脚本(出题人的初始化脚本、标准答案)
现在报 SYSTEM_ERROR,不再当成学生超时甩 TLE。
engine.ts 头部那张防护对照表按实测重写 —— 原来那版把 query_only
写成等价于 authorizer 白名单,是不成立的。另记一笔:stock sql.js 的
wasm 没导出 progress_handler / interrupt / set_authorizer / limit,
想要得自己编,别再去翻了。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 21:59:42 -06:00 |
|
|
|
e3faa689e7
|
feat(阶段2补课): SQL 判题链路 + 最后两个后台端点
新后端此前完全没有 SQL 判题(旧 judge/sql_runner.py 378 行 + sql_dispatcher.py
113 行无对应实现),阶段 2 纵切时漏了这条与沙箱完全不同的路径。
judge/sql/engine.ts 判题核心,移植自 sql_runner.py,判定口径逐条对齐
judge/sql/child.ts 子进程入口
judge/sql/index.ts 父进程:spawn + 硬超时
judge/run.ts language === "SQL" 时分流,不经判题沙箱
POST admin/sql-test-cases/preview 题目页展示数据预览
POST admin/sql-test-cases/generate AI 按标准答案倒推初始化脚本
题目保存时重新生成 sqlDisplay(对齐旧 generate_sql_display):取测试点 1 的初始化
脚本 + 标准答案跑一遍,失败一律拦下不让保存 —— 展示数据直接决定学生看到的表结构
与期望结果,宁可不保存也不能存错的。
## 防护换了实现,逐条实测
bun:sqlite 没有 authorizer / progress_handler / setlimit,且实测 Worker.terminate()
杀不掉跑飞的查询(原生代码占着线程)。改用「WASM 引擎 + 独立子进程」:
ATTACH → WASM 无宿主文件系统绑定,结构上够不到(比旧的 authorizer 更强)
查询题只读 → PRAGMA query_only=1
超时 → 子进程外部 SIGKILL
单值内存 → 子进程 ulimit -d
八条提交实测:正确→Accepted;列少一个/漏过滤→Wrong Answer;语法错误→Compile Error;
查询题里 INSERT→运行错误并说明;递归 CTE 死循环→CPU 超时;hex(zeroblob(2e8))→内存超限;
attach '/etc/passwd'→打不开。
## 踩到的两个坑(已写进 docs/specs/phase3-coverage.md)
1. ulimit 必须用 -d 不能用 -v。-v 限虚拟地址空间而 JS 引擎预留巨量地址,实测 -v 之下
Bun 退出时有概率 panic(SIGILL),结果早已写出但进程异常终止,父进程读到空串
误判成超时 —— 6 次里坏 2 次。换 -d 后 12/12 稳定。
2. 子进程写完结果直接 SIGKILL 自己,不走 process.exit()——后者仍有清理会撞限额。
至此 admin/api.ts 已无任何指向旧后端的调用。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 17:03:41 -06:00 |
|
|
|
764e0d28cc
|
feat(阶段4): 标签管理 / 批量打标签 / 题目可见性 / 卡点与 AC 趋势 / 流程图 AI
GET/PUT/DELETE admin/problem-tags[/:id]
POST admin/problems/batch-tag
PUT admin/problems/:id/visibility
GET admin/problems/stuck
GET admin/problems/ac-trend
POST admin/problems/flowchart
要点:
- 后台标签列表用 leftJoin 且不加 having,能看到 problemCount=0 的标签 ——
那正是要清理的那些。oj 侧的 /problem-tags 才过滤 >0。
- 标签改名撞上已有标签视为合并:只给「还没挂目标标签」的题目补关系,
否则会撞 (problem_id, problemtag_id) 唯一约束。
- 批量打标签:add 时按需新建标签、remove 时只认已有标签 ——
否则「移除」会顺手造出一堆空标签。名字去重且大小写不敏感。
- **旧 ProblemVisibleAPI 的 `self.error(...)` 少写了 return**,题目不存在时会继续
往下跑并抛 AttributeError(500)。这里正常返回 404。
顺带记下一条阶段 5 的必做项(见 phase3-coverage.md 文末):本地库按显式 id 从生产
导入,序列没跟着走,第一次新建标签就撞 problem_tag_pkey。只要切换流程里有
「导出→导入到新库」这一步,就必须重置全部序列,否则读全正常、第一次写才炸。
实测:学生 403;大小写重复与空白名去重后 tagCount=1、重复 add 幂等、
remove 不存在的标签 404 且不新建;纯改名 merged=false、合并 merged=true
affectedCount=1 且只剩一个标签;可见性取反两次复原、不存在的题 404。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 16:30:48 -06:00 |
|
|
|
359b91ab4d
|
docs(阶段3): 记录 7 条 Minor 的逐条结论
其中两条判为无需改动并说明理由:M-2(user-progress 的 realName)已被 F2 的
sampleUser 默认关闭开关覆盖,现在与旧后端一样返回 null;M-3(练习答案下发)
旧后端逐字相同,属教程练习「客户端比对」的既有设计,不是本次重写引入的回归。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 07:01:13 -06:00 |
|
|
|
ced8f3ee1b
|
docs(阶段3): 记录出口标准达成;补跑 prettier
覆盖率对账表更新:admin 侧 3/45 已实现,缺口 42。达成判据是 apps/web 的
oj/ 与 shared/ 两个目录已无指向旧 Django 的运行时调用,残留的 utils/http
引用只剩 ApiResponse 这一个类型。
顺带补跑 npm fmt,几个此前未格式化的文件随之改动,均为纯格式。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 06:48:20 -06:00 |
|
|
|
cb6d42363b
|
docs(阶段3): 修复波复评通过,安全 findings 收口
8 条(F1-F6 + 收尾 F4b/F5b)全部 ADDRESSED,修复 diff 内无新引入破坏。
复评补上了控制方没验充分的 F4b:真造了一条比赛提交,确认数据库存真值
而 API 返回给本人的是 info:{} / ip:null / contestId:null。
另核实 sampleUser() 是真正的默认关闭开关(覆盖全部 14 个下发点)、
isRegularUser 全仓确实只有一个调用点、.env 加载器优先级正确、
限流参数与旧后端 options/options.py 逐值吻合。
评审产物从 gitignore 的 .superpowers/sdd/ 归档进 docs/specs/ 以免丢失。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 06:26:20 -06:00 |
|
|
|
9c04b00e3f
|
docs(阶段3): 权限与泄露双评审报告 + 合并修复清单
两份评审独立进行、互不知情,各自命中同两条问题(匿名可读用户档案、
realName 无条件下发),独立复现提高可信度。严重度取更严一方 ——
使用者是中职学生,姓名邮箱班级属个人信息。
3 Critical / 3 Important,F1-F3 已由控制方独立实跑复现。
无敏感字段泄露、无泄题,比赛权限重建得最好。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 01:43:55 -06:00 |
|
|
|
0f999aa5b1
|
docs: 阶段 0/1/2 出口标准核验 + 阶段 3 覆盖率对账
核验为逐条实跑,不采信文档声称。阶段 0/1/2 出口标准全部通过,
其中阶段 2 判题链路端到端实测(注册→登录→提交→JudgeServer→WS 推送)。
覆盖率对账:oj 侧 65 条已全部实现,admin 侧 45 条一条未做。
新旧路径不同名(API 已重新设计),对照关系为人工按语义逐条比对。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-07 01:25:36 -06:00 |
|
|
|
0a8fcef3f2
|
chore(阶段1): 题目样本导入脚本(不含用户数据)
|
2026-08-06 21:14:23 -06:00 |
|
|
|
63faf5c6c0
|
docs: 更正本机开发环境约束 —— Docker 可用
根 CLAUDE.md 长期写着本机跑不了 Docker/PostgreSQL/Redis/判题沙箱,实测不成立:
docker 29.7.2 与 docker-compose 5.4.0 早已安装,只是服务未启用、用户不在 docker 组。
另确认判题沙箱不需要特权模式(read_only + cap_drop,只减能力不加)。
影响:阶段 2 判题竖线可在本机完整验证并反复试错,不必每次推服务器。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 20:30:17 -06:00 |
|
|
|
9f5dd95289
|
docs: raw_password 保留决策及其对 7.1 结论的影响
user.raw_password 明文列是有意的运维需求(教师查学生密码),决定保留。
据此如实收窄 7.1 的结论:argon2id 升级不防"数据库泄露",只解决 pbkdf2
的 CPU 开销和脱离 Django 哈希格式,不得描述为"提升密码安全性"。
附一条未采纳的备选(应用层可逆加密)供日后备查。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 20:24:01 -06:00 |
|
|
|
1251b4e27d
|
docs(阶段0): 端点清单人工裁决完成
6 条 REVIEW 全判 KEEP:5 条是提取盲点造成的假阴性(原生 fetch 4 条、
动态变量路径 1 条),judge_server_heartbeat 是判题机注册心跳、不经前端,
新架构沙箱镜像原样复用故必须保留。
最终:新后端需实现 110 个端点,砍掉 17 个(13%)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 20:22:34 -06:00 |
|
|
|
f68b04baf0
|
chore(阶段0): 取回生产库 schema,解阻塞阶段 1
34 张表(27 业务 + 7 Django 框架),schema-only,无 COPY/INSERT、
无密码哈希、无邮箱。阶段 1 的 drizzle-kit pull 据此离线生成 TS schema。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 20:20:54 -06:00 |
|
|
|
e3fe9e1ab9
|
docs(阶段0): 更正存量盘点数字,ground truth 改为可独立核验
设计文档 §4 原写「端点 122、DEPRECATED 16、前端调用 78、疑似无人调用约
35%」四项全错:前三项来自漏抓 5 个端点的提取器和只数字面量的前端统计,
35% 是从 (122−78)/122 推的。改为实测值 127 / 17 / 148 条 method+path
(104 条不同路径)/ 23 个无调用 = 18%。减法空间是 18% 不是三分之一,
后续阶段按此排期。
实施计划里的 ground truth 原本就是那个有 bug 的脚本自己产出的,自检退化成
「脚本必须复现自己的 bug」。改为 127 / 17 / 104 并写明独立核验方式。
另:§7 引导语两处改三处;7.3 把「启动时一次性 loadDict」提成衍生约束小节,
附实测数据(200 词逐条 39.4ms vs 一次性 0.98ms,且 loadDict 语义确认为累加)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 20:08:53 -06:00 |
|
|
|
ae5eea7250
|
fix(阶段0): 端点提取器漏抓 5 个端点,补反向对账
提取器按文件名白名单扫 <app>/urls/{oj,admin}.py,漏掉两类真实挂载:
tutorial/urls/tutorial.py(文件名不在白名单)和 utils/urls.py(没有
urls/ 目录,被 statSync 的 catch 吞掉),共 5 个端点,其中 4 个前端在用。
改为以 OnlineJudge/oj/urls.py 为唯一入口解析 26 条 include,side 与路径
前缀直接取挂载前缀,app 取 Python 模块名首段。127(oj 77 / admin 50),
DEPRECATED 17,与 cat */urls/*.py utils/urls.py | grep -c "path(" 一致。
reconcile.ts 补上反向对账:前端调用了但后端查无此端点的路径会告警并写进
产出的 markdown,让同类系统性盲区不再依赖人眼评审。修完后 orphan 为 0。
另:生成日期改用本地时区(toISOString 是 UTC,本地 UTC+8 晚间会写成前一天);
补记盲点 3(src/utils/download.ts 的独立 axios 实例,提取器抓不到)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 20:08:53 -06:00 |
|
|
|
ec563ef64b
|
chore(阶段0): 验证 jieba 替代方案
@node-rs/jieba@2.0.1 在 Bun 1.3.11 下通过验证:NAPI 绑定正常加载,
cut 结果符合预期,1000 次切词 2ms。API 与预期有出入——没有
insertWord/addWord,改用 loadDict 加载自定义词典缓冲区达到同等效果。
结论写入设计文档 7.3 节。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 19:48:27 -06:00 |
|
|
|
b4cbfd85b0
|
chore(阶段0): 端点对账脚本与机器初判清单
KEEP 100 / CUT 16 / REVIEW 6,合计 122。
修复 brief key() 里的归一化 bug:/^\/?api\/(admin\/)?/ 会把后端
admin 端点的 admin/ 前缀也剥掉,但前端 http 客户端共用一个 axios
实例(baseURL: /api),admin 接口路径是前端代码里手写的字面
admin/xxx,不该被剥。未修复时 REVIEW 卡在 40(几乎全是被误判的
admin 端点),修复后降到 6。
REVIEW 里 5 条经核实是提取脚本的已知/新发现盲点(动态变量传路径、
原生 fetch() 调用)导致的假阴性,已在生成的 markdown 里写明提示;
唯一真正需要人工裁决的是 judge_server_heartbeat(判题机而非前端
调用的接口)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 19:40:25 -06:00 |
|
|
|
3da7482741
|
docs: 阶段 0 实施计划 + 端点提取器
计划覆盖端点盘点、人工裁决、jieba 验证、取回生产库 schema 四件事。
相对设计文档有两处偏离,已在计划内说明:阶段 0 不删旧代码只产出清单
(与"旧仓库全程冻结"一致);不写测试(遵循项目既定策略)。
盘点中发现两处事实,已修正设计文档:
- /api/sessions 前端从不调用,User.session_keys 只写不读,选 opaque
token 而非 JWT 的原始理由不成立,理由已换成账号封禁需即时生效
- SessionRecordMiddleware 每个已登录请求都写库,新后端不要复刻
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 19:24:41 -06:00 |
|
|
|
ec4f649a2e
|
docs: OJ2 后端重写设计文档
将 Django 后端重写为 Bun + TypeScript 的设计方案,含前后端 monorepo
结构、技术选型与分阶段路线。
两处高风险技术假设已实测验证,spike 代码见 docs/spikes/:
- Django pbkdf2 密码哈希可在 Bun 侧验证,存量密码无需重置
- tree-sitter 可用 WASM 在服务端运行,且比现状更易部署
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-06 19:16:57 -06:00 |
|