Skip to content

跨端 vocabulary 表 Schema 对照

版本: Schema v51 最后更新: 2026-05-13 关联: docs/plans/cefr-llm-evaluation-and-ui-passthrough.md 原则 4

设计原则

原则 4:三端 vocabulary schema 一致性优先(接受有意冗余)

RVH (SQLite) / Supabase (PostgreSQL) / RB (SQLite via Rust) 三端共享同一份 vocabulary 表结构。字段集合保持一致,即使某字段在某端无业务意义。 加字段:三端同步加;删字段:三端同步删;类型差异由各端 DB 类型系统决定。

三端列集合对照(v51,17 列)

#列名RVH SQLiteSupabase PostgreSQLRB SQLite备注
1wordTEXT PK COLLATE NOCASETEXT PKTEXT PKRVH COLLATE 是大小写护栏;应用层 lemmatizer 已归一
2ipa_pronunciationTEXTTEXTTEXTIPA 音标
3pronunciation_urlTEXTTEXTTEXT音频 URL
4primary_cefr_levelTEXTTEXTTEXT'A1'..'C2' / NULL
5cefr_inferred 🆕v48INTEGER NOT NULL DEFAULT 0BOOLEAN NOT NULL DEFAULT falseINTEGER NOT NULL DEFAULT 0推断 vs 权威
6cefr_source 🆕v49TEXTTEXTTEXT'oxford'/'cefr_j'/'llm'/'freq'/'fallback'/NULL
7word_tags 🆕v50TEXTTEXTTEXTJSON array 字符串
8pos_definitionsTEXT (JSON 字符串)JSONBTEXT (JSON 字符串)多词性结构化数据
9frequency_rankINTEGERINTEGERINTEGER词频排名
10sourceTEXT NOT NULL DEFAULT 'preinstalled'TEXT NOT NULL DEFAULT 'preinstalled'TEXT NOT NULL DEFAULT 'preinstalled''preinstalled'/'backfilled'/'fallback'
11last_accessed_atTEXT (ISO8601)TIMESTAMPTZTEXT (ISO8601)LRU 时间戳
12etymologyTEXTTEXTTEXT词源描述
13word_formsTEXT (JSON 字符串)TEXTTEXT (JSON 字符串)词形变化
14audio_local_pathTEXTTEXTTEXT本地音频路径(跨端无业务意义,但保持 schema 一致)
15word_familyTEXT (JSON 字符串)TEXTTEXT (JSON 字符串)词族数组(Phase 5 填充)
16created_atTEXT NOT NULL (ISO8601)TIMESTAMPTZ NOT NULL DEFAULT NOW()TEXT NOT NULL (ISO8601)创建时间
17updated_atTEXT NOT NULL (ISO8601)TIMESTAMPTZ NOT NULL DEFAULT NOW()TEXT NOT NULL (ISO8601)更新时间

预装库专属列(红线 #10)— 仅 RVH/RB SQLite,不进 Supabase

以下列由 RVH pipeline 单点产出进预装库 reading_vocab.db,RB byte-equal 只读消费, 不在上方 Supabase 同步矩阵(vocabulary 表跨端策略:Supabase 仅当共享缓存,这些是预装内禀数据):

列名RVH SQLiteRB SQLiteSupabase备注
emoji 🆕v53TEXTTEXT❌ 无具象名词 OpenMoji hexcode / NULL
canonical_surface 🆕v54TEXTTEXT❌ 无习语可读引用形(归一键 word 的展示形)/ NULL=普通词。匹配只走 word,本列纯展示

类型差异(DB 系统能力差异,非 schema 不一致)

PostgreSQL 比 SQLite 类型更丰富,差异由 SDK / 应用层自动处理:

Supabase 类型RVH/RB SQLite 等价转换方
BOOLEANINTEGER (0/1)supabase-flutter 自动转 bool;写时接受 1/0 或 true/false
JSONBTEXT (JSON 字符串)SDK 自动转 Map/List;写时接受 JSON 字符串或 Object
TIMESTAMPTZTEXT (ISO8601)应用层处理 .toIso8601String()DateTime.parse()

RVH 端代码已防御类型差异supabase_vocabulary_service.dart):

