No description
  • TypeScript 85.5%
  • PLpgSQL 7%
  • Shell 4.6%
  • JavaScript 2.1%
  • CSS 0.4%
  • Other 0.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Rey Koxha 744d9431f4
All checks were successful
Build Images / worker (push) Successful in 2m11s
Build Images / web (push) Successful in 2m48s
Quality / Deploy-Readiness (Prod-Konfig) (push) Successful in 1m44s
Security / Dependency Audit (push) Successful in 47s
Security / Secret Scan (push) Successful in 8s
Quality / Format, Lint, Typecheck, Unit Tests (push) Successful in 6m2s
Quality / XRechnung-Konformität (KoSIT) (push) Successful in 1m21s
Quality / Migrations, RLS, Drift (push) Successful in 2m33s
Quality / Backup→Restore Roundtrip (push) Successful in 1m30s
Quality / Upgrade-Pfad (letztes Release → HEAD) (push) Successful in 1m54s
Quality / Browser E2E (push) Successful in 2m59s
Quality / E2E Paranoid (Rate-Limit, Actions, Compliance) (push) Successful in 7m34s
fix(rls): persist portal staff notifications write-only
2026-08-24 04:35:28 +02:00
.forgejo docs: add governed Fachkatalog and PS 880 evidence model 2026-08-23 15:31:18 +02:00
apps fix(rls): persist portal staff notifications write-only 2026-08-24 04:35:28 +02:00
docs fix(rls): persist portal staff notifications write-only 2026-08-24 04:35:28 +02:00
infra docs: add governed Fachkatalog and PS 880 evidence model 2026-08-23 15:31:18 +02:00
packages fix(rls): persist portal staff notifications write-only 2026-08-24 04:35:28 +02:00
scripts fix(ci): restore format and complexity gates 2026-08-24 03:33:48 +02:00
.dockerignore fix(ops): resume interrupted one-click deploys 2026-08-12 17:11:14 +02:00
.editorconfig Initial 2026-05-17 04:17:38 +02:00
.env.example fix: align feature implementation and security 2026-08-23 09:24:55 +02:00
.gitattributes fix: make migration history release-ready 2026-08-09 21:32:14 +02:00
.gitignore fix: resume updates with refreshed operator 2026-08-20 23:37:11 +02:00
.gitleaks.toml fix: allowlist historical gitleaks model fixtures 2026-08-20 06:09:58 +02:00
.gitleaksignore feat(n8n): add workflow-specific integration setup 2026-07-14 15:21:45 +02:00
.npmrc fix: migrate pnpm build approvals 2026-06-16 13:39:46 +02:00
.nvmrc chore: prepare v0.2.0 release on Node 24 LTS 2026-07-14 11:38:41 +02:00
.prettierignore feat: add non-blocking RFC 3161 audit anchors 2026-08-21 18:42:40 +02:00
.prettierrc fix(tooling): format:check unter Windows benutzbar machen 2026-08-02 22:08:26 +02:00
AGENTS.md docs: add governed Fachkatalog and PS 880 evidence model 2026-08-23 15:31:18 +02:00
CHANGELOG.md docs: add governed Fachkatalog and PS 880 evidence model 2026-08-23 15:31:18 +02:00
eslint.config.mjs fix: make migration history release-ready 2026-08-09 21:32:14 +02:00
FEATURES.md feat(compliance): align legal workflows and expand Fachkatalog 2026-08-24 02:40:53 +02:00
LICENSE Initial commit 2026-05-17 04:16:23 +02:00
package.json docs: add governed Fachkatalog and PS 880 evidence model 2026-08-23 15:31:18 +02:00
pnpm-lock.yaml docs: add governed Fachkatalog and PS 880 evidence model 2026-08-23 15:31:18 +02:00
pnpm-workspace.yaml fix: make GwG uploads discardable and organized 2026-08-19 13:22:30 +02:00
README.md docs: add governed Fachkatalog and PS 880 evidence model 2026-08-23 15:31:18 +02:00
SECURITY.md chore: prepare v0.2.0 release on Node 24 LTS 2026-07-14 11:38:41 +02:00
taxtronik fix(ops): make deploy the primary setup path 2026-08-12 15:59:57 +02:00
tsconfig.base.json refactor(theme/ui/forms/libs): Dark-Mode-Tokens, Component-Klassen, lib-Konsolidierung, Form-UX, GwG-/Stammdaten-Härtung 2026-05-28 02:22:20 +02:00
turbo.json chore: prepare v0.2.0 release on Node 24 LTS 2026-07-14 11:38:41 +02:00

