379 lines
15 KiB
SQL
379 lines
15 KiB
SQL
-- Referenz-Schema. Laufende Migrationen liegen in grotti/migrations/*.sql
|
|
-- (001_base.sql entspricht diesem Stand, danach nummerierte Änderungen).
|
|
|
|
CREATE TABLE IF NOT EXISTS projects (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
name text NOT NULL,
|
|
notes text NOT NULL DEFAULT '',
|
|
status text NOT NULL DEFAULT 'idee',
|
|
quote jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
folder text NOT NULL DEFAULT '',
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE projects ADD COLUMN IF NOT EXISTS folder text NOT NULL DEFAULT '';
|
|
|
|
CREATE TABLE IF NOT EXISTS spools (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
name text NOT NULL,
|
|
brand text NOT NULL DEFAULT '',
|
|
material_type text NOT NULL DEFAULT '',
|
|
color text NOT NULL DEFAULT '',
|
|
price_per_kg double precision NOT NULL DEFAULT 0,
|
|
density double precision NOT NULL DEFAULT 1.24,
|
|
volumetric double precision NOT NULL DEFAULT 12,
|
|
remaining_g double precision NOT NULL DEFAULT 1000,
|
|
printer_host text NOT NULL DEFAULT '',
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS files (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
project_id bigint REFERENCES projects (id) ON DELETE SET NULL,
|
|
spool_id bigint REFERENCES spools (id) ON DELETE SET NULL,
|
|
name text NOT NULL,
|
|
stored_path text NOT NULL,
|
|
source text NOT NULL,
|
|
kind text NOT NULL,
|
|
printer_family text NOT NULL DEFAULT '',
|
|
filaments jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
weight_g double precision NOT NULL DEFAULT 0,
|
|
estimated_s double precision NOT NULL DEFAULT 0,
|
|
thumb_entry text NOT NULL DEFAULT '',
|
|
plate text NOT NULL DEFAULT '',
|
|
size_bytes bigint NOT NULL DEFAULT 0,
|
|
mtime double precision NOT NULL DEFAULT 0,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
UNIQUE (source, stored_path)
|
|
);
|
|
|
|
ALTER TABLE files ADD COLUMN IF NOT EXISTS slice_meta jsonb NOT NULL DEFAULT '{}'::jsonb;
|
|
|
|
CREATE TABLE IF NOT EXISTS sends (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
printer_host text NOT NULL,
|
|
filename text NOT NULL,
|
|
file_id bigint REFERENCES files (id) ON DELETE SET NULL,
|
|
project_id bigint REFERENCES projects (id) ON DELETE SET NULL,
|
|
spool_id bigint REFERENCES spools (id) ON DELETE SET NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE sends ADD COLUMN IF NOT EXISTS ace_map jsonb NOT NULL DEFAULT '[]'::jsonb;
|
|
ALTER TABLE sends ADD COLUMN IF NOT EXISTS bed_leveling boolean NOT NULL DEFAULT false;
|
|
|
|
CREATE TABLE IF NOT EXISTS runs (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
printer_host text NOT NULL,
|
|
printer_name text NOT NULL DEFAULT '',
|
|
filename text NOT NULL DEFAULT '',
|
|
file_id bigint REFERENCES files (id) ON DELETE SET NULL,
|
|
project_id bigint REFERENCES projects (id) ON DELETE SET NULL,
|
|
spool_id bigint REFERENCES spools (id) ON DELETE SET NULL,
|
|
state text NOT NULL DEFAULT '',
|
|
started_at timestamptz,
|
|
ended_at timestamptz,
|
|
duration_s double precision NOT NULL DEFAULT 0,
|
|
weight_g double precision NOT NULL DEFAULT 0,
|
|
filament_cost double precision NOT NULL DEFAULT 0,
|
|
energy_cost double precision NOT NULL DEFAULT 0,
|
|
moonraker_job_id text NOT NULL,
|
|
deducted boolean NOT NULL DEFAULT false,
|
|
needs_spool boolean NOT NULL DEFAULT false,
|
|
verdict text NOT NULL DEFAULT '',
|
|
material_type text NOT NULL DEFAULT '',
|
|
UNIQUE (printer_host, moonraker_job_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS files_project ON files (project_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS runs_started ON runs (started_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS printers (
|
|
id uuid PRIMARY KEY,
|
|
name text NOT NULL,
|
|
host text NOT NULL UNIQUE,
|
|
family text NOT NULL DEFAULT '',
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE printers ADD COLUMN IF NOT EXISTS locked boolean NOT NULL DEFAULT false;
|
|
|
|
CREATE TABLE IF NOT EXISTS ideas (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
title text NOT NULL,
|
|
body text NOT NULL DEFAULT '',
|
|
status text NOT NULL DEFAULT 'offen',
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS materials (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
name text NOT NULL UNIQUE,
|
|
brand text NOT NULL DEFAULT '',
|
|
material_type text NOT NULL DEFAULT '',
|
|
density double precision NOT NULL,
|
|
volumetric double precision NOT NULL,
|
|
volumetric_s1 double precision,
|
|
machines text NOT NULL DEFAULT 'beide',
|
|
price_per_kg double precision NOT NULL DEFAULT 0,
|
|
note text NOT NULL DEFAULT ''
|
|
);
|
|
|
|
ALTER TABLE spools ADD COLUMN IF NOT EXISTS colors jsonb NOT NULL DEFAULT '[]'::jsonb;
|
|
ALTER TABLE spools ADD COLUMN IF NOT EXISTS ace_slot smallint;
|
|
ALTER TABLE spools ADD COLUMN IF NOT EXISTS material_id bigint REFERENCES materials (id) ON DELETE SET NULL;
|
|
ALTER TABLE spools ADD COLUMN IF NOT EXISTS chargen_nr text;
|
|
ALTER TABLE spools ADD COLUMN IF NOT EXISTS hersteller_charge text NOT NULL DEFAULT '';
|
|
ALTER TABLE spools ADD COLUMN IF NOT EXISTS code text;
|
|
ALTER TABLE spools ADD COLUMN IF NOT EXISTS archived_at timestamptz;
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS spools_chargen_nr ON spools (chargen_nr) WHERE chargen_nr IS NOT NULL AND chargen_nr <> '';
|
|
CREATE UNIQUE INDEX IF NOT EXISTS spools_code ON spools (code) WHERE code IS NOT NULL AND code <> '';
|
|
-- Ein ACE-Platz gehört höchstens einer Spule.
|
|
CREATE UNIQUE INDEX IF NOT EXISTS spools_host_slot
|
|
ON spools (printer_host, ace_slot)
|
|
WHERE printer_host <> '' AND ace_slot IS NOT NULL;
|
|
|
|
CREATE TABLE IF NOT EXISTS events (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
host text NOT NULL DEFAULT '',
|
|
printer text NOT NULL DEFAULT '',
|
|
kind text NOT NULL,
|
|
message text NOT NULL DEFAULT '',
|
|
filename text NOT NULL DEFAULT '',
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
read_at timestamptz
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS events_unread ON events (read_at, created_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS print_queue (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
file_id bigint NOT NULL REFERENCES files (id) ON DELETE CASCADE,
|
|
host text NOT NULL DEFAULT '',
|
|
family text NOT NULL DEFAULT '',
|
|
priority integer NOT NULL DEFAULT 100,
|
|
status text NOT NULL DEFAULT 'waiting',
|
|
spool_id bigint REFERENCES spools (id) ON DELETE SET NULL,
|
|
ace_map jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
bed_leveling boolean NOT NULL DEFAULT false,
|
|
override_machine boolean NOT NULL DEFAULT false,
|
|
message text NOT NULL DEFAULT '',
|
|
steps jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
step_index integer NOT NULL DEFAULT 0,
|
|
repeat_total integer NOT NULL DEFAULT 1,
|
|
repeat_done integer NOT NULL DEFAULT 0,
|
|
phase text NOT NULL DEFAULT '',
|
|
phase_started_at timestamptz,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE print_queue ADD COLUMN IF NOT EXISTS steps jsonb NOT NULL DEFAULT '[]'::jsonb;
|
|
ALTER TABLE print_queue ADD COLUMN IF NOT EXISTS step_index integer NOT NULL DEFAULT 0;
|
|
ALTER TABLE print_queue ADD COLUMN IF NOT EXISTS repeat_total integer NOT NULL DEFAULT 1;
|
|
ALTER TABLE print_queue ADD COLUMN IF NOT EXISTS repeat_done integer NOT NULL DEFAULT 0;
|
|
ALTER TABLE print_queue ADD COLUMN IF NOT EXISTS phase text NOT NULL DEFAULT '';
|
|
ALTER TABLE print_queue ADD COLUMN IF NOT EXISTS phase_started_at timestamptz;
|
|
ALTER TABLE print_queue ADD COLUMN IF NOT EXISTS retry_count integer NOT NULL DEFAULT 0;
|
|
ALTER TABLE print_queue ADD COLUMN IF NOT EXISTS wait_reason text NOT NULL DEFAULT '';
|
|
|
|
CREATE INDEX IF NOT EXISTS print_queue_waiting ON print_queue (status, priority, id);
|
|
CREATE INDEX IF NOT EXISTS print_queue_running_host ON print_queue (host, status) WHERE status = 'running';
|
|
|
|
-- Nach dem Druck: Platte manuell quittieren, bevor „wenn frei“ den nächsten Job startet.
|
|
CREATE TABLE IF NOT EXISTS bed_status (
|
|
host text PRIMARY KEY,
|
|
needs_clear boolean NOT NULL DEFAULT false,
|
|
cleared_at timestamptz,
|
|
message text NOT NULL DEFAULT ''
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
username text NOT NULL UNIQUE,
|
|
password_hash text NOT NULL,
|
|
role text NOT NULL DEFAULT 'operator',
|
|
active boolean NOT NULL DEFAULT true,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
last_login timestamptz
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS api_tokens (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
user_id bigint NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
|
name text NOT NULL DEFAULT '',
|
|
token_hash text NOT NULL UNIQUE,
|
|
token_prefix text NOT NULL DEFAULT '',
|
|
role text NOT NULL DEFAULT 'operator',
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
last_used timestamptz,
|
|
revoked_at timestamptz,
|
|
expires_at timestamptz
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS api_tokens_user ON api_tokens (user_id) WHERE revoked_at IS NULL;
|
|
|
|
-- OIDC später: Identitäten an lokale User binden.
|
|
CREATE TABLE IF NOT EXISTS oauth_identities (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
user_id bigint NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
|
provider text NOT NULL,
|
|
subject text NOT NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
UNIQUE (provider, subject)
|
|
);
|
|
|
|
-- Druckbericht: Soll/Ist, Charge, Live-Fortschritt
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS weight_planned_g double precision NOT NULL DEFAULT 0;
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS weight_used_g double precision NOT NULL DEFAULT 0;
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS weight_source text NOT NULL DEFAULT '';
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS filament_used_mm double precision NOT NULL DEFAULT 0;
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS filament_total_mm double precision NOT NULL DEFAULT 0;
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS progress_last double precision NOT NULL DEFAULT 0;
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS estimated_s double precision NOT NULL DEFAULT 0;
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS chargen_nr text;
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS message text NOT NULL DEFAULT '';
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS objects jsonb NOT NULL DEFAULT '[]'::jsonb;
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS runs_chargen_nr
|
|
ON runs (chargen_nr) WHERE chargen_nr IS NOT NULL AND chargen_nr <> '';
|
|
|
|
ALTER TABLE events ADD COLUMN IF NOT EXISTS run_id bigint REFERENCES runs (id) ON DELETE SET NULL;
|
|
CREATE INDEX IF NOT EXISTS events_run ON events (run_id) WHERE run_id IS NOT NULL;
|
|
|
|
-- Abzug je Spule (Messwert oder Schätzwert)
|
|
CREATE TABLE IF NOT EXISTS run_spools (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
run_id bigint NOT NULL REFERENCES runs (id) ON DELETE CASCADE,
|
|
spool_id bigint NOT NULL REFERENCES spools (id) ON DELETE RESTRICT,
|
|
ace_slot smallint,
|
|
weight_g double precision NOT NULL DEFAULT 0,
|
|
weight_planned_g double precision NOT NULL DEFAULT 0,
|
|
cost double precision NOT NULL DEFAULT 0,
|
|
is_estimate boolean NOT NULL DEFAULT false,
|
|
UNIQUE (run_id, spool_id, ace_slot)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS run_spools_spool ON run_spools (spool_id);
|
|
CREATE INDEX IF NOT EXISTS run_spools_run ON run_spools (run_id);
|
|
|
|
-- Abschnitte bei Rollenwechsel mitten im Druck
|
|
CREATE TABLE IF NOT EXISTS run_segments (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
run_id bigint NOT NULL REFERENCES runs (id) ON DELETE CASCADE,
|
|
spool_id bigint NOT NULL REFERENCES spools (id) ON DELETE RESTRICT,
|
|
ace_slot smallint,
|
|
mm_start double precision NOT NULL DEFAULT 0,
|
|
mm_end double precision,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
closed_at timestamptz
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS run_segments_run ON run_segments (run_id);
|
|
CREATE INDEX IF NOT EXISTS run_segments_open
|
|
ON run_segments (run_id) WHERE mm_end IS NULL;
|
|
|
|
-- Temperatur / Fortschritt während des Drucks
|
|
CREATE TABLE IF NOT EXISTS run_samples (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
run_id bigint NOT NULL REFERENCES runs (id) ON DELETE CASCADE,
|
|
sampled_at timestamptz NOT NULL DEFAULT now(),
|
|
nozzle double precision,
|
|
nozzle_target double precision,
|
|
bed double precision,
|
|
bed_target double precision,
|
|
chamber double precision,
|
|
fan double precision,
|
|
speed_factor double precision,
|
|
extrude_factor double precision,
|
|
layer integer,
|
|
progress double precision,
|
|
filament_used_mm double precision,
|
|
mmu_tool smallint,
|
|
nozzle_power double precision,
|
|
bed_power double precision
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS run_samples_run_time ON run_samples (run_id, sampled_at);
|
|
|
|
ALTER TABLE run_samples ADD COLUMN IF NOT EXISTS nozzle_power double precision;
|
|
ALTER TABLE run_samples ADD COLUMN IF NOT EXISTS bed_power double precision;
|
|
|
|
-- Objekt-Chargen für Etiketten
|
|
CREATE TABLE IF NOT EXISTS run_labels (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
run_id bigint NOT NULL REFERENCES runs (id) ON DELETE CASCADE,
|
|
object_name text NOT NULL DEFAULT '',
|
|
chargen_nr text NOT NULL,
|
|
excluded boolean NOT NULL DEFAULT false,
|
|
UNIQUE (run_id, object_name)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS run_labels_chargen ON run_labels (chargen_nr);
|
|
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS verdict_reason text NOT NULL DEFAULT '';
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS pieces_ok int NOT NULL DEFAULT 0;
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS pieces_bad int NOT NULL DEFAULT 0;
|
|
|
|
CREATE TABLE IF NOT EXISTS maintenance_parts (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
printer_host text NOT NULL,
|
|
part_key text NOT NULL,
|
|
label text NOT NULL DEFAULT '',
|
|
installed_at timestamptz NOT NULL DEFAULT now(),
|
|
life_hours double precision NOT NULL DEFAULT 0,
|
|
life_meters double precision NOT NULL DEFAULT 0,
|
|
note text NOT NULL DEFAULT ''
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS maintenance_log (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
printer_host text NOT NULL,
|
|
part_key text NOT NULL,
|
|
event text NOT NULL DEFAULT '',
|
|
hours_at double precision NOT NULL DEFAULT 0,
|
|
meters_at double precision NOT NULL DEFAULT 0,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
note text NOT NULL DEFAULT ''
|
|
);
|
|
|
|
ALTER TABLE printers ADD COLUMN IF NOT EXISTS start_window jsonb NOT NULL DEFAULT '{}'::jsonb;
|
|
|
|
CREATE TABLE IF NOT EXISTS customers (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
name text NOT NULL,
|
|
email text NOT NULL DEFAULT '',
|
|
notes text NOT NULL DEFAULT '',
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS orders (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
customer_id bigint REFERENCES customers (id) ON DELETE SET NULL,
|
|
title text NOT NULL,
|
|
status text NOT NULL DEFAULT 'idee',
|
|
due_at date,
|
|
notes text NOT NULL DEFAULT '',
|
|
quote jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS order_items (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
order_id bigint NOT NULL REFERENCES orders (id) ON DELETE CASCADE,
|
|
file_id bigint REFERENCES files (id) ON DELETE SET NULL,
|
|
qty int NOT NULL DEFAULT 1,
|
|
unit_price double precision NOT NULL DEFAULT 0,
|
|
material_type text NOT NULL DEFAULT '',
|
|
color text NOT NULL DEFAULT '',
|
|
done_ok int NOT NULL DEFAULT 0,
|
|
done_bad int NOT NULL DEFAULT 0,
|
|
note text NOT NULL DEFAULT ''
|
|
);
|
|
|
|
ALTER TABLE print_queue ADD COLUMN IF NOT EXISTS order_item_id bigint REFERENCES order_items (id) ON DELETE SET NULL;
|
|
ALTER TABLE runs ADD COLUMN IF NOT EXISTS order_item_id bigint REFERENCES order_items (id) ON DELETE SET NULL;
|