-- Viewer accounts, device linking, watch progress, shelf prefs CREATE TYPE "WatchMediaType" AS ENUM ('MOVIE', 'EPISODE'); CREATE TABLE IF NOT EXISTS "viewer_users" ( "id" TEXT NOT NULL, "email" TEXT NOT NULL, "password_hash" TEXT NOT NULL, "name" TEXT, "enabled" BOOLEAN NOT NULL DEFAULT true, "app_access" BOOLEAN NOT NULL DEFAULT true, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "viewer_users_pkey" PRIMARY KEY ("id") ); CREATE UNIQUE INDEX IF NOT EXISTS "viewer_users_email_key" ON "viewer_users"("email"); CREATE TABLE IF NOT EXISTS "viewer_devices" ( "id" TEXT NOT NULL, "viewer_user_id" TEXT NOT NULL, "name" TEXT NOT NULL, "platform" TEXT NOT NULL DEFAULT 'android_tv', "refresh_token_hash" TEXT NOT NULL, "last_seen_at" TIMESTAMP(3), "revoked" BOOLEAN NOT NULL DEFAULT false, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "viewer_devices_pkey" PRIMARY KEY ("id") ); CREATE UNIQUE INDEX IF NOT EXISTS "viewer_devices_refresh_token_hash_key" ON "viewer_devices"("refresh_token_hash"); CREATE INDEX IF NOT EXISTS "viewer_devices_viewer_user_id_idx" ON "viewer_devices"("viewer_user_id"); CREATE TABLE IF NOT EXISTS "device_link_codes" ( "id" TEXT NOT NULL, "code_hash" TEXT NOT NULL, "code_display" TEXT, "device_name" TEXT NOT NULL, "platform" TEXT NOT NULL DEFAULT 'android_tv', "expires_at" TIMESTAMP(3) NOT NULL, "consumed_at" TIMESTAMP(3), "viewer_user_id" TEXT, "claim_token_hash" TEXT, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "device_link_codes_pkey" PRIMARY KEY ("id") ); CREATE UNIQUE INDEX IF NOT EXISTS "device_link_codes_code_hash_key" ON "device_link_codes"("code_hash"); CREATE UNIQUE INDEX IF NOT EXISTS "device_link_codes_claim_token_hash_key" ON "device_link_codes"("claim_token_hash"); CREATE INDEX IF NOT EXISTS "device_link_codes_expires_at_idx" ON "device_link_codes"("expires_at"); CREATE TABLE IF NOT EXISTS "watch_progress" ( "id" TEXT NOT NULL, "viewer_user_id" TEXT NOT NULL, "media_type" "WatchMediaType" NOT NULL, "movie_id" TEXT, "episode_id" TEXT, "series_id" TEXT, "position_ms" INTEGER NOT NULL DEFAULT 0, "duration_ms" INTEGER NOT NULL DEFAULT 0, "completed" BOOLEAN NOT NULL DEFAULT false, "hidden_from_continue" BOOLEAN NOT NULL DEFAULT false, "updated_at" TIMESTAMP(3) NOT NULL, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "watch_progress_pkey" PRIMARY KEY ("id") ); CREATE UNIQUE INDEX IF NOT EXISTS "watch_progress_viewer_user_id_movie_id_key" ON "watch_progress"("viewer_user_id", "movie_id"); CREATE UNIQUE INDEX IF NOT EXISTS "watch_progress_viewer_user_id_episode_id_key" ON "watch_progress"("viewer_user_id", "episode_id"); CREATE INDEX IF NOT EXISTS "watch_progress_viewer_user_id_updated_at_idx" ON "watch_progress"("viewer_user_id", "updated_at"); CREATE INDEX IF NOT EXISTS "watch_progress_viewer_user_id_hidden_from_continue_completed_idx" ON "watch_progress"("viewer_user_id", "hidden_from_continue", "completed"); CREATE TABLE IF NOT EXISTS "viewer_shelf_preferences" ( "id" TEXT NOT NULL, "viewer_user_id" TEXT NOT NULL, "shelf_id" TEXT NOT NULL, "visible" BOOLEAN NOT NULL DEFAULT true, "sort_order" INTEGER NOT NULL DEFAULT 0, CONSTRAINT "viewer_shelf_preferences_pkey" PRIMARY KEY ("id") ); CREATE UNIQUE INDEX IF NOT EXISTS "viewer_shelf_preferences_viewer_user_id_shelf_id_key" ON "viewer_shelf_preferences"("viewer_user_id", "shelf_id"); CREATE INDEX IF NOT EXISTS "viewer_shelf_preferences_viewer_user_id_sort_order_idx" ON "viewer_shelf_preferences"("viewer_user_id", "sort_order"); DO $$ BEGIN ALTER TABLE "viewer_devices" ADD CONSTRAINT "viewer_devices_viewer_user_id_fkey" FOREIGN KEY ("viewer_user_id") REFERENCES "viewer_users"("id") ON DELETE CASCADE ON UPDATE CASCADE; EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN ALTER TABLE "device_link_codes" ADD CONSTRAINT "device_link_codes_viewer_user_id_fkey" FOREIGN KEY ("viewer_user_id") REFERENCES "viewer_users"("id") ON DELETE SET NULL ON UPDATE CASCADE; EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN ALTER TABLE "watch_progress" ADD CONSTRAINT "watch_progress_viewer_user_id_fkey" FOREIGN KEY ("viewer_user_id") REFERENCES "viewer_users"("id") ON DELETE CASCADE ON UPDATE CASCADE; EXCEPTION WHEN duplicate_object THEN null; END $$; DO $$ BEGIN ALTER TABLE "viewer_shelf_preferences" ADD CONSTRAINT "viewer_shelf_preferences_viewer_user_id_fkey" FOREIGN KEY ("viewer_user_id") REFERENCES "viewer_users"("id") ON DELETE CASCADE ON UPDATE CASCADE; EXCEPTION WHEN duplicate_object THEN null; END $$;