TaxTronik

TaxTronik

Kanzlei- und Mandanten-Dashboard für deutsche Steuerberater. On-Premise pro Kanzlei.

Überblick

TaxTronik verbindet Kanzlei-Workflows, Mandantenportal, Dokumentenablage, Compliance und Hintergrund-Jobs in einem lokalen Deploy. Die Software ist auf steuerliche Berufsgeheimnisse und revisionsnahe Anforderungen ausgelegt: Postgres-RLS, App-Level-Tenant-Filter, TOTP für Mitarbeiter, Magic-Link für Mandanten, S3-kompatibler Object-Store ohne öffentliche Direktlinks, ClamAV, Audit-Hash-Chain und externe RFC-3161-Zeitstempel. Produktion verwendet einen externen RFC-3161-Dienst; ob ein qualifizierter eIDAS-Dienst erforderlich ist, entscheidet die Kanzlei anhand ihres konkreten Nachweisbedarfs.

Letzter getaggter Release-Stand: 0.2.1. Die zugehörigen Änderungen stehen im Changelog.

Dokumentation nach Zielgruppe: docs/README.md. Aktuelle Einarbeitung und Übergabe: docs/HANDOFF.md. Vollständige Architektur: docs/architecture.md.

Tech-Stack

Schicht Wahl
Web/App Next.js 16 App Router, React 19, TypeScript
Auth Auth.js v5, Mitarbeiter mit Passwort + TOTP, Mandanten mit Magic-Link
Datenbank Postgres 18, Prisma, Row-Level Security
Storage SeaweedFS S3-API, Object-Lock, ClamAV-Scan vor Commit
Jobs BullMQ Worker, Redis
Workflows BullMQ für Kernkontrollen; n8n optional für Kommunikation/Integrationen
Risk / TCMS optionales on-prem Signal (/v1/*, historische RISK_LAYER_*-Namen)
Deploy Docker Compose, On-Premise, Reverse Proxy davor

Entwicklung

Voraussetzungen:

  • Docker Desktop oder Docker Engine
  • Node.js 24 LTS (>=24.11.0 <25)
  • Corepack/pnpm 11: corepack enable

Einmaliges Setup:

./scripts/setup.sh

Windows PowerShell:

.\scripts\setup.ps1

Das Setup erzeugt .env, generiert Secrets, startet Postgres/Redis/SeaweedFS/ ClamAV/Mailhog/n8n, installiert Pakete, migriert die DB, legt Buckets an und seedet Demo-Daten.

Zusätzliche Retention-/Object-Lock-Fixtures für lokale Abnahmetests:

pnpm demo:retention

Das erzeugt GwG-Testfälle für löschreif/nicht löschreif sowie Object-Lock abgelaufen/aktiv. Nicht in Produktion ausführen.

Danach starten:

pnpm --filter @taxtronik/web dev
pnpm --filter @taxtronik/worker dev

App: http://localhost:3000/staff/login

Der Dev-Seed erzeugt admin@taxtronik.local; das einmalige Passwort steht in der Seed-Ausgabe und in packages/db/.admin-credentials.txt. Beim ersten Login wird TOTP eingerichtet. Danach die Credentials-Datei löschen.

Nützliche lokale Dienste:

Dienst URL
Mailhog http://localhost:8025
n8n http://localhost:5678
SeaweedFS Master http://localhost:9333
SeaweedFS Filer http://localhost:8888

Optionales Signal lokal/nativ:

.\scripts\win\Start-SignalDev.ps1

Der Dev-Starter erwartet den Signal-Checkout standardmäßig als Nachbarverzeichnis ..\signal, ergänzt die lokale .env um getrennte Bearer- und Operator-Tokens und startet Engine sowie LLM. Beim ersten Lauf installiert er außerdem den hash-gepinnten Python-3.12-CPU-Stack für Embeddings. Danach ist unter Administration → Integrationen → Signal-Embedding der Index-Build verfügbar; BGE-M3 lädt beim ersten Build etwa 2,3 GB. Reine CPU-Ausführung ist voll funktionsfähig, aber bei Embedding-Build und LLM-Inferenz ein deutlicher Performance-Bottleneck. Hat der Starter Tokens ergänzt, müssen bereits laufende Web- und Worker-Prozesse einmal neu gestartet werden.

Ein anderer Checkout kann explizit angegeben werden:

.\scripts\win\Start-SignalDev.ps1 -SignalRoot C:\src\signal

RISK_LAYER_URL ist ein Operator-Backend-Ziel und darf Docker-Service-DNS (http://risk-layer:8000), Loopback (http://127.0.0.1:8000) oder eine interne IP enthalten. INTERNAL_FETCH_HOSTS wird dafür nicht benötigt. Die Allowlist gilt nur für ausdrücklich als trusted-internal markierte Infrastrukturziele; tenant-/admin-konfigurierte RSS-, TSA- und Update-Ziele bleiben strikt öffentlich. Das mitgelieferte n8n-Ziel besitzt ausschließlich eine eng begrenzte Ausnahme für Host, Port und zulässige Pfade und wertet die globale Allowlist nicht aus.

Wichtig bei Docker: 127.0.0.1/localhost wird aus dem App-Container heraus als App-Container selbst interpretiert, nicht als Host. Im Compose-Stack mit Risk-Layer-Profil deshalb RISK_LAYER_URL=http://risk-layer:8000 verwenden. Bei einer separat auf dem Host laufenden Engine eine interne Adresse nutzen, die aus dem taxtronik-app-Container erreichbar ist.

Im Produktions-Deploy entscheidet SIGNAL_DEPLOYMENT über die Verantwortung: managed lässt TaxTronik ein CPU-Komplett-Image einschließlich der hash-gepinnten Quantenlos-Runtime entweder aus dem gewählten Signal-Git-Stand lokal bauen oder versioniert aus einer Registry beziehen. Zusätzlich werden das revisions-/SHA-256-gepinnte Granite-4.1-8B-GGUF und eine gepinnte llama-server-CPU-Engine einmalig provisioniert und read-only eingebunden. Damit ist die KI-Vertiefung auch ohne GPU vollständig verfügbar; CPU-Inferenz bleibt allerdings ein klar ausgewiesener Performance-Bottleneck und kann mehrere Minuten dauern; external bindet eine native/GPU- oder anderweitig betriebene Signal-Instanz ausschließlich per API an. Im externen Modus führt TaxTronik garantiert keinen Pull, Start, Stop oder Update für Signal aus.

Reset:

./scripts/setup.sh --reset
./scripts/setup.sh --skip-seed

PowerShell:

.\scripts\setup.ps1 -Reset
.\scripts\setup.ps1 -SkipSeed

Produktivbetrieb

Produktiv läuft der Stack über die Operator-CLI ./taxtronik. Sie wählt immer die richtigen Compose-Dateien, nutzt die Root-.env und validiert sie vorab (doctor) statt mitten im Deploy abzubrechen. Die SeaweedFS-S3- Konfiguration entsteht erst im Container flüchtig unter /run; es gibt keine hostseitige Klartext-Konfigurationskopie mehr.

deploy ist der einzige Hauptweg — sowohl für die Erstinstallation als auch für spätere Deployments:

./taxtronik deploy      # bei Bedarf konfigurieren, bestätigen und vollständig installieren
# optional getrennt: ./taxtronik config && ./taxtronik deploy

Der Assistent bietet eine gesunde Standardmethode für bestehende Server mit vorhandenem Reverse-Proxy und einen bewusst streng gesperrten 1-Klick-Weg mit Traefik/Let's Encrypt für komplett leere Linux-/Docker-Maschinen. Er fragt Bezugsweg, Domains, Admin/Kanzlei, SMTP und Signal ab, zeigt vor jeder Änderung eine Zusammenfassung und verlangt eine wörtliche Bestätigung. Auf Debian/Ubuntu installiert der bestätigte 1-Klick-Weg fehlende Basispakete, Docker/Compose und die gepinnte Node-/pnpm-Laufzeit selbst. Details und Voraussetzungen: Erstinstallation.

bootstrap bleibt nur als veralteter Kompatibilitätsalias für deploy erhalten. Im Normalfall danach:

./taxtronik deploy      # bauen/pullen + migrieren + starten + Health-Smoke
./taxtronik update      # git ff-only + Backup + bauen/pullen + migrieren + starten
./taxtronik backup      # manuelles Postgres-Backup nach backups/ + S3-Backup-Bucket
./taxtronik backup-files # Kanzleidateien aus SeaweedFS nach backups/object-store
./taxtronik backup-full # quiesziertes, age-verschlüsseltes und signiertes Full-Backup
./taxtronik backup-verify <dir> [public-key]
./taxtronik backup-decrypt <dir> <leeres-ziel> [age-identity] [public-key]
./taxtronik restore --list
./taxtronik restore --latest --target-url <postgres-url>
./taxtronik restore --file backups/<dump> --target-url <postgres-url>
./taxtronik doctor      # .env prüfen (--fix generiert fehlende Secrets)
./taxtronik rollback    # zurück auf den vorherigen Stand (keine Migration)

Mutierende Restores haben bewusst keinen impliziten DATABASE_URL-Fallback. Ein In-place-Produktionsrestore ist nur über den expliziten --production-target-Pfad im DR-Runbook möglich; dieser stoppt App, Worker und n8n und lässt sie bis zur Prüfung des über --release-version gebundenen Release-Vertrags gestoppt.

Builds über Forgejo CI

Der Forgejo-Workflow Build Images baut Web- und Worker-Image bei build-relevanten Pushes auf main, bei Pull Requests sowie bei manuellem Start. Diese Läufe sind reine, frühzeitige Build-Prüfungen: Sie benötigen keine Registry-Zugangsdaten und veröffentlichen keine Images.

Verwendbare Produktions-Images entstehen über annotierte, geschützte SemVer-Tags (für diesen Stand v0.2.1). Der Workflow Release Images führt für exakt den Tag-Commit im selben Release-DAG die vollständige CI- und Security-Suite aus; erst danach baut, scannt und testet er Web und Worker, lädt die CycloneDX-SBOMs als CI-Artefakt hoch und veröffentlicht die Images in der Forgejo-Registry. Abschließend publiziert er das verpflichtende, Ed25519-signierte Manifest v2 mit Commit- sowie beiden Image-Digests. Auf dem Server zeigt TAXTRONIK_DEPLOY_CHANNEL=release zusammen mit TAXTRONIK_IMAGE_PREFIX=git.hirschmann-koxha.de/taxtronik auf die Registry, TAXTRONIK_VERSION auf das Release. Die Operator-CLI verifiziert Manifest, Tag und Checkout und deployt getrennte web:version@sha256:…-/worker:version@sha256:…-Referenzen; auch die OCI- Revision muss stimmen. Mutable Tags werden nicht als Release-Vertrag akzeptiert. Details und Rollback-Pfad: docs/operations/release.md

Im Source-Kanal (TAXTRONIK_DEPLOY_CHANNEL=source) wird die Version automatisch als source-<Git-Commit> geführt; eine SemVer-Eingabe gibt es dort nicht. Nach erfolgreichen lokalen Builds räumt die Operator-CLI ungenutzten Docker-BuildKit-Cache auf (until=168h). Das lässt sich mit TAXTRONIK_BUILD_CACHE_PRUNE=off abschalten oder per TAXTRONIK_BUILD_CACHE_PRUNE_UNTIL=336h anpassen. Registry-Deploys pullen fertige Images und führen keinen Build-Cache-Prune aus.

Backup-Scope: ./taxtronik backup sichert nur Postgres; backup-files erzeugt nur eine sichtbare Byte-Kopie der SeaweedFS-Buckets. backup-full erstellt dagegen einen zusammenhängenden Wiederanlaufpunkt: Schreibdienste werden quiesziert, beide DBs sowie Byte-Export gesichert und SeaweedFS-/Redis-/n8n- Volumes cold gesnapshottet. Die gesamte Nutzlast einschließlich .env wird age-verschlüsselt und durch ein Ed25519-signiertes SHA-256-Inventar versiegelt; ein getrenntes S3-Offsite-Ziel kann nur mit Versioning + Object Lock COMPLIANCE verwendet werden. Voraussetzungen und Restore-Drill: docs/operations/disaster-recovery.md.

Der Worker erstellt zusätzlich täglich um 01:00 UTC einen Postgres-Dump und streamt ihn direkt in den S3-Backup-Bucket. Dieser automatische Lauf erzeugt keine lokale Air-Gap-Kopie und sichert nicht die SeaweedFS-Dokument-Buckets; dafür ist regelmäßig ./taxtronik backup-full beziehungsweise eine getestete externe SeaweedFS-Replikation erforderlich.

./taxtronik update macht bewusst kein git reset --hard. Wenn lokale Änderungen oder ein nicht-fast-forward Stand existieren, bricht das Kommando ab.

Hinweis zum nächsten Update: Durch die Umstellung der Session-Cookie-Namen auf __Host-/__Secure--Präfixe werden einmalig alle aktiven Sessions invalidiert (Re-Login nötig), und Betreiber mit einer früher kopierten nginx-Config sollten dort die duplizierten Security-add_header-Zeilen entfernen (siehe infra/nginx/taxtronik.conf.example — sonst überschreibt nginx die token-spezifische no-referrer-Referrer-Policy der App).

Wichtige .env-Werte für ein Multi-Domain-Deploy:

NODE_ENV=production
TAXTRONIK_IMAGE_PREFIX=git.hirschmann-koxha.de/taxtronik
TAXTRONIK_VERSION=0.2.1
# Der interaktive Release-Deploy setzt beide Werte automatisch:
UPDATE_MANIFEST_URL=https://git.hirschmann-koxha.de/TaxTronik/updates/raw/branch/main/manifest.json
UPDATE_PUBLIC_KEY=NE1YtBNNPFM545o1VqoBNTcKIPmZP0rmvLq22YyqKaU=

NEXTAUTH_URL=https://kanzlei.example.de
PORTAL_PUBLIC_URL=https://mandanten.example.de
STAFF_COOKIE_DOMAIN=kanzlei.example.de
PORTAL_COOKIE_DOMAIN=mandanten.example.de
NEXTAUTH_TRUST_HOST=true
TRUST_PROXY_REQUIRED=true

POSTGRES_PASSWORD=...
TAXTRONIK_APP_PASSWORD=...
AUTH_SECRET=...
N8N_ENCRYPTION_KEY=...
S3_SECRET_KEY=...

# Ausschließlich für die befristete Migration alter /api/n8n/*-Callbacks:
N8N_LEGACY_CALLBACKS_ENABLED=false
# N8N_HMAC_SECRET=... # bei Callback-Flag oder Outbound-Legacy-URL Pflicht, >= 32 Zeichen

# Produktion: n8n-UI/API immer unter einer eigenen Domain
N8N_HOST=n8n.example.de
N8N_WEBHOOK_URL=https://n8n.example.de/
N8N_PROXY_HOPS=1
N8N_BIND=127.0.0.1
# Nur für Migration bestehender Installationen; neue Routen werden pro
# Workflow in Administration → Einstellungen → n8n-Automatisierung gepflegt:
# N8N_WEBHOOK_BASE_URL=http://n8n:5678/webhook

# Optional: Signal / TCMS. Der interaktive Deploy fragt Modus und Bezugsweg ab.
# managed + source: TaxTronik aktualisiert den Signal-Checkout und baut lokal.
SIGNAL_DEPLOYMENT=managed
SIGNAL_DEPLOY_CHANNEL=source
SIGNAL_GIT_URL=https://git.hirschmann-koxha.de/TaxTronik/signal.git
SIGNAL_GIT_REF=main
SIGNAL_GIT_DIR=/opt/signal
# Alternativ ein bereits veröffentlichtes Image beziehen:
# SIGNAL_DEPLOY_CHANNEL=image
# SIGNAL_IMAGE=git.hirschmann-koxha.de/taxtronik/risk-layer-engine:<signal-release>
RISK_LAYER_URL=http://risk-layer:8000
# Bearer- und Operator-Token werden im managed-Modus getrennt generiert.
RISK_LAYER_TOKEN=...
RISK_LAYER_OPERATOR_TOKEN=...

# Alternativ: native/GPU-Installation oder anderweitig betriebenes Signal.
# TaxTronik nutzt dann nur die API und führt niemals Signal-Updates aus:
# SIGNAL_DEPLOYMENT=external
# SIGNAL_IMAGE=
# RISK_LAYER_URL=http://10.10.0.42:8000

SMTP_HOST=mail.example.de
SMTP_PORT=587
SMTP_USER=...
SMTP_PASSWORD=...
SMTP_FROM="TaxTronik <noreply@example.de>"

Mailhog ist ausschließlich Teil des lokalen Dev-Stacks. In Produktion müssen SMTP_HOST, SMTP_PORT und SMTP_FROM auf ein echtes SMTP-Relay zeigen; ./taxtronik doctor blockt mailhog sowie localhost:1025/127.0.0.1:1025.

n8n-Integration

TaxTronik trennt die n8n-Instanz von den eigentlichen Workflow-Zielen: Instanz-UI, Management-API (/api/v1), Webhook-Präfix (/webhook) und exakte Production-Webhook-URL eines veröffentlichten Workflows sind verschiedene Adressen. Neue und eigene Workflows werden unter Administration → Einstellungen → n8n-Automatisierung mit ihrer exakten Production-URL registriert und abonnieren nur die benötigten Events. Mehrere Ziele pro Event werden unabhängig zugestellt. Neue oder geänderte Ziele bleiben zunächst deaktivierte Entwürfe: erst synthetisch testen, dann unverändert in einem zweiten Speichervorgang aktivieren.

N8N_WEBHOOK_URL bestimmt die von n8n angezeigte externe Webhook-Basis. N8N_WEBHOOK_BASE_URL ist dagegen nur der TaxTronik-Legacy-Fallback <basis>/<event> und soll bei neuen Installationen leer bleiben; der Production-Compose-Default ist deshalb leer. Wird er für eine Bestandsmigration gesetzt, ist wie beim Legacy-Callback-Flag ein mindestens 32 Zeichen langes N8N_HMAC_SECRET Pflicht. Der Wert ersetzt keine konkreten Workflow-Ziele. Test-URLs mit /webhook-test/ sind nicht produktionsfähig; der Workflow muss in n8n veröffentlicht sein.

Für die Gegenrichtung erzeugt der Assistent ein separates, tenantgebundenes Callback-Credential aus Key-ID, einmal angezeigtem Bearer-Token und minimalen Scopes. Neue Workflows rufen damit ausschließlich /api/integrations/n8n/v1/* auf. Der n8n-Management-API-Key und das pro Tenant gespeicherte Outbound-HMAC-Secret sind davon unabhängige Zugangsdaten. Die globalen Legacy-Callbacks /api/n8n/* liefern standardmäßig vor jeder Authentifizierung 404. Nur für eine befristete Bestandsmigration werden sie mit N8N_LEGACY_CALLBACKS_ENABLED=true und einem mindestens 32 Zeichen langen N8N_HMAC_SECRET freigeschaltet. Beim Workflow-Import materialisiert TaxTronik App-Basis, Key-ID und Mail-Nicht-Geheimnisse interaktiv; Bearer-, HMAC- und SMTP-Secrets bleiben n8n-Credentials. Die App-Basis wird getrennt als TaxTronik-Adresse aus n8n gespeichert (BUNDLED: in Produktion http://app:3000, im lokalen Dev-Stack http://host.docker.internal:3000; extern: eine aus der n8n-Laufzeit erreichbare öffentliche Adresse). Die Vorlagen benötigen weder $env noch die editionsabhängigen $vars und sind mit n8n Community kompatibel.

Geführtes Setup, eigene Workflows, Eventkatalog und Datenschutz: n8n-Automatisierungen. Betrieb und Fehlerdiagnose: Day-2 Operations.

Reverse Proxy und TLS liegen vor der App. Die Compose-Ports sind auf localhost gebunden; der Object-Store bleibt intern. Das nginx-Beispiel enthält den Single-Host-Default, Hinweise für /api/integrations/n8n/v1/* und Legacy-/api/n8n/*, den eigenen n8n-UI-VHost und ein Staff-/Portal-Split-Setup: infra/nginx/taxtronik.conf.example

Für getrennte Staff-/Mandanten-Domains:

  • NEXTAUTH_URL zeigt auf die Staff-/Kanzlei-URL.
  • PORTAL_PUBLIC_URL zeigt auf die Mandantenportal-URL und wird für Mandanten-Magic-Links, PoA- und GwG-Onboarding-Links genutzt.
  • STAFF_COOKIE_DOMAIN und PORTAL_COOKIE_DOMAIN sind Subdomain-spezifisch, nie die Parent-Domain.
  • n8n ruft neue App-Endpunkte unter /api/integrations/n8n/v1/* mit tenantgebundenem, scoped Callback-Credential auf; TaxTronik materialisiert die intern oder per Proxy erreichbare App-Basis beim Import in die ausgewählten Vorlagen.

Details: docs/operations/subdomain-trennung.md, n8n-Anwenderdokumentation und infra/n8n/workflows/README.md.

Weitere Betriebsrunbooks:

Weitere Operator-Kommandos (docker-compose-Passthrough):

./taxtronik ps
./taxtronik logs app --tail 80
./taxtronik logs worker --tail 80
./taxtronik --infra up -d      # nur Infra (Postgres/Redis/S3/ClamAV)
./taxtronik down

Qualitätssicherung

pnpm lint
pnpm typecheck
pnpm test
pnpm test:ops
pnpm e2e
pnpm verify:schema-drift
pnpm verify:chain

Hinweise:

  • pnpm lint prüft TypeScript (@typescript-eslint), React Hooks (eslint-plugin-react-hooks), Next.js-Konventionen (@next/eslint-plugin-next) und domänenspezifische AST-Regeln (RBAC-Guardrails).
  • pnpm test läuft via Turborepo über alle Workspaces mit Test-Skript — neben der Web-App auch die Worker-Jobs (apps/worker/src/jobs/__tests__) und die Packages (u. a. tax, evidence, db, crypto, http-utils, rss, n8n-shared), inkl. Auth-Suiten für TOTP, Magic-Link und Lockout.
  • pnpm test:ops prüft die Operator-CLI-Gates (doctor, Prod-SMTP ohne Mailhog, Risk-Layer-Paarung, Build-Cache-Prune, Restore-Quellwahl), die fail-closed Update-/Backup-Reihenfolge und restriktive Secret-Dateirechte ohne echten Deploy.
  • E2E-Login-Tests brauchen E2E_TOTP_SECRET.
  • RLS-Cross-Tenant-Tests skippen lokal ohne DB-URLs, schlagen in CI aber fehl, wenn DATABASE_URL oder DATABASE_APP_URL fehlt.
  • pnpm verify:chain prüft die Audit-Hash-Chain.
  • Der CI-Job restore fährt einen echten Backup→Restore-Roundtrip (runner --out-filerestore --file) und prüft Zeilenzahlen sowie die Audit-Hash-Chain auf der wiederhergestellten DB. Lokal: DATABASE_URL=… bash scripts/restore-selftest.sh (siehe docs/operations/disaster-recovery.md, Abschnitt 7.1).
  • Das Assurance-Modell bündelt Threat Model, Known Limits und Release-Gates: docs/assurance/assurance-model.md.

Projektstruktur

apps/
  web/       Next.js UI, API-Routen, Server Actions, Backup/Restore
  worker/    BullMQ Worker für Reminder, Audit, n8n-Outbox, Backup und Wartung
  e2e/       Playwright-Tests

packages/
  config/      ENV-Schema und zentrale Runtime-Konfiguration
  crypto/      Kryptografie-Helfer
  db/          Prisma-Schema, Migrationen, RLS/Tenant-Kontext
  elster/      ERiC-/ELSTER-Integrationsgrenzen und Adapterlogik
  evidence/    Audit-Hash-Chain, Archive, Verify-CLI
  http-utils/  Safe Fetch, SSRF-Guards, Netzwerk-Utilities
  mail/        Template-Mail-Versand (SMTP, Dispatch, Safe-Markdown) für Web + Worker
  n8n-shared/  Eventkatalog, HMAC-Signatur und Outbox-Enqueue-Kern für App/Worker -> n8n
  risk-layer/  Zustandsloser §4-Engine-Client (Risk Analysis)
  rss/         RSS-Fetching und Parser
  storage/     S3/SeaweedFS-Client, Retention, Scan-Pipeline
  tax/         Steuertermine und fachliche Rechenlogik

infra/
  compose/  Docker-Compose Basis, Dev- und App-Overrides
  docker/   Dockerfiles für Web und Worker
  n8n/      Versionierte Workflow-Exports
  nginx/    Reverse-Proxy-Beispiel
  scripts/  Postgres-/Storage-Init

docs/
  README.md      Zielgruppenorientierter Dokumentationsindex
  adr/           Architecture Decision Records
  anwenderdoku/  Versioniertes Benutzerhandbuch
  assurance/     Bedrohungs-/Kontrollmodell und Prüfvorlagen
  compliance/    DSGVO, GoBD, GwG, eIDAS und Readiness
  development/   Entwicklungs-/Testverfahren und Modulbeschreibungen
  fachkatalog/   Fachregeln mit Review- und Umsetzungsstatus
  operations/    Betrieb, Disaster Recovery, Subdomains
  archive/       Historische, nicht mehr geltende Unterlagen

Compliance

TaxTronik ist für regulatorisch sensible Kanzleidaten gebaut:

  • Berufsgeheimnis / Mandantentrennung: Postgres-RLS plus App-Level-Filter.
  • GoBD: Object-Lock, Audit-Hash-Chain, Tagesversiegelung, Retention.
  • DSGVO: Lösch-/Auskunftskonzepte, Portal-/Staff-Trennung, minimale öffentliche Angriffsfläche.
  • GwG: Verifizierungs-Workflows und systemische Schranken.
  • eIDAS: RFC-3161-Zeitstempel-Adapter; die PoA-Bestätigung per Magic-Link und E-Mail-Code wird nicht als fortgeschrittene oder qualifizierte Signatur zugesagt.

Sicherheitslücken vertraulich melden: siehe SECURITY.md.

Vor Produktivstart sollte ein externer Penetrationstest und ein Restore-Test aus einem echten Backup erfolgen.

Lizenz

Der Projektquellcode steht unter der GNU Affero General Public License, Version 3. Der vollständige Lizenztext liegt in LICENSE.