# Entwickler-Übergabe — ISMS-Tool > Stand: 2026-07-22 · Branch `dev` (Produktionshärtung + Benutzerverwaltung) · Basis `main` > Zweck: Kontext, Setup und Konventionen, damit ein neuer Entwickler direkt weiterarbeiten kann. > Fachlicher Status (fertig/offen) siehe **`docs/HANDOVER-PM.md`**. Neue Härtungs-/Verwaltungspakete: §10. --- ## 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) ```bash # 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.ts` — **auf ü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: ```bash npx prisma migrate diff --from-config-datasource prisma.config.ts \ --to-schema prisma/schema.prisma --script > prisma/migrations/_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 --noEmit`** → **`npm run lint`** → **`npm 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 nicht-destruktiv** (Phase-1-Härtung Paket 3, `prisma/import-policies.ts`): Diff/Upsert über stabile Schlüssel (`code`/`reqId`/`key`/`blId`/`nr`). Vorhandenes wird inhaltlich aktualisiert, aber **Status/Override/Freigabe** (PolicyDocument) und **nutzergepflegte Variablenwerte** bleiben erhalten; entfernte Paket-Einträge werden **deaktiviert** (`archivedAt`) statt gelöscht (aktive Ansichten filtern `archivedAt: null`). Verwaltete Register aus `import-managed.ts` (CRYPTO/RISKMATRIX/CLASSIFICATION/HANDBUCH) liegen außerhalb des Paket-Namensraums und werden nicht angetastet. Jeder Lauf liefert einen Änderungsreport (Audit-Log, Entity `policy_package`); `{ dryRun: true }` erzeugt die Vorschau ohne Schreibzugriff. Akzeptanztest: `npx tsx scripts/test-reimport.ts`. 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. Produktionshärtung & Benutzerverwaltung (umgesetzt, Branch `dev`) Aufbauend auf dem Fundament wurden mehrere Härtungspakete umgesetzt (feingranulare Commits auf `dev`): - **API-Modul-Durchsetzung (§3.4):** zentraler `moduleGuard("")` in `src/server/action-guard.ts`; jede mutierende Action eines gegateten Moduls läuft über `guard(...)` (Session → `assertModuleEnabled` → RBAC). Vollständigkeitscheck `scripts/check-module-guards.ts` (Registry Action→Modul) als `prebuild` — Build failt bei nicht zugeordneter Action-Datei. Neue Action-Datei ⇒ dort eintragen (Modul-Key oder `EXEMPT`). - **Plattform-Admins getrennt:** Store `PlatformAdmin` (kein `tenant_id`), eigene NextAuth-Instanz `src/server/platform-auth.ts` (eigener Cookie/basePath `/api/platform-auth`, Session ohne Tenant), Login `/platform/login`, Bereich unter `src/app/(platform)/…`. **MFA (TOTP, `src/server/mfa.ts`) ist optional** — Enrollment nur erzwungen, wenn `PlatformSetting.mfaRequired` (Singleton) an ist; Umschaltung + Self-Service unter `/platform/profile`. Rate-Limit/Lockout am Login bleiben. Audit `scope=platform` via `writePlatformAudit`. - **Nicht-destruktiver Richtlinien-Re-Import:** siehe §9 Punkt 2. - **Benutzer- & Rollenverwaltung (ohne E-Mail-Flow):** - Plattform-Admin je Mandant: `src/server/actions/platform-users.ts` + `components/platform-tenant-users.tsx`, eingebettet in `/admin/[id]`. Anlegen mit **Initial-/Einmal-Passwort** (selbst setzen oder generiert, einmalig angezeigt), Rollen, Deaktivieren/Reaktivieren, Passwort-Reset. - Mandanten-Admin intern: `src/server/actions/tenant-users.ts` + `components/tenant-users-manager.tsx`/`role-manager.tsx`, Seite `/settings/users` (nur `user:manage`/`role:manage`). Benutzer-CRUD **und** Rollen-CRUD (eigene Rollen + Permissions; Standardrollen schreibgeschützt/klonbar). Strikt `dbForTenant(session)` → kein Cross-Tenant. **Lockout-Schutz** für den letzten aktiven Mandanten-Admin. - **Force-Change:** neue Nutzer starten mit `mustChangePassword=true`; das `(app)`-Layout leitet autoritativ (DB) auf `/change-password` und sperrt deaktivierte Konten. Passwort-Policy: `src/lib/password-policy.ts` (Validierung, client-safe) + `src/server/password.ts` (Argon2id-Hash + Generator); Quelle `TenantSettings.securityPolicy.password`. - **Nutzer-MFA optional:** Tenant-Login (`auth.ts`) verlangt TOTP nur bei eingerichteter MFA; Self-Service unter `/account`. `role:manage` ist neu im RBAC-Katalog (Mandanten-Admin). - **Bearbeiten:** je Nutzer sind **Name & E-Mail** (E-Mail eindeutig je Mandant), Rollen, Aktiv/Deaktiviert und Passwort-Reset editierbar — in beiden Konsolen. - **Zuständigkeit Einstellungen (Superadmin vs. Tenant-Admin):** **Kern-Einstellungen** (aktive Module, TISAX-/Schutzbedarf-**Tiefe**, Richtlinienpaket) steuert ausschließlich der **Superadmin** in der Admin-Konsole (`/admin/[id]`, u. a. `setTenantTisaxLevel`). Der **Tenant-Admin** pflegt in `/settings` nur seinen Bereich (Stammdaten/Branding → ISMS-Variablen) + Benutzer/Rollen; die TISAX-Tiefe ist dort nur noch als Read-only-Anzeige. - **Zukunftssicher:** `createTenantUser`/`createUser` kapseln die Aktivierung über Initial-/Einmal-Passwort — der spätere **E-Mail-Einladungs-Flow (Paket 4)** lässt sich als alternative Aktivierung (Token statt Passwort) einhängen, ohne die UI umzubauen. ## 11. Nächste sinnvolle Aufgaben (Einstiegspunkte) - **SMTP + Einladungs-/Aktivierungs-/Reset-Flow (Paket 4, M):** transaktionale Mails (Nodemailer), signierte Einladungs-/Reset-Tokens; ersetzt/ergänzt den Initial-Passwort-Weg. - **Admin Phase 2 — Impersonation (M):** neues Modell `ImpersonationSession`, Cookie-basierter effektiver Tenant + Banner, Ablauf, Audit. - **Tenant-weite MFA-Pflicht scharfschalten (S):** `securityPolicy.mfaRequired` wird von `disableOwnMfa` bereits respektiert; Enrollment-Erzwingung analog zum Force-Change-Gate (Seite außerhalb der `(app)`-Shell) nachziehen. - **NIS2-Modul (L):** eigenes Modul inkl. Incident-Reporting mit Fristen-Timern. - **Richtlinien-Versionierung/Diff (M–L)** und **DOCX/PDF-Export (M)**. Weitere Details, Priorisierung und Aufwände: **`docs/HANDOVER-PM.md`**. Projekt-Spec: **`docs/SPEC.md`** + Modul-Prompts/Mockups.