Files
certvia/docs/HANDOVER-DEV.md
T
msolarczekandClaude Opus 4.8 8e4040d1da Separater Superadmin-Store + eigener Login + MFA-Pflicht (Phase-1-Härtung Paket 2)
Plattform-Administratoren sind nicht länger isPlatformAdmin-Nutzer innerhalb eines
Mandanten, sondern ein getrennter Store mit eigener Auth-Domäne — Voraussetzung
für den sicheren Betrieb beim ersten echten Kunden.

Store & Migration
- Neues Modell PlatformAdmin (kein tenant_id): Argon2id-Hash, TOTP-Secret,
  Recovery-Codes (nur SHA-256-Hashes), Fehlversuchszähler + Sperre, lastLogin.
- AuditLog.tenant_id nullable → mandantenlose Plattform-Ereignisse (scope=platform).
- Datenmigration: bestehende isPlatformAdmin-Nutzer in den neuen Store übernommen
  (gleicher Hash → Login sofort möglich), Flag mandantenweit auf false gesetzt.

Getrennter Login + MFA
- Zweite NextAuth-Instanz (server/platform-auth.ts) mit eigenem Cookie und
  eigenem basePath /api/platform-auth; Session trägt bewusst KEINEN tenantId.
- TOTP-MFA (otplib): Enrollment beim ersten Login (/platform/enroll-mfa, QR +
  Klartext-Secret), danach bei jedem Login erzwungen; 10 einmalige Recovery-Codes.
- Härtung: Konto-Sperre nach 5 Fehlversuchen (15 min), Audit aller Anmeldungen,
  Fehlversuche und Sperren (scope=platform).

Autorisierung / Trennung
- Admin-Konsole nach (platform)/admin verschoben; (platform)/layout.tsx erzwingt
  Plattform-Session + aktivierte MFA. Mandanten-Session hat KEINEN Zugriff auf /admin.
- Mandanten-Shell zeigt keinen /admin-Link mehr; admin-Actions prüfen die
  Plattform-Session statt des abgelösten Flags.
- provision/seed setzen isPlatformAdmin nicht mehr; Seed legt den Demo-Plattform-
  Admin (admin@demo.example) im getrennten Store an.

Browser-verifiziert: Plattform-Login → erzwungenes MFA-Enrollment → Recovery-Codes →
/admin; Login ohne Code scheitert (?error=1); Mandanten-Session auf /admin wird auf
/platform/login umgeleitet. tsc + lint + build + Guard-Check grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 20:55:12 +02:00

11 KiB
Raw Blame History

Entwickler-Übergabe — ISMS-Tool

Stand: 2026-07-20 · Branch main · letzter Commit 6ddeedf Zweck: Kontext, Setup und Konventionen, damit ein neuer Entwickler direkt weiterarbeiten kann. Fachlicher Status (fertig/offen) siehe docs/HANDOVER-PM.md.


