Einsatzverwaltung für Feuerwehren und Vereine.
  • Vue 74.2%
  • TypeScript 24%
  • JavaScript 1.4%
  • Shell 0.2%
  • Dockerfile 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Julian Krauser cf6bae33d1
All checks were successful
buildByTag-arm-and-amd / build (amd) (push) Successful in 3m44s
buildByTag-arm-and-amd / build (arm) (push) Successful in 4m9s
buildByTag-arm-and-amd / combine (push) Successful in 2m39s
1.10.0
2026-09-10 16:18:10 +02:00
.claude claude config 2026-08-26 16:26:22 +02:00
.forgejo/workflows enhance: ci workflow with checks, beta-build and layer caching 2026-08-30 15:39:23 +02:00
public update logo 2025-10-23 06:37:01 +02:00
src enhance: navigation button in card 2026-09-10 15:59:15 +02:00
.dockerignore update baseSearchSelect Usage to core package 2026-07-06 17:17:46 +02:00
.env.example change accorfing to admin 2025-09-21 18:11:42 +02:00
.env.production change accorfing to admin 2025-09-21 18:11:42 +02:00
.eslintrc.cjs base structure 2025-02-16 10:48:16 +01:00
.gitignore claude config 2026-08-26 16:26:22 +02:00
.ignore claude config 2026-08-26 16:26:22 +02:00
.mcp.json claude config 2026-08-26 16:26:22 +02:00
.npmrc explicit npmrc docker usage 2026-03-22 13:43:58 +01:00
.prettierrc base structure 2025-02-16 10:48:16 +01:00
CLAUDE.md claude config 2026-08-26 16:26:22 +02:00
Dockerfile explicit npmrc docker usage 2026-03-22 13:43:58 +01:00
entrypoint.sh fix: csp for ws and manifest 2026-09-04 11:59:20 +02:00
env.d.ts base structure 2025-02-16 10:48:16 +01:00
index.html fix: csp for ws and manifest 2026-09-04 11:59:20 +02:00
LICENSE change accorfing to admin 2025-09-21 18:11:42 +02:00
nginx.conf change: provide labels for satellite to own tile server 2026-09-10 11:41:15 +02:00
package-lock.json 1.10.0 2026-09-10 16:18:10 +02:00
package.json 1.10.0 2026-09-10 16:18:10 +02:00
README.md change: provide labels for satellite to own tile server 2026-09-10 11:41:15 +02:00
tsconfig.app.json icon picker 2026-08-04 10:25:09 +02:00
tsconfig.json base structure 2025-02-16 10:48:16 +01:00
tsconfig.node.json base structure 2025-02-16 10:48:16 +01:00
vite.config.ts fix: extend CSP to allow wasm for qrcode scanner 2026-09-09 17:56:57 +02:00

FF Operation

Einsatzverwaltung für Feuerwehren und Vereine.

Einleitung

Dieses Repository dient hauptsächlich zur Verwaltung Einsätzen oder Übungen der Feuerwehr oder Arbeitseinsätzen eines Vereins. Es ist ein Frontend-Client, der auf die Daten des ff-operation-server Backends zugreift. Die Webapp bietet eine Möglichkeit Anwesenheiten und Zeiten zu verwalten. Benutzer können eingeladen und Rollen zugewiesen werden.

Eine Demo dieser Seite finden Sie unter https://operation-demo.ff-admin.de.

Installation

Docker Compose Setup

Um den Container hochzufahren, erstellen Sie eine docker-compose.yml Datei mit folgendem Inhalt:

version: "3"

services:
  ff-operation-app:
    image: code.jk-effects.cloud/ff-admin/ff-operation/app:latest
    container_name: ff_operation
    restart: unless-stopped

    #environment:
    #  - SERVERADDRESS=<backend_url (https://... | http://...)> # wichtig: ohne Pfad
    #  - FRAME_ANCESTORS=<erlaubte Einbett-Origins, leerzeichengetrennt, z. B. https://verein.de https://www.verein.de>

Wenn keine Server-Adresse angegeben wird, wird versucht das Backend unter der URL des Frontends zu erreichen. Dazu muss das Backend auf der gleichen URL wie das Frontend laufen. Zur Unterscheidung von Frontend und Backend bei gleicher URL müssen alle Anfragen mit dem PathPrefix /api an das Backend weitergeleitet werden.

FRAME_ANCESTORS ist optional und standardmäßig leer - damit darf die Anwendung ausschließlich von sich selbst per <iframe> eingebettet werden. Um das Einbetten auf anderen Webseiten zu erlauben, die erlaubten Origins mit vollständigem Schema, ohne Pfad, leerzeichengetrennt angeben.

Führen Sie dann den folgenden Befehl im Verzeichnis der compose-Datei aus, um den Container zu starten:

docker-compose up -d

Manuelle Installation

Klonen Sie dieses Repository und installieren Sie die Abhängigkeiten:

git clone https://code.jk-effects.cloud/ff-admin/ff-operation.git
cd ff-operation
npm install
npm run build
npm run start

Konfiguration

Ein eigenes Favicon und Logo kann über das verwenden Volume ausgetauscht werden. Es dürfen jedoch nur einzelne Dateien ausgetauscht werden.

Content-Security-Policy (CSP)

Die Anwendung wird mit einer strikten CSP ausgeliefert (siehe nginx.conf). Freigeschaltet ist nur, was tatsächlich gebraucht wird:

