-- Migration: 003_qualifications_fixed.sql -- Qualifikationen & Zertifikate Modul (korrigiert für INTEGER IDs) -- Verfügbare Qualifikationstypen (System-weit) CREATE TABLE IF NOT EXISTS qualification_types ( id SERIAL PRIMARY KEY, key VARCHAR(50) UNIQUE NOT NULL, name VARCHAR(100) NOT NULL, description TEXT, category VARCHAR(50) NOT NULL DEFAULT 'general', has_expiry BOOLEAN DEFAULT true, validity_months INTEGER, is_required BOOLEAN DEFAULT false, icon VARCHAR(10) DEFAULT '📜', sort_order INTEGER DEFAULT 0, is_system BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT NOW() ); -- Standard-Qualifikationstypen einfügen (nur wenn Tabelle leer) INSERT INTO qualification_types (key, name, description, category, has_expiry, validity_months, is_required, icon, sort_order, is_system) SELECT * FROM (VALUES ('sachkunde_34a', '§34a Sachkundenachweis', 'Sachkundeprüfung nach §34a GewO', 'legal', false, NULL::int, true, '📋', 1, true), ('unterrichtung_34a', '§34a Unterrichtungsnachweis', '40-Stunden Unterrichtung nach §34a GewO', 'legal', false, NULL::int, false, '📋', 2, true), ('waffensachkunde', 'Waffensachkunde', 'Sachkundenachweis für Waffenbesitz', 'weapons', false, NULL::int, false, '🔫', 10, true), ('waffenschein_gruen', 'Waffenschein (grün)', 'Waffenschein für Schusswaffen', 'weapons', true, 36, false, '🟢', 11, true), ('waffenschein_gelb', 'Waffenschein (gelb)', 'Kleiner Waffenschein', 'weapons', true, 36, false, '🟡', 12, true), ('erste_hilfe', 'Erste-Hilfe-Kurs', 'Erste-Hilfe-Ausbildung (9 UE)', 'safety', true, 24, false, '🏥', 20, true), ('brandschutzhelfer', 'Brandschutzhelfer', 'Ausbildung zum Brandschutzhelfer', 'safety', true, 36, false, '🔥', 21, true), ('evakuierungshelfer', 'Evakuierungshelfer', 'Ausbildung zum Evakuierungshelfer', 'safety', true, 24, false, '🚪', 22, true), ('defibrillator', 'AED/Defibrillator', 'Einweisung Automatisierter Externer Defibrillator', 'safety', true, 24, false, '💓', 23, true), ('fuehrerschein_b', 'Führerschein Klasse B', 'PKW Führerschein', 'driving', true, NULL::int, false, '🚗', 30, true), ('fuehrerschein_c', 'Führerschein Klasse C', 'LKW Führerschein', 'driving', true, 60, false, '🚛', 31, true), ('fuehrerschein_d', 'Führerschein Klasse D', 'Bus Führerschein', 'driving', true, 60, false, '🚌', 32, true), ('personenschutz', 'Personenschutz', 'Ausbildung zum Personenschützer', 'special', false, NULL::int, false, '🛡️', 40, true), ('hundefuehrer', 'Diensthundeführer', 'Ausbildung zum Diensthundeführer', 'special', true, 12, false, '🐕', 41, true), ('intervention', 'Interventionskraft', 'Ausbildung zur Interventionskraft (IK)', 'special', false, NULL::int, false, '⚡', 42, true), ('nsk', 'NSK (Notruf-Service-Kraft)', 'Notruf- und Service-Leitstelle', 'special', false, NULL::int, false, '📞', 43, true), ('sprache_englisch', 'Englisch', 'Englischkenntnisse', 'language', false, NULL::int, false, '🇬🇧', 50, true), ('sprache_franzoesisch', 'Französisch', 'Französischkenntnisse', 'language', false, NULL::int, false, '🇫🇷', 51, true), ('sprache_russisch', 'Russisch', 'Russischkenntnisse', 'language', false, NULL::int, false, '🇷🇺', 52, true), ('sprache_tuerkisch', 'Türkisch', 'Türkischkenntnisse', 'language', false, NULL::int, false, '🇹🇷', 53, true), ('sprache_arabisch', 'Arabisch', 'Arabischkenntnisse', 'language', false, NULL::int, false, '🇸🇦', 54, true) ) AS v(key, name, description, category, has_expiry, validity_months, is_required, icon, sort_order, is_system) WHERE NOT EXISTS (SELECT 1 FROM qualification_types LIMIT 1); -- Custom Qualifikationstypen pro Organisation CREATE TABLE IF NOT EXISTS org_qualification_types ( id SERIAL PRIMARY KEY, org_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, key VARCHAR(50) NOT NULL, name VARCHAR(100) NOT NULL, description TEXT, category VARCHAR(50) DEFAULT 'custom', has_expiry BOOLEAN DEFAULT true, validity_months INTEGER, icon VARCHAR(10) DEFAULT '📜', sort_order INTEGER DEFAULT 100, created_at TIMESTAMP DEFAULT NOW(), UNIQUE(org_id, key) ); -- Mitarbeiter-Qualifikationen CREATE TABLE IF NOT EXISTS employee_qualifications ( id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, org_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, qualification_type_id INTEGER REFERENCES qualification_types(id), org_qualification_type_id INTEGER REFERENCES org_qualification_types(id), issued_date DATE, expiry_date DATE, issuer VARCHAR(255), certificate_number VARCHAR(100), level VARCHAR(50), document_url TEXT, document_name VARCHAR(255), status VARCHAR(20) DEFAULT 'active', verified_by INTEGER REFERENCES users(id), verified_at TIMESTAMP, notes TEXT, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), CONSTRAINT chk_qualification_type CHECK ( (qualification_type_id IS NOT NULL AND org_qualification_type_id IS NULL) OR (qualification_type_id IS NULL AND org_qualification_type_id IS NOT NULL) ) ); -- Indices CREATE INDEX IF NOT EXISTS idx_emp_qual_user ON employee_qualifications(user_id); CREATE INDEX IF NOT EXISTS idx_emp_qual_org ON employee_qualifications(org_id); CREATE INDEX IF NOT EXISTS idx_emp_qual_expiry ON employee_qualifications(expiry_date); CREATE INDEX IF NOT EXISTS idx_emp_qual_status ON employee_qualifications(status); -- Erinnerungen CREATE TABLE IF NOT EXISTS qualification_reminders ( id SERIAL PRIMARY KEY, employee_qualification_id INTEGER NOT NULL REFERENCES employee_qualifications(id) ON DELETE CASCADE, reminder_date DATE NOT NULL, days_before INTEGER NOT NULL, sent BOOLEAN DEFAULT false, sent_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_qual_reminder_date ON qualification_reminders(reminder_date, sent);