dart
// 读 cefr_inferred — 同时处理 PostgreSQL BOOLEAN (转 num) 和 SQLite INT
cefrInferred: ((data['cefr_inferred'] as num?)?.toInt() ?? 0) == 1

FK 关系跨端对照(v51 起 RESTRICT 化)

FK 关系RVH 端Supabase 端RB 端ON DELETE
notebook_entries.word → vocabulary.word✓ (user_notebook_entries)RESTRICT 🔧v51 (原 CASCADE)
excluded_words.word → vocabulary.word❌ v43 已删✓ (user_excluded_words)TBDRESTRICT 🔧v51 (Supabase 端)

保留 CASCADE 的关系(业务合理):

  • reading_sources.note_id → reading_notes.id
  • word_sources.notebook_entry_id → notebook_entries.id
  • word_sources.reading_source_id → reading_sources.id

详见 schema.md v51 变更摘要

跨端 sync 不同步的字段

虽然 schema 含这些字段,但 sync 流程显式 NULL 化(避免一端的本地状态污染另一端):

字段说明
audio_local_pathRVH 本地音频路径,跨端无意义
last_accessed_atLRU 仅本地行为,跨端无意义

详见 plan Track B 实施约束

改动 vocabulary schema 的强制流程

加 / 删 / 改任何 vocabulary 列时必须三端同步改动

  1. RVH 端(本仓库):

    • assets/sql/01_create_tables.sql
    • lib/shared/data/database/app_database.dart::_schemaVersion
    • assets/sql/0[123]_*.sql 文件头版本号
    • docs/database/schema.md 顶部版本 + 加变更摘要
    • 改本文件「v51」处对照表
    • lib/features/vocabulary_filtering/data/models/vocabulary_item_model.dart(Freezed)+ vocabulary_entity.dart(Equatable + copyWith + props)
    • lib/features/vocabulary/data/services/supabase_vocabulary_service.dart(PostgREST 读取)
    • tools/vocabulary_builder_v3/lib/models/vocabulary_entry.dart + pipeline 各 step 的 JSON 读写
    • tools/vocabulary_builder_v3/lib/db_generator.dart CREATE TABLE + INSERT
    • dart run build_runner build --delete-conflicting-outputs
  2. Supabase 端(后端真相源 = RB,2026-06-15 起):

    • 共享表 DDL 改 RB ~/reading-browser/supabase/sql/sync-tables.sql + Supabase Dashboard 执行(RVH 不再写共享表 migration;原 supabase/migrations/ 死历史目录 2026-08-28 已删,见 git 历史)
    • Edge Function(含 lookup-or-fetch-word)源码在 RB ~/reading-browser/supabase/functions/,如需用新字段在 RB 改 + 从 RB 部署
  3. RB 端~/reading-browser/,外部仓库):

    • 改 RB 的 SQLite schema(Rust src-tauri/src/db/migrations/
    • 改 RB 的 vocabulary 数据模型
    • 改 RB 的 sync push/pull
    • 三端同周发版(RVH + RB + Supabase migration)

历史变更追溯

版本变更RVH commitSupabase migration
v34 (2026-03)vocabulary 瘦身(删 9 字段)+ pos_definitions 引入-20260321_v34_slim_vocabulary_items.sql
v43 (2026-04)word 升 PK + 跨端 UUID 漂移消除4a8f...20260426_v43_word_pk_rebuild.sql
v47 (2026-05)reading_notes 封面字节直传(红线 #6c)dfff432-
v48 (2026-05)加 cefr_inferred 列bbedeab(合并入 v51)
v49 (2026-05)加 cefr_source 列bbedeab(合并入 v51)
v50 (2026-05)加 word_tags 列3722fab(合并入 v51)
v51 (2026-05-13)Supabase 重建 + FK CASCADE→RESTRICT + Edge Function 升级8a471a620260513_v51_vocabulary_rebuild_fk_restrict.sql
2026-05-21 修订DROP user_notebook_entries_word_fkey + user_excluded_words_word_fkey(缓冲池模型下 Supabase 两条 word FK 无业务价值;RB 端 push 撞 23503 触发)(本批 commit)20260521_drop_user_word_fkeys.sql