-- Channels: user-defined broadcast channels with their schedule template CREATE TABLE IF NOT EXISTS channels ( id TEXT PRIMARY KEY NOT NULL, owner_id TEXT NOT NULL, name TEXT NOT NULL, description TEXT, timezone TEXT NOT NULL DEFAULT 'UTC', -- JSON-encoded ScheduleConfig (the shareable/exportable template) schedule_config TEXT NOT NULL DEFAULT '{"blocks":[]}', -- JSON-encoded RecyclePolicy recycle_policy TEXT NOT NULL DEFAULT '{"cooldown_days":30,"cooldown_generations":null,"min_available_ratio":0.2}', created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_channels_owner ON channels(owner_id); -- Generated 48-hour schedules (resolved from a channel's template) CREATE TABLE IF NOT EXISTS generated_schedules ( id TEXT PRIMARY KEY NOT NULL, channel_id TEXT NOT NULL, valid_from TEXT NOT NULL, valid_until TEXT NOT NULL, generation INTEGER NOT NULL, FOREIGN KEY (channel_id) REFERENCES channels(id) ON DELETE CASCADE ); -- Composite index supports both "find active at time T" and "find latest" CREATE INDEX IF NOT EXISTS idx_schedules_channel_valid ON generated_schedules(channel_id, valid_from DESC); -- Individual scheduled slots within a generated schedule. -- The MediaItem snapshot is stored as JSON so the EPG survives library changes. CREATE TABLE IF NOT EXISTS scheduled_slots ( id TEXT PRIMARY KEY NOT NULL, schedule_id TEXT NOT NULL, start_at TEXT NOT NULL, end_at TEXT NOT NULL, -- JSON-encoded MediaItem (metadata snapshot at generation time) item TEXT NOT NULL, source_block_id TEXT NOT NULL, FOREIGN KEY (schedule_id) REFERENCES generated_schedules(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_slots_schedule_start ON scheduled_slots(schedule_id, start_at); -- Playback history for the recycle policy engine CREATE TABLE IF NOT EXISTS playback_records ( id TEXT PRIMARY KEY NOT NULL, channel_id TEXT NOT NULL, item_id TEXT NOT NULL, played_at TEXT NOT NULL, generation INTEGER NOT NULL, FOREIGN KEY (channel_id) REFERENCES channels(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_playback_channel_date ON playback_records(channel_id, played_at DESC);