Direktive Erlaubt Warum
default-src 'self' Fallback für alles, was unten nicht explizit aufgeführt ist.
script-src 'self' 'wasm-unsafe-eval' Ausschließlich selbst ausgelieferte JS-Dateien, kein Inline-Script, kein CDN. 'wasm-unsafe-eval' erlaubt WebAssembly-Kompilierung (QR-Scanner, siehe unten), ohne das viel mächtigere 'unsafe-eval' zu öffnen.
style-src 'self' 'unsafe-inline' Vue/Tailwind erzeugen Inline-Styles zur Laufzeit (:style-Bindings) - ohne 'unsafe-inline' wäre die UI kaputt.
img-src 'self' data: blob: + Backend-Origin data:/blob: für dynamisch erzeugte Bilder (z. B. QR-Codes), Backend-Origin für Logo/Favicon/hochgeladene Bilder.
font-src 'self' data: Alle Schriften sind selbst gehostet, keine externen Font-CDNs.
connect-src 'self' + Backend-Origin (https:// und wss://) + https://*.tile.openstreetmap.org + https://server.arcgisonline.com + https://tiles.ff-admin.de REST-API sowie Socket.IO (https:// deckt wss:// nicht automatisch mit ab, daher ein eigener Eintrag); die Kartenkachel-Quellen der Leaflet-Karte (OSM, Esri-Satellitenbild), die per fetch() geholt und offline gecacht werden (useOfflineTiles.ts), sowie die zentral gehostete .pmtiles-Beschriftungsdatei (protomaps-leaflet, per HTTP-Range-Requests, siehe Repo ff-operation-tiles).
frame-src 'self' blob: Der PDF-Viewer (FileViewer.vue) zeigt Dateien über eine blob:-URL in einem <iframe> an.
manifest-src 'self' + Backend-Origin Das PWA-Manifest wird dynamisch vom Backend ausgeliefert (/api/public/manifest.webmanifest), nicht als statische Datei im Frontend.
object-src 'none' Keine <object>/<embed>-Einbettung im Code.
base-uri 'self' Verhindert, dass ein injizierter <base>-Tag relative URLs umleitet.
form-action 'self' Alle Formulare senden nur an die eigene Origin.
frame-ancestors 'self' + FRAME_ANCESTORS Wer diese App per <iframe> einbetten darf - siehe Docker Compose Setup oben.

Die Kartenkacheln selbst landen nicht direkt als <img src="https://tile..."> im DOM, sondern werden erst per fetch() geholt und dann als blob:-URL gerendert - dafür reicht img-src blob: (schon vorhanden), die eigentliche Netzwerkanfrage braucht aber den connect-src-Eintrag.

Die Backend-Origin und die erlaubten Einbett-Origins werden beim Containerstart aus SERVERADDRESS/FRAME_ANCESTORS eingesetzt (siehe entrypoint.sh). Ist SERVERADDRESS leer, läuft die API unter derselben Origin wie das Frontend - die zusätzlichen Backend-Einträge entfallen dann automatisch.

Der QR-/Barcode-Scanner (vue-qrcode-reader) lädt seinen WebAssembly-Reader standardmäßig von einem externen CDN (jsdelivr) nach - das würde sowohl an connect-src 'self' als auch, offline, an der PWA-Vorhaltung scheitern. @ff-admin/cores viteQrcodeWasm()-Vite-Plugin liefert die Datei stattdessen same-origin unter /zxing_reader.wasm aus und wird im Service Worker mitgecacht - dadurch ist dafür keine zusätzliche CSP-Freigabe nötig.

Zusätzlich gesetzt: X-Content-Type-Options: nosniff, X-Frame-Options: SAMEORIGIN (Fallback für Browser ohne frame-ancestors-Unterstützung - wird von jedem aktuellen Browser ignoriert, sobald frame-ancestors gesetzt ist) und Referrer-Policy: strict-origin-when-cross-origin.

Beim Einbetten in eine fremde Seite (FRAME_ANCESTORS) reicht die CSP allein nicht für alle Funktionen: Kamera (QR-Login-Scanner), Standortabfrage (useGeolocation.ts), Passkeys/WebAuthn und Push-Benachrichtigungen werden über die Permissions-Policy gesteuert, die vom Elternframe an das <iframe> vererbt werden muss. Die einbettende Seite muss dafür allow="camera; geolocation; publickey-credentials-get" am <iframe>-Tag setzen, sonst funktionieren diese Features im eingebetteten Zustand nicht - das lässt sich nicht über unsere nginx.conf steuern.

Einrichtung

  1. Admin Benutzer erstellen: Erstellen Sie einen Admin Benutzer unter dem Pfad /setup, um auf die Einsatzverwaltung Zugriff zu erhalten. Nach der Erstellung des ersten Benutzers wird der Pfad automatisch geblockt.

  2. Rollen und Berechtigungen: Unter Benutzer > Rollen können die Rollen und Berechtigungen für die Benutzer erstellt und angepasst werden.

  3. Nutzer einladen: Unter Benutzer > Benutzer können weitere Nutzer eingeladen werden. Diese erhalten dann eine E-Mail mit einem Link, um ein TOTP zu erhalten.

Fragen und Wünsche

Bei Fragen, Anregungen oder Wünschen können Sie sich gerne melden.
Wir freuen uns über Ihr Feedback und helfen Ihnen gerne weiter.
Schreiben Sie dafür eine Mail an julian.krauser@jk-effects.com.