Replace the JSON-blob columns (feeds.articles, rules.affected_feeds)
with proper relational tables:
- articles(feed,key,…,is_read,grabbed) with UNIQUE(feed,key) and indexes,
so dedup and grabbed become INSERT OR IGNORE / WHERE-key queries and a
poll inserts only new rows instead of rewriting the whole feed blob.
- rule_feeds(rule,feed) join table for a rule's feed scope.
The webui RSS engine now operates on rows via a row-level store API
(feed/article/rule/indexer upsert/list/etc.) instead of holding the
feeds/rules/indexers in memory and saving whole lists; the in-memory
copies and rss_save/rss_load are gone. The poller, the auto-download
rules, force-run, manual download, refresh and search all read/write the
DB directly. A one-time migration upgrades an existing webui.db in place
(moving the old JSON blobs into the new tables, preserving article
read/grabbed flags and rule scoping, then dropping the legacy columns).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>