1. Repository & Zugriff

  • Lokaler Pfad: ~/Projects/ISMS-Tool
  • Git-Remote (Gitea, nur HTTP): http://gitea-vkbhbn2qdkz5ppk9q4qgb0tn.192.168.1.207.sslip.io/msolarczek/ISMS-Tool.git (interner Server; kein SSH). Zugangstoken liegt im macOS-Schlüsselbund (nicht im Repo, nicht in Klartext weitergeben). Für git push wird der Token als HTTP-Passwort verwendet.
  • Default-Branch: main (es wird direkt auf main committet; Commits sind fein granular je Thema).
  • Commit-Konvention: deutschsprachige, aussagekräftige Messages; Referenz auf Spec-Abschnitte (z. B. „§7b"). Co-Authored-By-Trailer für KI-Beiträge.

2. Tech-Stack (verifizierte Versionen)

Bereich Technologie
Runtime Node.js 26
Framework Next.js 16 (App Router, React 19, Server Components + Server Actions, Turbopack im Dev)
Sprache TypeScript (strict)
DB / ORM PostgreSQL (mit pgvector) · Prisma 7 (@prisma/client + @prisma/adapter-pg, prisma.config.ts)
Auth NextAuth v5 (Credentials, JWT-Session) · Passwörter mit @node-rs/argon2
i18n next-intl (Default de, en vorbereitet; Catalog in messages/de.json/en.json)
UI Tailwind v4 + shadcn/ui (Base-UI-Variante), Dark-Theme über zentrale CSS-Tokens in src/app/globals.css
Spezial Handlebars + marked (Richtlinien-Rendering), @xyflow/react + @dagrejs/dagre (Abhängigkeitsgraph), zod (Validierung)

Scripts (package.json): dev (next dev), build, start, lint (eslint). Seed: npx tsx prisma/seed.ts.


3. Setup (von Null)

# 1. Repo klonen (Token als HTTP-Passwort)
git clone http://gitea-…/msolarczek/ISMS-Tool.git
cd ISMS-Tool

# 2. Abhängigkeiten
npm install

# 3. .env anlegen (Vorlage vorhanden)
cp .env.example .env
#   Wichtige Variablen: DATABASE_URL (Postgres inkl. pgvector), AUTH_SECRET, AUTH_URL,
#   optional REDIS_URL, AI_PROVIDER/AI_API_KEY, SMTP_* (noch ungenutzt).

# 4. Infrastruktur starten (docker-compose.yml im Repo-Root)
docker compose up -d postgres  # Postgres mit pgvector (Image pgvector/pgvector:pg16)
#   Weitere Services im Compose: app, worker, redis, minio (Objektspeicher, für späteren
#   Logo-Upload), mailhog (SMTP-Dev). Für lokale Entwicklung reicht i. d. R. 'postgres'.

# 5. Prisma-Client + Migrationen
npx prisma generate
npx prisma migrate deploy      # wendet alle Migrationen an (inkl. RLS-Policies)

# 6. Seed (Demo-Mandant, Kataloge, Richtlinienpaket, Admin-Konsole)
npx tsx prisma/seed.ts

# 7. Dev-Server
npm run dev                    # http://localhost:3000  (Port 3000, siehe .claude/launch.json)

Demo-Logins (Passwort Demo1234!): admin@demo.example (Mandanten-Admin + ISB), auditor@demo.example, owner@demo.example, user@demo.example — alle über den Mandanten-Login /login.

Plattform-Admin (Betrieb): getrennter Store + eigener Login /platform/login (TOTP-MFA-Pflicht, Enrollment beim ersten Login). Demo-Konto: admin@demo.example / Demo1234! (gleiche Adresse, aber getrennte Session ohne Mandantenkontext). Das frühere isPlatformAdmin-Flag ist abgelöst; die Admin-Konsole /admin ist nur mit Plattform-Session erreichbar. Siehe Paket 2 der Produktionshärtung.


4. Architektur & tragende Konventionen

Mandantenfähigkeit (kritisch!)

  • Jede Fachtabelle hat tenant_id. Nie ohne Mandantenkontext queren.
  • Zentraler Guard dbForTenant(tenantId) in src/server/db.ts: filtert reads automatisch nach tenantId, injiziert ihn bei create, prüft Ownership bei findUnique/update/delete. Neue tenant-bezogene Modelle müssen in TENANT_MODELS (in db.ts) eingetragen werden.
  • Zusätzlich Postgres Row Level Security je Tabelle (Policy tenant_isolation, gesetzt in den Migrationen). Superadmin/plattformweite Reads laufen über den rohen prisma-Client (nicht dbForTenant).
  • Session (src/server/auth.ts) trägt tenantId, roles, permissions, isPlatformAdmin.

RBAC

  • Katalog + Rollen-Blueprints in src/server/rbac.ts (PERMISSIONS, ROLE_DEFS). Serverseitige Durchsetzung: requirePermission(session, "x:y") / hasPermission(...). UI-Verstecken ist nur Komfort.

Modul-Gating (§3.4)

  • Modul-Katalog in src/lib/modules.ts. Je Mandant TenantModule-Zeilen (enabled). Navigation blendet deaktivierte Module aus (layout.tsx).
  • Serverseitige Durchsetzung: requireModule("key") in src/server/modules.ts, angewandt als Modul-layout.tsx je Routenordner (assets/, processes/, risks/, measures/, policies/, suppliers/, dependencies/) → schützt auch Unterrouten. In Server-Actions läuft der Layout-Guard erst nach der Mutation, daher zusätzlich requireModule im Action-guard() (bisher exemplarisch nur policies.tsauf übrige Action-Dateien nachzuziehen).

UI-Muster

  • Detail/Bearbeiten/Anlegen überwiegend als URL-gesteuerte Popups (?detail=/?edit=/?new=1, src/components/modal.tsx) — Ausnahme: Richtlinien-Dokumente wurden bewusst auf eigene Seiten (/policies/[code], .../edit) umgestellt.
  • Dark-Theme: keine hartkodierten Hex-Werte in Komponenten — zentrale Tokens verwenden (--bg-0, --panel, --surface-soft, --band, --ok/--warn/--risk/--info, …).
  • Formulare mit „einem Speichern-Button" nutzen HTML-form-Attribut-Assoziation (form="id").
  • Alle sichtbaren Texte über den next-intl-Catalog (messages/*.json) — Admin-/Register-Detailtexte teils bewusst inline-Deutsch.

Prisma-7-Migrationen (Eigenheit)

Nicht-interaktiv, in zwei Schritten:

npx prisma migrate diff --from-config-datasource prisma.config.ts \
  --to-schema prisma/schema.prisma --script > prisma/migrations/<ts>_name/migration.sql
# RLS-DO-Block manuell an die migration.sql anhängen (siehe bestehende Migrationen)
npx prisma migrate deploy

(Die interaktiven migrate dev-Prompts sind in dieser Umgebung blockiert; Flag-Namen in Prisma 7 geändert: --from-config-datasource/--to-schema.)


5. Verzeichnisstruktur (Auszug)

src/
  app/(app)/            # geschützter App-Bereich (Sidebar-Shell = layout.tsx)
    dashboard/ assets/ processes/ risks/ measures/ dependencies/ suppliers/
    policies/           # Richtlinien: page + [code]/(page,edit) + layout.tsx (Modul-Guard)
    admin/ admin/[id]/  # Plattform-Admin-Konsole (Superadmin)
    settings/           # Kunden-Einstellungen (tenant:manage)
  app/login/            # Login
  components/           # UI + Fach-Modals (asset-, supplier-, service-, policy-*.tsx …)
  server/
    auth.ts db.ts rbac.ts modules.ts provision.ts audit.ts
    risk-calc.ts dependency-graph.ts
    actions/            # Server Actions je Modul (assets, risks, measures, suppliers,
                        #   services, policies, admin, tenant-settings)
  lib/                  # modules, policy-render, supplier(+include), risk, control-titles,
                        #   isa-controls, levels, measure, utils
prisma/
  schema.prisma  seed.ts  import-policies.ts  import-managed.ts  migrations/
messages/  de.json  en.json
seed/isms-vorlagenpaket-v2/   # VDA-ISA-Vorlagenpaket (Richtlinien/Verfahren, mapping.json, Baseline …)
docs/  SPEC.md  HANDOVER-PM.md  HANDOVER-DEV.md  *.html (Mockups)

6. Modul-Kurzreferenz (wo liegt was)

  • Richtlinien: Rendering-Engine src/lib/policy-render.ts (Handlebars, Flags, BL-Entfernung, applyProtection für TISAX-Level), Import prisma/import-policies.ts + prisma/import-managed.ts, UI src/app/(app)/policies/** + src/components/policy-*.tsx, Actions src/server/actions/policies.ts. Control-Titel src/lib/control-titles.ts.
  • Lieferanten/IT-Service: Engine src/lib/supplier.ts, Includes src/lib/supplier-include.ts, UI src/components/supplier-modals.tsx/service-modals.tsx/supplier-cockpit.tsx, Actions suppliers.ts/services.ts.
  • Admin/Mandanten: Provisionierung src/server/provision.ts (von Seed und actions/admin.ts genutzt, idempotent), actions/tenant-settings.ts (Stammdaten → ISMS-Variablen via syncPolicyVariablesFromSettings).
  • Risiko/Graph: src/server/risk-calc.ts, src/server/dependency-graph.ts, src/lib/risk.ts.

7. Datenmodell — zentrale Modelle

Tenant, TenantSettings (Quelle der ISMS-Variablen), TenantModule, User (isPlatformAdmin), Role/Permission/RolePermission/UserRole, AuditLog (scope: tenant|platform). Fachlich: Asset/AssetRelation, Process/ProcessAsset/BiaEntry, Risk/RiskAsset/Measure/RiskMeasure, Threat/Vulnerability, SupplierProfile/ITServiceProfile (+ Assessments/Contracts/Ndas/Evidence/Raci/Maturity), Richtlinien: PolicyDocument/PolicyRequirement/PolicyVariable/PolicyBaselineParam/PolicyEvidence + verwaltete Register (CryptoEntry, ClassificationClass/HandlingAspect/HandlingRule, RiskMatrixClass/RiskEwLevel/RiskDamageDimension, HandbookTopic).


8. Verifikations-Workflow

Nach jeder Änderung: npx tsc --noEmitnpm run lintnpm run build. Danach wo relevant Browser-Verifikation (Dev-Server + Login admin@demo.example). Bei DB-Änderungen: Migration erzeugen/anwenden + npx tsx prisma/seed.ts neu laufen lassen. Für das Richtlinien-Rendering existiert ein Residue-Check-Muster (rückstandsfrei über Flag-Kombinationen, angelehnt an seed/.../_verify.py).


9. Bekannte Fallstricke

  1. Beschädigte Seed-Tokens: Das VDA-ISA-Paket enthält in einigen VA-RACI-Tabellen (VA-05/08/09/10/12/13) abgeschnittene {{VAR |-Tokens. Bei jedem Paket-Update erneut prüfen & reparieren (sonst bricht Handlebars). Scan: unbalancierte {{/}} je Zeile.
  2. Richtlinien-Re-Import ist destruktiv (delete+recreate): setzt per-Dokument-Status/Override/Freigabe zurück. „Deaktivieren statt löschen" ist offene Anforderung.
  3. RLS-Kontext: RLS-Policies erwarten current_setting('app.tenant_id'). Die App nutzt primär den dbForTenant-Guard; wenn direkte DB-Zugriffe hinzukommen, app.tenant_id in der Transaktion setzen.
  4. Turbopack-HMR kann veraltete Fehler/MISSING_MESSAGE zeigen, nachdem messages/*.json geändert wurde → Dev-Server neu starten. Produktions-Build ist maßgeblich.
  5. Prisma-7-Migrationsflow wie in §4 (kein migrate dev).
  6. .next-Cache nicht löschen, während der Dev-Server läuft (Turbopack-Korruption) → Server stoppen, rm -rf .next, neu starten.
  7. TISAX-Flags: FLAG_HIGH_PROTECTION ist im Modell stets aktiv, FLAG_ELEVATED_PROTECTION wird abgeleitet (applyProtection) — nie manuell setzen. Effektiver Level = Dokument-Override sonst global.

10. Nächste sinnvolle Aufgaben (Einstiegspunkte)

  • API-Modul-Enforcement vervollständigen (S): await requireModule("<key>") in den guard()/Action-Einstiegen der übrigen Action-Dateien ergänzen (Vorlage: actions/policies.ts).
  • Admin Phase 2 — Impersonation (M): neues Modell ImpersonationSession, Cookie-basierter effektiver Tenant + Banner, Ablauf, Audit.
  • NIS2-Modul (L): eigenes Modul inkl. Incident-Reporting mit Fristen-Timern.
  • Richtlinien-Versionierung/Diff (ML) und DOCX/PDF-Export (M).

Weitere Details, Priorisierung und Aufwände: docs/HANDOVER-PM.md. Projekt-Spec: docs/SPEC.md + Modul-Prompts/Mockups.