Florian WildeandClaude Opus 5 49ce06f206
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s
feat: Projektgerüst, gehärteten Betriebsstand und Prozess aufsetzen
Legt die Grundlage, auf der alle weiteren Meilensteine nur noch Fachlichkeit
ergänzen: Next 16 mit App Router und TypeScript strict, Tailwind 4, Prisma 7,
Vitest 5, Playwright, ESLint, Prettier und die Hooks für Lint und Commits.

Zwei Dinge sind bewusst so gebaut und durch Tests festgehalten:

Die Datenbank ist im Betriebsstand von außen nicht erreichbar. Sie hat kein
ports:-Mapping und hängt allein im Netz "intern", das ohne Gateway läuft; nur
"web" kommt zusätzlich nach draußen. tests/betriebsstand.test.ts schlägt an,
falls ein Port-Mapping zurückkehrt. Geprüft, nicht behauptet: docker compose up
startet den Stack, 5432 ist vom Host aus zu, aus "web" offen.

pnpm pruefe:doku hält Dokumentation und Code zusammen — Version im Changelog,
Issue-Dateien gegen ihre Übersicht, keine Verweise auf fehlende Dateien, keine
fehlenden Bilder. Das Skript wurde gegen vier eingebaute Fehler gegengeprüft.

Drei Versions-Obergrenzen sind nötig und in CLAUDE.md begründet: eslint bleibt
auf 9.x, weil eslint-plugin-react keinen Nachfolger für eslint 10 hat und das
Regelwerk sonst beim Laden abbricht; typescript bleibt auf 6.0.x, weil
typescript-eslint TypeScript 7 noch nicht unterstützt; prisma ist exakt auf
7.10.0 gepinnt, weil sein latest-Tag auf einen 8.0-RC zeigt, der von
@prisma/client aber nicht.

Auth.js entfällt entgegen der ursprünglichen Vorgabe: v5 steht dauerhaft auf
Beta, das Projekt ist im Wartungsmodus und sein Prisma-Adapter deckt Prisma 7
nicht ab. Stattdessen openid-client und jose, wie in ProxLedger.

Dieser erste Commit geht direkt auf main, weil es noch keinen Branch gibt, von
dem abzuzweigen wäre. Ab #006 läuft jedes Issue über einen eigenen Branch.

Closes #5

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-24 23:33:49 +02:00

laufzettel

Checklisten für wiederkehrende IT-Arbeiten. Versionierte Vorlagen, daraus gestartete Läufe, im Team abgearbeitet, abgeschlossen und unveränderlich archiviert — mit Historie je Gerät und je Mitarbeiter. Einstieg über QR-Aufkleber: Code scannen, Geräteseite öffnen, loslegen.

Stand: in Entwicklung auf v0.1.0 (MVP). Der Fortschritt steht in docs/issues/README.md, Entscheidungen im Entwicklungstagebuch.

Zwei Betriebsmodi

Modus Für wen Kunden-Ebene Verzeichnis
INTERN (Standard) eine Firma, eigene Mitarbeiter unsichtbar eigenes AD per LDAP
DIENSTLEISTUNG IT-Dienstleister mit mehreren Kunden sichtbar manuell oder per CSV je Kunde

Der Modus liegt in der Datenbank und ist vom Admin ohne Neustart umschaltbar. Jede kundenbezogene Zeile trägt immer eine Kunden-Zuordnung, im Modus INTERN die eigene Organisation — deshalb ist der Wechsel eine Datenänderung und keine Migration.

Voraussetzungen

  • Node 24 (.nvmrc) und pnpm 12 über corepack, oder nur Docker mit Compose-Plugin
  • PostgreSQL 17 (im Compose-Stand enthalten)

Entwicklung

corepack enable pnpm
pnpm install
cp .env.example .env          # APP_SECRET und Passwörter ausfüllen
pnpm db:up                    # PostgreSQL auf 127.0.0.1:5433
pnpm db:migrate
pnpm db:seed
pnpm dev                      # http://localhost:3000

APP_SECRET erzeugen:

openssl rand -base64 48

Qualitätsschranken

pnpm lint && pnpm typecheck && pnpm test && pnpm pruefe:doku

