标签列表按题目数 > 0 过滤,但计数没有像 /problems 那样限制 visible=true 且非赛题,导致标签在首页出现、点进去却一道题都没有。 同时把旧仓库冻结政策收紧写进 CLAUDE.md:从今天起旧仓库零改动, 不再有内部小修的例外,所有后续工作只落在 OJ2。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
19
CLAUDE.md
19
CLAUDE.md
@@ -2,19 +2,16 @@
|
|||||||
|
|
||||||
OJ2 是判题狗(Online Judge)的后端重写:Django 6 → Bun + TypeScript,前后端同仓。
|
OJ2 是判题狗(Online Judge)的后端重写:Django 6 → Bun + TypeScript,前后端同仓。
|
||||||
上一代在 `../OnlineJudge/`(Django)和 `../ojnext/`(Vue SPA),**两者都是回滚路径,
|
上一代在 `../OnlineJudge/`(Django)和 `../ojnext/`(Vue SPA),**两者都是回滚路径,
|
||||||
默认冻结。**
|
完全冻结、一行都不改。**
|
||||||
|
|
||||||
冻结的目的是「回滚那天旧站能原样起来、和新站看到同一份数据」,不是「一个字节都不许动」。
|
> **2026-08-26 起**:旧仓库零改动,没有例外——包括修 bug、包括不影响外部接口的
|
||||||
所以红线是**外部可观测的东西**:
|
> 内部小修(日志、缓存实现之类,以前允许,现已收紧)。所有后续工作,包括在旧仓库
|
||||||
|
> 里发现的 bug,都只落在 OJ2:先确认 OJ2 是否有对应逻辑、是否重现了同样的问题,
|
||||||
|
> 只在 OJ2 里修;旧仓库那边如实告知用户"未处理,按当前政策不动旧仓库",不要顺手改掉。
|
||||||
|
|
||||||
- **不许动**:接口路径与响应结构、数据库 schema、磁盘上的数据布局、密码哈希格式、
|
冻结的目的是「回滚那天旧站能原样起来、和新站看到同一份数据」——改 OJ2 时,接口路径
|
||||||
依赖版本。这些一动,回滚就不再是「把上游切回去」那么简单。
|
与响应结构、数据库 schema 这些外部可观测的东西都要小心,一动回滚就不再是「把上游
|
||||||
- **可以动**:纯内部实现的小修(缓存放哪、日志、注释),前提是签名、异常、
|
切回去」那么简单。
|
||||||
返回结构逐一对齐不变,且 `uv run ruff check` 通过。改完在 commit message 里
|
|
||||||
写清楚为什么值得破例。
|
|
||||||
|
|
||||||
已发生的破例:`utils/cache.py` 的 `JsonDataLoader` 把一言数据集塞 Redis,每次请求
|
|
||||||
都要把 323KB 的 pickle 拉过网络再反序列化,改成了进程内缓存。响应结构没动。
|
|
||||||
|
|
||||||
设计文档:`docs/specs/2026-08-06-bun-backend-rewrite-design.md`
|
设计文档:`docs/specs/2026-08-06-bun-backend-rewrite-design.md`
|
||||||
切换手册:`docs/specs/phase5-cutover-runbook.md` ← 上线当天照这份走
|
切换手册:`docs/specs/phase5-cutover-runbook.md` ← 上线当天照这份走
|
||||||
|
|||||||
@@ -148,9 +148,16 @@ problemRoutes.get("/problems", optionalAuth, async (c) => {
|
|||||||
|
|
||||||
problemRoutes.get("/problem-tags", async (c) => {
|
problemRoutes.get("/problem-tags", async (c) => {
|
||||||
const keyword = c.req.query("keyword")?.trim()
|
const keyword = c.req.query("keyword")?.trim()
|
||||||
|
// 只数公开题库里可见的题:隐藏的题和比赛题都不算,否则标签会出现在
|
||||||
|
// 首页列表里,点进去却一道题都筛不出来(对齐 /problems 的过滤条件)
|
||||||
const rows = await db.select({ id: schema.problemTag.id, name: schema.problemTag.name, problemCount: countDistinct(schema.problemTags.problemId) })
|
const rows = await db.select({ id: schema.problemTag.id, name: schema.problemTag.name, problemCount: countDistinct(schema.problemTags.problemId) })
|
||||||
.from(schema.problemTag)
|
.from(schema.problemTag)
|
||||||
.innerJoin(schema.problemTags, eq(schema.problemTags.problemtagId, schema.problemTag.id))
|
.innerJoin(schema.problemTags, eq(schema.problemTags.problemtagId, schema.problemTag.id))
|
||||||
|
.innerJoin(schema.problem, and(
|
||||||
|
eq(schema.problem.id, schema.problemTags.problemId),
|
||||||
|
eq(schema.problem.visible, true),
|
||||||
|
isNull(schema.problem.contestId),
|
||||||
|
))
|
||||||
.where(keyword ? ilike(schema.problemTag.name, `%${keyword}%`) : undefined)
|
.where(keyword ? ilike(schema.problemTag.name, `%${keyword}%`) : undefined)
|
||||||
.groupBy(schema.problemTag.id, schema.problemTag.name).having(sql`count(${schema.problemTags.problemId}) > 0`)
|
.groupBy(schema.problemTag.id, schema.problemTag.name).having(sql`count(${schema.problemTags.problemId}) > 0`)
|
||||||
.orderBy(asc(schema.problemTag.name))
|
.orderBy(asc(schema.problemTag.name))
|
||||||
|
|||||||
Reference in New Issue
Block a user