主题
CLAUDE.md
本文件为 Claude Code 提供项目上下文。最常引用的规则放在前部。
⚠️ 跨端 Sync 协议红线的正文在
rvh/lib/features/sync/CLAUDE.md(本文件 §跨端 Sync 协议红线只留索引 + 编号对照表)。碰该目录下的文件时它自动注入,但全程走 Bash(cat/grep/sed)干活时注入不触发 —— 改 sync 代码前请显式读一次那份。
项目入口
🔴 动手前先确认环境装得起来。 干净 clone 现在能
flutter pub get(2026-08-29 / T4-10 把 opencv_dart 的 path override 从pubspec.yaml移进本机专属的pubspec_overrides.yaml之后),但.env按设计不进 git,缺了flutter analyze会因asset '.env' doesn't exist直接退 1;构建 Android APK 还额外需要本机那份local_packages/opencv_dart(约 100MB,且内含一条本机绝对路径,拷给别人也不能直接用)。 补齐步骤见 QUICKSTART.md 开头那两节(唯一真相源,别在这里再写一份)。 判断装到哪一步:ls .env→ 能 analyze / test;再ls local_packages/opencv_dart pubspec_overrides.yaml→ 能构建 APK。
5 分钟上手:QUICKSTART.md
文档导航:docs/README.md(按受众/任务/层级查找)
核心文档(必读)
| 文档 | 内容 |
|---|---|
| product.md | 指针 → 产品定位与功能清单的真相源在仓根 docs/product.md(双端唯一一份,移动端那节在 §双端产品形态);规划归 backlog/roadmap,as-built 归 CHANGELOG |
| design.md | 架构+业务模型+UI 流程(数据库权威引用 docs/database/) |
| decisions.md | 重大技术决策(ADR) |
| development.md | 代码规范+常见问题 |
| docs/database/schema.md | 表结构 + ER 图(权威) |
| docs/deployment/supabase-setup-guide.md | Supabase 配置 |
| docs/deployment/edge-function-deployment-guide.md | Edge Function 部署 |
7 层文档体系
Layer 1 项目入口 / 2 产品业务 / 3 开发规范 / 4 架构设计 / 5 专项技术 / 6 辅助工具 / 7 自动化维护。详见 docs/README.md。
⚠️ 代码修改后的应用重启规则
🤖 Claude 自动化行为:每次修改代码后必须自动重启 app(用户明确要求)。
🔴 重启前强制检查:
- 必须先运行
/code-check-before-restartSkill(用户说"跳过检查"时可绕过) - 检查通过后才能执行
flutter run - 发现 P0 高危问题必须修复后再重启
默认规则:所有代码修改后用热重启(Hot Restart, R 键),不要用热重载(r)。
完全重新安装的场景:
- 修改
pubspec.yaml、assets 配置、原生代码(Android/iOS) - 修改数据库 schema
- 出现无法解释的运行时错误
操作命令:
bash
# 步骤 1:重启前检查(强制)
/code-check-before-restart
# 步骤 2:检查通过后,热重启(flutter run 窗口按 R 键)
# 步骤 3:完全重新安装
flutter clean && flutter run -d <device_id>💡 flutter run 的操作细节(USR2 信号实测失效、启动检测轮询、libsqlite3 下载兜底)见 Claude 私有 memory
build_workarounds,不重复写进团队规则。
重启前检查清单:
- 静态分析:
flutter analyze— 有 errors → 阻止重启 - 代码复查(< 2 分钟):检查
git diff --name-only HEAD列表- 无手动构造 Entity/Model(应使用
toEntity()/toModel()) - 无强制解包
xxx!(应加 null 检查) - 无类型不匹配(String vs Enum)
- 条件分支完整(处理 null/empty/error)
- 无手动构造 Entity/Model(应使用
- 专项检查提醒:
- 改 UI → 提醒
/ui-compliance-check - 改架构层 → 提醒
/clean-arch-check - 改数据库 → 提醒
/doc-sync-check
- 改 UI → 提醒
默认部署设备:跑 ./scripts/run_android.sh 自动选唯一在线设备,不写死串号(多设备处理细节见 memory build_workarounds)。
⚠️ 代码提交规则
核心目标:避免大量改动后忘记提交,commit 历史清晰。
Claude 主动提醒提交的时机:
- 用户确认功能正常("没问题""可以了""测试通过")
- 连续 3+ 轮修改-测试稳定
- 5+ 文件未提交
- 会话即将结束 / 用户切换新任务
阶段性提交(10+ 文件或跨 3+ 模块时):按架构层拆分 — 数据层 → 业务层 → UI 层 → 联调,每完成一层独立提交。
提交流程:用户确认 → /code-review → /doc-sync-check → 生成 commit message → git add + git commit。
Commit 格式:
<type>(<scope>): <subject>
feat(ocr): 添加百度 OCR 支持
fix(database): 修复索引缺失问题
docs: 更新架构文档异常处理:用户拒绝提交则尊重决定不反复提醒;同一批变更只提醒一次。
⚠️ 缺陷修复流程
核心原则:正向解决,不绕开不降级
- 先按既定设计分析问题 — 理解原始架构意图,在框架内寻找方案,追溯根本原因
- 不要轻易绕开 — "临时方案"会变成永久债务
- 不要轻易降级 — 功能降级是最后选择,保持架构完整性优先
示例:
- ❌ OCR 失败 → 禁用第二次 OCR(降级)
- ✅ OCR 失败 → 分析透视矫正质量差的原因 → 修复图像处理参数
- ❌ 4 层架构不工作 → 改回直接查本地(绕开)
- ✅ 4 层架构不工作 → 分析哪一层失败 → 修复该层缺陷
修复后、测试前的代码逻辑复查(必须)
- 复查修复逻辑 — 边界条件、异常处理、错误处理完整性
- 检查潜在缺陷 — 空指针、异步错误、依赖有效性、并发与资源泄漏
- 确认完整性 — 是否解决根本原因、是否引入新问题、依赖外部服务是否可用
- 记录风险 — 测试前告知用户潜在问题
原则:宁可多花 2 分钟复查,也不要浪费用户 10 分钟测试有缺陷的代码。
🔒 安全操作规则
以下操作不可撤销或影响共享状态,Claude 必须先用 AskUserQuestion 征得用户明确同意才能执行。
危险操作清单
| 操作 | 影响 | 等级 |
|---|---|---|
git restore <file> / git checkout -- <file> | 丢弃工作区改动 | 🔴 |
git restore --staged <file> | 取消暂存 | 🟡 |
git reset --hard <commit> | 重置丢弃改动 | 🔴 |
git clean -fd | 删除未跟踪文件 | 🔴 |
git push --force | 覆盖远程历史(绝不对 main 强推) | 🔴 |
rm -rf <directory> | 递归删除目录 | 🔴 |
rm <file> / 删除 lib/ docs/ 下文件 | 删除文件/源码 | 🔴 |
DROP TABLE / DELETE FROM <table> | 数据库数据丢失 | 🔴 |
删除 assets/databases/lampio_dict.db | 它是指向 RB 那份的 symlink(红线 #10)—— 删了不丢数据,但破坏「只有一份」的结构前提,cross-end-check.sh §B 会红 | 🔴 |
| 修改 Schema 版本号 | 触发 DB 重建 | 🟡 |
修改 .env / pubspec.yaml / .git/config | 配置改变 | 🟡 |
删除 .git/ | 丢失 Git 历史 | 🔴 |
操作流程
- 检测到危险操作 → 停止
- AskUserQuestion 询问 — 列出受影响文件、明确标注"⚠️ 不可撤销"
- 用户确认 → 执行 → 报告结果
- 数据库类操作额外提醒备份
豁免(无需确认的安全操作)
- Git 只读:
status/diff/log/add/commit/pull/push(非 force) - 文件读取:Read 工具、
cat/ls/find/grep - 数据库
SELECT查询
异常处理
- 用户拒绝 → 询问替代方案
- 用户要求"跳过所有确认" → Claude 拒绝("危险操作必须逐个确认")
🔄 跨端 Sync 协议红线(正文已下沉 · 本节只留索引 + 编号对照表)
🔒 正文在
rvh/lib/features/sync/CLAUDE.md(2026-08-29 T2-1 原样下沉,一字未改): 14 条红线的 Dart 落地形状、守卫 grep、本端独有证据,以及「跨端契约镜像 backlog」。 碰rvh/lib/features/sync/下任何文件时它自动注入;走 Bash 干活(cat/grep/sed)不触发注入 —— 改 sync 代码前请显式读一次那份。契约本体(规则 / 为什么 / 反例)仍在根CLAUDE.md§4 ·src-tauri/CLAUDE.md§2 ·docs/cross-end/。改契约 → 改根;改 Dart 落地 → 改那份。
| # | 一句话 |
|---|---|
| #5b | user_id 必填 —— save 路径 + pull 路径双侧守门 |
| #5d | Watermark = server_updated_at(trigger 维护的权威服务器时钟) |
| #5e | 预装库单点 + Lemmatizer JSON 双端 byte-equal |
| #5f | push 必经 onConflict(非 PK UNIQUE 表) |
| #5g | word_cloze_contexts 双端共写 + pull 后必经 reconcile 重新封顶 |
| #5h | push dirty-check 必须按 user_id 过滤 |
| #6b | pull 父表禁 INSERT OR REPLACE / ConflictAlgorithm.replace |
| #6c | 封面 BLOB 跨端契约 |
| #6d | last_opened_at RVH pull-only |
| #6e | reading_notes 删除必走软删 + 手工级联软删子树 |
| #6f | 墓碑父行不算存在:子树按父表算 + pull 父行必须三态 |
| #6g | 墓碑行 synced_at 怎么写 —— W / P1 / P2 / P3 |
| #6h | next_review_date 必须带 UTC 标识符(写侧 + 读侧) |
| #6i | pull 分支②「本地已删 + remote 活」的 skip 必须以「墓碑仍待推」为条件 |
| —— | 跨端契约镜像 backlog(RB 红线在本端的对齐状态,唯一真相源) |
🔒 编号对照表(别按编号跨仓对照)
两仓编号在 6x 段实际分叉:RVH 的 #6d 是 last_opened_at,RB 的 #6d 是墓碑 synced_at。 跨仓引用必须带仓名(写「RB #6d」或「RVH #6g」,不要写裸 #6d)。
🔒 2026-08-29(T4-4)裁定:两仓编号不统一,本表是永久消歧器,不是过渡措施。 理由三条(与 T4-1「编号消歧而不重编号」同款):① rvh/ 内约 350 处引用带编号 (lib/test 注释 130+ 处、docs/cross-end/ 的冻结 handoff、CHANGELOG、SQL 注释), 重编号 = 在禁改的历史记述里造死链;② 两套编号已经在混用且工作正常 —— 凡本仓没有本地编号的条目,Dart 注释直接写 RB 的号(红线 #7 / #9 / #6a / #1 都在场), 真正会出事的只有 6x 段那几个同号不同义的,正是本表在挡;③ 重编号没有任何机械守卫 (没有 lint 能验一个裸 #6d 指的是哪个仓),做完就开始漂。 替代做法 = 双向指针:根 CLAUDE.md §4 每条写明对端编号,本表反向写明根侧位置。
| 主题 | RVH(本文件) | RB | 契约叙述在 |
|---|---|---|---|
| user_id 必填(save + pull 双侧) | #5b | #5b | src-tauri/CLAUDE.md §2 |
watermark = server_updated_at | #5d | #5d / #5a / #5d′ | src-tauri/CLAUDE.md §2 |
| 预装库单点(symlink)/ lemmatizer JSON 双端 byte-equal | #5e | #10 | 根 CLAUDE.md §4 |
| push 必经 onConflict(非 PK UNIQUE 表) | #5f | (无独立编号条) | 本节 ↓(RVH 侧唯一叙述) |
| cloze 语境池双端共写 + reconcile 封顶 | #5g | (写在 §3 Auth & Sync) | 根 CLAUDE.md §3 |
| push dirty-check 按 user_id 过滤 | #5h | #5i | 根 CLAUDE.md §4 |
pull 父表禁 INSERT OR REPLACE | #6b | (写在 #6 正文) | 本节 ↓(RVH 侧唯一叙述) |
push payload deleted_at 传真值 | 写在 #6e | #6b | src-tauri/CLAUDE.md §2 |
| 封面 BLOB 跨端契约 | #6c | (无编号条) | 本节 ↓(RVH 侧唯一叙述) |
last_opened_at RVH pull-only | #6d | (写在 §3 Merge 策略) | 根 CLAUDE.md §3 |
| reading_notes 软删 + 级联子树 | #6e | #6a(RB 为全表通则) | src-tauri/CLAUDE.md §2 |
| 墓碑父行不算存在(子树 + pull 三态) | #6f | #6a / #6c | src-tauri/CLAUDE.md §2 |
墓碑行 synced_at 怎么写(W/P1/P2/P3) | #6g | #6d | 根 CLAUDE.md §4 |
next_review_date 必须带 UTC 标识符 | #6h | (尚未立编号条) | docs/cross-end/40-rb-learning-loop-handoff.md §3.1 |
| 分支②「本地墓碑 + 云端活行」按「墓碑仍待推」拆两支 | #6i | #6e | 根 CLAUDE.md §4 |
写 word 前必经归一(键空间规则) | (无本地编号,注释直接写 红线 #9) | #9 | 根 CLAUDE.md §4 #9 + rvh/lib/features/sync/CLAUDE.md §跨端契约镜像 backlog |
save_word 须复活软删条目 | (无本地编号,注释直接写 红线 #7) | #7 | src-tauri/CLAUDE.md §2 + rvh/lib/features/sync/CLAUDE.md §跨端契约镜像 backlog |
开发流程
待办记在哪(先看这条,别记错地方)
✅ 合仓已全部完成并归档(2026-08-29)
rvh/从 2026-08-28 起就是reading-browser仓的子目录;五个阶段 + T4-1 ~ T4-10 十项全部 ✅,最后一项(老 gitee 仓归档)由用户于 2026-08-29 置为「关闭」。 计划与评估已归档为docs/plans/archive/rvh-merge-plan.md与docs/plans/archive/rvh-merge-evaluation.md—— 它们从此是历史记述, 不再是进度真相源,挑活前也不需要再扫那张台账(原来要防的 T4-3 / T4-5 / T4-6 都做完了)。⚠️ 那两份归档件里的交接 prompt、
~/reading_vocab_helper路径、sync-rvh-vocabulary.sh都是双仓时期的写法,别照着当操作指南。合仓沉淀下来的活的东西:跨端契约 → 仓根CLAUDE.md§4 · 本端落地与守卫 → 本文件 · 机械守卫 →scripts/cross-end-check.sh/scripts/check-vocab-asset.sh/.github/workflows/ci-cross-end.yml/ci-rvh.yml。🔒 路径基准(本文件长期有效,与合仓无关):markdown 链接是 rvh-相对 (写 docs/README.md 指的是
rvh/docs/README.md),而反引号里的路径一律仓根相对 —— 这句话里第一个路径刻意不加反引号:加了就会被守门脚本按仓根解析而报失效(写这段时当场踩到)。 (pnpm run check:claude-paths按这个基准校验,本文件也在它的清单里)—— 两套基准并存。另:
rvh/docs/plans/backlog.md顶部那节「⏸ 全线暂停中」同批订正。
跨会话待办池 = docs/plans/backlog.md。新会话起步先扫它; 「未修 / 待定 / 需产品决策」的条目一律写这里。
CHANGELOG.md 只记 as-built(做了什么、为什么这么做),不承载待办 —— 写进去会被埋在 版本记录里,没人会去 CHANGELOG 找待办。需要交叉引用时,CHANGELOG 侧留一句话 + 链到 backlog。
历史:根目录
TODO.md(四象限法,2026-01-14 停更)已于 2026-08-17 删除, 内容全量归档至 backlog-archive.md(含 19 条待办的 逐条核实结论:多数早已完成或失效,仅 4 条仍有效并已并入 backlog.md)。
新功能
- product.md 确认优先级 → 2. design.md 了解架构 → 3. development.md 遵循规范 → 4. 更新 backlog.md(待办)+ CHANGELOG.md(as-built)→ 5. 检查文档同步
架构变更
- decisions.md 记录 ADR → 2. 更新 design.md → 3. 执行文档同步检查
数据库变更
- 更新
assets/sql/*.sql→ 2. 更新app_database.dart的_schemaVersion→ 3. 更新 schema.md → 4. 执行文档同步检查
数据库管理策略
开发阶段:简化重建策略,不做迁移。
- DDL 与 DML 分离(脚本在
assets/sql/) - 表结构变更 → 直接重建(不保留数据)
- 初始化数据更新 → 改 SQL 脚本自动应用
- ❌ 不做兼容判断、不做渐进式迁移
- ⚠️ 开发阶段每次重建会丢失所有数据(可接受),生产环境需补迁移
修改流程:改 SQL → 改 schema.md → 升 _schemaVersion → 重启应用。
时间戳用 {CURRENT_TIMESTAMP} 占位符。所有表结构以 SQL 文件为准。
文档维护机制
完整规则见 docs/guides/doc-maintenance-guide.md。
文档同步(代码变更触发更新)
由 /doc-sync-check Skill 自动检测。映射:
| 变更类型 | 必须更新 |
|---|---|
| 🔴 数据库 Schema | schema.md、assets/sql/*.sql、CHANGELOG.md |
| 🟠 架构 | design.md、decisions.md(ADR)、CHANGELOG.md |
| 🟡 功能 | product.md、backlog.md(留下的待办)、CHANGELOG.md |
| 🟢 配置 | docs/deployment/、.env.example |
| 🔵 性能优化 | docs/database/optimization.md、CLAUDE.md(性能现状) |
Schema 版本号:仅在 schema.md + _schemaVersion + assets/sql/ 头部维护,其他文档统一引用 schema.md,不再硬编码版本号。
新增文档规则
- 新建
docs/*.md→ 必须同步更新 docs/README.md。 ⚠️ 没有任何东西会拦你 —— 原文写着「pre-commit hook 拦截」,但本仓默认不装 hook (.git/hooks/是空的),而且那个 hook 从来不查文档索引,只跑dart format/flutter analyze/ 架构 grep。2026-08-30 订正。真正在守的只有仓根scripts/check-doc-links.mjs(管链接悬不悬挂,不管索引全不全)。 - 命名:
docs/下 kebab-case,根目录 UPPER_CASE - 单条技术决策 → 记到 decisions.md(ADR),不新建文档
- 检测到 5+ 个
.md同时改动 → 提醒运行bash scripts/doc-consistency-check.sh
USER_NOTES.md(用户需求备忘录)
- 本地文件,不在仓库里(2026-08-28 并入 RB 仓计划 T2-3 裁定转本地未跟踪)。工作区有就照下面用;新克隆没有它属正常,不要去创建
- 用户维护,Claude 只读(仅可加
<!-- SYNCED: YYYY-MM-DD -->标记) - 解决跨会话需求遗忘
- 会话结束前:若讨论了重要需求但未写代码,主动帮用户整理草稿,提醒"是否记录到 USER_NOTES.md?"
- 用户说"根据 USER_NOTES.md 更新 docs":读未标 SYNCED 的条目 → 更新 product.md / design.md / decisions.md → 标 SYNCED
Material 3 设计规范
详见 docs/ui-guidelines/ — 5 份专项指南(按钮/对话框/表单/卡片/导航)。
速查
- 按钮:
FilledButton(主操作) /FilledButton.tonal(次要) /OutlinedButton(取消) /TextButton(链接) - 圆角:按钮 12px、对话框 28px、卡片 12px
- 颜色:用
colorScheme.xxx,禁止Colors.xxx硬编码 - 文本:用
theme.textTheme.bodyMedium等语义化样式,避免硬编码fontSize - 间距:4dp 倍数(8/12/16/24...)
触发条件:修改 UI 代码(Button / Dialog / TextField / Card / AppBar / 设置颜色或文本样式)前先 Read 对应 style-guide.md。
文件组织规范
- 日志 →
rvh/logs/<模块>_YYYY-MM-DD.log(本子项目自己这份,rvh/scripts/run_android.sh按相对路径写) - 备份 / 临时 → 仓根的
backups/与temp/(见根CLAUDE.md§12)
🔴 2026-08-31:rvh 侧的
temp/与backups/已删除 —— 两个目录只有README.md+.gitkeep、 全仓零写入方,而同一个仓里维护两套 scratch 约定就是第二本账。logs/留下,因为run_android.sh真在写它。
禁止在根目录或代码目录创建上述文件。详见 logs/README.md。
⚠️ .gitignore 的「目录靠 .gitkeep 追踪、文件忽略」这套写法,在合仓后曾整个失效: 仓根一条无锚定的 logs 规则把 rvh/logs/ 连目录一起排除了,父级目录一旦被排除, 本文件旁边那两条 !logs/README.md / !logs/.gitkeep 反选再也收不回来 —— 那两个文件此前只是靠「已 tracked」活着。2026-08-31 把根规则锚定成 /logs/ 后才真正生效。 守卫 pnpm run check:tracked-ignored(被跟踪却被 ignore 的文件数必须为 0)。
代码规范速查
- 文件名:小写蛇形(
ocr_repository.dart) - 类名:大驼峰(
VocabularyNotebookPage) - 变量:小驼峰(
vocabularyName) - 私有:前缀下划线(
_privateMethod) - Lint:
flutter_lints
项目当前状态
本节为 Claude 提供跨会话锚点。
数据库
- 版本:见 schema.md(权威)/
app_database.dart_schemaVersion(v51 起) - 模式:3 层回填(本地 → Supabase 共享缓存 → Edge Function API 兜底)
- 主库:
lampio.db(用户数据);预装库:assets/databases/lampio_dict.db(首次启动导入 18916 词,预装版本 v29) - 表数:12
- 关键设计:
vocabulary19 列(v34 瘦身 + v48-v50 加 CEFR audit/tags 字段 + v53 加 emoji + v54 加 canonical_surface);pos_definitions含 POS 级别 translations + per-POS CEFR + 义项级 differentiation/collocations(预装 v19,跨端 ⑤,仅带 synonyms 的 def)cefr_inferred/cefr_source/word_tags正交字段(v48-v50),LLM 评估透传到 UI "约 X" 标识word_tags短语 idiomaticity 三档 tag 值(预装 v24):phrase 行加idiomaticity:always|context|literal(非组合性类型层判定,RB「只自动高亮 always 桶」根治 41% 误报);always 2776 / context 3451 / literal 383(v24 floor 清理 round-3:A 类all along→context [gate-A 复测唯一硬 FP,HOMONYM 空间陷阱] + B 类 12 个纯话语功能子集→literal [no matter what/pay attention/for the most part/by far/on purpose/in spite of/right away/the other day/from time to time/once in a while/how come/fair enough,纯话语功能学习价值低 → 既不自动露也不送 §9 深度模式];确定性覆盖层phrase_idiomaticity_overrides.json单点产出、零 LLM、纯 additive;静态 idiomaticity 治理自此冻结,残留 occurrence 级 FP 交 RB §9 LLM 深度模式 ceiling,详见 docs/cross-end/15 §12)。历史:v23 gate-A 双轨 retag(track-① surface 陷阱 demote 249 + track-② lemma 折叠in a fix→context /all right reserveprune,lemma 折叠是合法归一非资产 bug,零 lemmatizer 改/零 PK 重算,详见 docs/cross-end/14)。词总数 18916(round30 −53 prune / +80 补词,小补轮再 −9 露骨词),跨端红线 #10 由 RB pipeline 单点产出(pipeline 2026-07-19 已迁 RB,RVH 纯消费),不进 Supabase 同步矩阵emoji正交字段(v53):具象名词 OpenMoji hexcode(505 词配图),跨端红线 #10 由 RB pipeline 单点产出(pipeline 已迁 RB,RVH 纯消费),不进 Supabase 同步矩阵canonical_surface正交字段(v54):习语可读引用形(归一键 word 逐 token lemmatize 后不可读,如rain cat and dog→raining cats and dogs),仅 phrase 行有值,供 RB review/popup 显示,匹配/同步零参与(红线 #10)proper_noun标签(round30,word_tags 值):1055 词(871→1055)。RVH 若要做专名过滤直接用该标签,别照抄 RB 早期的「name POS」判据(实测误伤 8–10% 真词:china(瓷器)senatematrixprairie…)example_translations(round30):pos_definitions[].definitions[].下与examples等长的平行数组(缺位补空串),86,817 处全覆盖。🔴 复习卡正面绝不能渲染它 —— cloze 防泄露只遮英文形态、对中文一无所知,中文译文必然含目标词词义 = 直接把答案递给用户;揭晓侧/详情页可显示。回归测试test/features/vocabulary_notebook/cloze_example_translation_leak_test.dart。⚠️examples/example_translations/example_source是按下标配对的三个平行数组,任何按下标增删其中之一的代码都会让此后每条例句配上别人的译文和来源(无异常、无日志、纯静默错位)—— 要动就三者一起动,并把「长度不齐」当硬错误判死,不要猜对齐方式- 预装库 prune 两阶段(v28):导入不再是纯 UPSERT,见
app_database.dart::prunePreinstalledVocabulary/retryPendingVocabPrune。⚠️ 软删不释放 FK(learning_entries.word→vocabulary(word)是 RESTRICT 且PRAGMA foreign_keys真开),故必须两阶段;禁止用PRAGMA foreign_keys=OFF绕。回归测试test/shared/database/preinstalled_prune_test.dart - 跨端 vocabulary schema 三端一致(RVH/Supabase/RB),详见 cross-end-schema-compatibility.md
- vocabulary→user 表 FK 用 RESTRICT(v51 改,原 CASCADE 是 footgun)
reading_notes.cover_image_dataBLOB(v47 字节直传,PostgREST bytea hex transit;详见红线 #6c)word_cloze_contexts(v57,RB v24 镜像):复习卡真实语境池(一词多语境,应用层封顶 5,无 UNIQUE/无 FK)。跨端同步表 5→6,本表独有 pull 后reconcile_cloze_pool合并去重+重新封顶(红线 #5g);双端共写(2026-08-17 评审放开 RVH 采集;v60 落地 OCR 采集 = 计划 Task H,采集侧四条硬条件见红线 #5g),复习卡背面抽屉显示真实语境句(目标词高亮;⚠️ RVH 不挖空 ——context_drawer_content.dart::_clozeBlankMode = false,2026-07-11 产品决策「小屏不挖空」。挖空是 RB 侧的形态)
测试覆盖率
Domain < 20% / Data < 10% / Presentation 无系统测试。MVP 阶段优先功能,后续补测试。
性能
- 词汇库:18916 个预装词条(12291 单词 + 预装短语库;round30 prune 53 死词形/露骨词 + 补 80 正确词形与专名,小补轮再删 9 个露骨词)
- OCR:< 2s(本地)/ < 1s(云端)
- 词汇查询:< 50ms(本地)/ < 200ms(Supabase)
- 详细:docs/database/optimization.md
开发阶段
- Alpha(v0.5.0-alpha),目标 2026-01-31
- ✅ 拍照识词 / 数据库架构 / 词汇笔记本 / 多词性定义展示 / 间隔重复学习(SM-2)
- 🚧 Known Words(阶段 1/5)/ 翻译集成
技术栈速查
- 平台:仅 iOS + Android(不支持 Web/Windows/macOS/Linux)
- 架构:Clean Architecture(Domain/Data/Presentation)
- 状态:Riverpod + riverpod_generator
- 数据库:SQLite(12 张表)
- OCR:Google ML Kit(本地) + 百度 OCR(云端)
- 图像:OpenCV Dart(本地修改版)
- 序列化:Freezed + json_serializable
项目结构
lib/
├── main.dart
├── core/ # 算法、工具、服务
├── features/ # 14 个模块(10 用户功能 + 2 基础设施 + 2 工具)
│ ├── welcome/, photo_recognition/, vocabulary_filtering/,
│ ├── vocabulary_notebook/, reading_tracking/, translation/,
│ ├── statistics/, settings/, books/, known_words/, reference_words/
│ ├── ocr/ # 底层基础设施,无 UI
│ ├── vocabulary/ # 数据服务,无 UI
│ ├── developer/ # 仅开发环境
│ └── vocabulary_test/ # 查询测试工具
└── shared/ # 数据库、组件、用例标准模块(Clean Architecture):features/[module]/{domain,data,presentation}/
关键文件位置
OCR:
lib/shared/domain/usecases/recognize_and_filter_usecase.dartlib/core/services/post_crop_image_processor.dart
数据库:
- 文档:docs/database/README.md / schema.md / optimization.md
- 代码:
lib/shared/data/database/app_database.dart - SQL:
assets/sql/01_create_tables.sql/02_create_indexes.sql/03_init_data.sql
学习系统:
- SM-2:
lib/core/algorithms/sm2_algorithm.dart - 笔记本:
lib/features/vocabulary_notebook/data/repositories/notebook_repository_impl.dart
项目 Skill(自动化工作流)
每个 Skill 的触发条件、检测内容、输出格式见对应 SKILL.md。
| Skill | 用途 / 触发 | 文档 |
|---|---|---|
/code-check-before-restart | flutter run 前强制(< 10s 快速验证) | SKILL.md |
/code-review | 提交前深度审查(支持 --full) | SKILL.md |
/doc-sync-check | 代码变更 → 检测需更新文档 | SKILL.md |
/doc-consistency-check | 文档内部一致性(Schema/断链/数据) | SKILL.md |
/ui-compliance-check | UI 文件变更(Material 3,支持 --full) | SKILL.md |
/clean-arch-check | 架构层文件变更(支持 --full) | SKILL.md |
/i18n-check | presentation 层 UI 文本变更(支持 --full) | SKILL.md |
/preinstalled-db-update | 预装库 / Schema 变更(6 步工作流) | SKILL.md |
典型工作流:修改 → /code-check-before-restart → flutter run 测试 → /code-review → /doc-sync-check → 提交
问题分级(统一):🔴 严重必修 / 🟠 重要建议修 / 🟡 可选优化 / 🟢 提示
常用命令
bash
flutter run -d <device_id> # flutter devices 查 ID
flutter analyze # 静态分析
flutter test # 测试
flutter clean && flutter pub get # 清理重建
dart run build_runner build --delete-conflicting-outputs # 代码生成快速自检(提交前):
bash
# 检查 Schema 版本号一致性
grep "_schemaVersion =" lib/shared/data/database/app_database.dart
head -5 assets/sql/03_init_data.sql | grep "Schema版本"
# 完整文档一致性检查
bash scripts/doc-consistency-check.sh快速问题解决
参考 development.md 常见问题:OCR 识别 → Q8;数据库锁定 → Q10;Mat 内存泄漏 → Q14。性能优化 → optimization.md。
重要提醒
- 修改后用
flutter run重启(不发布到 pub.dev) - 项目使用
flutter_lints - 需求评估流程:用户提新需求时先做"需求澄清"(追问模糊点、拆解、指出歧义、分离问题与方案),确认问题清晰后再做结构化评估(问题→UX→功能价值→可行性→成本→ROI→风险),结果记录到 USER_NOTES.md
最后更新:2026-08-28(并入 RB 仓,跨端红线一节去镜像 —— 见 docs/plans/archive/rvh-merge-plan.md T3-8)