xuyue and Claude Opus 5.5
38a331c2b7
feat(布置作业): 能布置「画流程图」「先画再写」,看板分清卡在画图还是写代码
...
Deploy / deploy (push) Canceled after 0s
布置时多一个「做什么」:写代码 / 先画再写 / 画流程图(只能选打开了画流程图的题)。
- 先画再写:一道题图画到 A/S、代码也交对才算做完;学生画一道写一道、全画完再写都行,
打开题目自动停在该做的那一步(图没画对停画布,画对了换到布置的语言)
- 也能分开布置:先一节画流程图,看板上「用这几道题写代码」再开一节;学生那边把今天
几节课的要求合起来,还没画完的照样看得到要画
- 看板格子是一条进度:图 1/6 → 空心「图 ✓」→ 代码 ✗ → ✓,先写代码没画图的写「缺图」;
卡在画图上的点开讲那张图(要改的框标红 + AI 的哪里错/怎么改),按走对几组归堆
- 写代码的课不再拿画对的流程图顶替做完;数据统计里画流程图的课数流程图提交
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-11-02 21:50:48 +08:00
xuyue and Claude Opus 5.5
df8af40d61
feat(布置作业): 课上老师改了作业,学生页面上弹出改了哪些题,点「刷新」就拿到新题单
...
Deploy / deploy (push) Canceled after 0s
看板「改 / 新的一节 / 清掉」和后台课堂作业的增改删,前后比较学生看到的那一节,
真变了才按班推 lesson_update(加了、去掉了、语言、顺序),走学生的 /ws/config,老师不收。
没点刷新又改会合并成一条。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-11-02 21:14:52 +08:00
xuyue and Claude Opus 5.5
b344bd1dd6
feat(布置作业): 能按知识点点选题目;一个班一天能布置几节课;数据统计认老师布置的课;后台能管布置过的课
...
Deploy / deploy (push) Canceled after 0s
- 课堂看板「选题」弹框:左边知识点(加必会题),右边搜题号/题名、点选,按点的先后排;
只列这次作业的语言能交的题(/problems、/problem-tags 加 ?language=)
- 一天多节课:0040 拿掉 class_lesson (class_name, day) 唯一约束,每次布置一行;
看板「改」只改当前一节,加「新的一节」;这一节布置超过 100 分钟时先问这节课做哪几道题。
不带 lessonId/newLesson 的老请求照旧改今天最后一节
- 数据统计「一行一节课」:布置过的课以布置为准(题目和顺序照布置、做完按全班算、标「布置」),
这些提交不再参与推断切段,也不算零散;详情页「做完」注明是这一天/这节课/这段时间
- 后台「课堂作业」:一节一行,改(班级/日子/时刻/语言/题目)、看统计、删除、补一节;
看板加「布置过的课」入口。题号校验和「做完」口径抽到 services/lesson.ts,三处共用
⚠️ 机房站点要和服务器一起升级:旧代码布置时 ON CONFLICT (class_name, day) 找不到约束会报错
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-11-02 20:41:25 +08:00
xuyue and Claude Opus 5.5
8427475337
chore(清理): 删掉并行试跑、搬库、Python3 别名、旧链接这些过渡期的兼容写法
...
Deploy / deploy (push) Canceled after 0s
- 部署:JUDGE_STATE_DIR 不再强制设;删掉搬库脚本和只为搬库存在的自检、提醒
- 语言:Python3 / Python2 别名表删掉,normalizeLanguage 改名 parseLanguage
- 旧链接:后台题单详情的跳转、用户列表 -last_login 的转换
- 旧页面:布置作业必须带 language(null = 没选);不再清旧版出题页草稿
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-26 14:15:04 +08:00
xuyue and Claude Opus 5.5
195069450f
style(格式化): 改成单引号、一行最长 160,全仓重新格式化
...
Deploy / deploy (push) Canceled after 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-26 13:52:24 +08:00
xuyue and Claude Opus 5.5
0faf78ad8f
feat(挑战): 做对之后可以加一条写法上的限制再做一遍,判题时记下谁做到了
...
借小丑牌的赌注档:同一道题加一条限制(「整首歌只用 1 次 print」)再做一遍,
给课上做得快的学生找事做(做完一节课的题,中位要空等 13 分钟)。
判定沿用 AST 规则,挑战配在 problem.challenges,做到的记在 challenge_success;
做对的提交顺手判一遍,挑战没做到也照样算做对。没过的规则带上是第几行。
0039 灌进第一批 56 道常用题的 73 条挑战,api 起来后拿历史上做对的代码补一遍谁已经做到了。
出题页能配挑战、从做对的代码里找候选;课堂看板的格子带上挑战状态。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-26 08:52:50 +08:00
xuyue and Claude Opus 5.5
df152f505d
feat(课堂看板): 「这节课」写上是哪位老师布置的,别的老师改题也不换人
...
Deploy / deploy (push) Canceled after 0s
看板题号后面从「09:56 布置」变成「09:56 徐越 布置」,老师首页「今天的课」同样带上名字。
老师写真名(用户名 lwp0201、little 认不出是谁),没填真名的退回用户名。
「改」不再覆盖 created_by,和布置时间一样认第一次布置的人。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-20 09:56:46 +08:00
xuyue and Claude Opus 5.5
940895f643
feat(课堂看板): 接口给做对了的格子带上今天每一次代码提交和第几次做对
...
原来今天最后一次提交只给没做对的格子;现在同一条查询取今天全部,做对了的格子
多带 trail(从早到晚的 id / 结果 / 时间)和 acceptedTry(今天第几次做对,
以前就做对了的为 null)。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-19 21:09:35 +08:00
xuyue and Claude Opus 5.5
465dbfd42f
refactor(后端): 权限判断收到一处,路由文件之间不再互相 import
...
- services/permissions.ts:「超管或创建者」原来在比赛、题单、比赛题目(4 处)、
services/contest.ts 各抄一遍,「题目全部权限」在题目和标签两个路由各写一份
- services/submission-filters.ts:提交列表的用户名 / 班级 / 题号筛选,原来
submission.ts、flowchart.ts 从 submission-statistics.ts 这个路由文件里拿
- services/class-activity.ts:课堂做题记录的口径和「正在上课的班」,原来后台
conf.ts 从 classroom.ts 路由里拿
- services/problem-tags.ts:标签名去重、按名查标签,原来 tag.ts 从 admin/problem.ts 拿
纯搬家。三种身份(超管 / 老师 / 学生)打了 26 个受影响的接口,改前改后状态码和响应体
逐字节一致,包括「不是自己的比赛 / 题单 / 题目报不存在」那几条。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-16 14:53:24 +08:00
xuyue and Claude Opus 5.5
e7b6e27b85
feat(课堂看板): 标出谁在线、谁今天没上过线,请假框里没上线的人分在前面一堆
...
机房有两人共用一台电脑的,同桌只有一个登着,只看「此刻在不在线」会把旁边的人
当成没来。所以每次记在线时按天再记一笔「今天最后一次上线」:
- 看板「在线」列(原「在写」):开着题的照旧写题号,其余写 在线 / N 分钟前在 / 今天没上线
- 还没交过的人里,今天没上过线的排最前
- 请假框分「今天没上线」「今天上过线」两堆,前一堆可以一键全勾上
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-15 13:50:59 +08:00
xuyue and Claude Opus 5.5
c8c38553ec
feat(首页): 新接口给老师首页列出今天在上课的每个班——这节课的题、几人交过、全做对几人、最后一次交题的时刻
...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 14:53:38 +08:00
xuyue and Claude Opus 5.5
1d406a50e4
feat(后台首页): 首页接口带上全站的数(学生、题目、提交、比赛、题单、自学、这周做题的人)、最近 30 天每天提交、系统错误、在线人数和正在上课的班
...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 14:17:00 +08:00
xuyue and Claude Opus 5.5
573a0f967f
feat(举手与协作): 老师能在看板上直接打开学生正在写的代码,同一道题好几个人举手能「讲完了,都放下」,举手面板写着每人错在哪
...
学生编辑器报「在写哪道题」,看板接口带 editing;新增 peek / dismiss 两条协作消息,
求助记录带这道题最后一次提交(判完新的一次会刷新)。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 13:04:57 +08:00
xuyue and Claude Opus 5.5
5c9d0ca501
feat(课堂看板): 「这节课」那排题号后面写上几点布置的,之后改题不变
...
Deploy / deploy (push) Canceled after 0s
class_lesson 加 created_at(0034,老数据用 updated_at 回填),「改」只动 updated_at;
清掉再布置算重新开始。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 10:21:39 +08:00
xuyue and Claude Opus 5.5
0a4f528c44
feat(课堂看板): 看板接口给没做对的格子带上今天最后一次提交,按错法归堆、点开讲错误要用
...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-13 10:02:50 +08:00
xuyue and Claude Opus 5.5
d83804b814
feat(班级PK): 班级 PK 只比两个班都布置过的同一批题,按做对的人占几成分输赢;登录了就能看,AI 分析由服务端现算
...
- 新接口 GET /rankings/pk:一个班过半的人交过算布置过,至少两个班布置过的题才比;
显示的整数百分比一样算平;口径和排名页一样(这学期、比赛不算、不计入排名的人不算)
- 不给班就用自己的班(老师用默认的班),只给一个班就配同年级一起布置过的题最多的班,
一样多挑班级对抗排得更前的
- 去掉 POST /classes/comparison(原来不登录也能查,综合分、四分位数、优秀率都按所选几个班算)
- /ai/class-pk-analysis 只收班号和时间段,数字和页面上的是同一份
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-10 09:06:21 +08:00
xuyue and Claude Opus 5.5
1c6e2b9d82
feat(排名): 排名页重做成领奖台加全班赛道,一眼看出自己第几、该追谁、谁在追自己
...
Deploy / deploy (push) Canceled after 0s
- 一张榜两个开关:本班 / 本年级 / 全服 × 这周 / 这学期 / 全部,默认本班 · 这学期。
原来最大那张全服 Top100 里,这学期在用的 25 级学生一个都进不去
- 做对一样多的不再按「提交少的在前」排,改成先做到的在前;名次旁边写比周一升降了几名
- 「你」那张卡:第几名、再做对几道上领奖台,要追的人早你几秒、追你的人晚你几秒
- 本年级 / 全服只列前面一段和你附近一段,中间折起来,点开再看
- 班级对抗按人均做对比,另有我和对手的名次走势、这周本班、每周冠军
- 老师不上榜,选班看;每行「⋯」能把怀疑抄代码的学生设成不计入排名(新增 user.rank_hidden_at,
首页周榜同样不算他),随时能恢复
- 去掉全服 Top10、日活两张图、在线人数和班级详情弹框里的统计词,以及它们背后的旧接口
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-10 07:26:15 +08:00
xuyue and Claude Opus 5.5
25d3296410
feat(SQL 题): 增删改题的期望结果标出执行后变了的格子,删掉的行写清是哪几行
...
学生原来只能拿两张表逐格对,看不出要改的是哪几行。现在改过的格子、新插的行标黄,
删掉的行在表下面写「删掉了 2 行(id 是 2、3)」。按第一列配对,对不上就不标。
数据表和期望结果抽成一个组件,后台出题页的预览也用它。
题型判断统一走契约的 isSqlProblem()。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-09 18:59:15 +08:00
xuyue and Claude Opus 5.5
fcf63c2ecb
fix(课堂看板): 作业里有 SQL 题就布置不上去(报「不能用 C 交」),也没法布置一节 SQL 课
...
- 布置作业的语言加上 SQL,数据库课整节选 SQL
- C / Python 的作业里可以夹 SQL 题:SQL 题只收 SQL,不受作业语言限制,交对 SQL 就算做完
(学生首页课堂条、看板格子、班里做了几个人三处一起改)
- 看板点 SQL 题的格子,提交列表按 SQL 筛,不再是一片空白;提交列表「这节课」遇到夹了
SQL 题的作业不再按 C 筛
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-09 18:18:10 +08:00
xuyue and Claude Opus 5.5
a18e129f4c
feat(课堂): 布置这节课的题时可以选用什么语言做,学生用别的语言交对不算这份作业做完
...
class_lesson 加一列 language(0024,可空:以前布置的、按提交推断出来的课都不限语言)。
布置时有题不支持选的语言就整个拒掉并点名是哪几道;看板的格子、学生首页的做完状态、
提交列表「这节课」都只认这个语言的代码提交,流程图照旧算。看板多给 lastLanguage 当默认值。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-30 09:54:21 +08:00
xuyue and Claude Opus 5.5
91d9c9c6d7
feat(首页): 登录后不再弹「登录速报」,上次来做了什么、哪道还没做对放进首页,带「接着做」
...
Deploy / deploy (push) Canceled after 0s
- 新接口 /me/last-visit:上次登录到这次登录之间的题库提交,不调 AI(原来要同步等模型最长 60 秒弹框才出来)
- 班里今天在做时让位给班里卡,只在卡底留一句;班里那天就是上次来那天时两张卡合成一张
- 第一次登录说「欢迎来到判题狗」,隔了 30 天以上说「好久不见」
- 删掉弹框、store 和 /ai/login-summary
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-30 00:28:14 +08:00
xuyue and Claude Opus 5.5
923516ad36
fix(课堂看板): 这节课整班在画流程图时,点格子、点名字进到的是一片空的代码提交列表
...
Deploy / deploy (push) Canceled after 0s
看板格子的次数原来是代码和流程图加在一起的,链接却总是去代码那边;名字链接看的「今天交过」
还把比赛提交算了进去。现在格子分开给代码 / 流程图次数、学生分开给今天交过代码 / 画过流程图,
只画了流程图的跳到提交列表的「流程图」那边。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-29 19:02:33 +08:00
xuyue and Claude Opus 5.5
26c8d65e89
fix(判题/统计): 老师重判一次题目提交数就多一;统计选 231 班会把 2311、2312 班也算进来
...
- 重判带上原来的结果,落库只做差量:提交数不变、旧结果那一格减一新结果加一,
通过数按新旧结果调整(原来重判当新提交记账,连点三次就多三)。重判时一起清掉 info,
判题中那几秒不再按旧结果显示「通过 2/3」
- 三个统计接口加 className,按 class_name 精确匹配(原来拼 ks231 做包含匹配)
- 流程图统计查几道题时要每道都拿到 A/S 才算完成;「每人最好的一次」截断时有标记,
题号上限 20 道和代码统计一致;流程图列表支持按整名匹配用户
- 删掉统计弹框走后没人用的展开行明细接口,以及每次都白算的「语法未过题数」「最近一次错在哪」
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-29 18:52:58 +08:00
xuyue and Claude Opus 5.5
ea480d5e0c
feat(提交列表): 老师也能重新判题;列表能按班级、一次按几道题筛,还带「通过几个测试点」
...
- 重新判题从只放超管改成老师及以上:前端一直给老师亮着按钮,点了只会「权限不足」
- /submissions、/flowcharts 加 className(user.class_name 精确匹配),题号可以一次填几道
- 列表每行带 caseSummary,口径和详情一致,在库里数完只回两个数
- 新增 GET /classroom/lesson:提交列表「这节课」按钮用,班级和题的取法同课堂看板
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-29 11:08:49 +08:00
xuyue and Claude Opus 5.5
ee66cef367
feat(课堂): 只画了流程图的学生也算来上过课、做完了题——推断这节课的题、班上几人做完、最近来了几次都认流程图
...
原来课堂那边只有「我的状态」和看板格子认流程图 A/S,其余统计只数代码提交:
全班画流程图的那节课推断不出题,课堂条和看板都是空的;只画了图的学生在看板上
「最近来了 0 次」。现在代码提交和流程图提交合成一张表来数,口径统一:
流程图 A/S 算做完,交过流程图(含评分中、评失败)算做过。
- 推断这节课的题、「班上 M 人做完」、最近几节课是哪几天
- 看板「最近来了几次」、最后提交时间、各题尝试次数
- 看板没选班时猜正在上课的班
- 班级对比、个人资料的通过数不在这次范围,仍然只数代码
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-29 00:06:54 +08:00
xuyue and Claude Opus 5.5
83b6b7a81a
fix(题目): 修掉代码审查查出的几处问题——流程图拿到的徽章不弹、点评弹窗读失败时关不掉等
...
- 流程图画到 A / S 拿到的题单徽章、成就原来不弹:流程图那条 WebSocket 只认评分完成 / 失败,
成就消息被丢掉了,要等下次换路由拉 pending 才出来
- 强制点评弹窗读不出点评、或者一直交不上时,「下一题 / 继续」按钮也给出来:原来弹窗关不掉,
只能按浏览器后退;拦下换题时就记上「继续」,按钮文字不会写错
- 「放回编辑器」走正常的换语言路子(画流程图时切回代码编辑器、读那门语言的草稿);
这道题已经不收的语言(0020 摘掉的 Java / JS / Go)置灰,只能复制
- 举着手时刚交对、1.5 秒内点下一题:原来「确定要换题吗」要问两遍(点评完再问一次),
现在同意过的那个地址不再问
- 课堂看板上评分中、评失败的流程图不再算「尝试过」,和学生的课堂条一个口径;
新加的流程图查询和其他查询并行,不再多等一轮数据库
- 课堂条的数据只认最后发出的那次请求:进页面那次后到的话会把刚做完的那道盖回「没做」
- 「A / S 算做完」收进契约,前后端只留一份;协作中老师的判断统一用 useTeacherCollab;
几处放错位置、说法过时的注释
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-28 19:35:07 +08:00
xuyue and Claude Opus 5.5
b5d2f1589e
feat(课堂看板): 流程图画到 A / S 在老师的看板上也算做完,只画了图的学生不再显示「没开始」
...
和学生首页的课堂条同一个口径:格子的状态、做对的时间、尝试次数都把流程图提交算进去;
「最后一次提交」也算上今天画的图。有的题这节课整个班都在画流程图,原来看板上是满屏「没开始」
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-28 18:42:53 +08:00
xuyue and Claude Opus 5.5
3fe3caa944
feat(流程图): 流程图画到 A / S 算这道题做完——题单进度、课堂条都认;加入题单之前画的图先藏起来
...
Deploy / deploy (push) Canceled after 0s
- 流程图评到 A 或 S,记进所有已加入、且包含这道题的题单(和判题那一路同一个口径,不看从哪个
入口交的),徽章和题单类成就照样推送。原来题单进度只在判代码时记,流程图作业在题单里永远是
「没做」。流程图提交的 id 进不了 problemset_submission(外键指向代码提交表),所以只写
progress_detail —— 解锁旧提交的那道闸看的也是它
- 课堂条(/me/class-activity)的 myStatus:流程图 A / S 也算 accepted,评完的非 A/S 算 tried
- 题单防抄闸门补到流程图上:加入题单之前画的图,对本人藏起来(列表 showLink、详情 404、
current / history 不数它),规则和代码提交同一份(problemSetJoinTimes 挪进 services/problemset)。
原来加入之前画到 A 的那张图点一下就能载回画布、交上去就是 A
- 新增 GET /problems/:id/flowchart/scores:一次给出自己评完的每一次的分数和等级,外加被藏起来
的次数(原来 history 一次只给一条,看分数走势得一页一页翻)
- 「A/S 算过关」和按分数定等级收进 flowchart/grade.ts;判题那边的记账 + 通知抽成
recordSolvedAndNotify,两条路共用
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-28 17:56:35 +08:00
xuyue and Claude Opus 5.5
a6bf845e06
feat(课堂看板): 标出最近几节课经常没交的学生,求助的学生置顶,点一下打开求助列表
...
Deploy / deploy (push) Canceled after 0s
2025 秋至少上过 5 节课的学生里,12.5% 七成以上的课一道都没交,37% 的学生贡献了
一半以上的「没交」;当堂那份「今天还没交过」把偶尔没来的和一直不动手的排在同一行。
- 看板接口给每个学生加 recentAttended:最近几节课(最多 5 节、不含今天、45 天内;
一节课 = 同班同日 ≥5 人做同一题)里交过几节,另给 recentLessons
- 「今天还没交过」拆成「经常没交」(≥3 节可比且最多交过 1 节)和其他;表格加一列
「最近 N 节」;只给老师看,投影模式不出现
- 求助读老师端常驻 WebSocket 的 collabStore.requests(不改后端):求助的学生置顶,
状态显示「举手了 / 老师在帮」,点一下打开求助列表;求助提示不论布没布置题都显示
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-27 22:47:24 +08:00
xuyue and Claude Opus 5.5
80106eaa04
feat(课堂): 老师的课堂看板——布置这节课的题、看全班谁还没开始谁卡住了,布置的题直接出现在学生首页
...
2025 秋平均每节课有 14 个平时在用的学生一道都没交(三分之一),交了 3 次以上还没过的
平均不到 1 个;而老师原来只能一道题一道题打开统计弹窗看。
- 新表 class_lesson(迁移 0023,仅建表):一个班一天一行,存老师布置的 problem.id 与顺序;
day 存东八区日历日文本,created_by CASCADE
- GET /classroom/board:这个班今天的题 × 全班学生(通过与否不限今天、今天交了几次、
最后提交时间);不给班级时猜最近两小时提交人数最多的班,不记老师上次选的
- PUT /classroom/lesson:按展示题号布置,对不上的题号点名拒绝,空数组 = 清掉
- /me/class-activity 优先返回老师布置的题(source = teacher),否则照旧推断
- 前端 /classroom:没交过的名单置顶,按 没交过 → 卡住 → 在做 → 做完 排序,15 秒刷新;
投影模式只显示每题完成人数、不出名字;用户菜单给老师加入口
- 学生首页:老师布置的标题写「今天老师布置的题」,没人交时不显示 0/0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-27 22:37:59 +08:00
xuyue and Claude Opus 5.5
039992dc86
feat(前台): 顶栏可以输入题号直达;首页列出班里最近一次课一起做的题和自己的完成情况
...
Deploy / deploy (push) Canceled after 0s
课上老师报题号、全班去找,是 2025 秋七成非比赛提交的来路,界面上原本没有它的入口。
- 顶栏(桌面端)加题号框,首页「找题」同一套逻辑:题号对上直接进题,否则去列表搜
- 新接口 GET /me/class-activity:同班同一天 ≥5 人做过的题,取最近 7 天里最近的一天,
附带我自己的状态与班里通过人数;首页据此显示「今天班里在做」卡片,没有就不占位
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-27 20:58:15 +08:00
xuyue
d25b5dbe6d
update
Deploy / deploy (push) Canceled after 0s
2026-09-27 19:36:28 +08:00
xuyue and Claude Opus 5.5
f2ca34fd4b
refactor(api): 请求体解析收成 readJson / parseBody
...
54 处 handler 都手写同一段:
const parsed = X.safeParse(await c.req.json().catch(() => null))
if (!parsed.success) return failure(c, 400, "invalid-request", ...)
漏写 .catch 就是一个畸形请求打出 500。
- http.ts 加 readJson(读 + 校验)和 parseBody(再加上 400)。parseBody 不给
message 时回 zod 的第一条 issue —— 后台表单原来就是这么写的,fallback 文案
「Invalid payload」/「参数错误」只在 issues 为空时才用得上,实际走不到
- 51 处换成 parseBody;另 3 处失败时带别的错误码或和路径参数一起判,换成 readJson
- 错误码、状态码、文案、判断顺序都不变
实跑核过:非 JSON 请求体回原来的固定文案,公告标题为空回 zod issue。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-09-27 15:04:19 +08:00
xuyue and Claude Opus 5
ed56a209ea
chore(格式): Prettier 统一到全仓,后端和契约一次性格式化
...
Deploy / deploy (push) Has been cancelled
原来只有 `apps/web` 在 Prettier 下(配置在 `apps/web/.prettierrc.toml`、脚本在
web 的 package.json),后端和契约从来没格式化过 —— 手写在 100 列上下,`db/schema.ts`
还是 drizzle-kit pull 留下的 tab 缩进。两套口径分叉久了,跨端改一处就得记着「这边
什么风格」。
- 配置搬到根目录 `.prettierrc.toml`,内容不变(`semi=false`,其余全默认,
printWidth 80 —— 和前端已有的格式一致,不另立一套宽度);
- 脚本统一成根目录 `bun run fmt`,覆盖 `apps/*/src`、`apps/web/tests` 和两个构建
配置;web 自己那份 `fmt` 和重复的 prettier 依赖删掉;
- `.prettierignore` 挡掉两类不该碰的:drizzle-kit 生成的 `src/db/meta/` 结构快照
(它是 db:generate 的比对输入,只该由 drizzle-kit 写)、unplugin 每次 dev 都会
重写的 `auto-imports.d.ts` / `components.d.ts`;
- 全量跑了一遍。纯格式,无行为改动:api typecheck / check:routes / check:ast、
前端 type-check 全过,起 api 打了接口确认正常。前端这 39 个文件的小改动是
prettier 版本漂移(类型断言的换行口径变了),不是新配置带来的。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-09-16 08:27:34 -06:00
xuyue and Claude Opus 5
ab47e71d6f
refactor(契约): 出参不再 parse,后台老题详情和站内信页不再 500
...
Deploy / deploy (push) Has been cancelled
## 出参改 satisfies
出参是后端自己刚拼出来的字面量,TS 编译期已经验过;再 xxxSchema.parse({...}) 一遍
拿不到任何新信息,唯一可能失败的输入是库里的历史数据,而失败的代价是 500。136 处
全部撤掉,撤的时候当场炸出两个一直存在的线上故障:
- 后台打开任何一道没编辑过的题都是 500 —— problem.last_update_time 是全库唯一可空
的列(961 道题里 470 道是 NULL),而 adminProblemSchema.lastUpdateTime 写的是
z.string();
- 收到过站内信的人打开消息页全是 500 —— embeddedSubmissionSchema 从
submissionDetailSchema 继承了 problemDisplayId 却没 omit,路由只填了同义的
problem;列表为空时才碰巧不炸,所以一直没人报。
两个都是读出侧校验自己造出来的故障,不是它拦住的故障。
## 校验责任挪回写入侧
- db/schema.ts:枚举型的列和几个形状确定的 JSONB 挂 .$type<>()(submission.result /
.language、problem.difficulty / .languages / .template / .astRules / .sqlConfig /
.sqlDisplay、achievement.rarity / .operator、exercise.type、reaction.type、
tutorial.type、problemset.difficulty / .status、flowchart_submission.status、
problemset_badge.condition_type、acm_contest_rank.submission_info)。只影响 TS、
不产生 SQL,断言逐列拿根目录那份生产备份核过全量数据。
- createProblemRequestSchema.languages 收窄成 problemLanguageSchema,兑现
problem.languages 列上的断言。
- 新增 routes/helpers.ts 的 asFilterValue():query 筛选值(result / language /
difficulty / status)要和收窄过的列比较时做纯类型交接,不加校验 —— 在这儿拦一道
会把「筛出空列表」变成「筛条件被忽略、返回全部」。
- 判题产物(submission.info / statistic_info / exercise.data)照旧放行,形状真相
在判题机那边;judge/sql、flowchart/run、events.ts 里对自家产物的 parse 一并撤掉。
- 仍然 parse 的只有 judge/events.ts 的 parseSubmissionEvent —— 从 Redis 收回来的
报文是真边界,失败返回 null 而不是 500。
顺带清掉两处重复的真相:stringArray 原本在 routes/helpers.ts、routes/problem.ts、
routes/submission.ts 各有一份拷贝,5 个调用点全部只作用于 problem.languages,列有类型后
三份一起删;routes/site.ts 里和契约同名同形的本地 interface Quote 也删了 —— loadSentences
读入时已经逐字段守过,那处 parse 同样是多余的。
## 文档
CLAUDE.md 那一节从「契约收紧要挑地方」改写成「出参不 parse,用 satisfies」,写明
三处写入侧闸门(入参 safeParse 58 处、列上 $type、语义校验函数);apps/web/CLAUDE.md
同步 —— 现在收紧字段的后果落在 tsc 编译期,但契约形状仍要对得上存量数据。
## 验证
- 生产备份全量:12.4 万条提交的 result 全在 -2..6,10、961 道题的 languages 均为合法
数组、10050 条榜单条目形状全对,无一例外;
- tsc -p apps/api 与 vue-tsc --noEmit 均 exit 0;check:routes 检查 177 条路由,无遮蔽;
前端 build、单二进制编译并在仓库目录之外启动均通过;
- 实跑 40+ 端点(学生端 / 后台 / AI / 榜单 / 题目回写往返),以及一次完整比赛 e2e:
建比赛 → 复制题目 → 错解 → 正解,把 judge/run.ts 榜单写入的三个分支全走到
(error_number 0→1、is_first_ac + ac_time 671、totalTime 1871 = 671 + 1×20×60),
后台核查页的勾选与 404 分支一并验过,测试数据已清理;
- 两个 500 用抓到的真实响应对着改动前的契约复验:lastUpdateTime 收到 null、
problemDisplayId 收到 undefined,改动后同样两个响应均通过。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_012j1vgeDqay8wKCh8dPgPcH
2026-09-10 18:14:05 -06:00
xuyue and Claude Opus 5
2c4d56b29a
refactor(后端): 清掉 Django 遗留的死列与手工级联,角色字符串收成一份
...
三条迁移,一次部署(0008/0009 含 DROP COLUMN,需要 OJ2_ALLOW_DESTRUCTIVE=1):
- 0008 删 IP 相关:比赛 IP 白名单(前端本来就没有输入框,detail.vue 无条件置空)、
submission.ip(前端从未显示过)、以及一次都没被调用过的 IP 限流桶。
judge_server.ip 是运维数据,保留。
- 0009 删九个只有 Django 时代写过、OJ2 一次都没读过的列:user 的 auth_token /
open_api / open_api_appkey / session_keys,user_profile 的 blog / github /
school / major / language。open_api 后台连开关都没有,那段「已经开着就不重置
appkey」的逻辑从上线起没进过 if。判据是「全仓零读取」而不是「看着没用」——
raw_password 同样刺眼却是在用的,别一起清掉。
- 0010 给 17 条外键补上删除动作,不再是 Django 留下的一律 NO ACTION。父行消失后
必然无意义、且不构成学生留痕的走 CASCADE(中间表、题单/教程/成就的组成部分、
user_profile 与 user_stat);需要人看见的继续拦着——submission.problem_id、
以及 user 的绝大多数外键,删用户撞外键会被 handler 翻译成「请改为禁用账号」,
这是有意的:全 CASCADE 会静默抹掉成就与进度,而 submission.user_id 压根没有
外键,结果是一半删一半留。六处手工级联随之删掉。
角色字符串收进 packages/contract/src/roles.ts:原先 ADMIN_ROLES / TEACHER_ROLES
在两个文件各抄一份、学生口径在四个文件各写一遍、前端 USER_TYPE 是第三份副本。
AuthUser.adminType 与 drizzle 的列都收窄成联合类型,二十多处 `=== "Super Admin"`
从此受编译器管着($type 是纯 TS 层的,generate 确认不产生任何 SQL 变更)。
顺带删掉 db/relations.ts —— drizzle-kit pull 的产物,全仓零引用。
一处行为变化:后台用户列表传非法的 ?type= 回 400,不再静默返回空列表;界面上的
下拉只有合法值,打不到这条。
验证:tsc / vue-tsc / vite build / check:routes 全过;三条迁移在 dev 库执行,
并逐条建 fixture 走 HTTP 接口验过删除连坐与拦截(题单五张子表连坐、user_badge
二级连坐、删有提交的题目仍 409、删有表情的用户仍 409)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01AeJoYc2t2d7cThVqMBYrBF
2026-09-02 22:57:45 -06:00
xuyue
2031e6a434
update
Deploy / deploy (push) Has been cancelled
2026-08-31 07:41:44 -06:00
xuyue and Claude Opus 5
8c00cdc947
feat(阶段3): oj 侧端点铺开(基线提交,未经评审)
...
由外部 agent (Codex) 在本会话额度中断期间完成。原样提交作为基线,
后续修复单独成 commit,便于区分与回退。
覆盖 oj 侧 65 个端点,新增 9 组路由(account/achievement/ai/classroom/
content/contest/flowchart/problemset/site)与对应 Zod 契约。
已核验:tsc --noEmit 退出码 0;API 可启动;/api/problems 返回真实数据;
judge 与 flowchart worker 均 ready。
未核验:权限边界与数据泄露,评审进行中。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 01:25:36 -06:00