Legt den kompletten Unterbau an, auf dem die Fachmodule aufsetzen. Betrieb: - docker-compose.yml mit Traefik, App, Worker, PostgreSQL 17 + PostGIS, Redis, MinIO und Gotenberg; Entwicklungs-Override ohne Traefik, dafuer mit Mailpit und Adminer - Mehrstufiges Dockerfile: eigener Benutzer, tini als PID 1, Healthcheck - .env.example mit einem Kommentar zu jeder Variable Mandantentrennung: - Row Level Security auf allen mandantenpflichtigen Tabellen - Zwei getrennte Datenbankverbindungen: florian_app mit aktiver RLS fuer die Anwendung, Eigentuemer-Zugang nur fuer Migration, Seed und Anmeldung - fuerOrganisation() als einziger Weg zu Fachdaten Nachvollziehbarkeit: - AuditLog append-only per Trigger; UPDATE ist dauerhaft gesperrt, DELETE nur im gekennzeichneten Aufbewahrungslauf - Geheimnisse werden vor dem Schreiben entfernt Anmeldung: - OIDC gegen ein extern betriebenes authentik, Rollen aus Gruppen nur als Vorbelegung beim ersten Login - Lokaler E-Mail/Passwort-Login als Rueckfallweg - Terminal per PIN und RFID mit zwei Schranken (Geraet, dann Person) Weiteres: - lib/authz.ts mit 9 Rollen und 38 Einzelrechten - lib/storage.ts (MinIO), lib/audit.ts, lib/warteschlange.ts (BullMQ) - Integrationen fuer Mail, Telegram und LLM hinter abschaltbaren Interfaces - tRPC v11, Basis-Layout mit Seitenleiste und dunkler Darstellung - Seed mit einer Beispielwehr: 16 Personen, 3 Fahrzeuge, 40 Geraete - 32 Vitest-Tests (davon 8 gegen eine echte Datenbank), 10 Playwright-Tests - README, Anleitung mit Screenshots, Roadmap, Aufwandsschaetzung, Devlog, Versionierungsregeln und Changelog Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
50 lines
1.5 KiB
TypeScript
50 lines
1.5 KiB
TypeScript
import { defineConfig, devices } from "@playwright/test";
|
|
|
|
/**
|
|
* End-to-End-Tests.
|
|
*
|
|
* Voraussetzung: der Stack läuft (docker compose up -d) und die Datenbank ist
|
|
* migriert und geseedet. Der Entwicklungsserver wird bei Bedarf selbst
|
|
* gestartet — ein bereits laufender wird wiederverwendet.
|
|
*/
|
|
const BASIS_URL = process.env.E2E_BASIS_URL ?? "http://localhost:3100";
|
|
|
|
export default defineConfig({
|
|
testDir: "./tests/e2e",
|
|
fullyParallel: true,
|
|
forbidOnly: Boolean(process.env.CI),
|
|
retries: process.env.CI ? 2 : 0,
|
|
workers: process.env.CI ? 1 : undefined,
|
|
reporter: process.env.CI ? [["list"], ["html", { open: "never" }]] : [["list"]],
|
|
timeout: 30_000,
|
|
expect: { timeout: 10_000 },
|
|
|
|
use: {
|
|
baseURL: BASIS_URL,
|
|
trace: "on-first-retry",
|
|
screenshot: "only-on-failure",
|
|
video: "retain-on-failure",
|
|
// Die Oberfläche ist durchgängig deutsch — auch der Browser soll es sein.
|
|
locale: "de-DE",
|
|
timezoneId: "Europe/Berlin",
|
|
},
|
|
|
|
projects: [
|
|
{ name: "chromium", use: { ...devices["Desktop Chrome"] } },
|
|
// Am Terminal im Gerätehaus steht ein Touchgerät — deshalb mitgetestet.
|
|
// Bewusst mit Chromium statt WebKit: das Terminal läuft auf einem
|
|
// Android-Tablet im Kiosk-Browser, nicht auf einem iPad.
|
|
{
|
|
name: "tablet",
|
|
use: { ...devices["Galaxy Tab S4 landscape"], browserName: "chromium" },
|
|
},
|
|
],
|
|
|
|
webServer: {
|
|
command: "npm run dev",
|
|
url: BASIS_URL,
|
|
reuseExistingServer: !process.env.CI,
|
|
timeout: 120_000,
|
|
},
|
|
});
|