Files
Florian-netz/drizzle/0000_opposite_santa_claus.sql
Claude a9666ff96c Workstream 2: Datenbankschema & Migrationen (Phase 1)
Vollständiges Drizzle-Schema (alle Tabellen/Enums/Indizes aus Spec §6):
brigades, users, merkmale(+optionen), vehicle_templates(+merkmale,+aliasse),
equipment_categories(+merkmale), vehicles, equipment, merkmal_values (EAV mit
typisierten Spalten + 4 Indizes), login_attempts, audit_log. Einzige initiale
Migration 0000 (idempotent: enum-DO-Blöcke, IF NOT EXISTS), scripts/migrate.ts,
db:* npm-Scripts.

Verifiziert (offline): tsc --noEmit OK; drizzle-kit check 'Everything's fine';
Migration 7 CREATE TYPE / 14 CREATE TABLE / 17 CREATE INDEX / 32 IF NOT EXISTS.
DEFERRED (kein Postgres im Sandbox — Ursache des vorherigen Stalls): live
db:migrate und DB-abhängige Schema-Tests; laufen in CI/Deploy mit Postgres.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 08:58:56 +02:00

187 lines
12 KiB
SQL

DO $$ BEGIN CREATE TYPE "public"."asset_status" AS ENUM('einsatzbereit', 'wartung', 'ausser_dienst'); EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN CREATE TYPE "public"."auth_typ" AS ENUM('authentik', 'local'); EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN CREATE TYPE "public"."entity_typ" AS ENUM('vehicle', 'equipment'); EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN CREATE TYPE "public"."geltungsbereich" AS ENUM('vehicle', 'equipment', 'both'); EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN CREATE TYPE "public"."merkmal_status" AS ENUM('active', 'proposed'); EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN CREATE TYPE "public"."merkmal_typ" AS ENUM('number', 'enum', 'boolean', 'text'); EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN CREATE TYPE "public"."role" AS ENUM('platform_admin', 'wehr_admin', 'wehr_read'); EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "brigades" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"name" text NOT NULL,
"art" text DEFAULT 'FF' NOT NULL,
"strasse" text,
"plz" text,
"ort" text,
"bundesland" text DEFAULT 'Niederösterreich' NOT NULL,
"lat" double precision,
"lng" double precision,
"geocode_query" text,
"geocoded_at" timestamp with time zone,
"geocode_status" text,
"funkrufname_schema" text,
"wehrfuehrer" text,
"telefon" text,
"email" text,
"aktiv" boolean DEFAULT true NOT NULL,
"erstellt_am" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "users" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"brigade_id" uuid,
"rolle" "role" NOT NULL,
"auth_typ" "auth_typ" NOT NULL,
"email" text NOT NULL,
"name" text NOT NULL,
"passwort_hash" text,
"aktiv" boolean DEFAULT true NOT NULL,
"erstellt_von" uuid,
"erstellt_am" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "users_email_uq" UNIQUE("email")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "merkmal_optionen" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"merkmal_id" uuid NOT NULL,
"wert" text NOT NULL,
"label" text NOT NULL,
"reihenfolge" integer DEFAULT 0 NOT NULL,
CONSTRAINT "merkmal_optionen_uq" UNIQUE("merkmal_id","wert")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "merkmale" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"slug" text NOT NULL,
"name" text NOT NULL,
"typ" "merkmal_typ" NOT NULL,
"einheit" text,
"geltungsbereich" "geltungsbereich" NOT NULL,
"status" "merkmal_status" DEFAULT 'proposed' NOT NULL,
"vorgeschlagen_von_brigade_id" uuid,
"erstellt_am" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "merkmale_slug_uq" UNIQUE("slug")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "vehicle_template_aliasse" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"template_id" uuid NOT NULL,
"alias" text NOT NULL,
"bestaetigt" boolean DEFAULT false NOT NULL,
CONSTRAINT "vehicle_template_aliasse_uq" UNIQUE("template_id","alias")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "vehicle_template_merkmale" (
"template_id" uuid NOT NULL,
"merkmal_id" uuid NOT NULL,
"vorgabewert_num" double precision,
"vorgabewert_text" text,
"vorgabewert_bool" boolean,
"pflicht" boolean DEFAULT false NOT NULL,
"reihenfolge" integer DEFAULT 0 NOT NULL,
CONSTRAINT "vehicle_template_merkmale_template_id_merkmal_id_pk" PRIMARY KEY("template_id","merkmal_id")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "vehicle_templates" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"code" text NOT NULL,
"name" text NOT NULL,
"beschreibung" text,
"reihenfolge" integer DEFAULT 0 NOT NULL,
CONSTRAINT "vehicle_templates_code_uq" UNIQUE("code")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "equipment_categories" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"name" text NOT NULL,
"reihenfolge" integer DEFAULT 0 NOT NULL,
CONSTRAINT "equipment_categories_name_uq" UNIQUE("name")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "equipment_category_merkmale" (
"category_id" uuid NOT NULL,
"merkmal_id" uuid NOT NULL,
"reihenfolge" integer DEFAULT 0 NOT NULL,
CONSTRAINT "equipment_category_merkmale_category_id_merkmal_id_pk" PRIMARY KEY("category_id","merkmal_id")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "equipment" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"brigade_id" uuid NOT NULL,
"category_id" uuid NOT NULL,
"vehicle_id" uuid,
"name" text NOT NULL,
"status" "asset_status" DEFAULT 'einsatzbereit' NOT NULL,
"erstellt_am" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "vehicles" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"brigade_id" uuid NOT NULL,
"template_id" uuid,
"name" text NOT NULL,
"funkrufname" text,
"status" "asset_status" DEFAULT 'einsatzbereit' NOT NULL,
"notiz" text,
"erstellt_am" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "merkmal_values" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"merkmal_id" uuid NOT NULL,
"entity_typ" "entity_typ" NOT NULL,
"entity_id" uuid NOT NULL,
"value_num" double precision,
"value_text" text,
"value_bool" boolean
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "login_attempts" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"key" text NOT NULL,
"erfolg" boolean NOT NULL,
"zeitpunkt" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "audit_log" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"actor_user_id" uuid,
"aktion" text NOT NULL,
"ziel_typ" text,
"ziel_id" uuid,
"details" jsonb,
"zeitpunkt" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "users" ADD CONSTRAINT "users_brigade_id_brigades_id_fk" FOREIGN KEY ("brigade_id") REFERENCES "public"."brigades"("id") ON DELETE restrict ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "merkmal_optionen" ADD CONSTRAINT "merkmal_optionen_merkmal_id_merkmale_id_fk" FOREIGN KEY ("merkmal_id") REFERENCES "public"."merkmale"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "merkmale" ADD CONSTRAINT "merkmale_vorgeschlagen_von_brigade_id_brigades_id_fk" FOREIGN KEY ("vorgeschlagen_von_brigade_id") REFERENCES "public"."brigades"("id") ON DELETE set null ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "vehicle_template_aliasse" ADD CONSTRAINT "vehicle_template_aliasse_template_id_vehicle_templates_id_fk" FOREIGN KEY ("template_id") REFERENCES "public"."vehicle_templates"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "vehicle_template_merkmale" ADD CONSTRAINT "vehicle_template_merkmale_template_id_vehicle_templates_id_fk" FOREIGN KEY ("template_id") REFERENCES "public"."vehicle_templates"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "vehicle_template_merkmale" ADD CONSTRAINT "vehicle_template_merkmale_merkmal_id_merkmale_id_fk" FOREIGN KEY ("merkmal_id") REFERENCES "public"."merkmale"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "equipment_category_merkmale" ADD CONSTRAINT "equipment_category_merkmale_category_id_equipment_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."equipment_categories"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "equipment_category_merkmale" ADD CONSTRAINT "equipment_category_merkmale_merkmal_id_merkmale_id_fk" FOREIGN KEY ("merkmal_id") REFERENCES "public"."merkmale"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "equipment" ADD CONSTRAINT "equipment_brigade_id_brigades_id_fk" FOREIGN KEY ("brigade_id") REFERENCES "public"."brigades"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "equipment" ADD CONSTRAINT "equipment_category_id_equipment_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."equipment_categories"("id") ON DELETE restrict ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "equipment" ADD CONSTRAINT "equipment_vehicle_id_vehicles_id_fk" FOREIGN KEY ("vehicle_id") REFERENCES "public"."vehicles"("id") ON DELETE set null ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "vehicles" ADD CONSTRAINT "vehicles_brigade_id_brigades_id_fk" FOREIGN KEY ("brigade_id") REFERENCES "public"."brigades"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "vehicles" ADD CONSTRAINT "vehicles_template_id_vehicle_templates_id_fk" FOREIGN KEY ("template_id") REFERENCES "public"."vehicle_templates"("id") ON DELETE set null ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "merkmal_values" ADD CONSTRAINT "merkmal_values_merkmal_id_merkmale_id_fk" FOREIGN KEY ("merkmal_id") REFERENCES "public"."merkmale"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
DO $$ BEGIN ALTER TABLE "audit_log" ADD CONSTRAINT "audit_log_actor_user_id_users_id_fk" FOREIGN KEY ("actor_user_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action; EXCEPTION WHEN duplicate_object THEN null; END $$;--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "brigades_latlng_idx" ON "brigades" USING btree ("lat","lng");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "merkmal_optionen_merkmal_idx" ON "merkmal_optionen" USING btree ("merkmal_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "merkmale_status_idx" ON "merkmale" USING btree ("status");--> statement-breakpoint
CREATE UNIQUE INDEX IF NOT EXISTS "merkmale_active_name_uq" ON "merkmale" USING btree ("name") WHERE "merkmale"."status" = 'active';--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "vtm_merkmal_idx" ON "vehicle_template_merkmale" USING btree ("merkmal_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "ecm_merkmal_idx" ON "equipment_category_merkmale" USING btree ("merkmal_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "equipment_brigade_idx" ON "equipment" USING btree ("brigade_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "equipment_category_idx" ON "equipment" USING btree ("category_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "equipment_vehicle_idx" ON "equipment" USING btree ("vehicle_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "vehicles_brigade_idx" ON "vehicles" USING btree ("brigade_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "vehicles_template_idx" ON "vehicles" USING btree ("template_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "mv_merkmal_num_idx" ON "merkmal_values" USING btree ("merkmal_id","value_num");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "mv_merkmal_bool_idx" ON "merkmal_values" USING btree ("merkmal_id","value_bool");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "mv_merkmal_text_idx" ON "merkmal_values" USING btree ("merkmal_id","value_text");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "mv_entity_idx" ON "merkmal_values" USING btree ("entity_typ","entity_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "login_attempts_key_zeit_idx" ON "login_attempts" USING btree ("key","zeitpunkt");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "audit_log_zeitpunkt_idx" ON "audit_log" USING btree ("zeitpunkt");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "audit_log_aktion_idx" ON "audit_log" USING btree ("aktion");