feat: add postgres migrations and repository adapters for vertical slice

This commit is contained in:
2026-05-31 05:43:21 +02:00
parent 4e2fc99065
commit 8c1a0e4519
15 changed files with 1324 additions and 39 deletions

View File

@@ -0,0 +1,3 @@
ALTER TABLE users ADD COLUMN username TEXT NOT NULL DEFAULT '';
ALTER TABLE users DROP COLUMN role;
ALTER TABLE users ADD CONSTRAINT users_username_unique UNIQUE (username);

View File

@@ -0,0 +1,52 @@
CREATE TABLE storage_volumes (
volume_id UUID PRIMARY KEY,
volume_name TEXT NOT NULL,
uri_prefix TEXT NOT NULL,
is_writable BOOLEAN NOT NULL DEFAULT true,
available_bytes BIGINT NOT NULL DEFAULT 0
);
CREATE TABLE library_paths (
path_id UUID PRIMARY KEY,
volume_id UUID NOT NULL REFERENCES storage_volumes(volume_id),
relative_path TEXT NOT NULL,
is_ingest_destination BOOLEAN NOT NULL DEFAULT false,
ownership_policy TEXT NOT NULL DEFAULT 'unassigned',
designated_owner_id UUID
);
CREATE TABLE quota_definitions (
quota_id UUID PRIMARY KEY,
owner_scope UUID NOT NULL,
is_enforced BOOLEAN NOT NULL DEFAULT true
);
CREATE TABLE quota_rules (
rule_id UUID PRIMARY KEY,
quota_id UUID NOT NULL REFERENCES quota_definitions(quota_id) ON DELETE CASCADE,
dimension TEXT NOT NULL,
limit_value BIGINT NOT NULL,
time_period TEXT NOT NULL,
is_unlimited BOOLEAN NOT NULL DEFAULT false
);
CREATE TABLE usage_ledger (
entry_id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id),
usage_type TEXT NOT NULL,
consumed_amount BIGINT NOT NULL,
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
context TEXT NOT NULL DEFAULT ''
);
CREATE TABLE ingest_sessions (
session_id UUID PRIMARY KEY,
uploader_user_id UUID NOT NULL REFERENCES users(id),
client_device_id TEXT NOT NULL,
original_filename TEXT NOT NULL,
client_checksum TEXT NOT NULL,
target_library_path_id UUID NOT NULL REFERENCES library_paths(path_id),
status TEXT NOT NULL DEFAULT 'uploading',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
error_message TEXT
);

View File

@@ -0,0 +1,23 @@
CREATE TABLE assets (
asset_id UUID PRIMARY KEY,
volume_id UUID NOT NULL REFERENCES storage_volumes(volume_id),
relative_path TEXT NOT NULL,
checksum TEXT NOT NULL,
asset_type TEXT NOT NULL,
mime_type TEXT NOT NULL,
file_size BIGINT NOT NULL,
is_processed BOOLEAN NOT NULL DEFAULT false,
owner_user_id UUID NOT NULL REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_assets_checksum ON assets(checksum);
CREATE INDEX idx_assets_owner ON assets(owner_user_id);
CREATE TABLE asset_metadata (
asset_id UUID NOT NULL REFERENCES assets(asset_id) ON DELETE CASCADE,
metadata_source TEXT NOT NULL,
data JSONB NOT NULL DEFAULT '{}',
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (asset_id, metadata_source)
);

View File

@@ -0,0 +1,33 @@
CREATE TABLE albums (
album_id UUID PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
creator_user_id UUID NOT NULL REFERENCES users(id),
cover_asset_id UUID,
start_date TIMESTAMPTZ,
end_date TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE album_entries (
album_id UUID NOT NULL REFERENCES albums(album_id) ON DELETE CASCADE,
asset_id UUID NOT NULL REFERENCES assets(asset_id) ON DELETE CASCADE,
sort_order INTEGER NOT NULL DEFAULT 0,
added_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
added_by_user_id UUID NOT NULL REFERENCES users(id),
PRIMARY KEY (album_id, asset_id)
);
CREATE TABLE tags (
tag_id UUID PRIMARY KEY,
name TEXT NOT NULL,
tag_source TEXT NOT NULL DEFAULT 'user_manual'
);
CREATE TABLE asset_tags (
asset_id UUID NOT NULL REFERENCES assets(asset_id) ON DELETE CASCADE,
tag_id UUID NOT NULL REFERENCES tags(tag_id) ON DELETE CASCADE,
tagged_by_user_id UUID,
confidence DOUBLE PRECISION NOT NULL DEFAULT 1.0,
PRIMARY KEY (asset_id, tag_id)
);