Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 84 additions & 84 deletions crates/apotheke/migrations/001_initial.sql

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions crates/apotheke/migrations/002_play_history.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- Play sessions: one row per contiguous playback of a media item.
-- A "session" starts when playback begins and ends when the user stops,
-- skips, or the track/episode/chapter finishes.
CREATE TABLE play_sessions (
CREATE TABLE IF NOT EXISTS play_sessions (
id BLOB NOT NULL PRIMARY KEY, -- SessionId (UUIDv7)
media_id BLOB NOT NULL, -- FK to media_registry
user_id BLOB NOT NULL REFERENCES users(id),
Expand All @@ -24,7 +24,7 @@ CREATE TABLE play_sessions (
device_name TEXT, -- which output device
quality_score INTEGER, -- quality at time of play
dsp_active INTEGER NOT NULL DEFAULT 0 -- was DSP chain active?
);
) STRICT;

CREATE INDEX idx_ps_user_time ON play_sessions(user_id, started_at DESC);
CREATE INDEX idx_ps_media ON play_sessions(media_id, started_at DESC);
Expand All @@ -34,19 +34,19 @@ CREATE INDEX idx_ps_media_type ON play_sessions(user_id, media_type, started_at

-- Daily aggregates: pre-computed for fast analytics queries.
-- Updated by a background task after each session ends.
CREATE TABLE play_stats_daily (
CREATE TABLE IF NOT EXISTS play_stats_daily (
user_id BLOB NOT NULL REFERENCES users(id),
date TEXT NOT NULL, -- YYYY-MM-DD
media_type TEXT NOT NULL,
sessions INTEGER NOT NULL DEFAULT 0,
total_ms INTEGER NOT NULL DEFAULT 0,
unique_items INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (user_id, date, media_type)
);
) STRICT;

-- Per-item lifetime stats: total plays, total time, first/last played.
-- Updated incrementally when sessions complete.
CREATE TABLE play_stats_item (
CREATE TABLE IF NOT EXISTS play_stats_item (
media_id BLOB NOT NULL,
user_id BLOB NOT NULL REFERENCES users(id),
play_count INTEGER NOT NULL DEFAULT 0,
Expand All @@ -55,17 +55,17 @@ CREATE TABLE play_stats_item (
first_played_at TEXT,
last_played_at TEXT,
PRIMARY KEY (media_id, user_id)
);
) STRICT;

CREATE INDEX idx_psi_user_plays ON play_stats_item(user_id, play_count DESC);
CREATE INDEX idx_psi_user_recent ON play_stats_item(user_id, last_played_at DESC);

-- Streak tracking: consecutive days with listening activity.
CREATE TABLE play_streaks (
CREATE TABLE IF NOT EXISTS play_streaks (
user_id BLOB NOT NULL REFERENCES users(id),
streak_start TEXT NOT NULL, -- YYYY-MM-DD
streak_end TEXT NOT NULL, -- YYYY-MM-DD
days INTEGER NOT NULL,
is_current INTEGER NOT NULL DEFAULT 1,
PRIMARY KEY (user_id, streak_start)
);
) STRICT;
20 changes: 10 additions & 10 deletions crates/apotheke/migrations/003_subsonic.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,50 @@
-- Per-user plaintext password for Subsonic legacy token auth.
-- Subsonic legacy auth is MD5-based and incompatible with Argon2id storage.
-- Users who want legacy Subsonic client support set this separately.
CREATE TABLE subsonic_passwords (
CREATE TABLE IF NOT EXISTS subsonic_passwords (
user_id BLOB NOT NULL PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
password TEXT NOT NULL
);
) STRICT;

-- Playlists
CREATE TABLE subsonic_playlists (
CREATE TABLE IF NOT EXISTS subsonic_playlists (
id BLOB NOT NULL PRIMARY KEY,
owner_id BLOB NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
comment TEXT,
public INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
);
) STRICT;

CREATE INDEX idx_sp_owner ON subsonic_playlists(owner_id);

CREATE TABLE subsonic_playlist_tracks (
CREATE TABLE IF NOT EXISTS subsonic_playlist_tracks (
playlist_id BLOB NOT NULL REFERENCES subsonic_playlists(id) ON DELETE CASCADE,
track_id BLOB NOT NULL REFERENCES music_tracks(id) ON DELETE CASCADE,
position INTEGER NOT NULL,
PRIMARY KEY (playlist_id, position)
);
) STRICT;

CREATE INDEX idx_spt_playlist ON subsonic_playlist_tracks(playlist_id);

-- Stars (track, album/release-group, artist/registry)
CREATE TABLE subsonic_stars (
CREATE TABLE IF NOT EXISTS subsonic_stars (
user_id BLOB NOT NULL REFERENCES users(id) ON DELETE CASCADE,
item_id BLOB NOT NULL,
item_type TEXT NOT NULL CHECK(item_type IN ('track', 'album', 'artist')),
starred_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
PRIMARY KEY (user_id, item_id)
);
) STRICT;

CREATE INDEX idx_ss_user ON subsonic_stars(user_id);

-- Ratings (1-5)
CREATE TABLE subsonic_ratings (
CREATE TABLE IF NOT EXISTS subsonic_ratings (
user_id BLOB NOT NULL REFERENCES users(id) ON DELETE CASCADE,
item_id BLOB NOT NULL,
rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5),
PRIMARY KEY (user_id, item_id)
);
) STRICT;

CREATE INDEX idx_sr_user ON subsonic_ratings(user_id);
8 changes: 4 additions & 4 deletions crates/apotheke/migrations/004_indexers.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- Indexer registry tables for Zetesis
-- Stores configured indexer endpoints and their cached capabilities.

CREATE TABLE indexers (
CREATE TABLE IF NOT EXISTS indexers (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
url TEXT NOT NULL,
Expand All @@ -15,14 +15,14 @@ CREATE TABLE indexers (
caps_json TEXT,
priority INTEGER NOT NULL DEFAULT 50,
added_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
);
) STRICT;

CREATE TABLE indexer_categories (
CREATE TABLE IF NOT EXISTS indexer_categories (
indexer_id INTEGER NOT NULL REFERENCES indexers(id) ON DELETE CASCADE,
category_id INTEGER NOT NULL,
name TEXT NOT NULL,
PRIMARY KEY (indexer_id, category_id)
);
) STRICT;

CREATE INDEX idx_indexers_enabled_status ON indexers(enabled, status);
CREATE INDEX idx_indexer_categories_indexer ON indexer_categories(indexer_id);
4 changes: 2 additions & 2 deletions crates/apotheke/migrations/005_requests.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- Aitesis request management tables
-- Tracks household media requests from submission through fulfillment.

CREATE TABLE requests (
CREATE TABLE IF NOT EXISTS requests (
id BLOB NOT NULL PRIMARY KEY,
user_id BLOB NOT NULL,
media_type TEXT NOT NULL,
Expand All @@ -14,7 +14,7 @@ CREATE TABLE requests (
deny_reason TEXT,
want_id BLOB,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
);
) STRICT;

CREATE INDEX idx_requests_user_status ON requests(user_id, status);
CREATE INDEX idx_requests_status ON requests(status);
4 changes: 2 additions & 2 deletions crates/apotheke/migrations/006_download_queue.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- Download queue persistence for Syntaxis.
-- Tracks all queued, active, and terminal download states for restart recovery.

CREATE TABLE download_queue (
CREATE TABLE IF NOT EXISTS download_queue (
id BLOB NOT NULL PRIMARY KEY,
want_id BLOB NOT NULL,
release_id BLOB NOT NULL,
Expand All @@ -18,6 +18,6 @@ CREATE TABLE download_queue (
completed_at TEXT,
failed_reason TEXT,
retry_count INTEGER NOT NULL DEFAULT 0
);
) STRICT;

CREATE INDEX idx_download_queue_status_priority ON download_queue(status, priority DESC);
4 changes: 2 additions & 2 deletions crates/apotheke/migrations/007_subtitles.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- Prostheke subtitle track storage.
-- Tracks acquired subtitle files per media item, one row per language/forced combination.

CREATE TABLE subtitles (
CREATE TABLE IF NOT EXISTS subtitles (
id BLOB NOT NULL PRIMARY KEY,
media_id BLOB NOT NULL,
language TEXT NOT NULL,
Expand All @@ -13,7 +13,7 @@ CREATE TABLE subtitles (
forced BOOLEAN NOT NULL DEFAULT FALSE,
score REAL NOT NULL,
acquired_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
);
) STRICT;

CREATE INDEX idx_subtitles_media ON subtitles(media_id);
CREATE UNIQUE INDEX idx_subtitles_media_lang ON subtitles(media_id, language, forced);
4 changes: 2 additions & 2 deletions crates/apotheke/migrations/008_renderers.sql
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
-- Renderer registry: tracks paired playback renderers.
CREATE TABLE renderers (
CREATE TABLE IF NOT EXISTS renderers (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
api_key_hash TEXT NOT NULL,
cert_fingerprint TEXT NOT NULL,
last_seen TEXT,
paired_at TEXT NOT NULL,
enabled INTEGER NOT NULL DEFAULT 1
);
) STRICT;

CREATE INDEX idx_renderers_enabled ON renderers (enabled);
8 changes: 4 additions & 4 deletions crates/apotheke/migrations/009_zones.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
ALTER TABLE renderers ADD COLUMN address TEXT NOT NULL DEFAULT '';
ALTER TABLE renderers ADD COLUMN created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'));

CREATE TABLE zones (
CREATE TABLE IF NOT EXISTS zones (
id TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
);
) STRICT;

CREATE TABLE zone_members (
CREATE TABLE IF NOT EXISTS zone_members (
zone_id TEXT NOT NULL REFERENCES zones(id) ON DELETE CASCADE,
renderer_id TEXT NOT NULL REFERENCES renderers(id) ON DELETE CASCADE,
joined_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
PRIMARY KEY (zone_id, renderer_id)
);
) STRICT;

CREATE INDEX idx_zone_members_renderer ON zone_members(renderer_id);