schema(dashboard): implement Phase 1 unified collections architecture

Add support for Carousel-style dashboard with unified collections architecture:

Database Schema Changes:
- Add user_dashboard_preferences table:
  - hidden_collections: TEXT[] for managing section visibility
  - collection_order: TEXT[] for custom ordering
  - items_per_section: INT for limiting items per section
- Update collections table:
  - user_id: Make nullable to support system-owned collections (NULL = system)
  - show_on_dashboard: BOOLEAN for controlling visibility
  - query_type: TEXT for different query types (continue-reading, recently-added, etc.)
  - priority: INT for display order (lower = higher priority)
  - is_system_collection: BOOLEAN for flagging system defaults
- Update collection_items table:
  - Add excluded BOOLEAN for user overrides of auto-assigned items

Indexes:
- idx_collections_dashboard: (user_id, show_on_dashboard, priority) WHERE show_on_dashboard = true
- idx_dashboard_prefs_user_library: (user_id, library_id)
- idx_collection_items_excluded: (collection_id, excluded) WHERE excluded = true

System Collections (pre-seeded defaults):
- continue-reading: Books with 0 < progress < 1
- recently-added: Newly added items to library
- recently-read: Books with progress >= 1
- not-started: Books with progress = 0 or no record

This implements Phase 1 of the Carousel-style dashboard redesign plan.
This commit is contained in:
2026-02-19 20:52:21 -05:00
parent ceca81f098
commit 3af2fb0ba4
3 changed files with 113 additions and 28 deletions
+39 -1
View File
@@ -847,19 +847,43 @@ CREATE INDEX IF NOT EXISTS idx_device_file_aliases_sha256 ON device_file_aliases
-- Create collections table (device-neutral collections)
CREATE TABLE IF NOT EXISTS collections (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
description TEXT,
color VARCHAR(7),
icon VARCHAR(50),
auto_assign_rules JSONB,
view_settings JSONB,
show_on_dashboard BOOLEAN DEFAULT false,
query_type TEXT DEFAULT 'filter',
priority INT DEFAULT 100,
is_system_collection BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(user_id, name)
);
CREATE INDEX IF NOT EXISTS idx_collections_user_id ON collections(user_id);
-- Index for dashboard queries
CREATE INDEX IF NOT EXISTS idx_collections_dashboard ON collections(user_id, show_on_dashboard, priority)
WHERE show_on_dashboard = true;
-- Create user_dashboard_preferences table
CREATE TABLE IF NOT EXISTS user_dashboard_preferences (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
library_id UUID REFERENCES libraries(id) ON DELETE CASCADE,
hidden_collections TEXT[] DEFAULT '{}',
collection_order TEXT[] DEFAULT '{}',
items_per_section INT DEFAULT 20,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(user_id, library_id)
);
-- Index for fast lookups
CREATE INDEX IF NOT EXISTS idx_dashboard_prefs_user_library ON user_dashboard_preferences(user_id, library_id);
-- Create collection_items table (which books belong to each collection)
CREATE TABLE IF NOT EXISTS collection_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
@@ -867,12 +891,26 @@ CREATE TABLE IF NOT EXISTS collection_items (
media_item_id UUID NOT NULL REFERENCES media_items(id) ON DELETE CASCADE,
added_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
added_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL,
excluded BOOLEAN DEFAULT false,
UNIQUE(collection_id, media_item_id)
);
CREATE INDEX IF NOT EXISTS idx_collection_items_collection ON collection_items(collection_id);
CREATE INDEX IF NOT EXISTS idx_collection_items_media ON collection_items(media_item_id);
-- Index for excluding auto-assigned items
CREATE INDEX IF NOT EXISTS idx_collection_items_excluded ON collection_items(collection_id, excluded)
WHERE excluded = true;
-- Insert 4 system collections (pre-seeded defaults)
-- These are user_id NULL to indicate system ownership
INSERT INTO collections (user_id, name, description, icon, color, show_on_dashboard, query_type, priority, is_system_collection, auto_assign_rules) VALUES
(NULL, 'continue-reading', 'Books you''re currently reading (0 < progress < 1)', '📖', '#7aa2f7', true, 'continue-reading', 1, true, 'null'),
(NULL, 'recently-added', 'Newly added items to this library', '🆕', '#9ece6a', true, 'recently-added', 2, true, 'null'),
(NULL, 'recently-read', 'Books you''ve finished (progress >= 1)', '', '#e0af68', true, 'recently-read', 3, true, 'null'),
(NULL, 'not-started', 'Books you haven''t read yet (progress = 0 or no record)', '📕', '#f7768e', true, 'not-started', 4, true, 'null')
ON CONFLICT (user_id, name) DO NOTHING;
-- Create device_shelf_mappings table (map Bookhoard collections to device-specific shelf names)
CREATE TABLE IF NOT EXISTS device_shelf_mappings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),