feat: add issue kanban/attachments/deadlines, dashboard widget DnD, and checklisten system
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
-- Migration 066: Issue due dates + file attachments
|
||||
-- Adds faellig_am column to issues and creates issue_dateien table.
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 1. Add due date column to issues
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
ALTER TABLE issues ADD COLUMN IF NOT EXISTS faellig_am TIMESTAMPTZ;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_issues_faellig_am ON issues(faellig_am) WHERE faellig_am IS NOT NULL;
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 2. Issue file attachments
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
CREATE TABLE IF NOT EXISTS issue_dateien (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
issue_id INT NOT NULL REFERENCES issues(id) ON DELETE CASCADE,
|
||||
dateiname VARCHAR(500) NOT NULL,
|
||||
dateipfad VARCHAR(1000) NOT NULL,
|
||||
dateityp VARCHAR(100),
|
||||
dateigroesse BIGINT,
|
||||
hochgeladen_von UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
hochgeladen_am TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_issue_dateien_issue_id ON issue_dateien(issue_id);
|
||||
46
backend/src/database/migrations/067_fahrzeug_typen.sql
Normal file
46
backend/src/database/migrations/067_fahrzeug_typen.sql
Normal file
@@ -0,0 +1,46 @@
|
||||
-- Migration 067: Fahrzeug-Typen (Vehicle Types)
|
||||
-- Dynamic vehicle type table with many-to-many junction to fahrzeuge.
|
||||
-- Seeds initial types from existing fahrzeuge.typ_schluessel values.
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 1. Fahrzeug-Typen
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fahrzeug_typen (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL UNIQUE,
|
||||
beschreibung TEXT,
|
||||
icon VARCHAR(50),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 2. Junction table (many-to-many)
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fahrzeug_fahrzeug_typen (
|
||||
fahrzeug_id UUID NOT NULL REFERENCES fahrzeuge(id) ON DELETE CASCADE,
|
||||
fahrzeug_typ_id INT NOT NULL REFERENCES fahrzeug_typen(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (fahrzeug_id, fahrzeug_typ_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_fft_fahrzeug_id ON fahrzeug_fahrzeug_typen(fahrzeug_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_fft_typ_id ON fahrzeug_fahrzeug_typen(fahrzeug_typ_id);
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 3. Seed types from existing typ_schluessel values
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT INTO fahrzeug_typen (name)
|
||||
SELECT DISTINCT typ_schluessel
|
||||
FROM fahrzeuge
|
||||
WHERE typ_schluessel IS NOT NULL AND typ_schluessel != ''
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
-- Populate junction table from existing assignments
|
||||
INSERT INTO fahrzeug_fahrzeug_typen (fahrzeug_id, fahrzeug_typ_id)
|
||||
SELECT f.id, ft.id
|
||||
FROM fahrzeuge f
|
||||
JOIN fahrzeug_typen ft ON ft.name = f.typ_schluessel
|
||||
WHERE f.typ_schluessel IS NOT NULL AND f.typ_schluessel != ''
|
||||
ON CONFLICT DO NOTHING;
|
||||
113
backend/src/database/migrations/068_checklisten.sql
Normal file
113
backend/src/database/migrations/068_checklisten.sql
Normal file
@@ -0,0 +1,113 @@
|
||||
-- Migration 068: Checklisten (Checklist system)
|
||||
-- Templates, vehicle-specific items, execution records, and due date tracking.
|
||||
-- Depends on: 067_fahrzeug_typen.sql (fahrzeug_typen table)
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 1. Checklist-Vorlagen (Templates)
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
CREATE TABLE IF NOT EXISTS checklist_vorlagen (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
fahrzeug_typ_id INT REFERENCES fahrzeug_typen(id) ON DELETE SET NULL,
|
||||
intervall VARCHAR(20) CHECK (intervall IN ('weekly','monthly','yearly','custom')),
|
||||
intervall_tage INT,
|
||||
beschreibung TEXT,
|
||||
aktiv BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 2. Vorlage Items (Template line items)
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
CREATE TABLE IF NOT EXISTS checklist_vorlage_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
vorlage_id INT NOT NULL REFERENCES checklist_vorlagen(id) ON DELETE CASCADE,
|
||||
bezeichnung VARCHAR(500) NOT NULL,
|
||||
beschreibung TEXT,
|
||||
pflicht BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
sort_order INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_cvi_vorlage_id ON checklist_vorlage_items(vorlage_id);
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 3. Fahrzeug-spezifische Checklist Items
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fahrzeug_checklist_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
fahrzeug_id UUID NOT NULL REFERENCES fahrzeuge(id) ON DELETE CASCADE,
|
||||
bezeichnung VARCHAR(500) NOT NULL,
|
||||
beschreibung TEXT,
|
||||
pflicht BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
aktiv BOOLEAN NOT NULL DEFAULT TRUE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_fci_fahrzeug_id ON fahrzeug_checklist_items(fahrzeug_id);
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 4. Checklist-Ausführungen (Execution records)
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
CREATE TABLE IF NOT EXISTS checklist_ausfuehrungen (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
fahrzeug_id UUID NOT NULL REFERENCES fahrzeuge(id) ON DELETE CASCADE,
|
||||
vorlage_id INT REFERENCES checklist_vorlagen(id) ON DELETE SET NULL,
|
||||
status VARCHAR(30) NOT NULL DEFAULT 'offen'
|
||||
CHECK (status IN ('offen','abgeschlossen','unvollstaendig','freigegeben')),
|
||||
ausgefuehrt_von UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
ausgefuehrt_am TIMESTAMPTZ,
|
||||
freigegeben_von UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
freigegeben_am TIMESTAMPTZ,
|
||||
notizen TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ca_fahrzeug_id ON checklist_ausfuehrungen(fahrzeug_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_ca_vorlage_id ON checklist_ausfuehrungen(vorlage_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_ca_status ON checklist_ausfuehrungen(status);
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 5. Ausführung Items (Execution line items / answers)
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
CREATE TABLE IF NOT EXISTS checklist_ausfuehrung_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
ausfuehrung_id UUID NOT NULL REFERENCES checklist_ausfuehrungen(id) ON DELETE CASCADE,
|
||||
vorlage_item_id INT REFERENCES checklist_vorlage_items(id) ON DELETE SET NULL,
|
||||
fahrzeug_item_id INT REFERENCES fahrzeug_checklist_items(id) ON DELETE SET NULL,
|
||||
bezeichnung VARCHAR(500),
|
||||
ergebnis VARCHAR(20) CHECK (ergebnis IN ('ok','nok','na')),
|
||||
kommentar TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_cai_ausfuehrung_id ON checklist_ausfuehrung_items(ausfuehrung_id);
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 6. Fälligkeiten (Due date tracking per vehicle+template)
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
CREATE TABLE IF NOT EXISTS checklist_faelligkeit (
|
||||
fahrzeug_id UUID NOT NULL REFERENCES fahrzeuge(id) ON DELETE CASCADE,
|
||||
vorlage_id INT NOT NULL REFERENCES checklist_vorlagen(id) ON DELETE CASCADE,
|
||||
naechste_faellig_am DATE NOT NULL,
|
||||
letzte_ausfuehrung_id UUID REFERENCES checklist_ausfuehrungen(id) ON DELETE SET NULL,
|
||||
PRIMARY KEY (fahrzeug_id, vorlage_id)
|
||||
);
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 7. Auto-update updated_at trigger for checklist_vorlagen
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_checklist_vorlagen_updated') THEN
|
||||
CREATE TRIGGER trg_checklist_vorlagen_updated BEFORE UPDATE ON checklist_vorlagen
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
END IF;
|
||||
END $$;
|
||||
@@ -0,0 +1,78 @@
|
||||
-- Migration 069: Checklisten permissions
|
||||
-- Adds checklisten feature group and permissions, seeds group_permissions.
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 1. Feature group
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT INTO feature_groups (id, label, sort_order) VALUES
|
||||
('checklisten', 'Checklisten', 15)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 2. Permissions
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT INTO permissions (id, feature_group_id, label, description, sort_order) VALUES
|
||||
('checklisten:view', 'checklisten', 'Ansehen', 'Checklisten und Ausführungen einsehen', 1),
|
||||
('checklisten:execute', 'checklisten', 'Ausfüllen', 'Checklisten ausfüllen und abschließen', 2),
|
||||
('checklisten:approve', 'checklisten', 'Freigeben', 'Checklisten nach Prüfung freigeben', 3),
|
||||
('checklisten:manage_templates', 'checklisten', 'Vorlagen verwalten', 'Vorlagen und Fahrzeugtypen erstellen und bearbeiten', 4),
|
||||
('checklisten:widget', 'checklisten', 'Widget', 'Checklisten-Widget im Dashboard anzeigen', 5)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- 3. Seed group permissions
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- dashboard_admin has hardwired full access (not seeded).
|
||||
|
||||
-- Kommando: all permissions
|
||||
INSERT INTO group_permissions (authentik_group, permission_id) VALUES
|
||||
('dashboard_kommando', 'checklisten:view'),
|
||||
('dashboard_kommando', 'checklisten:execute'),
|
||||
('dashboard_kommando', 'checklisten:approve'),
|
||||
('dashboard_kommando', 'checklisten:manage_templates'),
|
||||
('dashboard_kommando', 'checklisten:widget')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Fahrmeister: view, execute, approve, widget (vehicle specialist)
|
||||
INSERT INTO group_permissions (authentik_group, permission_id) VALUES
|
||||
('dashboard_fahrmeister', 'checklisten:view'),
|
||||
('dashboard_fahrmeister', 'checklisten:execute'),
|
||||
('dashboard_fahrmeister', 'checklisten:approve'),
|
||||
('dashboard_fahrmeister', 'checklisten:widget')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Zeugmeister: view, execute, approve, widget (equipment specialist)
|
||||
INSERT INTO group_permissions (authentik_group, permission_id) VALUES
|
||||
('dashboard_zeugmeister', 'checklisten:view'),
|
||||
('dashboard_zeugmeister', 'checklisten:execute'),
|
||||
('dashboard_zeugmeister', 'checklisten:approve'),
|
||||
('dashboard_zeugmeister', 'checklisten:widget')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Chargen: view, execute, widget
|
||||
INSERT INTO group_permissions (authentik_group, permission_id) VALUES
|
||||
('dashboard_chargen', 'checklisten:view'),
|
||||
('dashboard_chargen', 'checklisten:execute'),
|
||||
('dashboard_chargen', 'checklisten:widget')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Moderator: view, widget
|
||||
INSERT INTO group_permissions (authentik_group, permission_id) VALUES
|
||||
('dashboard_moderator', 'checklisten:view'),
|
||||
('dashboard_moderator', 'checklisten:widget')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Atemschutz: view, execute, widget
|
||||
INSERT INTO group_permissions (authentik_group, permission_id) VALUES
|
||||
('dashboard_atemschutz', 'checklisten:view'),
|
||||
('dashboard_atemschutz', 'checklisten:execute'),
|
||||
('dashboard_atemschutz', 'checklisten:widget')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Mitglied: view, widget
|
||||
INSERT INTO group_permissions (authentik_group, permission_id) VALUES
|
||||
('dashboard_mitglied', 'checklisten:view'),
|
||||
('dashboard_mitglied', 'checklisten:widget')
|
||||
ON CONFLICT DO NOTHING;
|
||||
Reference in New Issue
Block a user