Ein Pre-Commit-Hook erzwingt Lint und Format, ein Commit-Msg-Hook Conventional Commits. Ende-zu-Ende-Tests: pnpm test:e2e.

Betrieb mit Docker Compose

cp .env.example .env          # APP_URL, APP_SECRET, POSTGRES_PASSWORD sind Pflicht
docker compose up -d --build

Die Migrationen laufen beim Start automatisch in einem eigenen Einmal-Dienst. Der Seed läuft absichtlich nicht automatisch — ihn startest du einmal von Hand:

docker compose run --rm migrate pnpm db:seed

Die Datenbank ist von außen nicht erreichbar

Das ist bewusst so gebaut und in tests/betriebsstand.test.ts festgehalten:

  • postgres hat kein ports:-Mapping, nur expose
  • postgres hängt ausschließlich im Netz intern, das internal: true ist — ein Netz ohne Gateway, also weder vom Host noch aus dem LAN erreichbar
  • nur web hängt zusätzlich im Netz extern (Reverse Proxy, OIDC, LDAP)
  • web bindet standardmäßig auf 127.0.0.1:3000; davor gehört ein Reverse Proxy

Prüfen:

nc -z localhost 5432 && echo "FEHLER: offen" || echo "dicht"
docker compose exec web nc -z postgres 5432 && echo "von innen erreichbar"

Für die Entwicklung gibt es docker-compose.dev.yml, das PostgreSQL auf 5433 öffnet. Diese Datei ist nicht für den Betrieb gedacht.

Reverse Proxy

Die App läuft hinter einem Reverse Proxy und hat keine fest verdrahteten Adressen. Maßgeblich ist APP_URL — sie steckt in den QR-Codes und in der OIDC-Rückruf-Adresse. Der Proxy muss X-Forwarded-Proto und X-Forwarded-Host setzen.

Sicherung

Der geschlossene Port ändert nichts an der Sicherung, sie läuft über den Dienstnamen:

docker compose exec -T postgres pg_dump -U laufzettel laufzettel | gzip > sicherung-$(date +%F).sql.gz

Zurückspielen:

gunzip -c sicherung-2026-09-24.sql.gz | docker compose exec -T postgres psql -U laufzettel laufzettel

Gesichert werden muss nur die Datenbank — die App hält keinen veränderlichen Zustand auf der Platte. Das Volume heißt laufzettel_datenbank.

Anmeldung

Zwei Wege, beide gleichzeitig möglich:

  • OIDC (Ziel: authentik) für den normalen Betrieb
  • lokal mit E-Mail und Passwort, nur wenn AUTH_LOCAL_ENABLED=true — für die Entwicklung und als Notfallzugang, wenn der Identitätsanbieter ausfällt

Die Rolle kommt bei jedem OIDC-Login aus dem groups-Claim und wird über OIDC_GROUP_ADMIN, OIDC_GROUP_EDITOR, OIDC_GROUP_TECHNICIAN und OIDC_GROUP_VIEWER zugeordnet. Unbekannte Benutzer werden beim ersten Login angelegt.

Rolle Darf
ADMIN alles, inkl. Benutzer, Verzeichnis, Abteilungen, Archiv-Verwaltung
REDAKTEUR Vorlagen anlegen, bearbeiten, veröffentlichen; alles was TECHNIKER darf
TECHNIKER Läufe starten, abarbeiten, abschließen, archivieren; Geräte pflegen
LESER nur lesen

Die Anbindung an authentik ist in docs/betrieb/authentik.md Schritt für Schritt beschrieben.

Umgebungsvariablen

Alle Variablen mit Erklärung stehen in .env.example. Pflicht sind APP_URL, APP_SECRET, POSTGRES_PASSWORD und DATABASE_URL; der Compose-Stand bricht ab, statt mit Standardwerten zu starten.

Dokumentation

Lizenz

Noch nicht festgelegt.

S
Description
No description provided
Readme
27 MiB
2026-10-02 22:17:05 +00:00
Languages
TypeScript 96.1%
Shell 2.4%
PLpgSQL 0.8%
JavaScript 0.5%
CSS 0.2%