Lageplan - Feuerwehr Krokier-App
Digitale Lageplan-Applikation für Schweizer Feuerwehren zur Einsatzdokumentation und taktischen Lagedarstellung. Multi-Tenant SaaS mit Karte, Journal, Symbolbibliothek und Druckexport.
Architektur-Übersicht
Tech Stack
| Schicht |
Technologie |
Zweck |
| Frontend |
Next.js 14, React 18, TypeScript |
SSR + SPA |
| UI |
TailwindCSS, shadcn/ui, Lucide Icons |
Styling + Komponenten |
| Karte |
MapLibre GL JS |
OSM + Satellit Tiles |
| Drag & Drop |
react-dnd + TouchBackend |
Symbol-Platzierung (Desktop + Mobile) |
| Datenbank |
PostgreSQL 16 + Prisma ORM |
Relationale Daten |
| Object Storage |
MinIO (S3-kompatibel) |
Icon-Upload |
| Auth |
JWT (jose) + httpOnly Cookies |
Session-Management |
| Validierung |
Zod |
Input-Validierung auf API-Ebene |
| E-Mail |
Nodemailer |
Passwort-Reset, Kontaktformular |
| PDF |
jsPDF + html2canvas |
Kartenexport |
| Container |
Docker Compose |
Deployment |
Features
Karte
- OSM + Satellitenansicht — Layer-Toggle oben rechts
- Zeichenwerkzeuge — Punkt, Linie, Polygon, Rechteck, Kreis, Pfeil, Freihand, Text, Gefahrenzone
- Symbolbibliothek — 22+ FKS/BABS-konforme Feuerwehr-Symbole in 9 Kategorien
- Drag & Drop + Tap-to-Place — Symbole auf Karte platzieren (Desktop + Touch)
- Symbol-Bearbeitung — Rechtsklick: Skalierung (0.3x-4x), Rotation (0-360°)
- Messwerkzeug — Distanzmessung mit Höhenprofil (Open-Meteo API), Druckverlust-Berechnung für Feuerwehrschläuche
- GPS-Standort — Automatische Geolocation bei App-Start
- Kartenposition persistent — Bleibt beim Tab-Wechsel und Projekt-Erstellung erhalten
- Offline-Tiles — Service Worker cached OSM-Tiles
Einsatz-Journal
- Zeitprotokoll — Einträge mit Zeitstempel, Was, Wer, Erledigt-Status
- SOMA-Checkliste — Vordefinierte Prüfpunkte (Ja/Ok Spalten), aus Templates initialisiert
- Pendenzen — Offene Aufgaben mit Was/Wer/Wann
- Druckansicht — Journal als formatiertes Dokument drucken
Einsatz-Verwaltung
- Erstellen/Laden/Löschen — Über Menü → "Einsätze verwalten"
- Auto-Save — Alle 30 Sekunden automatisch in DB + localStorage
- Export — PNG, PDF (mit Metadaten-Header), GeoJSON
- Sperren — Projekte können gesperrt werden (nur SERVER_ADMIN kann entsperren)
Admin-Bereich (/admin)
- Benutzer — CRUD, Rollen zuweisen, Passwort zurücksetzen
- Tenants — Organisationen verwalten, Mitglieder, Abo-Status
- Symbole — Upload (PNG/SVG/JPEG/WebP, max 5MB), Kategorien
- Schlauchtypen — Konfigurierbare Druckverlust-Parameter
- System — SMTP-Einstellungen, Kontakt-E-Mail, Test-E-Mail
Sicherheit & Multi-Tenancy
- 4 Rollen — SERVER_ADMIN, TENANT_ADMIN, OPERATOR, VIEWER
- Tenant-Isolation — Jeder Tenant sieht nur eigene Projekte/Benutzer
- JWT httpOnly Cookies — Kein Token im localStorage
- Zod-Validierung — Alle API-Inputs validiert
- IDOR-Schutz — Sub-Ressourcen (Journal, CheckItems) werden gegen Projekt-Zugehörigkeit geprüft
- Passwort-Hashing — bcrypt mit 12 Rounds
- Reset-Token — Kryptographisch sicher (32 Bytes), 1h Ablauf, nie in API-Response exponiert
Projekt-Struktur
Datenbank-Schema (Prisma)
Kern-Models
- Tenant — Organisation (Feuerwehr), mit Abo-Plan, Limits, Logo
- User — E-Mail/Passwort, Rolle, Reset-Token
- TenantMembership — User ↔ Tenant Zuordnung (M:N)
- Project — Einsatz mit Titel, Ort, mapCenter/mapZoom, isLocked
- Feature — GeoJSON-Zeichnung (Geometrie + Properties als JSON)
Journal-Models
- JournalEntry — Zeitprotokoll-Eintrag (time, what, who, done)
- JournalCheckItem — SOMA-Checkliste (label, confirmed, ok)
- JournalPendenz — Offene Aufgabe (what, who, whenHow, done)
- JournalCheckTemplate — Vorlagen für Checklisten-Punkte
Konfigurations-Models
- IconCategory — Symbolkategorie (Feuer, Wasser, Gefahrstoffe, ...)
- IconAsset — Hochgeladenes Symbol (fileKey → MinIO)
- HoseType — Schlauchtyp mit Druckverlust-Parametern
- SystemSetting — Key-Value Store (SMTP, Kontakt-E-Mail)
Rollen & Berechtigungen
| Aktion |
SERVER_ADMIN |
TENANT_ADMIN |
OPERATOR |
VIEWER |
| Alle Projekte sehen |
✓ |
- |
- |
- |
| Tenant-Projekte sehen |
✓ |
✓ |
✓ |
✓ |
| Zeichnen/Bearbeiten |
✓ |
✓ |
✓ |
- |
| Projekt erstellen |
✓ |
✓ |
✓ |
- |
| Projekt löschen |
✓ |
✓ |
Eigene |
- |
| Benutzer verwalten |
Alle |
Eigener Tenant |
- |
- |
| Tenants verwalten |
✓ |
- |
- |
- |
| System-Einstellungen |
✓ |
- |
- |
- |
Schnellstart
Voraussetzungen
Installation
App: http://localhost:3000
Standard-Logins (nach Seed)
Umgebungsvariablen
| Variable |
Beschreibung |
Default |
DATABASE_URL |
PostgreSQL Connection String |
siehe .env.example |
NEXTAUTH_SECRET |
JWT Secret (min. 32 Zeichen!) |
- |
MINIO_ENDPOINT |
MinIO Host |
localhost |
MINIO_PORT |
MinIO API Port |
9000 |
MINIO_ACCESS_KEY |
MinIO Zugangsdaten |
minioadmin |
MINIO_SECRET_KEY |
MinIO Passwort |
minioadmin123 |
MINIO_BUCKET |
Bucket Name |
lageplan-icons |
MINIO_PUBLIC_URL |
Öffentliche MinIO URL |
http://localhost:9002 |
Docker Services
| Service |
Port |
Beschreibung |
web |
3000 |
Next.js App |
db |
5432 |
PostgreSQL 16 |
minio |
9002 (API), 9003 (Console) |
MinIO Object Storage |
Produktion
Security-Hinweise
NEXTAUTH_SECRET muss in Produktion gesetzt werden (min. 32 Zeichen)
- SMTP-Passwörter werden in der DB als
isSecret: true markiert
- Reset-Tokens werden nie in API-Responses exponiert (nur in Server-Logs wenn kein SMTP)
- Alle Sub-Ressourcen-Zugriffe (Journal-Einträge, CheckItems, Pendenzen) prüfen Projekt-Zugehörigkeit
- Cookie:
httpOnly, secure (in Produktion), sameSite: lax
- Datei-Uploads: Nur PNG/SVG/JPEG/WebP, max 5MB, UUID-Dateinamen