elpatron e907b637b8
Deploy Unraid / build (push) Successful in 1m30s
Deploy Unraid / deploy (push) Successful in 24s
Merge pull request 'Backup und Restore unter Einstellungen' (#9) from feature/backup-restore into main
Reviewed-on: #9
2026-09-01 20:36:50 +02:00

PKV · Beihilfe Abrechnung

Selbst gehostete Web-App zur Verwaltung von Krankheitskosten für Beamte (Beihilfe + PKV).

Features

  • Mandantenfähig (Haushalt / Familie)
  • Passkey-Login mit E-Mail-OTP-Recovery
  • Versicherte mit Debeka/DKV-Profil (Pensionär-Defaults 70/30)
  • Leistungserbringer-Stammdaten
  • Vorgänge mit Workflow: Eingang → Bezahlt → Beihilfe → Bescheid → PKV → Erstattung → Archiv
  • Beleg-Erfassung einzeln oder als Stapel (Scan/Upload); optionale KI-Extraktion (OpenRouter)
  • Beihilfebescheid: Mehrfachzuordnung, Archiv, nicht erstattbare Positionen (Steuer-Export CSV/PDF)
  • Kontoauszug einlesen und Umsätze den Vorgängen zuordnen
  • Dashboard: offene Erwartungen (Pipeline vs. unbezahlte Rechnungen), Fristen, Steuerjahr
  • Vorgänge-Filter inkl. Status „Nicht bezahlt“
  • Lokale Dokumentenablage (Paperless optional)
  • Backup/Restore des Haushalts (ZIP unter Einstellungen)
  • PWA-Manifest

Schnellstart (Entwicklung)

cp .env.example .env
# BETTER_AUTH_SECRET setzen (mind. 32 Zeichen)

./scripts/dev.sh          # Postgres (Docker) + Next.js
# alternativ manuell:
# docker compose up postgres -d
# npm install && npm run db:migrate && npm run db:seed-dev && npm run dev

Optional Beispieldaten: npm run db:seed-dev

App: http://localhost:3000 (Next.js wählt bei belegtem Port automatisch z.B. 3001 — Auth nutzt dann die aktuelle Browser-URL)

./scripts/dev.sh restart / stop starten den Dev-Server neu bzw. beenden ihn (Postgres bleibt).

Dev-Login (lokal)

Nach npm run db:seed-dev:

Feld Wert
E-Mail dev@example.com
OTP 123456 (fest in Entwicklung)

Der OTP gilt nur für die in DEV_SEED_EMAIL konfigurierte Adresse und nur außerhalb von Production. Enthalten sind zwei Versicherte (Debeka/DKV) und ein Beispiel-Vorgang.

Konto anlegen (Onboarding)

  1. E-Mail eingeben → Bestätigungscode anfordern
  2. OTP aus E-Mail (oder Server-Log ohne SMTP) eingeben
  3. Passkey auf diesem Gerät einrichten (empfohlen)
  4. Haushalt benennen → Versicherte erfassen

Weitere Passkeys (z.B. zweites Handy): Einstellungen → Passkeys.

E-Mail / Gmail (OTP-Versand)

Für echte OTP-Mails in .env eintragen (siehe .env.example):

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=ihr.name@gmail.com
SMTP_PASS=ihr-16-stelliges-app-passwort
SMTP_FROM=ihr.name@gmail.com

Bei Gmail: App-Passwort erstellen (2FA muss aktiv sein).
Ohne SMTP erscheint der Code im Terminal ([DEV EMAIL] …).

Docker (vollständig)

cp .env.example .env
docker compose --profile dev up

Mit Paperless:

docker compose --profile dev --profile paperless up

Produktion:

docker compose up --build
docker compose --profile prod up  # mit Caddy

Dokument-Backend

Modus Konfiguration
local (Standard) DOCUMENT_BACKEND=local
Paperless mitgeliefert docker compose --profile paperless up + DOCUMENT_BACKEND=paperless
Externes Paperless DOCUMENT_BACKEND=paperless, PAPERLESS_URL, PAPERLESS_TOKEN

Umgebungsvariablen

Siehe .env.example (lokal) bzw. .env.unraid.example (Produktion).

Wichtige optionale Werte:

  • OPENROUTER_API_KEY — KI-Extraktion (global; alternativ pro Benutzer unter Einstellungen)
  • OPENROUTER_MODEL — Default-Modell für die Extraktion (global; in den Einstellungen überschreibbar)
  • DOCUMENT_BACKEND / PAPERLESS_* — Dokumentenablage

Deployment auf Unraid (Gitea CI/CD)

Dauerhaft laufen Postgres + App auf Unraid; Migrationen als Einmal-Job. Deploy per Gitea Actions über den vorhandenen Gitea-Runner mit Docker-Socket.

Komponente Wert
Gitea https://gitea.elpatron.me
Repository elpatron/pkv-beihilfe-tool
Runner Gitea-Runner auf Unraid (Docker-Socket)
Appdata /mnt/user/appdata/pkv-beihilfe
App-URL https://tower.warbler-bearded.ts.net (Tailscale Serve; intern :3010)

Architektur

Push auf main → Gitea Actions (ubuntu-latest auf Unraid)
  → Docker-Image bauen & in Gitea Container Registry pushen
  → docker-compose auf Unraid aktualisieren (Postgres + Migrate + App)

Workflow: .gitea/workflows/deploy-unraid.yml

Einmalige Einrichtung

1. Gitea Actions aktivieren

Im Repository: Einstellungen → Aktionen → Repository-Aktionen aktivieren.

2. Container-Registry aktivieren

In Gitea: Site-Administration → Packages (falls noch nicht aktiv) und im Repo unter Einstellungen → Pakete prüfen, dass Container-Pakete erlaubt sind.

3. Registry-Token als Repository-Secret

GITEA_TOKEN reicht für docker push nicht — ein Personal Access Token (PAT) ist nötig:

  1. Gitea → Einstellungen → Anwendungen → Zugriffstoken erstellen
  2. Scopes: mindestens write:package (optional read:package)
  3. Im Repository: Einstellungen → Actions → Secrets → REGISTRY_TOKEN anlegen (Wert = PAT)

Der Workflow loggt sich mit Benutzer ${{ gitea.actor }} und diesem Secret ein.

4. Appdata auf Unraid vorbereiten

Auf Unraid als root (wurde bereits eingerichtet unter /mnt/user/appdata/pkv-beihilfe):

bash /mnt/user/appdata/pkv-beihilfe/repo/scripts/setup-unraid-appdata.sh \
  /mnt/user/appdata/pkv-beihilfe/repo

Das legt .env mit zufälligem BETTER_AUTH_SECRET und DB-Passwort an sowie postgres/ und documents/ Volumes.

5. .env anpassen

Datei /mnt/user/appdata/pkv-beihilfe/.env bearbeiten:

  • BETTER_AUTH_URL / PASSKEY_RP_ID — Tailscale-Serve-Hostname (HTTPS), siehe .env.unraid.example
  • SMTP_* — für OTP-Mails in Produktion empfohlen
  • optional OPENROUTER_API_KEY / OPENROUTER_MODEL für KI
  • optional DOCUMENT_BACKEND=paperless + PAPERLESS_URL=http://192.168.177.5:8000 (bestehendes Paperless auf Unraid)

Vorlage: .env.unraid.example

6. Erstes Deployment

Push auf main startet den Workflow automatisch, oder manuell unter Aktionen → Deploy Unraid → Ausführen.

Manuelles Deployment

ssh root@192.168.177.5
export APP_IMAGE=gitea.elpatron.me/elpatron/pkv-beihilfe-tool:latest
export MIGRATE_IMAGE=gitea.elpatron.me/elpatron/pkv-beihilfe-tool-migrate:latest
/mnt/user/appdata/pkv-beihilfe/deploy.sh

Dateien

Datei Zweck
docker-compose.unraid.yml Produktions-Stack (wird nach Appdata kopiert)
scripts/deploy-unraid.sh Pull, Migration, Neustart
scripts/setup-unraid-appdata.sh Ersteinrichtung Appdata
scripts/dev.sh Lokaler Dev-Server (Postgres + Next.js)
scripts/configure-gitea-runner-unraid.sh Runner-Label für Unraid-Deploy (einmalig)
.gitea/workflows/deploy-unraid.yml CI/CD-Workflow
Dockerfile (Targets runner, migrate) App- und Migrations-Image

Hinweise

  • Kein öffentlicher Port, kein Funnel. Zugriff nur im Tailnet über Tailscale Serve (https://tower.warbler-bearded.ts.net → App :3010). LAN-HTTP unter :3010 bleibt intern, ist aber kein Secure Context.
  • Passkeys brauchen HTTPS (oder http://localhost). Deshalb Serve statt WireGuard/LAN-IP — unter http://192.168.x.x melden Browser „WebAuthn is not supported“. In der Appdata-.env:
    • BETTER_AUTH_URL=https://tower.warbler-bearded.ts.net
    • PASSKEY_RP_ID=tower.warbler-bearded.ts.net (Hostname ohne Schema und Port) Serve auf Unraid: tailscale serve --bg 3010 (MagicDNS + HTTPS-Zertifikate im Tailscale-Admin).
  • Backups: Unter Einstellungen → Sicherung den Haushalt als ZIP exportieren (Vorgänge + Belege). Zusätzlich /mnt/user/appdata/pkv-beihilfe/postgres und documents/ regelmäßig sichern (vollständiger Serverstand inkl. Login).
  • Der Runner nutzt den Host-Docker-Socket — Deploy-Schritte laufen über docker run … docker:28.1-cli mit Volume /mnt/user/appdata/pkv-beihilfe.

Lizenz

Privates Projekt.

S
Description
No description provided
Readme
1.3 MiB
Languages
TypeScript 97.7%
Shell 1.2%
CSS 0.7%
Dockerfile 0.3%
JavaScript 0.1%