-- ITSM-Plattform: PostgreSQL-Schema -- Mandantenfaehig (mehrere Organisationen auf einer Instanz, Daten per tenant_id getrennt). -- Enthaelt audit_log fuer Nachvollziehbarkeit gemaess ISO 27001 A.12.4 / DSGVO Art. 30. CREATE TABLE IF NOT EXISTS tenants ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), dsb_name TEXT, -- Datenschutzbeauftragter/Kontakt dsb_email TEXT, retention_tickets_days INTEGER NOT NULL DEFAULT 1095, -- DSGVO Speicherbegrenzung (Default ~3 Jahre) retention_audit_days INTEGER NOT NULL DEFAULT 1825, -- Audit-Log-Aufbewahrung (Default ~5 Jahre) sla_antwort_minuten INTEGER NOT NULL DEFAULT 480, sla_loesung_minuten INTEGER NOT NULL DEFAULT 2880 ); CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, tenant_id INTEGER NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, email TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'agent', -- 'admin' | 'agent' active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), last_login_at TIMESTAMPTZ ); CREATE TABLE IF NOT EXISTS services ( id SERIAL PRIMARY KEY, tenant_id INTEGER NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, name TEXT NOT NULL, beschreibung TEXT, kategorie TEXT, gebucht BOOLEAN NOT NULL DEFAULT TRUE, endpoint TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS tickets ( id SERIAL PRIMARY KEY, tenant_id INTEGER NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, ticket_nr TEXT NOT NULL, titel TEXT NOT NULL, beschreibung TEXT, service_id INTEGER REFERENCES services(id) ON DELETE SET NULL, status TEXT NOT NULL DEFAULT 'Offen', prioritaet TEXT NOT NULL DEFAULT 'Mittel', kategorie TEXT NOT NULL DEFAULT 'Task', zugewiesen_an TEXT, ersteller_id INTEGER REFERENCES users(id) ON DELETE SET NULL, fortschritt INTEGER NOT NULL DEFAULT 0, sla_antwort_minuten INTEGER, sla_loesung_minuten INTEGER, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE (tenant_id, ticket_nr) ); CREATE TABLE IF NOT EXISTS ticket_timeline ( id SERIAL PRIMARY KEY, ticket_id INTEGER NOT NULL REFERENCES tickets(id) ON DELETE CASCADE, tenant_id INTEGER NOT NULL, zeit TIMESTAMPTZ NOT NULL DEFAULT now(), akteur TEXT, text TEXT ); CREATE TABLE IF NOT EXISTS audit_log ( id SERIAL PRIMARY KEY, tenant_id INTEGER REFERENCES tenants(id) ON DELETE CASCADE, user_id INTEGER REFERENCES users(id) ON DELETE SET NULL, zeit TIMESTAMPTZ NOT NULL DEFAULT now(), aktion TEXT NOT NULL, entity_typ TEXT, entity_id TEXT, details JSONB, ip TEXT ); CREATE INDEX IF NOT EXISTS idx_tickets_tenant_status ON tickets (tenant_id, status); CREATE INDEX IF NOT EXISTS idx_tickets_tenant_kategorie ON tickets (tenant_id, kategorie); CREATE INDEX IF NOT EXISTS idx_timeline_ticket ON ticket_timeline (ticket_id); CREATE INDEX IF NOT EXISTS idx_audit_tenant_zeit ON audit_log (tenant_id, zeit DESC); CREATE INDEX IF NOT EXISTS idx_services_tenant ON services (tenant_id); CREATE INDEX IF NOT EXISTS idx_users_tenant ON users (tenant_id);