139 lines
5.1 KiB
SQL
139 lines
5.1 KiB
SQL
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
|
|
|
CREATE TYPE "DevicePlatform" AS ENUM ('MACOS', 'IPHONE');
|
|
CREATE TYPE "TrackStatus" AS ENUM ('ACTIVE', 'DELETED');
|
|
CREATE TYPE "UploadSessionStatus" AS ENUM ('PENDING', 'READY_TO_UPLOAD', 'COMPLETED', 'FAILED');
|
|
CREATE TYPE "EntityType" AS ENUM ('TRACK', 'AUDIO_ASSET', 'ARTWORK_ASSET');
|
|
CREATE TYPE "EventAction" AS ENUM ('CREATED', 'UPDATED', 'DELETED');
|
|
|
|
CREATE TABLE "devices" (
|
|
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
|
|
"platform" "DevicePlatform" NOT NULL,
|
|
"device_name" TEXT NOT NULL,
|
|
"app_version" TEXT NOT NULL,
|
|
"install_token_hash" TEXT NOT NULL,
|
|
"last_seen_at" TIMESTAMP(3) NOT NULL,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT "devices_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
CREATE TABLE "tracks" (
|
|
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
|
|
"primary_audio_asset_id" UUID,
|
|
"artwork_asset_id" UUID,
|
|
"title" TEXT NOT NULL,
|
|
"artist" TEXT NOT NULL,
|
|
"album" TEXT,
|
|
"album_artist" TEXT,
|
|
"genre" TEXT,
|
|
"disc_number" INTEGER,
|
|
"track_number" INTEGER,
|
|
"year" INTEGER,
|
|
"duration_ms" INTEGER,
|
|
"status" "TrackStatus" NOT NULL DEFAULT 'ACTIVE',
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"deleted_at" TIMESTAMP(3),
|
|
CONSTRAINT "tracks_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
CREATE TABLE "audio_assets" (
|
|
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
|
|
"track_id" UUID,
|
|
"sha256" TEXT NOT NULL,
|
|
"storage_key" TEXT NOT NULL,
|
|
"original_filename" TEXT NOT NULL,
|
|
"mime_type" TEXT NOT NULL,
|
|
"file_extension" TEXT NOT NULL,
|
|
"file_size_bytes" BIGINT NOT NULL,
|
|
"bit_rate_kbps" INTEGER,
|
|
"sample_rate_hz" INTEGER,
|
|
"channels" INTEGER,
|
|
"duration_ms" INTEGER,
|
|
"source_device_id" UUID,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT "audio_assets_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
CREATE TABLE "artwork_assets" (
|
|
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
|
|
"sha256" TEXT NOT NULL,
|
|
"storage_key" TEXT NOT NULL,
|
|
"mime_type" TEXT NOT NULL,
|
|
"width" INTEGER,
|
|
"height" INTEGER,
|
|
"file_size_bytes" BIGINT NOT NULL,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT "artwork_assets_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
CREATE TABLE "upload_sessions" (
|
|
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
|
|
"device_id" UUID NOT NULL,
|
|
"expected_sha256" TEXT NOT NULL,
|
|
"expected_size_bytes" BIGINT NOT NULL,
|
|
"received_bytes" BIGINT NOT NULL DEFAULT 0,
|
|
"temp_storage_path" TEXT NOT NULL,
|
|
"status" "UploadSessionStatus" NOT NULL DEFAULT 'PENDING',
|
|
"expires_at" TIMESTAMP(3) NOT NULL,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT "upload_sessions_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
CREATE TABLE "library_events" (
|
|
"id" BIGSERIAL NOT NULL,
|
|
"entity_type" "EntityType" NOT NULL,
|
|
"entity_id" UUID NOT NULL,
|
|
"action" "EventAction" NOT NULL,
|
|
"payload_version" INTEGER NOT NULL DEFAULT 1,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT "library_events_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
CREATE TABLE "device_sync_cursors" (
|
|
"device_id" UUID NOT NULL,
|
|
"last_event_id" BIGINT NOT NULL DEFAULT 0,
|
|
"last_full_sync_at" TIMESTAMP(3),
|
|
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT "device_sync_cursors_pkey" PRIMARY KEY ("device_id")
|
|
);
|
|
|
|
CREATE UNIQUE INDEX "tracks_primary_audio_asset_id_key" ON "tracks"("primary_audio_asset_id");
|
|
CREATE UNIQUE INDEX "tracks_artwork_asset_id_key" ON "tracks"("artwork_asset_id");
|
|
CREATE UNIQUE INDEX "audio_assets_sha256_key" ON "audio_assets"("sha256");
|
|
CREATE UNIQUE INDEX "audio_assets_storage_key" ON "audio_assets"("storage_key");
|
|
CREATE UNIQUE INDEX "artwork_assets_sha256_key" ON "artwork_assets"("sha256");
|
|
CREATE UNIQUE INDEX "artwork_assets_storage_key" ON "artwork_assets"("storage_key");
|
|
|
|
ALTER TABLE "audio_assets"
|
|
ADD CONSTRAINT "audio_assets_track_id_fkey"
|
|
FOREIGN KEY ("track_id") REFERENCES "tracks"("id")
|
|
ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
ALTER TABLE "audio_assets"
|
|
ADD CONSTRAINT "audio_assets_source_device_id_fkey"
|
|
FOREIGN KEY ("source_device_id") REFERENCES "devices"("id")
|
|
ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
ALTER TABLE "tracks"
|
|
ADD CONSTRAINT "tracks_primary_audio_asset_id_fkey"
|
|
FOREIGN KEY ("primary_audio_asset_id") REFERENCES "audio_assets"("id")
|
|
ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
ALTER TABLE "tracks"
|
|
ADD CONSTRAINT "tracks_artwork_asset_id_fkey"
|
|
FOREIGN KEY ("artwork_asset_id") REFERENCES "artwork_assets"("id")
|
|
ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
ALTER TABLE "upload_sessions"
|
|
ADD CONSTRAINT "upload_sessions_device_id_fkey"
|
|
FOREIGN KEY ("device_id") REFERENCES "devices"("id")
|
|
ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
ALTER TABLE "device_sync_cursors"
|
|
ADD CONSTRAINT "device_sync_cursors_device_id_fkey"
|
|
FOREIGN KEY ("device_id") REFERENCES "devices"("id")
|
|
ON DELETE CASCADE ON UPDATE CASCADE;
|