来源:notes/documents/网页端改用_Note_ID_与「其他文档」模块实施记录.md

网页端改用 Note ID 与「其他文档」模块实施记录

2026-09-22 一天之内把「网页版按路径认笔记」改成「按 Note ID 认笔记」,并把 notes/ 下不是正式笔记的那 47 篇 分出去单独做一个模块。相关 spec 在 .scratch/web-documents-split-and-note-id-api/(已 resolved)与 .scratch/web-note-identity-by-id/(Q1 被前者回答)。

一句话结果

网页端的「笔记」= notes/documents/ 的 115 篇,每篇按 note_id 取;其余 47 篇进脊上第四格「其他文档」, 按路径取、按目录分组、原样渲染、不搜索。「日程」的笔记线深链也改成 Note ID。线上 aef8363 已 READY。

改了什么

本地事实源(工作区根)

  • scripts/backfill_note_created_at.py(dry-run 默认):把 115 篇 documents/ 笔记的文件创建时间 写进 front matter 的 created_at(日期粒度)。逐条确认过:115 篇全部一致,重跑零变更。
  • scripts/check_note_created_at.py:并排看 文件创建时间 / created_at / git 首次提交 / 注册时间, 报告落 config/note_created_at_report.json。回填后退出码 0(无 mismatch / unreadable)。
  • scripts/note_cli.py:新建笔记写 created_at(取当天),重同步时沿用文件里已有的值,不被重置。 这一步不可省——create --apply --force 会整份重写 front matter,不特意保留就会把创建时间冲掉。

产物(web/scripts/)

  • generate-notes.mjs 产出两个集合:notesdocuments/,带 idcreatedAt)与 others
  • 构建期两条硬断言:documents/ 下有笔记缺 note_id、或两个文件共用同一个 note_id,直接构建失败。

接口

接口 服务谁 身份
GET /api/notes/entry?id= 笔记 + 日程 Note ID
GET /api/notes / /api/notes/search 笔记 Note ID(只含 documents/)
GET /api/others 其他文档 Note Path
GET /api/notes/detail?path= 其他文档(保留原读法) Note Path
GET /api/daily/* 日程 笔记线新增 noteIdnotePath 降为档号

同一接口不再接受两种身份:detail?path=documents/ 路径返回 404 是设计,不是 bug。

前端

  • 脊上第四格由占位「材料与来源」落成「其他文档」(ADR-0009 的格数没动)。
  • 路由:?n= 装 Note ID、?o= 装其他文档路径;旧书签 ?n=documents/xx.md 由前端在已加载的索引里 解析成 id 后改写地址栏,实测可用。
  • 页边档号区:笔记是「档号 / 创建 / 更新」,其他文档是「档号 / 分类 / 更新」。

验证

  • npm run build 通过;npm test 53/53;npm run linttsc -b 干净。
  • npm run preview:local + Playwright:笔记 115 篇且只有「文档」一组;其他文档按 来源 25 / 书籍 11 / 专题 6 / 项目 4 / 知识库 1 分组;旧 path 链接 canonical 成 id; 日程笔记线深链落到 ?n=note_2972af60fe554c7b;无 console 错误。
  • 线上:页面引用的 JS 哈希与本地构建一致;/api/notes/entry/api/others 都在(未登录返回 401, 而不是 404)。

踩到的坑(留给下一次)

  • 文件创建时间只在开发机上可信。 构建容器是 git clone,所有文件的出生时间等于检出时刻;本机 birthtime 却是真的(某篇笔记 2026-06-10、BERT 全文 2026-06-06)。所以创建时间只能落进文件。 而且 birthtime 会随文件被重新生成而变化——实测有 2 篇就有这个痕迹(提交次日才落盘)。写进 created_at 之后才稳定。
  • git log --name-only 会漏掉合并提交带来的文件。 2026-08-30 那次迁移是合并进来的,整棵树扫一遍 会看不见那 71 篇的首次提交;改成单路径查询(git log --diff-filter=A -1 -- <path>)才对得上。
  • React 的 hook 不能写在 early return 之后。useEffect 挪到 if (!state) return 下面就炸 「Rendered more hooks than during the previous render」(minified error #310),整页白屏。
  • note_cli.py create 的 dry-run 与 --apply 生成的 note_id 不同,拿 dry-run 的 id 去查 status 必然 LookupError。真要 id 就执行 --apply 后从输出里读。
  • git add -u 不含新增文件。 有一次只提交了 .scratch/ 的 spec,notes/documents/ 下的笔记文件 漏了,得补一个提交。
  • 本地 Playwright 的 chromium 版本与虚拟环境不一致时,需要显式指定 executable_path 才能起浏览器。

遗留(不在这轮范围里)

  • 那 47 篇「其他文档」不补 note_id、不进注册表、不进日历——这正是本次修掉的错位。
  • documents/ 里有 2 篇有 note_id 却没注册(06_dg板卡X5_BPU推理服务_开放词表检测YOLO-World接入.md02_dg板卡X5_BPU推理服务_可视化HTML.md)。
  • 5 个迁移期手写 id 不是 note_<16hex> 形态(含上面那个 note_dg_bpu_html_viz)。
  • note_path_aliases 里 71 条旧路径现在都不在盘上了:改过名的旧链接仍然打不开(别名在 SQLite 里, 构建期读不到)。
  • notes 表的 path 存了两种前缀形态(41 条带 notes/、71 条裸相对路径),对比时要自己归一。