feat(cockpit): Modul-Baukasten – Einsatz-Cockpit frei zusammenstellbar (v1.5.0)
Jede Feuerwehr stellt ihr Cockpit selbst zusammen (Wunsch: modular & einfach): M0 – Zerlegt: - SOMA + Pendenzen als eigenständige Modul-Komponenten, gemeinsame Typen (journal/types.ts), einheitliche ModuleCard-Hülle M1 – Registry & Verwaltung: - Modul-Registry src/lib/modules.ts, Konfiguration pro Mandant in tenants.modulesConfig (JSONB, idempotente Migration) - API GET/PUT /api/tenant/modules (normalisiert + validiert via normalizeModules) - "Module"-Button im Journal (Admins): an/aus, Reihenfolge hoch/runter, eigene Module löschen M2 – Eigene Module: - Generisches Tabellen-Modul: frei definierbare Spalten (Text / Haken mit Zeitstempel / Auto-Zeit), max 8 Spalten - Generische Daten-API /api/projects/[id]/modules/[moduleId]/items (+ [itemId]), neue Tabelle module_items, Live-Sync über journal-refresh Events M3 – Feld-Vorlagen: - Checkliste, Atemschutz-Überwachung (Trupp/Druck/Zeit/Draussen), Kräfte vor Ort (Name/Funktion/seit/Weg), Lagemeldungen (Hauptbereich), leeres Modul mit Spalten-Editor Eingebaute Module (Journal/SOMA/Pendenzen) bleiben ohne Konfiguration exakt wie bisher — kaputte Configs fallen sicher auf den Standard zurück. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,8 @@ async function migrate() {
|
||||
// Journal
|
||||
`ALTER TABLE journal_entries ADD COLUMN IF NOT EXISTS "isCorrected" BOOLEAN DEFAULT false`,
|
||||
`ALTER TABLE journal_entries ADD COLUMN IF NOT EXISTS "correctionOfId" TEXT`,
|
||||
// Modul-Baukasten (Cockpit-Konfiguration pro Mandant)
|
||||
`ALTER TABLE tenants ADD COLUMN IF NOT EXISTS "modulesConfig" JSONB`,
|
||||
]
|
||||
let added = 0
|
||||
for (const sql of columnMigrations) {
|
||||
@@ -131,6 +133,17 @@ async function migrate() {
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"projectId" TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE
|
||||
)`,
|
||||
// Modul-Baukasten: generische Zeilen für Tabellen-Module
|
||||
`CREATE TABLE IF NOT EXISTS module_items (
|
||||
id TEXT PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
"moduleId" TEXT NOT NULL,
|
||||
data JSONB NOT NULL DEFAULT '{}',
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"projectId" TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE
|
||||
)`,
|
||||
`CREATE INDEX IF NOT EXISTS module_items_project_module_idx ON module_items("projectId", "moduleId")`,
|
||||
]
|
||||
for (const sql of tableMigrations) {
|
||||
try { await prisma.$executeRawUnsafe(sql) } catch (e) { /* table might already exist */ }
|
||||
|
||||
@@ -74,6 +74,8 @@ model Tenant {
|
||||
notes String?
|
||||
hiddenIconIds String[] @default([])
|
||||
journalSuggestions String[] @default([])
|
||||
// Modul-Baukasten: Cockpit-Konfiguration (siehe src/lib/modules.ts). NULL = Standard.
|
||||
modulesConfig Json?
|
||||
|
||||
// Privacy consent
|
||||
privacyAccepted Boolean @default(false)
|
||||
@@ -193,6 +195,7 @@ model Project {
|
||||
journalPendenzen JournalPendenz[]
|
||||
exerciseGoals ExerciseGoal[]
|
||||
rapports Rapport[]
|
||||
moduleItems ModuleItem[]
|
||||
|
||||
@@map("projects")
|
||||
}
|
||||
@@ -349,6 +352,24 @@ model JournalPendenz {
|
||||
@@map("journal_pendenzen")
|
||||
}
|
||||
|
||||
// Generischer Datenspeicher für Tabellen-Module (Modul-Baukasten).
|
||||
// data enthält die Zellwerte gemäss Spaltendefinition des Moduls,
|
||||
// z.B. { "trupp": "Trupp 1", "druck": "280", "out": true, "outAt": "..." }
|
||||
model ModuleItem {
|
||||
id String @id @default(uuid())
|
||||
moduleId String
|
||||
data Json @default("{}")
|
||||
sortOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
projectId String
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([projectId, moduleId])
|
||||
@@map("module_items")
|
||||
}
|
||||
|
||||
model JournalCheckTemplate {
|
||||
id String @id @default(uuid())
|
||||
label String
|
||||
|
||||
Reference in New Issue
Block a user