本页是核心表的字段级速查字典,只展开日常最常用的表,不复制完整 CREATE TABLE。库与进程的归属、库间引用关系、为什么不能跨库 JOIN,先看数据库结构;业务语义看领域模型与数据归属 可执行的 DDL 事实来源始终是各库自己的 schema SQL:
  • rakull_server/data_server/app/db/schema.sql(PostgreSQL 库 rakull_data,58 张表)
  • rakull_server/data_server/app/db/collection_schema.sql(PostgreSQL 库 rakull_collection,2 张表)
  • rakull_server/user_manager/app/db/schema.sql(SQLite 库 local_auth.db,5 张表)

类型约定

rakull_data / rakull_collection(PostgreSQL)下表不逐条重复的通用约定:
  • 自增主键统一为 BIGINT GENERATED ALWAYS AS IDENTITY;ID 外键列也是 BIGINT
  • 时间戳存为 UTC 的 TEXTDEFAULT now_compact() 复刻旧 SQLite 的 datetime('now')YYYY-MM-DD HH:MM:SS),高精度时间用 DEFAULT now_iso_ms()
  • JSON 仍存 TEXT 列(没有 jsonb 列);0/1 布尔用 SMALLINT;浮点用 DOUBLE PRECISION;媒体字节用 BYTEA
  • schema 里还有 12 个从旧 SQLite 触发器移植的用户触发器(plpgsql)。
local_auth.db(SQLite)按 SQLite 的动态类型与亲和性标注;连接由 app/local_auth/db.py 统一执行 PRAGMA journal_mode=WALPRAGMA foreign_keys=ON

rakull_data 核心 6 表

articles

字段PostgreSQL 类型默认值与约束
idBIGINT GENERATED ALWAYS AS IDENTITY主键,自增
user_idBIGINTNOT NULL;逻辑指向 user_manager.users.id
titleTEXTNOT NULL DEFAULT ''
authorTEXTNOT NULL DEFAULT ''
introTEXTNOT NULL DEFAULT ''
summaryTEXTNOT NULL DEFAULT ''
raw_contentTEXTNOT NULL DEFAULT ''
genreTEXTNOT NULL DEFAULT 'article';仅 articleinterviewsong
output_languageTEXTNOT NULL DEFAULT 'zh';应用约定 zhenzh-Hant,数据库未设 CHECK
explanation_levelTEXTNOT NULL DEFAULT 'N3';CHECK 限制为 N1N2N3N4N5es_lowes_highjhhs
primary_binding_idTEXTNOT NULL DEFAULT '';兼容/诊断用的精确 ModelBinding UUID;新文章客户端留空
primary_modelTEXTNOT NULL DEFAULT '';文章选择的去重模型名;留空表示使用有效默认模型
fallback_modelTEXTNOT NULL DEFAULT ''
statusTEXTNOT NULL DEFAULT 'completed';仅 completedpartially_completedprocessingfailedcancelled
progressINTEGERNOT NULL DEFAULT 100;CHECK 范围 0–100
metadataTEXTNOT NULL DEFAULT '{}';JSON 文本
is_publicSMALLINTNOT NULL DEFAULT 0;CHECK 仅 0/1
guest_visibleSMALLINTNOT NULL DEFAULT 0;CHECK 仅 0/1
created_atTEXTNOT NULL DEFAULT now_compact()(UTC 文本)
命名索引:idx_articles_user(user_id)idx_articles_genre(genre)idx_articles_visibility(is_public, guest_visible)

weekly_recommendations

字段PostgreSQL 类型默认值与约束
article_idBIGINT主键;物理外键 → articles.id ON DELETE CASCADE
sort_orderINTEGERNOT NULL DEFAULT 0
created_atTEXTNOT NULL DEFAULT now_compact()(UTC 文本)
命名索引:idx_weekly_recs_order(sort_order)。一篇文章最多出现一次;列表按 sort_order,再按 created_at 读取。

article_favorites

字段PostgreSQL 类型默认值与约束
user_idBIGINT联合主键;逻辑指向 user_manager.users.id
article_idBIGINT联合主键;物理外键 → articles.id ON DELETE CASCADE
created_atTEXTNOT NULL DEFAULT now_iso_ms();UTC 高精度时间文本
命名索引:idx_article_favorites_user_created(user_id, created_at DESC, article_id DESC)。收藏写入和删除均幂等,列表按最新收藏优先并重新套用文章可见性。

media_objects

