b46dbbe889
- Astro 5 SSR (node standalone) + React, OKLCH tokens (no tailwind) - migrations/001_init.sql: full schema per 03-datenmodell-api - lib: db+migrations, crypto (AES-256-GCM), auth (argon2+signed session, ratelimit), storage (S3/MinIO, presigned URLs), openrouter (POST /v1/images, cost) - middleware: init-once + session guard + admin gate; /api/health (db+storage) - login + studio placeholder; seeds (till/lea, default recipes); Dockerfile - verified: astro build passes
169 lines
6.9 KiB
SQL
169 lines
6.9 KiB
SQL
-- Klarbild — Initiales Schema (siehe 03-datenmodell-api.md)
|
|
-- Wird beim Start automatisch angewandt (nummerierte SQL-Dateien, keine ORM-Magie).
|
|
|
|
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
|
|
|
-- Nutzerinnen -------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
username text UNIQUE NOT NULL,
|
|
password_hash text NOT NULL,
|
|
role text NOT NULL DEFAULT 'user' CHECK (role IN ('user','admin')),
|
|
display_name text,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Rezepte (gespeicherte Voreinstellungen) --------------------------------
|
|
CREATE TABLE IF NOT EXISTS recipes (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name text NOT NULL,
|
|
tasks jsonb NOT NULL DEFAULT '[]'::jsonb, -- z.B. ["clean","format","deliver"]
|
|
output_format text,
|
|
orientation text,
|
|
crop_mode text,
|
|
dpi int NOT NULL DEFAULT 300,
|
|
contour_mm numeric,
|
|
model_key text,
|
|
delivery text NOT NULL DEFAULT 'library' CHECK (delivery IN ('library','picdrop','both')),
|
|
picdrop_gallery text,
|
|
custom_instruction text,
|
|
is_default bool NOT NULL DEFAULT false,
|
|
created_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Aufträge (ein Stapel) ---------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS jobs (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
created_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
origin text NOT NULL DEFAULT 'web' CHECK (origin IN ('web','telegram')),
|
|
recipe_snapshot jsonb NOT NULL,
|
|
status text NOT NULL DEFAULT 'queued'
|
|
CHECK (status IN ('queued','running','paused','done','cancelled')),
|
|
total int NOT NULL DEFAULT 0,
|
|
done_count int NOT NULL DEFAULT 0,
|
|
failed_count int NOT NULL DEFAULT 0,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
finished_at timestamptz
|
|
);
|
|
|
|
-- Ordner ------------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS folders (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name text NOT NULL,
|
|
picdrop_gallery text,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Positionen (ein Bild in einem Auftrag) ---------------------------------
|
|
CREATE TABLE IF NOT EXISTS items (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
job_id uuid REFERENCES jobs(id) ON DELETE CASCADE,
|
|
position int NOT NULL DEFAULT 0,
|
|
status text NOT NULL DEFAULT 'queued'
|
|
CHECK (status IN ('queued','running','done','failed','skipped')),
|
|
attempts int NOT NULL DEFAULT 0,
|
|
error_message text,
|
|
source_path text,
|
|
result_path text,
|
|
filename text,
|
|
output_px text,
|
|
source_quality text CHECK (source_quality IN ('original','compressed')),
|
|
dpi int,
|
|
has_alpha bool NOT NULL DEFAULT false,
|
|
model_used text,
|
|
prompt_used text,
|
|
cost numeric, -- tatsächliche Kosten aus usage.cost
|
|
folder_id uuid REFERENCES folders(id) ON DELETE SET NULL,
|
|
delivery_status text NOT NULL DEFAULT 'none'
|
|
CHECK (delivery_status IN ('none','pending','delivered','failed')),
|
|
delivered_at timestamptz,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS items_job_idx ON items(job_id);
|
|
CREATE INDEX IF NOT EXISTS items_created_idx ON items(created_at DESC);
|
|
|
|
-- Druckaufträge -----------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS print_jobs (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
created_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
note text,
|
|
status text NOT NULL DEFAULT 'open' CHECK (status IN ('open','done')),
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
CREATE TABLE IF NOT EXISTS print_job_items (
|
|
print_job_id uuid REFERENCES print_jobs(id) ON DELETE CASCADE,
|
|
item_id uuid REFERENCES items(id) ON DELETE CASCADE,
|
|
PRIMARY KEY (print_job_id, item_id)
|
|
);
|
|
|
|
-- Freigabelinks -----------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS share_links (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
token text UNIQUE NOT NULL,
|
|
scope_type text NOT NULL CHECK (scope_type IN ('selection','folder')),
|
|
scope_ref jsonb NOT NULL,
|
|
expires_at timestamptz,
|
|
password_hash text,
|
|
revoked bool NOT NULL DEFAULT false,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Telegram ---------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS telegram_links (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
chat_id bigint UNIQUE NOT NULL,
|
|
user_id uuid REFERENCES users(id) ON DELETE CASCADE,
|
|
default_recipe_id uuid REFERENCES recipes(id) ON DELETE SET NULL,
|
|
active bool NOT NULL DEFAULT true,
|
|
linked_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
CREATE TABLE IF NOT EXISTS telegram_pairing_codes (
|
|
code text PRIMARY KEY,
|
|
user_id uuid REFERENCES users(id) ON DELETE CASCADE,
|
|
expires_at timestamptz NOT NULL,
|
|
used_at timestamptz
|
|
);
|
|
CREATE TABLE IF NOT EXISTS telegram_drafts (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
chat_id bigint NOT NULL,
|
|
media_group_id text,
|
|
file_refs jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
last_received_at timestamptz NOT NULL DEFAULT now(),
|
|
status text NOT NULL DEFAULT 'collecting'
|
|
CHECK (status IN ('collecting','awaiting_recipe','dispatched','discarded')),
|
|
notice_message_id bigint
|
|
);
|
|
|
|
-- Einstellungen (eine Zeile) ---------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS settings (
|
|
id int PRIMARY KEY DEFAULT 1 CHECK (id = 1),
|
|
openrouter_key_enc text,
|
|
picdrop_host text,
|
|
picdrop_protocol text CHECK (picdrop_protocol IN ('ftps','sftp')),
|
|
picdrop_port int,
|
|
picdrop_user text,
|
|
picdrop_password_enc text,
|
|
picdrop_base_path text,
|
|
default_dpi int NOT NULL DEFAULT 300,
|
|
default_crop_mode text NOT NULL DEFAULT 'crop',
|
|
concurrency int NOT NULL DEFAULT 2,
|
|
cricut_sheet_cm text NOT NULL DEFAULT '17.1x23.5',
|
|
monthly_budget numeric,
|
|
n8n_webhook_url text,
|
|
telegram_bot_token_enc text,
|
|
telegram_webhook_secret text
|
|
);
|
|
|
|
-- Modelle -----------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS models (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
model_id text NOT NULL,
|
|
label text NOT NULL,
|
|
description text,
|
|
active bool NOT NULL DEFAULT true,
|
|
is_default bool NOT NULL DEFAULT false,
|
|
supports_alpha bool NOT NULL DEFAULT false,
|
|
sort int NOT NULL DEFAULT 0
|
|
);
|