Files
Lageplan/README.md

13 KiB

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

┌─────────────────────────────────────────────────────────┐
│                    Browser (Client)                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌────────┐  │
│  │ MapView  │  │ Journal  │  │  Admin   │  │Landing │  │
│  │(MapLibre)│  │  View    │  │  Panel   │  │  Page  │  │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └───┬────┘  │
│       └──────────────┴─────────────┴─────────────┘      │
│                         │ fetch()                        │
├─────────────────────────┼───────────────────────────────┤
│                  Next.js 14 Server                       │
│  ┌──────────────────────┼──────────────────────────┐    │
│  │              API Routes (/api/*)                 │    │
│  │  ┌────────┐  ┌──────────┐  ┌──────────────────┐ │    │
│  │  │  Auth  │  │ Projects │  │  Admin (Users,   │ │    │
│  │  │ (JWT)  │  │ Features │  │  Tenants, Icons) │ │    │
│  │  └───┬────┘  │ Journal  │  └────────┬─────────┘ │    │
│  │      │       └────┬─────┘           │           │    │
│  │      └────────────┼─────────────────┘           │    │
│  │                   │                              │    │
│  │  ┌────────────────┼────────────────────────┐    │    │
│  │  │          Prisma ORM + Tenant Guard      │    │    │
│  │  └────────────────┼────────────────────────┘    │    │
│  └───────────────────┼─────────────────────────────┘    │
├───────────────────────┼─────────────────────────────────┤
│  ┌────────────┐  ┌────┴───────┐  ┌──────────────────┐  │
│  │ PostgreSQL │  │   MinIO    │  │  SMTP (optional) │  │
│  │  (Prisma)  │  │ (S3 Icons) │  │  (Nodemailer)    │  │
│  └────────────┘  └────────────┘  └──────────────────┘  │
└─────────────────────────────────────────────────────────┘

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

lageplan/
├── docker-compose.yml          # PostgreSQL, MinIO, Web-App
├── Dockerfile                  # Multi-Stage Build (deps → builder → runner)
├── docker-entrypoint.sh        # DB-Migration + Seed beim Container-Start
├── prisma/
│   ├── schema.prisma           # 15 Models, 4 Enums
│   └── seed.js                 # Demo-Daten (Tenants, Users, Symbole, Projekt)
├── public/
│   └── sw.js                   # Service Worker für Offline-Tile-Caching
├── src/
│   ├── app/
│   │   ├── page.tsx            # Landing Page (/)
│   │   ├── login/page.tsx      # Login
│   │   ├── register/page.tsx   # Registrierung (erstellt Tenant + User)
│   │   ├── reset-password/     # Passwort-Reset
│   │   ├── admin/page.tsx      # Admin-Panel
│   │   ├── app/page.tsx        # Haupt-App (Karte + Journal)
│   │   └── api/
│   │       ├── auth/           # login, logout, me, register, forgot/reset-password
│   │       ├── projects/       # CRUD + features, journal, export
│   │       ├── admin/          # users, tenants, icons, categories, settings
│   │       ├── icons/          # Public icon listing + image serving
│   │       ├── hose-types/     # Schlauchtyp-Konfiguration
│   │       ├── contact/        # Kontaktformular
│   │       └── tenants/        # Public tenant info by slug
│   ├── components/
│   │   ├── map/
│   │   │   └── map-view.tsx    # MapLibre GL Karte (~1650 Zeilen)
│   │   ├── journal/
│   │   │   └── journal-view.tsx # Einsatz-Journal
│   │   ├── layout/
│   │   │   ├── topbar.tsx      # Header mit Menü, Speichern, Einsatz-Verwaltung
│   │   │   ├── left-toolbar.tsx # Zeichenwerkzeuge
│   │   │   └── right-sidebar.tsx # Symbole + Karte/Journal Tabs
│   │   ├── dialogs/            # ProjectDialog, TextDialog, LineLabelDialog, HoseSettings
│   │   ├── providers/
│   │   │   └── auth-provider.tsx # React Context für Auth-State
│   │   └── ui/                 # shadcn/ui Basis-Komponenten
│   └── lib/
│       ├── auth.ts             # JWT erstellen/verifizieren, Login, Rollen-Checks
│       ├── tenant.ts           # Tenant-Filter, Projekt-Zugriffsprüfung
│       ├── db.ts               # Prisma Client Singleton
│       ├── minio.ts            # MinIO Upload/Download/Delete
│       ├── email.ts            # SMTP aus DB laden, E-Mail senden
│       ├── validations.ts      # Zod Schemas (Login, Project, Feature, Icon)
│       ├── fw-symbols.ts       # 22 eingebaute SVG Feuerwehr-Symbole
│       └── utils.ts            # Hilfsfunktionen (cn, formatDateTime)

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

  • Docker & Docker Compose

Installation

cp .env.example .env
docker compose up -d

App: http://localhost:3000

Standard-Logins (nach Seed)

Benutzer E-Mail Passwort Rolle
Admin admin@lageplan.local admin123 SERVER_ADMIN
Editor editor@demo.local editor123 OPERATOR
Viewer viewer@demo.local viewer123 VIEWER

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

# 1. Sichere Secrets setzen
NEXTAUTH_SECRET=$(openssl rand -base64 32)
POSTGRES_PASSWORD=$(openssl rand -base64 16)

# 2. .env anpassen
# 3. Starten
docker compose up -d

# 4. Optional: Reverse Proxy (nginx/traefik) für HTTPS

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