字段PostgreSQL 类型默认值与约束
idBIGINT GENERATED ALWAYS AS IDENTITY主键,自增
kindTEXTNOT NULL;仅 sentence_audioscenario_audioupload_audioupload_videoupload_image
content_typeTEXTNOT NULL DEFAULT 'application/octet-stream'
byte_sizeINTEGERNOT NULL DEFAULT 0
dataBYTEA可空;OBJECT_STORE=local 时句子/情景音频字节内联于此,cos 时为 NULL
storage_keyTEXT可空;OBJECT_STORE=cos 时指向腾讯云 COS 对象 key,local 时为 NULL
cache_hashTEXT可空;内容寻址缓存哈希(文本 + 声优 + 内容类型)
created_atTEXTNOT NULL DEFAULT now_compact()(UTC 文本)
除主键外有一个部分索引:idx_media_objects_cache_hash(cache_hash) WHERE cache_hash IS NOT NULL。数据库没有强制 datastorage_key 至少一个非空。这张表是关系库与对象存储的交汇点,两种字节落点(local 内联 BYTEA / cos 只存 key)的组合关系见数据库结构的「关系库与对象存储如何配合」一节。

sentences

字段PostgreSQL 类型默认值与约束
idBIGINT GENERATED ALWAYS AS IDENTITY主键,自增
article_idBIGINTNOT NULL;物理外键 → articles.id ON DELETE CASCADE
sentence_indexINTEGERNOT NULL;与 article_id 联合唯一
sentenceTEXTNOT NULL DEFAULT ''
full_promptTEXTNOT NULL DEFAULT '[]';JSON 数组文本
translationTEXTNOT NULL DEFAULT ''
explanationTEXTNOT NULL DEFAULT ''
furiganaTEXTNOT NULL DEFAULT '[]';JSON 数组文本
analysis_statusTEXTNOT NULL DEFAULT 'pending';仅 pendingsuccessfailedskip
explain_statusTEXT可空;非空时仅 explainingexplainedfailed
audio_object_idBIGINT可空;物理外键 → media_objects.id ON DELETE SET NULL
audio_voiceTEXTNOT NULL DEFAULT ''
tts_errorTEXTNOT NULL DEFAULT '';最近一次经过清理和截断的 TTS 错误
noteTEXTNOT NULL DEFAULT ''
metadataTEXTNOT NULL DEFAULT '{}';JSON 文本
created_atTEXTNOT NULL DEFAULT now_compact()(UTC 文本)
约束与索引:UNIQUE(article_id, sentence_index);命名索引 idx_sentences_article(article_id)

feedback

字段PostgreSQL 类型默认值与约束
idBIGINT GENERATED ALWAYS AS IDENTITY主键,自增
user_idBIGINT可空;逻辑指向 user_manager.users.id,空值允许匿名
article_idBIGINT可空;同库上下文 ID,但没有物理外键
sentence_indexINTEGER可空;与 article_id 一起标识可选句子上下文,没有物理约束
categoryTEXTNOT NULL DEFAULT 'other';仅 bugsuggestioncontentotherpublish_request
messageTEXTNOT NULL
created_atTEXTNOT NULL DEFAULT now_compact()(UTC 文本)
除主键外没有索引。publish_request 是“申请公开”复用的反馈类别,不是单独的表。

local_auth.db(SQLite)5 表

users

字段SQLite 类型默认值与约束
idINTEGER主键,自增
usernameTEXTNOT NULL UNIQUE
password_hashTEXTNOT NULL
roleTEXTNOT NULL DEFAULT 'user';仅 userroot
created_atTEXTNOT NULL DEFAULT datetime('now')
last_donation_atTEXT可空;最近一次未被驳回的赞助时间
last_donation_amountREALNOT NULL DEFAULT 0;单位是 last_donation_currency,不是 CNY
last_donation_currencyTEXTNOT NULL DEFAULT ''
last_donation_methodTEXTNOT NULL DEFAULT ''wechatkofibmcother
donation_total_cnyREALNOT NULL DEFAULT 0;累计金额,按静态汇率折算为 CNY
donation_countINTEGERNOT NULL DEFAULT 0
donation_prompt_muted_untilTEXT可空;在此时间之前客户端隐藏「赞助」入口
username 的 UNIQUE 约束会创建 SQLite 自动索引。 后 7 个字段是 donations汇总缓存app/donations/service.pyrefresh_rollup() 每次写入都从 donations 重新计算(而不是累加),因此不会与明细不一致。驳回某条赞助会连带清掉静默期。

invite_codes

字段SQLite 类型默认值与约束
idINTEGER主键,自增
codeTEXTNOT NULL UNIQUE
is_activeINTEGERNOT NULL DEFAULT 1;仅 0/1
created_byINTEGER可空;物理外键 → users.id ON DELETE SET NULL
created_atTEXTNOT NULL DEFAULT datetime('now')
code 的 UNIQUE 约束会创建 SQLite 自动索引。

registration_requests

