docs/old-database-schema.md
Rama main · réplica de lectura del repositorio original.
# Legacy Database Schema (Preserved)
> This document preserves the legacy schema snapshot for migration development and validation. SQL DDL is the single source of truth for table/column definitions.
## Full DDL (Authoritative)
```sql
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`);
```
## Business Logic Notes
### 1) Entity relationships
- `groups -> feeds -> items` is a two-level one-to-many chain.
- `feeds.group_id` links each feed to a group.
- `items.feed_id` links each item to a feed.
- Legacy schema declares foreign keys (`fk_feeds_group`, `fk_items_feed`).
### 2) Soft-delete model
- 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.
### 3) Deduplication and uniqueness semantics
- 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 != NULL` in unique indexes, so multiple rows with `guid=NULL` are allowed (must be preserved in migrations).
### 4) Feed pull status fields (`feeds`)
- `last_build`: last content update time.
- `failure` + `consecutive_failures`: latest error and failure streak.
- `suspended`: pull disabled flag.
- `req_proxy`: per-feed proxy setting.
### 5) Reading state fields (`items`)
- `unread`: unread flag (default `true`).
- `bookmark`: bookmark flag (default `false`).
- Both are indexed for high-frequency filtering.
### 6) Application-level semantics
- App bootstrap ensures default group exists: `id=1`, `name="Default"`.
- `unread_count` is a virtual field in app models and is not persisted.
## Legacy Migration History
### After `v0.8.7`
- Added unique constraint for feed links via `idx_link`.
- Migration removed duplicate feeds and kept the row with the smallest `id`.