Step 1 of the build order in docs/decisions.md. Boots, applies migrations before serving, and serves a health check and an empty admin page. - 001_init.sql is the full schema from docs/spec.md, including the check constraints and indexes the old app lacked - The startup sweep fails submissions left mid-conversion by a restart; an in-process goroutine dies with the process and those rows would otherwise say converting forever - Admin is Basic Auth from env on its own listener, fatal at startup when ADMIN_PASSWORD is unset
88 lines
2.9 KiB
SQL
88 lines
2.9 KiB
SQL
create table users (
|
|
id bigserial primary key,
|
|
name text not null,
|
|
email text not null unique,
|
|
password_hash text not null,
|
|
avatar text,
|
|
banned boolean not null default false,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create table sessions (
|
|
token text primary key,
|
|
user_id bigint not null references users (id) on delete cascade,
|
|
idle_ttl interval not null,
|
|
expires_at timestamptz not null,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create index on sessions (user_id);
|
|
|
|
create table invites (
|
|
id bigserial primary key,
|
|
code text not null unique,
|
|
is_valid boolean not null default true,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create table songs (
|
|
id bigserial primary key,
|
|
title text not null,
|
|
artist text not null,
|
|
genre text not null,
|
|
description text,
|
|
audio_file text not null,
|
|
duration_seconds integer not null,
|
|
source_url text,
|
|
submitted_by bigint not null references users (id),
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create index on songs (created_at desc);
|
|
|
|
create table submissions (
|
|
id bigserial primary key,
|
|
user_id bigint not null references users (id) on delete cascade,
|
|
status text not null default 'queued',
|
|
status_msg text,
|
|
source_url text,
|
|
tmp_path text,
|
|
title text,
|
|
artist text,
|
|
genre text,
|
|
description text,
|
|
created_at timestamptz not null default now(),
|
|
constraint submissions_status check (
|
|
status in ('queued', 'downloading', 'converting', 'ready', 'failed')
|
|
)
|
|
);
|
|
|
|
-- The submission quota (5 per rolling 24h, failures excluded) reads this.
|
|
create index on submissions (user_id, created_at desc);
|
|
|
|
create table reviews (
|
|
id bigserial primary key,
|
|
song_id bigint not null references songs (id) on delete cascade,
|
|
reviewer_id bigint not null references users (id),
|
|
score integer not null check (score between 1 and 100),
|
|
text text not null,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (song_id, reviewer_id)
|
|
);
|
|
|
|
create index on reviews (song_id);
|
|
|
|
-- The queue asks "songs this member has not reviewed" — that lookup is by reviewer.
|
|
create index on reviews (reviewer_id, song_id);
|
|
|
|
create table reports (
|
|
id bigserial primary key,
|
|
user_id bigint not null references users (id) on delete cascade,
|
|
body text not null,
|
|
page text,
|
|
user_agent text,
|
|
resolved_at timestamptz,
|
|
created_at timestamptz not null default now()
|
|
);
|