Add Objects/Sites module - DB schema
This commit is contained in:
110
db/migrations/003_qualifications_fixed.sql
Normal file
110
db/migrations/003_qualifications_fixed.sql
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
-- 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);
|
||||||
179
db/migrations/004_objects.sql
Normal file
179
db/migrations/004_objects.sql
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
-- Migration: 004_objects.sql
|
||||||
|
-- Objektverwaltung / Wachobjekte
|
||||||
|
|
||||||
|
-- Wachobjekte/Standorte
|
||||||
|
CREATE TABLE IF NOT EXISTS objects (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
org_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
-- Basisdaten
|
||||||
|
name VARCHAR(200) NOT NULL,
|
||||||
|
short_name VARCHAR(50),
|
||||||
|
object_number VARCHAR(50), -- Interne Objektnummer
|
||||||
|
|
||||||
|
-- Typ
|
||||||
|
object_type VARCHAR(50) DEFAULT 'other', -- building, event, construction, retail, industrial, residential, other
|
||||||
|
|
||||||
|
-- Adresse
|
||||||
|
street VARCHAR(200),
|
||||||
|
house_number VARCHAR(20),
|
||||||
|
postal_code VARCHAR(10),
|
||||||
|
city VARCHAR(100),
|
||||||
|
country VARCHAR(50) DEFAULT 'Deutschland',
|
||||||
|
|
||||||
|
-- Koordinaten (für Karte/GPS)
|
||||||
|
latitude DECIMAL(10, 8),
|
||||||
|
longitude DECIMAL(11, 8),
|
||||||
|
|
||||||
|
-- Kontaktdaten Objekt
|
||||||
|
phone VARCHAR(50),
|
||||||
|
email VARCHAR(255),
|
||||||
|
|
||||||
|
-- Details
|
||||||
|
description TEXT,
|
||||||
|
size_sqm INTEGER, -- Größe in m²
|
||||||
|
floors INTEGER, -- Anzahl Etagen
|
||||||
|
|
||||||
|
-- Zugang
|
||||||
|
access_info TEXT, -- Zugangsinfos (Schlüssel, Codes, etc.)
|
||||||
|
parking_info TEXT, -- Parkhinweise
|
||||||
|
|
||||||
|
-- Kundenreferenz
|
||||||
|
customer_id INTEGER, -- Später für CRM-Modul
|
||||||
|
customer_name VARCHAR(200),
|
||||||
|
|
||||||
|
-- Status
|
||||||
|
status VARCHAR(20) DEFAULT 'active', -- active, inactive, archived
|
||||||
|
|
||||||
|
-- Bilder
|
||||||
|
image_url TEXT,
|
||||||
|
|
||||||
|
created_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
created_by INTEGER REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_objects_org ON objects(org_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_objects_status ON objects(status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_objects_type ON objects(object_type);
|
||||||
|
|
||||||
|
-- Ansprechpartner pro Objekt
|
||||||
|
CREATE TABLE IF NOT EXISTS object_contacts (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
object_id INTEGER NOT NULL REFERENCES objects(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
-- Kontaktdaten
|
||||||
|
name VARCHAR(200) NOT NULL,
|
||||||
|
role VARCHAR(100), -- z.B. "Hausmeister", "Objektleiter", "Notfall"
|
||||||
|
company VARCHAR(200),
|
||||||
|
phone VARCHAR(50),
|
||||||
|
mobile VARCHAR(50),
|
||||||
|
email VARCHAR(255),
|
||||||
|
|
||||||
|
-- Verfügbarkeit
|
||||||
|
availability TEXT, -- z.B. "Mo-Fr 8-17 Uhr"
|
||||||
|
|
||||||
|
-- Priorität
|
||||||
|
is_primary BOOLEAN DEFAULT false,
|
||||||
|
is_emergency BOOLEAN DEFAULT false, -- Notfallkontakt
|
||||||
|
|
||||||
|
notes TEXT,
|
||||||
|
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_object_contacts_object ON object_contacts(object_id);
|
||||||
|
|
||||||
|
-- Dienstanweisungen pro Objekt
|
||||||
|
CREATE TABLE IF NOT EXISTS object_instructions (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
object_id INTEGER NOT NULL REFERENCES objects(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
title VARCHAR(200) NOT NULL,
|
||||||
|
category VARCHAR(50) DEFAULT 'general', -- general, patrol, emergency, access, reporting
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
|
||||||
|
-- Sortierung/Priorität
|
||||||
|
sort_order INTEGER DEFAULT 0,
|
||||||
|
is_critical BOOLEAN DEFAULT false, -- Wichtig hervorheben
|
||||||
|
|
||||||
|
-- Version
|
||||||
|
version INTEGER DEFAULT 1,
|
||||||
|
|
||||||
|
created_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
created_by INTEGER REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_object_instructions_object ON object_instructions(object_id);
|
||||||
|
|
||||||
|
-- Dokumente pro Objekt (Lagepläne, Schlüssellisten, etc.)
|
||||||
|
CREATE TABLE IF NOT EXISTS object_documents (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
object_id INTEGER NOT NULL REFERENCES objects(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
name VARCHAR(200) NOT NULL,
|
||||||
|
document_type VARCHAR(50), -- floorplan, keylist, contract, photo, other
|
||||||
|
file_url TEXT NOT NULL,
|
||||||
|
file_size INTEGER,
|
||||||
|
mime_type VARCHAR(100),
|
||||||
|
|
||||||
|
description TEXT,
|
||||||
|
|
||||||
|
uploaded_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
uploaded_by INTEGER REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_object_documents_object ON object_documents(object_id);
|
||||||
|
|
||||||
|
-- Checkpoints/Kontrollpunkte pro Objekt (für Wächterkontrolle)
|
||||||
|
CREATE TABLE IF NOT EXISTS object_checkpoints (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
object_id INTEGER NOT NULL REFERENCES objects(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
name VARCHAR(100) NOT NULL,
|
||||||
|
location_description TEXT, -- Wo genau ist der Punkt
|
||||||
|
|
||||||
|
-- QR/NFC Code
|
||||||
|
code VARCHAR(100) UNIQUE, -- Der zu scannende Code
|
||||||
|
code_type VARCHAR(20) DEFAULT 'qr', -- qr, nfc, manual
|
||||||
|
|
||||||
|
-- Position in Rundgang
|
||||||
|
sort_order INTEGER DEFAULT 0,
|
||||||
|
|
||||||
|
-- GPS (optional)
|
||||||
|
latitude DECIMAL(10, 8),
|
||||||
|
longitude DECIMAL(11, 8),
|
||||||
|
|
||||||
|
-- Status
|
||||||
|
active BOOLEAN DEFAULT true,
|
||||||
|
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_object_checkpoints_object ON object_checkpoints(object_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_object_checkpoints_code ON object_checkpoints(code);
|
||||||
|
|
||||||
|
-- Anforderungen pro Objekt (welche Qualifikationen werden benötigt)
|
||||||
|
CREATE TABLE IF NOT EXISTS object_requirements (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
object_id INTEGER NOT NULL REFERENCES objects(id) ON DELETE CASCADE,
|
||||||
|
qualification_type_id INTEGER REFERENCES qualification_types(id),
|
||||||
|
org_qualification_type_id INTEGER REFERENCES org_qualification_types(id),
|
||||||
|
is_mandatory BOOLEAN DEFAULT true,
|
||||||
|
notes TEXT,
|
||||||
|
|
||||||
|
CONSTRAINT chk_object_req_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)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_object_requirements_object ON object_requirements(object_id);
|
||||||
|
|
||||||
|
-- Objekt-Typen Referenz
|
||||||
|
COMMENT ON TABLE objects IS 'Wachobjekte/Standorte - object_type: building, event, construction, retail, industrial, residential, other';
|
||||||
|
COMMENT ON TABLE object_contacts IS 'Ansprechpartner pro Objekt';
|
||||||
|
COMMENT ON TABLE object_instructions IS 'Dienstanweisungen - category: general, patrol, emergency, access, reporting';
|
||||||
|
COMMENT ON TABLE object_documents IS 'Dokumente - document_type: floorplan, keylist, contract, photo, other';
|
||||||
|
COMMENT ON TABLE object_checkpoints IS 'Kontrollpunkte für Wächterkontrolle';
|
||||||
Reference in New Issue
Block a user