package main import ( "context" "github.com/jackc/pgx/v5/pgxpool" ) func ensureRuntimeDeviceSchema(ctx context.Context, db *pgxpool.Pool) error { queries := []string{ `CREATE EXTENSION IF NOT EXISTS pgcrypto`, `ALTER TABLE IF EXISTS devices ADD COLUMN IF NOT EXISTS phone_number TEXT NOT NULL DEFAULT ''`, `ALTER TABLE IF EXISTS devices ADD COLUMN IF NOT EXISTS computer_name TEXT NOT NULL DEFAULT ''`, `ALTER TABLE IF EXISTS devices ADD COLUMN IF NOT EXISTS device_category TEXT NOT NULL DEFAULT ''`, `ALTER TABLE IF EXISTS devices ADD COLUMN IF NOT EXISTS loaned_to_user_id UUID REFERENCES users(id) ON DELETE SET NULL`, `ALTER TABLE IF EXISTS devices ADD COLUMN IF NOT EXISTS loaned_until DATE`, `ALTER TABLE IF EXISTS operations ADD COLUMN IF NOT EXISTS completed_at TIMESTAMPTZ`, ` CREATE TABLE IF NOT EXISTS device_relations ( device_id UUID NOT NULL REFERENCES devices(id) ON DELETE CASCADE, related_device_id UUID NOT NULL REFERENCES devices(id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (device_id, related_device_id), CONSTRAINT device_relations_no_self_reference CHECK (device_id <> related_device_id) ) `, ` CREATE TABLE IF NOT EXISTS milestone_hardware_child_devices ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), milestone_hardware_id TEXT NOT NULL, milestone_device_id TEXT NOT NULL, device_type TEXT NOT NULL, name TEXT NOT NULL DEFAULT '', display_name TEXT NOT NULL DEFAULT '', short_name TEXT NOT NULL DEFAULT '', enabled BOOLEAN NOT NULL DEFAULT true, recording_enabled BOOLEAN NOT NULL DEFAULT false, recording_storage_id TEXT NOT NULL DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE (milestone_hardware_id, milestone_device_id, device_type) ) `, `ALTER TABLE IF EXISTS milestone_hardware_child_devices ADD COLUMN IF NOT EXISTS recording_enabled BOOLEAN NOT NULL DEFAULT false`, `ALTER TABLE IF EXISTS milestone_hardware_child_devices ADD COLUMN IF NOT EXISTS recording_storage_id TEXT NOT NULL DEFAULT ''`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS server_folders_storage_root_label TEXT NOT NULL DEFAULT 'Storage D'`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS server_folders_storage_root_path TEXT NOT NULL DEFAULT 'D:/Milestone-Speicher'`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS server_folders_archive_root_label TEXT NOT NULL DEFAULT 'Archive E'`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS server_folders_archive_root_path TEXT NOT NULL DEFAULT 'E:/'`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS active_directory_server_url TEXT NOT NULL DEFAULT ''`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS active_directory_base_dn TEXT NOT NULL DEFAULT ''`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS active_directory_bind_username TEXT NOT NULL DEFAULT ''`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS active_directory_bind_password_encrypted BYTEA`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS active_directory_user_group TEXT NOT NULL DEFAULT 'SE_Sachbearbeitung'`, `ALTER TABLE IF EXISTS milestone_settings ADD COLUMN IF NOT EXISTS active_directory_skip_tls_verify BOOLEAN NOT NULL DEFAULT false`, ` CREATE TABLE IF NOT EXISTS calendar_events ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), title TEXT NOT NULL, start_at TIMESTAMP NOT NULL, end_at TIMESTAMP NOT NULL, all_day BOOLEAN NOT NULL DEFAULT false, location TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', color TEXT NOT NULL DEFAULT 'indigo' CHECK (color IN ('indigo', 'blue', 'emerald', 'amber', 'rose', 'slate')), recurrence TEXT NOT NULL DEFAULT 'none', recurrence_weekday INTEGER, recurrence_ordinal INTEGER, recurrence_exceptions JSONB NOT NULL DEFAULT '[]'::JSONB, created_by UUID REFERENCES users(id) ON DELETE SET NULL, updated_by UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT calendar_events_valid_range CHECK (end_at > start_at) ) `, ` DO $$ DECLARE constraint_name TEXT; BEGIN FOR constraint_name IN SELECT c.conname FROM pg_constraint c JOIN pg_class t ON t.oid = c.conrelid WHERE t.relname = 'calendar_events' AND c.contype = 'c' AND pg_get_constraintdef(c.oid) ILIKE '%recurrence%' LOOP EXECUTE format('ALTER TABLE calendar_events DROP CONSTRAINT %I', constraint_name); END LOOP; END $$ `, `ALTER TABLE IF EXISTS calendar_events ADD COLUMN IF NOT EXISTS recurrence_weekday INTEGER`, `ALTER TABLE IF EXISTS calendar_events ADD COLUMN IF NOT EXISTS recurrence_ordinal INTEGER`, `ALTER TABLE IF EXISTS calendar_events ADD COLUMN IF NOT EXISTS recurrence_exceptions JSONB NOT NULL DEFAULT '[]'::JSONB`, `UPDATE calendar_events SET recurrence_exceptions = '[]'::JSONB WHERE recurrence_exceptions IS NULL`, `CREATE INDEX IF NOT EXISTS idx_calendar_events_start_at ON calendar_events(start_at)`, } for _, query := range queries { if _, err := db.Exec(ctx, query); err != nil { return err } } return nil }