This document preserves the legacy schema snapshot for migration development and validation. SQL DDL is the single source of truth for table/column definitions.
CREATE TABLE `groups` (
`id` integer PRIMARY KEY AUTOINCREMENT,
`created_at` datetime,
`updated_at` datetime,
`deleted_at` integer,
`name` text NOT NULL
);
CREATE TABLE sqlite_sequence(name,seq);
CREATE UNIQUE INDEX `idx_name` ON `groups`(`deleted_at`,`name`);
CREATE TABLE `feeds` (
`id` integer PRIMARY KEY AUTOINCREMENT,
`created_at` datetime,
`updated_at` datetime,
`deleted_at` integer,
`name` text NOT NULL,
`link` text NOT NULL,
`last_build` datetime,
`failure` text DEFAULT "",
`group_id` integer,
`suspended` numeric DEFAULT false,
`req_proxy` text,
`consecutive_failures` integer DEFAULT 0,
CONSTRAINT `fk_feeds_group` FOREIGN KEY (`group_id`) REFERENCES `groups`(`id`)
);
CREATE TABLE `items` (
`id` integer PRIMARY KEY AUTOINCREMENT,
`created_at` datetime,
`updated_at` datetime,
`deleted_at` integer,
`title` text NOT NULL,
`guid` text,
`link` text,
`content` text,
`pub_date` datetime,
`unread` numeric DEFAULT true,
`feed_id` integer,
`bookmark` numeric DEFAULT false,
CONSTRAINT `fk_items_feed` FOREIGN KEY (`feed_id`) REFERENCES `feeds`(`id`)
);
CREATE INDEX `idx_items_feed_id` ON `items`(`feed_id`);
CREATE INDEX `idx_items_title` ON `items`(`title`);
CREATE INDEX `idx_items_unread` ON `items`(`unread`);
CREATE INDEX `idx_items_bookmark` ON `items`(`bookmark`);
CREATE UNIQUE INDEX `idx_guid` ON `items`(`deleted_at`,`guid`,`feed_id`);
CREATE UNIQUE INDEX `idx_link` ON `feeds`(`deleted_at`,`link`);groups -> feeds -> itemsis a two-level one-to-many chain.feeds.group_idlinks each feed to a group.items.feed_idlinks each item to a feed.- Legacy schema declares foreign keys (
fk_feeds_group,fk_items_feed).
- All business tables use
deleted_at(Unix timestamp) for logical delete. - Deletes update
deleted_at; rows are not physically removed. - Unique indexes include
deleted_at, so deleted historical rows can coexist with new active rows.
- Group name uniqueness:
idx_name(deleted_at, name). - Feed link uniqueness:
idx_link(deleted_at, link). - Item deduplication key:
idx_guid(deleted_at, guid, feed_id). - SQLite caveat:
NULL != NULLin unique indexes, so multiple rows withguid=NULLare allowed (must be preserved in migrations).
last_build: last content update time.failure+consecutive_failures: latest error and failure streak.suspended: pull disabled flag.req_proxy: per-feed proxy setting.
unread: unread flag (defaulttrue).bookmark: bookmark flag (defaultfalse).- Both are indexed for high-frequency filtering.
- App bootstrap ensures default group exists:
id=1,name="Default". unread_countis a virtual field in app models and is not persisted.
- Added unique constraint for feed links via
idx_link. - Migration removed duplicate feeds and kept the row with the smallest
id.