字段SQLite 类型默认值与约束
idINTEGER主键,自增
usernameTEXTNOT NULL
password_hashTEXTNOT NULL
invite_codeTEXTNOT NULL;保存提交值,没有物理外键
remarksTEXTNOT NULL DEFAULT ''
statusTEXTNOT NULL DEFAULT 'pending';仅 pendingapprovedrejected
reviewed_byINTEGER可空;物理外键 → users.id ON DELETE SET NULL
reviewed_atTEXT可空
created_atTEXTNOT NULL DEFAULT datetime('now')
命名索引:idx_regreq_status(status)。用户名是否已有待审核申请由应用查询检查,不是 UNIQUE 约束。

usage_events

字段SQLite 类型默认值与约束
idINTEGER主键,自增
user_idINTEGERNOT NULL;物理外键 → users.id ON DELETE CASCADE
kindTEXTNOT NULL
ref_idTEXT可空
occurred_atTEXTNOT NULL DEFAULT datetime('now')
命名索引:idx_usage_user_time(user_id, occurred_at)

donations

字段SQLite 类型默认值与约束
idINTEGER主键,自增
user_idINTEGERNOT NULL;物理外键 → users.id ON DELETE CASCADE
methodTEXTNOT NULL;仅 wechatkofibmcother
amountREALNOT NULL CHECK (amount > 0);单位是 currency
currencyTEXTNOT NULL DEFAULT 'CNY'
amount_cnyREALNOT NULL DEFAULT 0;按 DONATION_FX_TO_CNY 折算,写入时算好
statusTEXTNOT NULL DEFAULT 'pending';仅 pendingconfirmedrejected
is_anonymousINTEGERNOT NULL DEFAULT 0;仅 0/1;为 1 时不进致谢名单
noteTEXTNOT NULL DEFAULT ''
reviewed_byINTEGER可空;物理外键 → users.id ON DELETE SET NULL
reviewed_atTEXT可空
donated_atTEXTNOT NULL DEFAULT datetime('now')
命名索引:idx_donations_user_time(user_id, donated_at)idx_donations_status(status) 支付发生在 RakuLL 之外,目前拿不到可信的支付结果,因此每条记录都是用户自行登记的,初始为 pendingrejected 的行不计入任何汇总,也不出现在致谢名单里。status 是为将来自动核验留的钩子(Ko-fi 服务端有 webhook,微信需要商户号),细节见赞助bmc(Buy Me a Coffee)已在 CHECK 里放开,以后启用不需要迁移。

rakull_collection(PostgreSQL)2 表

collections

字段PostgreSQL 类型默认值与约束
idBIGINT GENERATED ALWAYS AS IDENTITY主键,自增
user_idBIGINTNOT NULL;逻辑指向 user_manager.users.id
nameTEXTNOT NULL
descriptionTEXTNOT NULL DEFAULT ''
created_atTEXTNOT NULL DEFAULT now_compact()(UTC 文本)
命名索引:idx_collections_user(user_id)

collection_items

字段PostgreSQL 类型默认值与约束
idBIGINT GENERATED ALWAYS AS IDENTITY主键,自增
collection_idBIGINTNOT NULL;同库物理外键 → collections.id ON DELETE CASCADE
article_idBIGINTNOT NULL;逻辑指向 rakull_data.articles.id(跨库,无 FK)
sentence_indexINTEGERNOT NULL;与 article_id 一起逻辑指向一条句子
frontTEXTNOT NULL DEFAULT '';收藏时快照
backTEXTNOT NULL DEFAULT '';收藏时快照
noteTEXTNOT NULL DEFAULT ''
grammarTEXTNOT NULL DEFAULT '';分组与排序标签
due_atTEXTNOT NULL DEFAULT '';SM-2 到期时刻;空串表示新卡,立即到期
last_reviewed_atTEXTNOT NULL DEFAULT ''
interval_minutesINTEGERNOT NULL DEFAULT 0;0 表示仍在学习步阶
easeDOUBLE PRECISIONNOT NULL DEFAULT 2.5;SM-2 难度系数,范围 1.3–3.0 由应用保证
repsINTEGERNOT NULL DEFAULT 0
lapsesINTEGERNOT NULL DEFAULT 0
card_versionINTEGERNOT NULL DEFAULT 0;乐观锁版本,提交复习时版本不符返回 409
created_atTEXTNOT NULL DEFAULT now_compact()(UTC 文本)
约束与索引:UNIQUE(collection_id, article_id, sentence_index);命名索引 idx_collitems_collection(collection_id)idx_collitems_grammar(collection_id, grammar)idx_collitems_due(due_at)。三个索引与全部 SM-2 列都直接建在 collection_schema.sql 中,bootstrap 时随表一起幂等创建。