Files
craftvia/docs/STAND-dev-branch.md
T
msolarczekandClaude Opus 5 c8e6f30a27
CI / build-and-check (push) Canceled after 0s
CI / audit (push) Canceled after 0s
CI / sbom (push) Canceled after 0s
Basis: Certvia dev@a48c5fb als Fundament für Craftvia
Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation
und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 11:05:39 +02:00

74 KiB
Raw Blame History

Entwicklungsstand dev — Konsolidierte Übergabe (PM + neue Entwickler)

Stand: 2026-07-30 · Branch dev · Sync-Hinweis: lokal deutlich vor origin/dev (origin/dev = 9b479ab); enthält u. a. Prod-Deployment-Vorbereitung, Wizard-Kickoff + Story A1-1 und diese Doku. dev ist auf origin (git.certvia.de) und local-gitea (intern) gepusht. Vor dem nächsten Push zuerst git fetch und prüfen, ob niemand weitere Commits hat. Alle Feature-Branches (Dev A: A1–A8; Dev B: F1–F4, B1–B7 inkl. Prüfziel-Follow-up) sowie Certvia-Branding, der Wizard-Parallelisierungs-Fix und zuletzt das Security-Härtungspaket P1/P2/P3 (F-01…F-20, u. a. RLS scharf F-04, moduleGuard-DB-Authz F-06, MFA-Replay, Container-/Supply-Chain-Härtung F-11/F-18) sowie SEC1 (Mailversand/Queue), SEC2 (Auth-Self-Service: Passwort-Reset/-Wechsel/E-Mail-Änderung, Session-Invalidierung, Rate-Limit) und zuletzt die TISAX-Umstrukturierung (M0–M4: Fundament, Strukturanalyse, Cockpit mit RACI/Evidence, Audit-Wizard, TISAX-Tasks, Wizard-Neustruktur; v3: Prozesshaus + geführtes BIA je Prozess) sowie SEC3/SEC4 (MFA pro Mandant erzwingen, WebAuthn/Passkeys, TOTP-Verschlüsselung at rest, Plattform-Admin-Verwaltung) sind per DevOps-Integration additiv nach dev konsolidiert (Gate grün); noch offene Feature-Branches rebasen auf dev. Deployment-Pflichtschritte aus dem Security-Paket siehe §1a (F-04 RLS scharfschalten, F-06×F-10 scripts/sync-role-permissions.ts nach migrate). SEC1/SEC2 fürs Deployment: eigener Mail-Worker-Service (npm run worker:mail = scripts/mail-worker.ts) nötig, echte SMTP-Variablen setzen, und die Queue nutzt Redis (REDIS_URL mit Passwort, BullMQ/ioredis) — der Worker fehlt noch in docker-compose.coolify.yml. · Basis-Doku: docs/HANDOVER-DEV.md, docs/HANDOVER-PM.md, docs/SPEC.md Zweck: Ein Dokument, das den kompletten Stand der Weiterentwicklung auf dev zusammenfasst — fachlich (für PM) und technisch (für einen neuen Entwickler). dev ist noch nicht nach main gemergt.

Neu (2026-08-07): feature/settings-roles-platform-ui integriert (Einstellungen umstrukturiert: Risikokriterien/Rollen als Menü-Karten + Link zur Plattform-Administration; neue Route /settings/risk-criteria). Zusätzlich Audit-Trail einsehbar je Mandant: wiederverwendbares server-gerendertes Popup (src/components/audit-trail.tsx, Muster wie die übrigen Popups über ?audit=1) an zwei Stellen — Mandanten-Einstellungen /settings (eigener Mandant, TENANT_MODELS/RLS-gefiltert) und Plattform-Konsole /admin/[id] (Superadmin, cross-tenant über Owner-Client auf den Mandanten gefiltert). Keine neue Migration. Gate grün (tsc/lint/build + 17/17 Tests), Popup im Browser verifiziert.

Fix (2026-08-07): dev-fix-platform-admin integriert — Proxy-Gate für Plattform-Routen (src/proxy.ts): /platform/login + /api/platform-auth sind jetzt public, und /admin, /admins, /profile, /platform gaten aufs Plattform-Session-Cookie und leiten anonyme Besucher auf /platform/login statt fälschlich auf die Mandanten-Login-Maske. Plus klarerer Modul-Toggle in /admin/[id] (Status-Pill + eigener „Aktivieren/Deaktivieren"-Button). Verifiziert: /admin|/admins|/profile → 307 /platform/login, /dashboard weiterhin → /login. Gate grün (17/17).

Fix (2026-08-07, 2): Plattform-Auth bekommt eigene Cookie-Namen für ALLE Auth.js-Cookies, nicht nur sessionToken (src/server/platform-auth.ts): auch csrfToken (__Host-platform-authjs.csrf-token) und callbackUrl (platform-authjs.callback-url). Grund: zwei Auth.js-Instanzen auf derselben Domain teilten sich die Default-Cookies authjs.csrf-token/authjs.callback-url; da ein Nutzer zugleich Mandanten- und Plattform-Konto sein kann, überschrieb die zuletzt aktive Instanz das gemeinsame CSRF-Cookie → CSRF-Validierung der Plattform-Instanz schlug fehl (Sign-out warf, CSRF-POSTs/Session-Erneuerung landeten auf der Login-Maske). Getrennte Cookie-Namen isolieren beide Auth-Domänen vollständig. Gate grün (17/17).

Fix (2026-08-07, 3): Plattform-Cookie-secure/Prefix folgt jetzt dem AUTH_URL-Protokoll (https:) statt NODE_ENV (src/server/platform-auth.ts, PLATFORM_SECURE_COOKIES), exakt wie Auth.js es für die Mandanten-Instanz tut (useSecureCookies ?? url.protocol === "https:"). Grund: im Container ist NODE_ENV=production, der interne Testserver wird aber ggf. über http bedient (AUTH_URL=http bzw. fehlendes X-Forwarded-Proto); ein hart auf __Secure-/__Host-/secure gesetztes Cookie wird vom Browser über http verworfen → Plattform-Session bleibt leer (jede Aktion → Login-Maske, Logout wirft), während die Mandanten-Session weiterläuft. Betriebshinweis: In Prod AUTH_URL=https://… setzen (dann greifen wieder secure-Cookies + __Host-/__Secure--Prefixe). Gate grün (17/17).

Identity/Mandanten (Option C), WS0 (Fundament) — 2026-08-11: globales Identity-Modell (kein tenant_id, nicht in TENANT_MODELS, keine RLS) + User.identityId; Migration identity_foundation; Reseed auf Identity+Membership inkl. 2. Mandant demo2 + Multi-Membership-Fixture multi@demo.example. Expand/Contract (User-Auth-Felder bleiben vorerst Legacy; Contract-Migration droppt sie am Ende von WS1–WS4). Neuer Test scripts/test-identity-schema.ts. Grundlage/Fahrplan: docs/FEINDESIGN-identity-mandanten.md, docs/KONZEPT-identity-mandanten.md, docs/UEBERGABE-identity-mandanten.md, docs/PROMPT-uebergabe-identity-mandanten.md. Nächste Schritte: WS1 (Login gegen Identity, Two-Step + MFA-pending) → WS2 (/select-tenant), parallel WS3/WS4/WS6; Abschluss = Contract-Migration.

Identity/Mandanten (Option C), WS1/WS3/WS4/WS6 — 2026-08-11 (feature/identity-auth-core → dev, --no-ff, Gate grün: tsc/lint/build + 21/21 Tests; noch nicht auf die Remotes gepusht):

  • WS1 Auth-Kern: auth.ts authentifiziert gegen die globale Identity (Passwort/MFA/Lockout an der Identity); Mitgliedschaften werden geladen, der aktive Mandant per Organisations-Slug oder Single-Membership gewählt (mehrere ohne Slug ⇒ noch kein Login → /select-tenant = WS2). Login-Kern als authorizeTenantCredentials() exportiert. Session/JWT (next-auth.d.ts) neu: identityId/activeMembershipId/memberships[] (optional, da Plattform-Auth dieselben Typen nutzt); tenantId = aktiver Mandant → 356 dbForTenant-Call-Sites unverändert. Test scripts/test-identity-login.ts.
  • WS4 Passwort/MFA an Identity: Passwortwechsel, MFA-Enroll/-Disable, Recovery-Codes und der Session-Kill-Switch (sessionsValidAfter) gehören der Identity (account.ts, account/page.tsx, sessions.ts). Guards (action-guard.ts, (app)/layout.tsx, change-password, enroll-mfa) lesen mustChangePassword/sessionsValidAfter/mfaEnrolledAt + globalen identity.status aus der Identity; Membership-Status/Rechte weiter aus User. Reset-Kette (auth-recovery/auth-selfservice/auth-token) auf PrincipalType "identity". Mandanten-Admin-Passwort-Reset entfernt (goldene Regel 5). E-Mail-Änderung für Mandanten-Konten deaktiviert = Phase 2. Test scripts/test-identity-account.ts. Abgetrennt (offen): WS4b WebAuthn→Identity (Schema-Migration + TENANT_MODELS + webauthn.ts; Passkey-Login läuft bis dahin mandantengebunden).
  • WS3 Einladungs-Lifecycle: Nutzeranlage nur per Einladung (goldene Regel 4) — TokenType "invitation" (7 Tage) + neue öffentliche Seite /invite + redeemInvitation. createTenantUser/createUser/inviteFunctionHolder ohne pwMode „set"; bekannte Identity → nur Mitgliedschaft ergänzen (kein Passwort-Reset), unbekannt → Identity + Einladung; neutrale Rückmeldung (kein Cross-Tenant-Leak). user-forms.tsx = reines Einladungsformular. Test scripts/test-invitation.ts.
  • WS6 Seed/Provision/Bootstrap: bereits durch WS0 abgedeckt (provisionTenant/seed.ts Identity-fähig, sync-role-permissions.ts orthogonal) — kein Netto-neuer Code.
  • Keine neue Migration (WS1/WS3/WS4/WS6 sind code-only; das WS0-Schema trägt).

Identity/Mandanten (Option C) — WS2/WS4b/WS5 + Contract, UMBAU KOMPLETT — 2026-08-11 (feature/identity-tenant-context → dev, --no-ff, Gate grün: tsc/lint/build + 23/23; noch nicht gepusht):

  • WS2 Mandantenkontext: Multi-Membership-Login ohne Organisations-Slug ergibt eine Session OHNE aktiven Mandanten → (app)/layout leitet auf /select-tenant. Wechsel server-autoritativ über setActiveTenant (actions/tenant-switch.ts, unstable_update + async jwt-update-Trigger → resolveActiveMembership: Rechte je Wechsel NEU aufgelöst). Sidebar-TenantSwitcher (nur bei >1 Mitgliedschaft). Browser-verifiziert: Wechsel demo↔demo2 inkl. Mandantenisolation (demo: 9 Assets, demo2: 0). Test scripts/test-tenant-switch.ts.
  • WS4b WebAuthn→Identity: Passkeys sind identitätsgebunden (Migration 20260811140000_webauthn_identity: webauthn_credentials verliert tenant_id/RLS, verweist auf identities); WebAuthnCredential raus aus TENANT_MODELS. Passkey-Login/-Verwaltung über identityId.
  • Contract-Migration (20260811150000_contract_user_auth_columns): die 10 ungenutzten User-Auth-Spalten entfernt (password_hash, must_change_password, failed_logins, locked_until, mfa_secret, mfa_enrolled_at, recovery_codes, last_totp_step, sessions_valid_after, is_platform_admin) → User = reine Mitgliedschaft (tenantId, identityId, email, name, status). Expand/Contract abgeschlossen. DROP COLUMN → kein Reset.
  • WS5 Two-Step-Login (Entscheidung A): /login Schritt 1 (E-Mail+Passwort) → bei aktiver MFA kurzlebiger, signierter, einzweckiger mfa_pending-Cookie (KEINE Session) → /login/mfa Schritt 2 → login-ticket-Provider prägt die Session. Bausteine verifyIdentityPassword/verifyIdentityMfa/finalizeIdentityLogin (kein Passwort-Orakel, Lockout wie beim vollen Login). src/server/login-ticket.ts (HMAC). Runtime-verifiziert. Test scripts/test-two-step-login.ts.
  • Damit ist der Umbau „Zentrale Identität mit Mandanten-Mitgliedschaften" vollständig (alle 5 goldenen Regeln + Entscheidung A). Zwei neue Migrationen. Offen: nur der Push auf beide Remotes (origin + local-gitea) — bewusst zurückgehalten. Phase-2 (per-Mandant Step-up, E-Mail-Änderung als Identity-Op, PlatformAdmin-Konsolidierung) bleibt ausgeklammert.

Richtlinien-Vorlagen Plattform-Editor + EN-Paket — 2026-08-11: dev-fix-platform-admin integriert — globale Vorlagen-Modelle + Migration policy_templates, Plattform-Editor (Entwurf/Veröffentlichen, Editoren für Anforderungen/Variablen), Sprachwahl je Mandant (setTenantLocale) und das komplette EN-Übersetzungspaket der Richtlinien-Vorlagen (Leitlinie, R01–R14, VA-01–VA-20, D01/P01, Baseline/Nachweisregister). Mandanten-Import liest die veröffentlichte DB-Version.

Härtung Argon2id — 2026-08-11: Passwort-Hash-Parameter fixiert/dokumentiert (src/server/password.ts, ARGON2_OPTIONS: m=19456 KiB, t=2, p=1, outputLen=32; Argon2id = Lib-Default). Salt automatisch pro Hash (PHC-String), kein Pepper (dokumentiert). Nur neue Hashes betroffen.

Härtung Phase 2–3 (Ops-Doku) — 2026-08-11 (Lane lane-haertung-ops, nur Markdown, kein App-Code/Migration, noch nicht nach dev gemergt): Phase 1 (Passwort-Pepper) ist erledigt (Argon2-secret, zentral, in dev) — unverändert. Phasen 2–3 liegen jetzt als Ops-Runbook vor: docs/DEPLOY-PROD-CONTABO.md um Host-Encryption at-rest (LUKS/dm-crypt fürs Daten-Volume pgdata+MinIO, Boot-Unlock-Verfahren A/B, Passphrase im Passwortmanager) und verschlüsselte Backups (pgBackRest aes-256-cbc + age je Umgebung + restic für MinIO, Coolify-Cron/Retention/Restore-Test, Bezug zur App-Backup-Engine BACKUP_ENC_KEY/§9) ergänzt; neues docs/SECRETS-REGISTER.md (Ownership + Rotationsregel je Umgebung für AUTH_SECRET/MFA_ENC_KEY/PASSWORD_PEPPER/BACKUP_ENC_KEY/pgBackRest-Key/age-Keypair; PASSWORD_PEPPER+MFA_ENC_KEY als nicht rotierbar = Reset markiert). Restore-Kohärenz-Regel prominent in beiden Docs: Umgebungs-Secrets stehen nicht im Artefakt → Restore in fremde Umgebung bricht Passwort-/MFA-Prüfung bzw. Entschlüsselung. DB-TLS (sslmode) + Vault/KMS bleiben Phase 2 (offen). Gate: nur .md, tsc/lint unberührt.

Merge-Zyklus 2026-08-11: WS0 + Richtlinien/EN-Lane + Argon2 zusammen nach dev konsolidiert. Konflikt nur in schema.prisma (User-Relationsblock → Union mit identity) + provision.ts (auto-merge: Identity-Upsert und Policy-Variablen). DB neu gebaut (migrate reset, 52 Migrationen, beide neuen koexistieren) + Seed. Gate grün: tsc/lint/build + 18/18 Tests.

Konfigurierbarer Backup-Zielspeicher — 2026-08-17 (lane-backup-target → dev, --no-ff): Backup-/DSGVO-Zielspeicher jetzt im Betreiber-Portal wählbar (/admin/backup, Full-Admin + MFA-Step-up) — Lokal (persistentes Volume) oder S3/MinIO. PlatformSetting erweitert (backupTarget, backupLocalDir, backupS3*, backupS3SecretKeyEnc verschlüsselt at-rest), Migration backup_target_config (additiv). Statisches backupStore → getBackupStore() mit Präzedenz DB → Env (S3_*/BACKUP_LOCAL_DIR) → lokaler Default .backups, fail-secure bei unvollständiger S3-Config; alle Call-Sites umgestellt. Persistentes backups-Volume (app + backup-worker, /app/.backups) — Lokal überlebt Redeploys. Neuer Test scripts/test-backup-target.ts. Gate grün (tsc/lint/build + 28/28), /admin/backup im Browser klickgeprüft (Lokal↔S3, Secret-Feld „nie Klartext"). Konzept/Prompt: docs/KONZEPT-backup-target.md, docs/PROMPT-lane-backup-target.md.

Modul „Vorfälle" (Incident-Management) IM-A — 2026-08-17 (lane-incidents-a → dev, vom Team): Fundament + Kern-Lifecycle/UI (Migration incidents, src/app/(app)/incidents/*, src/server/actions/incidents.ts, docs/KONZEPT-incidents.md, Test scripts/test-incidents.ts). IM-B (Meldefristen/Notifications) noch in Arbeit (eigener Branch lane-incidents-b).

Direkt-Download der Sicherung + S3-Bucket-Selbstheilung — 2026-08-17 (lane-backup-download @ fe13a84 → dev, --no-ff): Neue Route /api/platform/backup/download (Full-Admin) — exportTenant(persist:false) streamt die verschlüsselte .cvb inline in den Browser, ohne Worker/Redis/S3 („Sicherung herunterladen"-Button im Export-Popup). S3BackupStore.ensureBucket() legt einen fehlenden MinIO-Bucket beim ersten put automatisch an (behebt „The specified bucket does not exist"). Neuer Test scripts/test-backup-download.ts. Gate grün (tsc/lint/build + 30/30). Merge über isoliertes Worktree (paralleler Team-Arbeitsbaum unberührt).

Modul „Vorfälle" IM-B/C/D (komplett) + Backup-Docker-Fix — 2026-08-18 (vom Team nach dev gemergt; von mir validiert + gepusht): IM-B (Meldefristen/Timer + Meldepflicht + Benachrichtigungen), IM-C (Verknüpfungen, Abschluss/Lessons-Learned, Export/Meldevorlagen), IM-D (E-Mail-to-Ticket Inbound + Provisionierung; Migration incident_inbound_d, Test scripts/test-incident-inbound.ts). Damit ist das Modul „Vorfälle" funktional komplett (IM-A…IM-D). Docker-Fix: prisma/schema.prisma wird jetzt auch in die runner-Stage kopiert — der Inline-Backup-Download läuft in der App (standalone), und die Backup-Topologie liest die Schema-Datei zur Laufzeit (Prisma 7 entfernt FK-Relationen aus dem Laufzeit-DMMF); sonst ENOENT → „Export fehlgeschlagen". Gate grün (tsc/lint/build + 33/33).


1. Executive Summary

Auf main lag das Fundament (Auth/RBAC/Mandanten-Isolation, Assets/BIA, Risiko, Maßnahmen, Abhängigkeiten, Lieferanten, Richtlinien Phase 1/2a, Admin-Konsole Phase 1). Der Branch dev ergänzt fünf große Blöcke — alle mit tsc+lint+build, Modul-Guard-Check und (wo relevant) Browser-Verifikation abgeschlossen:

  1. Produktionshärtung Phase 1 — API-seitige Modul-Durchsetzung, getrennter Superadmin-Store mit eigenem Login + MFA, nicht-destruktiver Richtlinien-Re-Import.

  2. Benutzer- & Rollenverwaltung (ohne E-Mail-Flow) — Plattform-Admin verwaltet Nutzer je Mandant; Mandanten-Admin verwaltet Nutzer und Rollen intern; Force-Change-Passwort, Passwort-Policy, optionale MFA je Nutzer; Popup-UI wie bei Assets.

  3. Freigabe-Workflow + Aufgaben-Modul — Richtlinien-Freigabe an eine konkrete Person, Bearbeitung im neuen Modul „Aufgaben", Dashboard-Kachel; plus zentralisierte Richtlinien-Governance (zentrale Variablen, Schutzbedarf, Coverage-Filter nach Assessment-Level).

  4. GAP-Report-Umsetzung (Richtlinien-Vorlagenpaket) — WP1–WP4 + E2: sechs neue Verfahrensanweisungen (ISB-Volltexte), Inline-VA-Verlinkung, Rendering-Fix, generisches editierbares Register-Datenmodell.

  5. Register-Konsolidierung in Fachmodule — vier generische Register in die Fachmodule überführt: Software und Projekte als eigene Asset-Typen (Popups wie bei Assets/Lieferanten), kritische IT-Dienste als schreibgeschützte Auto-Sicht aus BIA, REG-NET auf Referenzfeld reduziert; Richtlinien-Links zeigen jetzt auf die Module statt auf Register.

  6. Produktions-Deployment-Vorbereitung (Commits cc8d486, f368d8f) — Prod-Bootstrap scripts/bootstrap-admin.ts (legt Erst-Superadmin im platformAdmin-Store + Mandant/Mandanten-Admin idempotent an, ersetzt in Prod den Demo-Seed; per BOOTSTRAP_*-Env im migrate-Job der docker-compose.coolify.yml); .env.prod.example; Fonts selbst gehostet (next/font/local, committete woff2 in src/app/fonts → reproduzierbarer Offline-Build, DSGVO); Runbook docs/DEPLOY-PROD-CONTABO.md (VPS/Coolify/Gitea, TLS app.certvia.de, Bootstrap, Backups, Go-Live-Checkliste).

  7. Branding-Umstellung auf Certvia — in dev integriert (Gate grün): getrennte Token-Ebenen --brand-* (Logo/Print/Export) vs. --ui-* (Produktpalette, inhaltlich unverändert) mit src/lib/brand.ts als JS-Pendant; Certvia-Logo als Inline-SVG-Komponente (<CertviaLogo>), Favicon-/PWA-Icons + site.webmanifest, Metadaten/OG/i18n/TOTP-Issuer, gebrandete Auth-Seiten sowie neue 404-/500-Seiten, Druck-/Dokument-CD (@media print + src/lib/document-brand.ts) als Andockpunkt für den offenen DOCX/PDF-Export, brandfähige E-Mail-Basis (src/lib/email-brand.ts), Mandanten-Branding-Default (resolveTenantBranding). GEFIM bleibt Dachmarke („Ein Produkt von GEFIM"). Reines Branding, keine Funktionsänderung — Ausnahme: der Route-Gate-Matcher in src/proxy.ts musste .webmanifest freigeben, sonst lieferte /site.webmanifest die Login-HTML. Details: docs/BRANDING-CERTVIA.md.

In Arbeit (parallele Entwicklung, 2-Lane Dev A × Dev B): Onboarding-Wizard (docs/wizard-uebergabe/). Beide Lanes bis hierher in dev konsolidiert (inkl. Dev-B B4, per Fast-Forward integriert):

  • Dev A: A1-1 — Wizard-Shell: Modul onboarding, Step-Registry (registerStep, Keys 1–9, guard kann Schritte ausblenden), resumierbarer Fortschritt (OnboardingProgress). F2 — generalisiertes ObjectReviewStatus (5 Zustände inkl. zurueckgewiesen) als wiederverwendbares Review-Enum; RBAC-Recht validate_objects + klonbare Rolle external_validator; Wizard-State-Machine mit Rechte-Trennung: Bearbeiter (onboarding:use) advance/rework/reset, Validator (validate_objects) validieren/zurückweisen (mit Begründung). „Weiter"-Gate: nur validiert zählt. Migration object_review_status. A1-2 — Dashboard-Kachel „Onboarding-Fortschritt" (Anteil validierter Schritte + nächster offener Schritt, verlinkt in den Wizard). A2-1 — Assessment-Level (AL2/AL3) als einzige Quelle des Schutzbedarfs: protectionFlags(level) (src/server/assessment-level.ts) leitet FLAG_HIGH_PROTECTION/FLAG_VERY_HIGH_PROTECTION zentral ab (Wizard/Provisioning seeden daraus, nicht mehr aus dem Fragebogen); Schutzbedarf-Frage Q-FEAT-01 + Regeln feat01-* entfernt. A2-2 — Scope-Objekt WizardScope + Filter-Engine (src/lib/scope-filter.ts: activeRequirements/scopeSummary, client-safe): filtert die Anforderungen nach AL-Baseline, FLAG_INCLUDE_SHOULD und Prüfzielen; Grunddaten seed/scoping/c1-scope.json (412 Anforderungen, generiert via scripts/build-c1-scope.ts); Action saveScope (moduleGuard('onboarding')) am Wizard-Schritt „scoping"; Migration wizard_scope; Tests scripts/test-scope-filter.ts (grün). A3-1 — Validierungs-Workflow generalisiert: wiederverwendbares generisches Objekt-Review (src/server/object-review.ts, src/lib/object-review.ts, src/components/object-review.tsx) über Objekttypen hinweg (u. a. Risiken), an Risk-/Task-Actions angebunden. A4 — ISMS-Rollen als Wizard-Schritt 3 „roles" inkl. Funktionstrennung FT-01…06 (src/lib/ft-rules.ts, Tests scripts/test-ft-rules.ts), ISB-Bestellung (src/lib/isb-bestellung.ts) und Rollen-Logik (src/server/roles.ts). A5-1 — Asset-Schritt (Wizard-Schritt 5) auf dem Bestandsmodul (steps/assets/step.tsx). A7 — Control-Assessment (Wizard-Schritt 7): Reifegrad-Engine R0–R3 + Zielreifegrad (src/lib/maturity.ts, Tests scripts/test-maturity.ts), Modell ControlAssessment (Migration control_assessments, RLS, in TENANT_MODELS) mit Belegstatus/Reifegrad-Bestätigung/Gap-Aufgaben; SoA-Kontext (src/server/soa-context.ts, actions/soa.ts), Control-Grunddaten seed/scoping/c5-controls.json. A6 — Standard-Risikokatalog (C4): globaler Katalog RiskCatalogEntry (Migration risk_catalog, kein RLS) + Import/Übernahme (prisma/import-risks.ts, /risks/catalog); A6-2 Standardmaßnahme→Aufgabe und Restrisiko-Akzeptanz (Migration risk_acceptance: Felder accepted_at/by/rationale an risks, VA-09). A8 — Gap-Konsolidierung (Wizard-Schritt 8): Aggregations-/Priorisierungs-Engine (src/lib/gap-consolidation.ts: Dedup, Priorisierung, Quick-Wins), Task-Abgleich + Kontext (src/server/gap-context.ts, src/server/actions/gap.ts), Tests scripts/test-gap-consolidation.ts (keine neue Migration/Modell).
  • Dev B: F1 (Task-Objekt um Wizard-Felder type/owner/dueDate/priority/status/resources/origin/links erweitert, Migration tasks_wizard_fields), B1 (Auto-Generierung von Aufgaben-Vorschlägen aus Triggern, C2 §8; src/lib/task-triggers.ts, src/lib/tasks.ts), F4 (Wizard-Flags in variables.schema.json: FLAG_PROTOTYPE_PROTECTION, FLAG_ISB_EXTERNAL, FLAG_ISB_INTERNAL; _verify.py = OK). F3+B2 — Regel-/Mapping-Engine: deklarative DSL (src/lib/rules/dsl.ts), Auswerter (engine.ts, evaluateCondition) und C2-§5-Regelwerk (feature-rules.ts: Feature-Flags, Schutzbedarf-Ableitung, Control-Scope, Risiko-/Aufgaben-Trigger); Tests scripts/test-rules.ts (18 Fälle, grün). B3 — Fragebogen als Wizard-Schritt 2 „context": Frage-Katalog A–F (src/lib/onboarding/questions.ts), Fakten-Ableitung (facts.ts, deriveContext über die Regel-Engine), Schritt-Komponente + saveFacts-Action (onboarding-facts.ts), Modell WizardFact (Migration wizard_facts, RLS, in TENANT_MODELS); echte Schritte via Side-Effect-Import register-steps.ts in die Registry eingeklinkt (überschreibt Platzhalter). Der Fragebogen schreibt nur Fakten/Flags, nie die gesperrten Zentralvariablen. B4 (Richtlinien-Import/Upload) — in dev integriert (Fast-Forward), Gate grün: B4-1 nicht-destruktiver Vorlagen-Import bei Aktivierung des Richtlinien-Moduls + Self-Service-Button (/policies, Report-Banner) und Admin-Button (src/server/actions/policy-package.ts, Trigger in toggleTenantModule); B4-2 „Eigene Richtlinie hochladen" (/policies/upload, policy-upload.ts) mit Pflicht-Control-Zuordnung + gekapseltem Storage-Adapter-Stub (src/server/storage/adapter.ts, echtes Backend = Epic S1) → EIGENES-Dokument (EIG-*) + PolicyRequirement-Zeilen (Coverage/Nachweislage); B4-3 neue Vorlagen P01_Prototypenschutz + VA-20 (Kap. 8.x) und D01_Datenschutz (9.x) + 5 mapping.json-Anforderungen (condition-gated per Prüfziel-Flag), _verify.py = OK. Keine neue Migration (nur String-Status/Seed-Content). B5 (Umsetzungshinweise C6) — in dev integriert, Gate grün: B5-1 Datenmodell ImplementationHint (Migration implementation_hints; globaler C6-Katalog, identisch je Mandant → kein tenantId/RLS) + C6-Import (~397 Hinweis-Blöcke via prisma/import-hints.ts / scripts/import-c6-hints.ts); B5-2 kontextsensitives Umsetzungshinweis-Panel (/policies/hints, src/server/actions/hints.ts), aus /policies verlinkt. Prüfziele Single Source (Follow-up zu A2): der context-Step seedet die Prüfziele aus WizardScope statt aus einer zweiten Quelle (Doppelquelle behoben; feature-rules.ts/facts.ts/questions.ts, test-rules.ts angepasst). B6 — Vorlagenpaket-Versionierung + kontrollierte Diff-Übernahme: Modell PolicyPackageState (Migration policy_package_state, RLS, in TENANT_MODELS) hält je Mandant Paket-Version/-Stand; stampPackageState (in prisma/import-policies.ts) beim Import; Updates-Ansicht /policies/updates zeigt/übernimmt Änderungen kontrolliert. B7-1 — Assessment-Readiness-Dashboard als Wizard-Schritt 9 „readiness" (src/lib/readiness.ts, Tests scripts/test-readiness.ts) mit Interpretationstexten (C9 §1/§2). B7-2 — VDA-ISA-Katalog-Export (CSV) + Management-Zusammenfassung (C9 §3/§4): Export-Route onboarding/export/route.ts, Export-Engine src/lib/export/vda-isa.ts + src/server/export-context.ts, Zusammenfassungs-Seite onboarding/summary, Tests scripts/test-vda-isa.ts. Damit ist B7 vollständig (keine neue Migration). Wizard-Schritte 4 + 6 (echte Komponenten) — Richtlinien-Schritt „policies" (Schritt 4, Guard: nur bei aktivem Richtlinien-Modul) und Risiken-Schritt „risks" (Schritt 6, Guard: nur bei aktivem Risiko-Modul) zeigen jetzt den echten Modul-Status statt Platzhalter (steps/policies/step.tsx, steps/risks/step.tsx, src/server/actions/onboarding-steps.ts) — keine Doppel-Datenhaltung. Damit sind alle Wizard-Schritte 1–9 echte Komponenten.
  • Offen: Keine offenen Feature-Branches mehr — alle bestehenden Lanes in dev konsolidiert (Dev A: A1–A8; Dev B: F1/B1/F4/F3+B2/B3/B4/B5/B6/B7 + Prüfziel-Follow-up). Nächste geplante Stories siehe §6.

Migrationen (31 neu, laufen beim Deploy automatisch über den Init-Container): platform_admins · policy_lifecycle_archived · user_mgmt_and_platform_settings · tasks · strip_tool_variable_articles · managed_registers · software_and_project_assets · onboarding_progress · tasks_wizard_fields · object_review_status · wizard_facts · wizard_scope · implementation_hints · policy_package_state · control_assessments · risk_catalog · risk_acceptance · task_description · control_implementations · login_lockout · mail_fundament (SEC1) · auth_tokens_sessions (SEC2) · tisax_m0_foundation · tisax_m1_m4_consolidated · tisax_rekey_onboarding_steps · tisax_v3_process_fields · tisax_v4_catalog_parent · tisax_v5_audit · tisax_v7_policy_domain · webauthn_credentials (SEC3) · platform_admin_role (SEC4)


1a. Sicherheitspaket P1/P2 (Branch dev-security-p1, Stand 2026-07-30)

Nach einem externen Secure-Code-Review (AEGIS-SAST, 21 Findings) wurde ein Härtungspaket umgesetzt: alle P1 (2) und P2 (5) sowie mehrere P3 sind behoben. Das Paket liegt auf dev-security-p1 (von dev abgezweigt, Gate grün, noch nicht nach dev gemergt). Parallelisiert in drei konfliktfreien Lanes plus Vorlauf, danach additiv integriert.

Finding Priorität Behebung Kern-Dateien
F-01 Auth.js „fail open" + Next.js-CVEs P1 next-auth→5.0.0-beta.32 (@auth/core 0.41.3), next→16.2.12; Guards positiv statt existenzbasiert; Fail-Secure-Startprüfung assertSecureEnv() (lazy/memoisiert, build-safe) package.json, src/server/env.ts, auth.ts, platform-auth.ts
F-02 Cross-Tenant-Leck bei findUnique+select P1 Tenant-Guard fail-closed: skalare where→findFirst mit tenantId-Vorfilter (verhindert statt erkennt), Compound-Unique→tenantId-Injektion + harter Abbruch; drei Aufrufstellen zusätzlich explizit gefiltert; Regressionstest src/server/db.ts, actions/risks.ts, actions/risk-catalog.ts, scripts/test-tenant-isolation.ts
F-03 Stored XSS im Richtlinien-Rendering P2 renderPolicyHtml sanitisiert marked-Output gegen strikte Allowlist (sanitize-html); Variablenwerte + Upload-Titel HTML-kodiert vor noEscape-Handlebars src/lib/policy-render.ts, actions/policy-upload.ts
F-05 Kein Brute-Force-Schutz Mandanten-Login P2 Kontosperre (5/15 min) + denied-Audit analog Plattform-Login; Enumeration via Dummy-Hash konstanter Laufzeit; DoS-Ausnahme letzter aktiver Admin auth.ts, Migration login_lockout (User.failedLogins/lockedUntil)
F-07 Keine Security-Header/CSP P2 CSP + HSTS + nosniff + X-Frame-Options: DENY + Referrer-/Permissions-Policy; unsafe-eval/ws: nur im Dev next.config.ts
F-08 Kritische Kontoänderung ohne Re-Auth P2/P3 Passwortwechsel verlangt aktuelles Passwort (+ TOTP bei aktiver MFA); MFA-Deaktivierung erfordert TOTP-Code; Ausnahme nur beim erzwungenen Erstwechsel actions/account.ts, actions/platform.ts
F-09 30-Tage-Sessions P3 maxAge 8 h (Mandant) / 2 h (Plattform) + updateAge auth.ts, platform-auth.ts
F-12 Weitere verwundbare Abhängigkeiten P3 overrides für postcss/sharp/valibot; Produktionsbaum (--omit=dev): 0 kritisch / 0 hoch (vorher 2/5) package.json
F-15 Upload ohne Validierung P3 Größenlimit vor RAM-Read, Endungs-/MIME-Allowlist, Magic-Byte-Prüfung, kanonischer MIME statt f.type actions/policy-upload.ts
F-16 (Teil) Isolationsverletzung unsichtbar P3 Verletzungen als [SECURITY]-Log; zentrale Audit-Anbindung (action:"denied") als Folge-TODO offen (Importzyklus audit.ts↔db.ts) src/server/db.ts
F-19 Unvalidiertes callbackUrl P4 Allowlist (nur eigene absolute Pfade), doppelt validiert src/app/login/page.tsx

Korrekturen am Bericht (dessen Codevorschläge waren an drei Stellen falsch): npm install next-auth@latest hätte auf v4 downgegradet (Major-Bruch) — korrekt ist 5.0.0-beta.32. Der pauschale findUnique→findFirst-Umbau bricht an den Compound-Unique-Keys (tenantId_key etc.) → stattdessen Hybrid-Guard. Das RLS-Snippet aus F-04 funktioniert nicht (Kontext in falscher Transaktion) → F-04 bewusst herausgelöst.

| F-06 JWT-Sessions ohne Widerruf | P2 | ✅ Branch dev-security-f06-session-auth (auf dev-security-f04-rls): moduleGuard prüft Kontostatus, mustChangePassword und effektive Rechte je Mutation autoritativ aus der DB statt aus dem JWT → Deaktivierung/Rechteentzug wirkt sofort (vorher bis Token-Ablauf); requirePlatformSession prüft Plattform-Admin-Status. Test test-action-guard-authz.ts (4 Nachweise), Browser-Regression ok | src/server/action-guard.ts, platform-auth.ts | | F-04 RLS definiert, aber wirkungslos | P2 | ✅ Separates Paket, Branch dev-security-f04-rls (auf dev-security-p1 aufgesetzt): env-gesteuert (RLS_ENFORCED). Zweite Verbindung als isms_app (RLS_DATABASE_URL, NOBYPASSRLS); dbForTenant setzt app.tenant_id transaktionslokal auf derselben Connection; Policies mit USING+WITH CHECK + FORCE auf allen 49 Tenant-Tabellen. Owner-Rolle (Superuser/BYPASSRLS) bleibt für Migrationen/Seed/Login und lokal unberührt → Default-Betrieb unverändert. Test test-rls-enforcement.ts (5 Nachweise) | src/server/db.ts, Migration rls_enforce, docker-compose.coolify.yml, .env*.example, DEPLOY-PROD-CONTABO.md |

Gate (kombinierter Stand A+B+C): tsc=0 · lint sauber · build grün · _verify.py=OK · test-tenant-isolation=OK (15 Fälle) · Browser-Smoke (Login, Dashboard, Richtlinien-Register, CSP-Header, Guard-Redirect) verifiziert. F-04 separat: tsc/lint/build grün · test-rls-enforcement=OK (5/5, inkl. Nachweis „Owner-Betrieb heil unter FORCE") · Owner-Pfad-Smoke verifiziert.

P3/P4-Paket (Branch dev-security-p3, auf dev-security-f06-session-auth, Stand 2026-07-30)

Vier dateidisjunkte Lanes, additiv gemergt, kombiniertes Gate grün. Nur die MFA-Lane migriert.

Finding Prio Behebung Kern-Dateien
F-10 Aufgaben-Modul ohne Rechteprüfung P3 Neues Recht task:write; guard("task:write") in createTask/proposeTasksFromTriggers/claimTask/updateTask; CreateTaskInput per Zod (Längen-/Größenlimits); owner/assignee gegen aktiven Mandanten-Nutzer geprüft rbac.ts, actions/tasks.ts
F-13 Privilege Escalation über role:manage P3 Pragmatische Variante (Entscheidung): Delegation erlaubt (Admin darf fachliche/geklonte Rollen für andere anlegen), aber Selbstzuweisung höher privilegierter Rollen gesperrt → Selbst-Eskalation ausgeschlossen; volle Auditierung actions/tenant-users.ts
F-20 Schwache Passwort-Policy bei Provisionierung P3 validatePassword(…, DEFAULT_PASSWORD_POLICY) statt min(8) actions/admin.ts
F-16-zentral Sicherheitsereignisse nur im Log P3 Importzyklus per Lazy-Import gelöst → Isolationsverletzung wird echter denied-Audit; Error-Boundary withActionErrors (generische Außenmeldung, volles internes Log) bereitgestellt db.ts, neu action-error.ts
F-17 Recovery-Codes SHA-256, TOTP-Replay P3 Recovery-Codes → Argon2id, Entropie 40→80 Bit (Alt-Codes per Kompatibilitätspfad bis Neuausstellung); TOTP-Replay-Schutz via lastTotpStep (User+PlatformAdmin) mfa.ts, auth.ts, platform-auth.ts, account.ts, platform.ts, Migration mfa_totp_replay
F-11 Supply Chain P3 npm ci (Base-Image → node:22.14.0-slim/glibc, npm 11 gepinnt), alle Images auf feste Tags/Digests, schlanke migrate-Stage, SBOM dokumentiert; lokaler docker build grün (386 MB) Dockerfile, docker-compose*.yml
F-18 Container-Härtung P3/P4 Redis-Passwort, internes Netz (internal: true), no-new-privileges/cap_drop: ALL/Ressourcenlimits, Dev-Compose auf 127.0.0.1 gebunden docker-compose*.yml, .env*.example
CI/Renovate (Begleitmaßnahmen) — .gitea/+.github/workflows/ci.yml (tsc/lint/build + npm audit --omit=dev --audit-level=high-Gate), renovate.json (Auth-Updates manuell) .gitea/, .github/, renovate.json

Gate (kombiniert): tsc=0 · lint · build · _verify.py=OK · 7 Sicherheitstests grün (tenant-isolation, rls-enforcement, action-guard-authz, tenant-users-authz, mfa-hardening, action-error) · Browser-Smoke (Task-Anlage F-10) verifiziert.

✅ Deployment-Schritt (F-06 × F-10) — automatisiert: Da F-06 Rechte DB-autoritativ prüft, wirkt eine neue Permission (z. B. task:write) erst, wenn scripts/sync-role-permissions.ts gegen die Ziel-DB läuft (legt Permission + Rolle→Recht-Verknüpfung an; additiv, idempotent). Ein reiner Re-Login genügt NICHT. Das läuft jetzt bei jedem Deploy automatisch im migrate-Init-Job (docker-compose.coolify.yml, direkt nach prisma migrate deploy, über die Owner-DATABASE_URL) — deckt jede künftig neu eingeführte Permission ab. Betroffene Nutzer danach neu einloggen. Manuell nachziehen nur, falls ohne Redeploy nötig: npx tsx scripts/sync-role-permissions.ts.

Noch offen: F-14 (Demo-Seed-Härtung — auf Wunsch bewusst zurückgestellt), F-21 (Monitoring/Log-Aggregation/Tamper-Schutz Audit-Trail — eigenes Betriebspaket). Damit sind alle P1, alle P2 und die adressierten P3 behoben. Details: AEGIS-Bericht.

Aktivierung F-04 in Prod: Rolle isms_app LOGIN+starkes Passwort geben, RLS_DATABASE_URL setzen, RLS_ENFORCED=true am app-Service; Migrations-/Owner-Rolle muss BYPASSRLS/Superuser sein. Anleitung in docs/DEPLOY-PROD-CONTABO.md. Lokal bewusst aus.


2. Für das Projektmanagement — fachlicher Status

✅ Neu fertig auf dev

Thema Nutzen Status
API-seitige Modul-Durchsetzung Deaktiviertes Modul sperrt jetzt auch Schreibzugriffe serverseitig (nicht nur Navigation); automatischer Vollständigkeitscheck als Build-Gate ✅
Getrennter Superadmin-Login Betreiber-Zugang unter /platform/login mit eigenem Store, ohne Mandantenkontext; Kundenfachdaten für Superadmin gesperrt ✅
MFA (optional) TOTP für Plattform-Admins und Mandanten-Nutzer freiwillig; Policy-Flag „MFA-Pflicht" kann Erzwingung wiederherstellen; Recovery-Codes ✅
Benutzerverwaltung (Superadmin) Superadmin legt je Kunde Nutzer an (Initial-/Einmal-Passwort), weist Rollen zu, deaktiviert/reaktiviert, setzt Passwörter zurück ✅
Benutzer- & Rollenverwaltung (Kunde) Mandanten-Admin verwaltet intern Nutzer und Rollen (eigene Rollen + granulare Rechte, Standardrollen klonbar); strikt mandantengetrennt; Lockout-Schutz ✅
Nutzer-Onboarding ohne E-Mail Start mit Initialpasswort + erzwungenem Wechsel beim ersten Login; E-Mail-Einladung (Paket 4) später nahtlos ergänzbar ✅
Popup-Bedienung Anlegen/Bearbeiten von Nutzern über Popups wie bei Assets; Tabelle nur Anzeige ✅
Zuständigkeiten geklärt Superadmin steuert Kern-Einstellungen (Module, TISAX-Tiefe); Mandanten-Admin nur seinen Bereich (Stammdaten, Nutzer/Rollen) ✅
Richtlinien-Governance zentral Zentrale Variablen (Unternehmensname, Rollen, Schutzbedarf) nur in Einstellungen pflegbar; Coverage-Matrix zeigt nur Controls des aktiven Assessment-Levels (AL2 ohne „sehr hoch") ✅
Scoping & zentraler Schutzbedarf (A2) Anforderungs-Scope leitet sich zentral aus Assessment-Level (AL2/AL3), FLAG_INCLUDE_SHOULD und den Prüfzielen ab — nicht mehr aus dem Fragebogen; Schutzbedarf hat damit eine einzige, konsistente Quelle (AL → Flags). Scope-Filter (scope-filter.ts) + c1-scope.json (412 Anforderungen) ✅
Umsetzungshinweise (B5) Kontextsensitive C6-Umsetzungshinweise (~397 Blöcke) zu den Controls, als eigenes Panel unter /policies/hints und aus den Richtlinien verlinkt — praktische Hilfestellung bei der Umsetzung ✅
Validierungs-Workflow generalisiert (A3) Das Vier-Augen-/Review-Muster ist jetzt objekttyp-übergreifend nutzbar (nicht nur Aufgaben) — z. B. für Risiken ✅
ISMS-Rollen & Funktionstrennung (A4) Wizard-Schritt „Rollen": ISMS-Rollen zuweisen, Funktionstrennungs-Regeln FT-01…06 prüfen (z. B. ISB ≠ IT-Leitung), ISB-Bestellung ✅
Vorlagen-Versionierung & Diff (B6) Das Vorlagenpaket ist versioniert; Updates werden je Mandant kontrolliert per Diff-Ansicht (/policies/updates) übernommen statt blind überschrieben ✅
Assessment-Readiness & Export (B7) Readiness-Dashboard (Reifegrad-Interpretation, C9) plus VDA-ISA-Katalog-Export (CSV) und Management-Zusammenfassung — Grundlage für Reporting/Abschluss ✅
Wizard-Schritte Richtlinien & Risiken (B) Onboarding-Schritte 4 (Richtlinien) und 6 (Risiken) zeigen den echten Modul-Status statt Platzhaltern — der Wizard ist damit über alle 9 Schritte durchgängig ✅
Umsetzungshinweise im Control-Schritt (#10) Je Control-Anforderung lassen sich die Umsetzungshinweise dokumentieren, abhaken und in eine Aufgabe überführen; der Umsetzungsstatus je Spiegelstrich fließt in den Reifegrad ein (ControlImplementation) ✅
Aufgaben/Maßnahmen-Vereinheitlichung (7-9) Aufgaben und Maßnahmen im selben Bedien-Design (gemeinsamer Anlage-Dialog); Standardmaßnahmen aus dem Risikokatalog werden zu echten, verknüpften Maßnahmen; neue Rolle pm mit Voll-Sicht auf Aufgaben (task:read_all) ✅
Wizard-UX-Feinschliff (#1/#3/#6) Interne Identifier aus den Wizard-Texten entfernt, Assets-Schritt gibt Rückmeldung beim „Aufgaben anlegen", Aufgaben-Sichtbarkeit als Pool-Popup ✅
Asset-Schritt (A5) Wizard-Schritt 5 bindet das Bestands-/Asset-Modul ein — Assets werden im Onboarding erfasst statt separat ✅
Control-Assessment & Reifegrad (A7) Wizard-Schritt 7: Controls bewerten (Belegstatus, Reifegrad R0–R3, Zielreifegrad); offene Punkte erzeugen automatisch Gap-Aufgaben ✅
Standard-Risikokatalog (A6) Vorgefertigter Risikokatalog (C4) zum Übernehmen; Standardmaßnahmen erzeugen Aufgaben; dokumentierte Restrisiko-Akzeptanz (VA-09) ✅
Gap-Konsolidierung (A8) Wizard-Schritt 8 bündelt alle offenen Punkte/Gaps aus den Schritten — dedupliziert, priorisiert (Quick-Wins) und gleicht sie mit Aufgaben ab ✅
Freigabe-Workflow + Aufgaben Einreicher wählt Freigeber → Aufgabe; Freigeben/Ablehnen (mit Kommentar) im Modul „Aufgaben" (Vier-Augen); Dashboard-Kachel für offene Freigaben ✅
Nicht-destruktiver Re-Import Richtlinien-Paket-Updates erhalten Status/Freigabe/Overrides/Variablenwerte; entfernte Einträge werden deaktiviert statt gelöscht; Änderungsreport ✅
GAP-Report Richtlinien 6 neue Verfahrensanweisungen (VA-14..19), alle zuständigen VAs inline verlinkt, Rendering-Fehler behoben, verwaltete Register editierbar ✅
Software-Verwaltung Software ist ein Asset (Typ SOFTWARE) und wird im Lieferantenbereich unter „Software" gepflegt (Popups wie IT-Services): Anbieter/Lieferant, Version/Patch-Stand, Freigabestatus, Freigeber, Review. Ersetzt die frühere „Software-Whitelist" ✅
Projekte Projekte sind Assets (Typ PROJECT) im Assetinventar: bewertbar wie Assets (Kritikalität C/I/A), Risiken zuordenbar, IS-Klassifizierung, ISB-Einbindung, Projektstatus — Bedienung als Popup ✅
Kritische IT-Dienste Schreibgeschützte Auto-Sicht (/assets?view=critical): leitet kritische Dienste automatisch aus Verfügbarkeit und BIA ab, mit RTO/RPO aus den verknüpften Prozessen und Abhängigkeiten — keine gepflegte Doppelliste mehr ✅
Register-Konsolidierung Doppelte Register (externe IT-Dienste, Software-Whitelist, kritische Dienste, Projekte) entfernt und in die Fachmodule überführt; Richtlinien-Verweise zeigen jetzt auf die Module. REG-NET (Netzplan) auf ein Referenz-/Speicherort-Feld reduziert ✅
Produktmarke Certvia Die Anwendung heißt und erscheint durchgängig als Certvia — Logo und Wortmarke, Tab-/App-Icon, Seitentitel, Anmelde- und Fehlerseiten, Druckansicht. GEFIM bleibt als Dachmarke sichtbar („Ein Produkt von GEFIM"). Ohne eigenes Mandanten-Logo zeigt jeder Kunde Certvia. Reine Design-Umstellung ohne Funktionsänderung ✅
Wizard-Parallelisierung (Fix) Bearbeitung und Validierung im Onboarding-Wizard entkoppelt — Schritte können parallel bearbeitet werden, statt streng nacheinander; dazu scripts/sync-role-permissions.ts zum Nachziehen neuer Rechte für bestehende Mandanten ✅

🟥 Bewusst zurückgestellt / offen

Thema Anmerkung
Paket 4 — SMTP + E-Mail-Einladungs-/Reset-Flow Auf Kundenwunsch später; Aktivierung läuft vorerst über Initial-/Einmal-Passwort, gekapselt für spätere Token-Aktivierung
Netzplan-Datei-Upload (REG-NET) Datei-Upload-/Storage-Infrastruktur existiert noch nicht; REG-NET verweist vorerst per Feld auf den extern gepflegten Netzplan. Upload als eigenes Paket (Storage-Backend + Coolify-Volume)
Tenant-weite MFA-Pflicht scharfschalten Flag securityPolicy.mfaRequired vorhanden + von „MFA deaktivieren" respektiert; Enrollment-Erzwingung beim Login noch nicht verdrahtet (analog Force-Change-Gate)
Admin Phase 2 Impersonation, Plan/Limits, Logo-Upload, DSGVO-Export/Retention
NIS2-Modul nie begonnen (großes Framework, Incident-Reporting mit Fristen-Timern)
Richtlinien-Versionierung/Diff, DOCX/PDF-Export offen
ISB-Freigabe der neuen GAP-Texte fachlicher Prozessschritt (kein Code): neue/geänderte VA-/Richtlinien-Texte durch den ISB freigeben
Platzhalter-Module SoA & Controls, Vorfälle, Nachweise, Management-Review, KI-Chat

3. Für neue Entwickler — technische Landkarte

Setup, Stack, Konventionen und Fallstricke unverändert in docs/HANDOVER-DEV.md (§1–§9). Hier nur, was dev ergänzt.

3.1 Neue Datenmodelle (Prisma)

Modell Zweck Mandantengebunden?
PlatformAdmin Getrennter Superadmin-Store (kein tenant_id), Argon2id, TOTP-Secret, Recovery-Codes, Lockout nein (plattformweit)
PlatformSetting (Singleton) Plattform-Policy, u. a. mfaRequired nein
Task / TaskComment Generisches Aufgaben-/Freigabe-Modell (erster Typ policy_approval), Kommentar-Historie ja
ManagedRegister / RegisterRow Generisches editierbares Register (code, columns JSON, Cross-Links supplier/asset) ja
SoftwareProfile 1:1 zu Asset (Typ SOFTWARE): Anbieter-Verknüpfung (providerAssetId→SUPPLIER), Version, Freigabestatus (SoftwareApprovalStatus), Freigeber, Kritikalität, Review ja
ProjectProfile 1:1 zu Asset (Typ PROJECT): IS-Klassifizierung, ISB-Einbindung, ProjectStatus. Kritikalität via C/I/A am Asset, Risiken via RiskAsset ja
AssetType neu Enum um SOFTWARE und PROJECT erweitert —
User.* neu mustChangePassword, mfaEnrolledAt, recoveryCodes ja
PolicyDocument.archivedAt, PolicyRequirement.archivedAt Lifecycle für nicht-destruktiven Re-Import (deaktivieren statt löschen) ja
AuditLog.tenantId nullable Plattform-Ereignisse ohne Mandantenbezug (scope=platform) —
WizardScope (A2) Scope des Onboarding-Wizards: Prüfziele, Geltungsbereich, Standorte, Ausschlüsse — Basis der Scope-Filter-Engine (scope-filter.ts) ja (RLS)
ImplementationHint (B5) Globaler C6-Umsetzungshinweis-Katalog je Anforderung (organisatorisch/technisch/Nachweise/Ressourcen, AL-Filter) nein (globaler Katalog, kein RLS)
PolicyPackageState (B6) Je Mandant: Version/Stand des importierten Vorlagenpakets — Basis für kontrollierte Diff-Übernahme von Updates ja (RLS)
ControlAssessment (A7) Je Mandant/Control: Belegstatus, Reifegrad (R0–R3), Zielreifegrad — Basis für Gap-Aufgaben und SoA ja (RLS)
RiskCatalogEntry (A6) Globaler Standard-Risikokatalog (C4) zum Übernehmen — Content identisch je Mandant nein (globaler Katalog, kein RLS)
ControlImplementation (#10) Je Mandant/Control-Spiegelstrich: Umsetzungsstatus (dokumentiert/abgehakt), koppelt an Reifegrad und Aufgaben ja (RLS)
Task.description (7-9) Beschreibungsfeld am bestehenden Task (Migration task_description) für die Aufgaben/Maßnahmen-Parität ja
Risk.acceptedAt/By/Rationale (A6) Restrisiko-Akzeptanz-Felder am bestehenden Risk (Migration risk_acceptance) ja

Alle neuen tenant-gebundenen Modelle sind in TENANT_MODELS (src/server/db.ts) und haben RLS-Policies (in den jeweiligen Migrationen).

3.2 Auth-Architektur (wichtig!)

  • Zwei getrennte NextAuth-Instanzen: Mandanten-Login (src/server/auth.ts, /login) und Plattform-Login (src/server/platform-auth.ts, eigener Cookie + basePath /api/platform-auth, /platform/login). Plattform-Session trägt keinen tenantId.
  • Superadmin-Bereich liegt unter src/app/(platform)/… (Layout erzwingt Plattform-Session + ggf. MFA); Mandanten-App unter src/app/(app)/….
  • MFA-Helfer src/server/mfa.ts (otplib TOTP + Recovery-Codes) — von Plattform- und Nutzer-MFA gemeinsam genutzt.
  • Force-Change: (app)-Layout prüft Kontostatus/mustChangePassword autoritativ aus der DB → /change-password bzw. Abmelde-Screen bei deaktivierten Konten.
  • Passwort-Policy: src/lib/password-policy.ts (reine Validierung, client-safe) + src/server/password.ts (Argon2id + Generator); Quelle TenantSettings.securityPolicy.password.

3.3 Modul-Durchsetzung (§3.4) — Konvention für neue Actions

  • Jede mutierende Server-Action eines gegateten Moduls läuft über moduleGuard("<key>") (src/server/action-guard.ts): Session → assertModuleEnabled → RBAC.
  • Vollständigkeitscheck scripts/check-module-guards.ts (als prebuild verdrahtet): jede Datei in src/server/actions/ muss dort eingetragen sein (Modul-Key oder EXEMPT), sonst failt der Build. → Neue Action-Datei? Dort eintragen.
  • Neues Modul tasks in src/lib/modules.ts (für Bestands-Tenants per Default aktiv, da fehlende TenantModule-Zeile = aktiv).

3.4 Wo liegt was (neu)

  • Superadmin/Plattform: src/app/(platform)/admin/**, /platform/{login,enroll-mfa,profile}, src/server/actions/{admin,platform,platform-users}.ts.
  • Benutzer-/Rollenverwaltung (Kunde): src/app/(app)/settings/users/, src/server/actions/{tenant-users,account}.ts, Komponenten user-table.tsx/user-forms.tsx/role-manager.tsx.
  • Aufgaben/Freigabe: src/app/(app)/tasks/, src/server/actions/tasks.ts (+ submitForApproval in policies.ts); Dashboard-Kachel in dashboard/page.tsx.
  • Register: src/components/generic-register.tsx, src/server/actions/register.ts, Definitionen in prisma/import-managed.ts (GENERIC_REGISTERS + RETIRED_REGISTERS-Cleanup).
  • Software (Lieferantenbereich): Tab in src/app/(app)/suppliers/page.tsx (?tab=software), src/components/software-modals.tsx, src/server/actions/software.ts, SOFTWARE_INCLUDE in src/lib/supplier-include.ts.
  • Projekte (Assetinventar): Typ-Filter/Popup in src/app/(app)/assets/page.tsx, src/components/project-modals.tsx, src/server/actions/projects.ts, PROJECT_INCLUDE in src/lib/supplier-include.ts.
  • Kritische IT-Dienste: Auto-Sicht-Zweig in src/app/(app)/assets/page.tsx (?view=critical) — abgeleitet aus Verfügbarkeit + BIA (ProcessAsset→Process→BiaEntry); Link-Ziel von resolveLink("REG-CRIT-SERVICES").
  • Richtlinien-Import (nicht-destruktiv): prisma/import-policies.ts (Diff/Upsert, { dryRun }, Änderungsreport, archivedAt).
  • Richtlinien-Import/Upload (B4): Actions src/server/actions/policy-package.ts (Import-Kapselung: Self-Service importPolicyPackage + Plattform importPolicyPackageForTenant) und policy-upload.ts (uploadOwnPolicy); Aktivierungs-Trigger in toggleTenantModule (admin.ts); Storage-Adapter src/server/storage/adapter.ts (Stub, Epic S1); UI src/app/(app)/policies/page.tsx (Buttons + Report-Banner) + src/app/(app)/policies/upload/page.tsx. Eigene Uploads liegen im Namensraum EIG-* (außerhalb des Paket-Namensraums → vom Re-Import unberührt).
  • Branding (in dev): Tokens in src/app/globals.css (--brand-* / --ui-*) mit JS-Pendant src/lib/brand.ts; Komponenten src/components/brand/{certvia-logo,tenant-brand,powered-by-gefim}.tsx; Assets public/assets/logo/, public/favicon/, public/site.webmanifest; Dokument-/Mail-CD src/lib/{document-brand,email-brand}.ts; Doku docs/BRANDING-CERTVIA.md (+ Design-Paket unter docs/branding/).
  • Vorlagenpaket (Source of Truth): seed/isms-vorlagenpaket-v2/ — 28→37 Dokumente (VA-14..19; P01/D01/VA-20 neu für Prototypen-/Datenschutz, B4-3), mapping.json (321 Anforderungen), variables.schema.json, Baseline, Nachweisregister, _verify.py (Rendering-/Anker-Check; nach Änderungen python3 _verify.py → OK).

3.5 Konventionen / Fallstricke (Ergänzungen)

  • Dev-Server & Server-Actions: Änderungen an Server-Actions greifen im Turbopack-Dev manchmal erst nach Neustart des Dev-Servers.
  • Migrations-Flow Prisma 7 wie gehabt (migrate diff --from-config-datasource … --to-schema … --script, dann RLS-DO-Block manuell anhängen, migrate deploy). Data-Migrationen (z. B. strip_tool_variable_articles) sind reine SQL-UPDATE-Migrationen.
  • Geteilte DB bei paralleler 2-Lane-Entwicklung (Dev A × Dev B): Beide Worktrees zeigen auf dieselbe lokale Postgres-DB. Dadurch enthält migrate diff --from-config-datasource fremde, vom anderen Branch angewandte Schemaänderungen (z. B. wollte A1-1 fälschlich Dev Bs tasks-Spalten links/origin/priority/resources droppen). Regel: beim Erzeugen einer Migration nur die eigenen DDL-Blöcke übernehmen und Fremd-Drops von Hand entfernen; anschließend prüfen, dass die Spalten/Objekte des anderen erhalten sind. Migrations-Reihenfolge & „nie gleichzeitig" strikt nach Contracts §6. Merge-Nachsorge: Wird eine Migration im anderen Branch neu erzeugt (anderer Timestamp) und die geteilte DB hat noch die alte angewandt, meldet migrate status „applied ≠ lokal". Fix ohne Datenverlust: stalen _prisma_migrations-Eintrag löschen + prisma migrate resolve --applied <neuer_name> (kein SQL läuft neu). So geschehen bei tasks_wizard_fields (…103650 in DB → …104412 committet).
  • Zentrale Variablen (Organisation/Rollen/Schutzbedarf-Flags, src/lib/policy-variables.ts) sind im Richtlinien-Editor gesperrt und werden serverseitig geblockt — nur in /settings pflegbar.
  • Rendering (Variante B): Tool-Variablen-Defaults ohne führenden Artikel (TOOL_TICKET=„Ticketsystem" etc.); der Fließtext setzt Artikel/Deklination. Bestandswerte werden per Migration migriert.
  • Register vs. Managed-Register-Docs: die verwalteten Register (CRYPTO/RISKMATRIX/CLASSIFICATION/HANDBUCH) sind spezifische Modelle; die verbliebenen REG-* (SENS-ROLES, AUDIT-PLAN, NET) nutzen das generische ManagedRegister-Modell. importPolicies archiviert nur den Paket-Namensraum (L00/R*/VA-*/BASELINE/NACHWEIS) — Register bleiben unberührt.
  • Register-Konsolidierung (Block 5): REG-EXT-SERVICES / REG-SW-WHITELIST / REG-CRIT-SERVICES / REG-PROJECTS sind stillgelegt (Liste RETIRED_REGISTERS in import-managed.ts löscht Dokument + ManagedRegister + Zeilen idempotent beim Import). Ihre {{LINK:REG-…}} in den Seed-Texten bleiben unverändert — nur resolveLink (src/lib/policy-render.ts) biegt sie auf die Modul-Routen um (/suppliers?tab=services|software, /assets?view=critical, /assets?type=PROJECT). Wer ein Register neu stilllegen will: Code aus GENERIC_REGISTERS entfernen, in RETIRED_REGISTERS eintragen, resolveLink-Fall ergänzen.
  • Software/Projekte als Asset-Typen: folgen exakt dem bestehenden Muster von SUPPLIER/IT_SERVICE (Asset + 1:1-Profil, refNo je Mandant, Cockpit-Popups auf /suppliers und /assets, backHref-gesteuert). Neue Action-Dateien (software.ts→suppliers, projects.ts→assets) sind in scripts/check-module-guards.ts registriert.

3.6 Demo-Logins (Passwort Demo1234!)

  • Mandanten-Login /login: admin@demo.example (Mandanten-Admin + ISB), bea.approver@demo.example (ISB, zweiter Freigeber für den Vier-Augen-Workflow), auditor@…, owner@…, user@….
  • Plattform-Login /platform/login: admin@demo.example (getrennte Session; MFA optional, Enrollment beim ersten Login nur wenn Policy es verlangt).

4. Commit-Übersicht (main..dev, neueste zuerst)

55260a7 Merge SEC3+SEC4 (MFA pro Mandant erzwingen, WebAuthn/Passkeys, TOTP-Verschlüsselung at rest, Plattform-Admin-Verwaltung) in dev
8a154f0 Merge TISAX v7-Fortsetzung (Fachbereich-Ableitung beim Import, Richtlinien nach Fachbereich im Onboarding, parametrisierbares Redirect-Ziel) in dev
a0c0d14 Merge TISAX v6/v7 (ABGABE-xlsx-Export, echter MinIO/S3-Adapter, PolicyDocument.domain/Fachbereich, Audit-Permissions) in dev
850b691 Merge TISAX v5 (Audit-Vorbereitung Phase 1: Audit-Übersicht/Wizard-Shell, Readiness/GAP-Tab, Nachweise-Tab, Control-Beschreibungen mit KI-Entwurf + ABGABE-CSV-Export) in dev
6370cee Merge TISAX v4 (Prozesshaus-Ausbau: Löschen, Katalog-Teilprozesse parentCode, Details-Overlay; BIA-Popup vereinfacht + Träger-/Risiko-Neuanlage) in dev
23df560 Merge TISAX v3 (Prozesshaus + geführtes BIA je Prozess, Popup-Bearbeitung Rollen/Kriterien, zusätzliche Prozess-Felder) in dev
f1c11aa Feature: Plattform-Konsole legt Tenant-Nutzer per Einladungslink an (wie Mandanten-Admin)
2bfc071 Merge TISAX-Integration (M0–M4 + Wizard-Neustruktur) in dev — Fundament, Strukturanalyse, Cockpit (RACI/Evidence), Audit-Wizard, TISAX-Tasks, Content-Seed; 3 Migrationen + RLS für neue Tabellen
2fd522c Feature: Benutzer-Anlegen verschickt Einladungslink per Mail (invitation-Template, /reset-Token 7 Tage) statt Passwort-Anzeige
4d28c86 Fix: Benutzer-/Mail-Actions graceful statt Fehlerseite + Formular-Werterhalt
6b4c6fb Coolify: Mail-Worker-Service (SEC1) ergänzt
c47ace0 Merge SEC1+SEC2: Mailversand/Queue (SEC1, BullMQ/ioredis/nodemailer, Worker) + Auth-Self-Service (SEC2, AuthToken, Reset/Passwortwechsel/E-Mail-Änderung, Session-Invalidierung, Rate-Limit) in dev
3998f9f Fix: /tasks SSR-Crash — entfernte Variable `open` im Untertitel wiederhergestellt
3932ff2 Merge 7-9/4: Aufgaben als Kanban-Board (Maßnahmen-Design) + Vorschläge/Bearbeiten korrigiert in dev
00e7e79 Dockerfile: Fachcontent (docs/wizard-uebergabe) ins migrate-Image für Demo-Seed (C4/C6)
fb1935e Dockerfile: Richtlinien-Vorlagenpaket (seed/) in migrate- und runner-Image
d0dfe0b Merge Security: P1/P2/P3-Härtungspaket (F-01…F-20) in dev — Tenant-Isolation, Auth/Session, RLS scharf (F-04), moduleGuard-DB-Authz (F-06), Web-Härtung, MFA-Replay, Supply-Chain/Container (F-11/F-18)
63b583d Merge Dev-A: A6-1 + A6-2 (Standard-Risikokatalog C4, Standardmaßnahme→Aufgabe, Restrisiko-Akzeptanz) in dev
e6c5e51 Merge Dev: UX-Fixes (#1/#3/#6) + Aufgaben/Maßnahmen-Vereinheitlichung (7-9) + Umsetzungshinweise Control-Schritt (#10, ControlImplementation) in dev
6b4b190 Merge Dev-B: Wizard-Schritte 4 (Richtlinien) + 6 (Risiken) — echte Komponenten statt Platzhalter in dev
0629613 Merge Branding: Umstellung auf Certvia (Design-Tokens, Logo/Icons, Metadaten, i18n, Auth-/Systemseiten, Dokument-CD) in dev
7f4a85c Merge Fix: Wizard-Bearbeitung von Validierung entkoppeln (Parallelisierung) + Rollen-Rechte-Sync-Skript in dev
6b20e13 Merge Dev-B: B7-2 (VDA-ISA-Katalog-Export CSV + Management-Zusammenfassung, C9) in dev
2cc422c Merge Dev-A: A8-1/A8-2 (Gap-Konsolidierungs-Engine) + A8 (Gap-Schritt 8: Aggregation/Priorisierung/Task-Abgleich) in dev
76cfebc Merge Dev-A: A5-1 (Asset-Schritt) + A7-1/A7-2 (Control-Assessment + Reifegrad-Engine) in dev
7dc5ae1 Merge Dev-B: B6 (Vorlagenpaket-Versionierung + kontrollierte Diff-Übernahme) in dev
1238564 Merge Dev-B: B7-1 (Assessment-Readiness-Dashboard + Interpretationstexte C9) in dev
de76856 Merge Dev-A: A4 (ISMS-Rollen Schritt 3 + Funktionstrennung FT-01…06) in dev
012c0fa Merge Dev-B: Prüfziele als Single Source aus WizardScope (Doppelquelle behoben) in dev
227d7a3 Merge Dev-A: A3-1 (generisches Objekt-Review / Validierungs-Workflow) in dev
8c9f648 Merge Dev-B: B5-1 + B5-2 (Umsetzungshinweise C6, kontextsensitives Panel) in dev  [+ 98d5e26 B5-1, 93e2f44 B5-2]
d5c11df Merge Dev-A: A2-1 + A2-2 (Assessment-Level zentral, Scope-Filter) in dev  [+ 69cc25a A2-1, 177df8b A2-2]
78be114 Doku: STAND B4 · c473cad B4-3 (P01/D01/VA-20) · eb7c899 B4-2 (Upload) · 269506b B4-1 (Import) — Dev B, per FF in dev
4e1b116 Merge Dev-B: B3 Fragebogen (Schritt 2 context) in dev  [+ f818093 B3-Feature-Commit]
872c35e Merge Dev-B: F3+B2 Regel-/Mapping-Engine in dev        [+ 20afd63 B2-Feature-Commit]
   (DevOps-Integration: dev-b2-regel-engine + dev-b3-fragebogen additiv gemergt; Gate grün)
b9d8027 Story A1-2: Dashboard-Kachel „Onboarding-Fortschritt" (Dev A)
949d7c5 Story F2: ObjectReviewStatus + external_validator + Wizard-Validierung (Dev A)
12c94fe Merge Dev-B-Lane in dev: F1 + B1 + F4  (Konsolidierung beider Lanes)
0d52090 F4: Wizard-Flags in variables.schema.json (Dev B)
ddd2dc4 B1: Auto-Generierung von Aufgaben-Vorschlägen (C2 §8) (Dev B)
30c3638 F1: Task-Objekt um Wizard-Felder erweitern (Contracts §1) (Dev B)
97b3b4e Story A1-1: Onboarding-Wizard-Shell (Step-Registry, State-Machine, Gate) (Dev A)
   (darüber Wizard-Kickoff-Commits: Sign-off, Dev-B-Bestätigung, Contracts, Übergabepaket)
   (sowie lokale Doku-Commits — Onboarding-Prompt + STAND-Updates)
f368d8f Fix: Fonts selbst hosten (next/font/local) + Bootstrap an Superadmin-Store anpassen
cc8d486 Feat: Prod-Bootstrap (Erst-Superadmin) + Contabo-Runbook
── ab hier auf origin/dev (gepusht) ──
9b479ab Software und Projekte als Assets + Auto-Sicht kritische Dienste
150a1d9 Register-Konsolidierung: 4 Register in Fachmodule überführt
0806030 Datenmodell: Asset-Typen SOFTWARE und PROJECT mit Fachprofilen
2ec0230 Doku: Konsolidierte Übergabe des dev-Stands (PM + neue Entwickler)
95d4479 GAP WP3.1: IMPL-Texte mit verwalteten Registern verdrahtet
bd56a47 GAP WP3.0: Generisches, editierbares Register-Datenmodell + Editor
b9784e5 GAP E2: ISA 3.1.3-Stub entfernt (3.1.2 deprecated)
b7d5df4 GAP WP2.2 (Rendering Variante B) + WP4 (Feinschliff)
36c2903 GAP WP1: Neue VAs 14–19 + Register + Baseline + Eltern-Wiring
522508a GAP WP2.1: Inline-VA-Verweise + Verify-Fix (F17)
742277f Doku: Benutzer-Popups, Aufgaben-Modul, Richtlinien-Governance, Demo-Approver
1d8f563 Freigabe-Workflow + Aufgaben-Modul + Dashboard-Kachel
73c9813 Benutzerverwaltung als Popup (Einstellungen + Admin)
959d816 Richtlinien-Fixes: zentrale Variablen, Schutzbedarf zentral, Coverage nach Level
d38b265 Benutzer bearbeiten (Name/E-Mail) + Kern-Einstellungen nur Superadmin
303dcd0 Doku: Produktionshärtung + Benutzer-/Rollenverwaltung
d0821e2 Paket B — Mandanten-Admin: Benutzer- & Rollenverwaltung
3db820e Paket C — MFA optional (Superadmin + Tenant)
908b098 Paket A — Plattform-Admin: Benutzerverwaltung je Mandant
db36c79 Fundament Benutzer-/Rollenverwaltung: Schema, Passwort-Policy, Force-Change
e07dcd9 Nicht-destruktiver Richtlinien-Re-Import (Härtung Paket 3)
8e4040d Separater Superadmin-Store + eigener Login + MFA (Härtung Paket 2)
8348764 API-seitige Modul-Durchsetzung (§3.4, Härtung Paket 1)

5. Deployment & Verifikation

  • Test-/Coolify-Deploy (Demo): dev deployen; die 7 neuen Migrationen laufen automatisch im Init-Container (prisma migrate deploy), Bootstrap-Seed legt Demo-Daten + Demo-Approver an. Die letzte Migration ändert das AssetType-Enum und legt zwei RLS-Tabellen an — einmal komplett durchlaufen lassen, bevor die neuen Ansichten getestet werden.
  • Prod-Deploy (ohne Demo-Seed): Runbook docs/DEPLOY-PROD-CONTABO.md. Statt Demo-Seed läuft scripts/bootstrap-admin.ts (Erst-Superadmin im platformAdmin-Store + Mandant/Mandanten-Admin, idempotent), gesteuert per BOOTSTRAP_*-Env im migrate-Job der docker-compose.coolify.yml; Env-Referenz .env.prod.example. Fonts sind selbst gehostet (kein Google-Fonts-Fetch zur Build-Zeit → reproduzierbarer Offline-Build).
  • Lokale Verifikation: npx tsc --noEmit → npm run lint → npm run build (führt prebuild-Guard-Check aus); für das Vorlagenpaket python3 seed/isms-vorlagenpaket-v2/_verify.py (OK = rückstandsfrei, Mapping sauber).
  • Sync-Status (Gitea aktuell offline): lokaler dev ist 27 Commits vor origin/dev (inkl. der beiden Dev-B-Integrations-Merges F3+B2 und B3). Sobald Gitea erreichbar ist: erst git fetch, prüfen ob origin/dev noch 9b479ab ist (bzw. ob jemand anderes gepusht hat), dann git push origin dev. Bei Divergenz nicht blind force-pushen — abstimmen.
  • Merge dev → main: liegt beim PM/Lead (Gitea-PR: …/msolarczek/ISMS-Tool/pulls/new/dev).

6. Empfohlene nächste Schritte

  1. ISB-Freigabe der neuen/angepassten Richtlinien- und VA-Texte (fachlich, inkl. P01/D01/VA-20 aus B4-3).
  2. Storage-Backend (Epic S1) — echten Adapter hinter src/server/storage/adapter.ts (B4-2-Stub) einhängen (S3/MinIO/Coolify-Volume); danach Datei-Persistenz eigener Richtlinien + Netzplan-Upload REG-NET.
  3. Wizard-Stories vollständig konsolidiert — Dev A: A1–A8, Dev B: F1–F4, B1–B7 (inkl. B7-2 Export + Prüfziel-Follow-up). Alle Feature-Branches in dev. Als Nächstes (neue Stories/Epics): SoA-/Reifegrad-Auswertungen auf Basis von A7, Reporting-Ausbau auf Basis des VDA-ISA-Exports, echtes Storage-Backend (Epic S1).
  4. Paket 4 — SMTP + E-Mail-Einladungs-/Aktivierungs-/Reset-Flow (Aktivierung ist bereits gekapselt).
  5. Tenant-weite MFA-Pflicht scharfschalten (Enrollment-Gate).
  6. Admin Phase 2 (Impersonation, Plan/Limits) oder NIS2-Modul — je nach Vertriebs-/Compliance-Priorität.

Hotfix: Docker-Build brach ohne PASSWORD_PEPPER ab (Deploy-Blocker)

  • Symptom: Coolify-Deploy „erfolgreich", aber KEINE certvia-Container. Ursache war der Image-Build selbst: RUN npx prisma generate && npm run build (Dockerfile:40) exit 1 → kein up.
  • Root Cause: src/server/auth.ts erzeugte den Konstant-Zeit-Dummy-Hash auf Modulebene (const DUMMY_HASH_PROMISE = hashPassword(...)). hashPassword() liest den PASSWORD_PEPPER, der zur Docker-Build-Zeit fehlt (nur DATABASE_URL-Platzhalter gesetzt). next build (Page-Data-Collection für /api/auth/[...nextauth]) lud das Modul → Import-Zeit-Throw (fail-secure) → Build-Abbruch. Lokal grün, weil .env den Pepper liefert (im Image per .dockerignore ausgeschlossen).
  • Fix: Dummy-Hash lazy + memoisiert (dummyHash()), Aufruf erst zur Laufzeit in verifyIdentityPassword — gleiches Muster wie assertSecureEnv()/pepper(). Konstant-Zeit-Verhalten (F-05) bleibt erhalten.
  • Verifiziert: docker build --target builder grün OHNE gesetzten PASSWORD_PEPPER (Coolify-Build-Bedingung); tsc grün.

Hotfix 2: incident-inbound-worker Crash-Loop riss den Stack ab

  • Symptom (nach Build-Fix): migrate ✅, app ✅ Ready, mail-/backup-worker ✅ — aber Coolify-Status flippte auf „exited" und riss den ganzen Stack ab. Ursache: incident-inbound-worker ohne IMAP-Konfig process.exit(1) + restart: unless-stopped → Crash-Loop → Coolify wertet Deploy als unhealthy → compose down (auch der gesunden App).
  • Fix: scripts/incident-inbound-worker.ts idlet jetzt bei fehlender IMAP-Konfig (idleUntilSignal()), statt zu exiten. Container bleibt „running", SIGTERM beendet sauber (Exit 0). Bei nachträglicher IMAP-Konfig: Container-Neustart aktiviert den Betrieb.
  • Verifiziert: tsc grün; Smoke-Test ohne IMAP-Env → Prozess bleibt am Leben, loggt Idle-Hinweis, kein Crash.

Merge: Objektspeicher MinIO → Garage (self-hosted)

  • feature/garage-migration → dev (--no-ff). Umsetzung des Konzepts docs/KONZEPT-garage-migration.md (4 Lanes), keine Datenmigration (nur Test-Instanzen, Neu-Deploy).
  • Infra: garage-Service ersetzt minio in docker-compose.yml + docker-compose.coolify.yml; deploy/garage.toml (Single-Node, s3_region=us-east-1, RPC-/Admin-Token); Volumes garage_meta (kritisch, ins Backup) + garage_data.
  • Provisioning: scripts/garage-provision.ts — idempotenter Init-Job (Layout + Bucket isms-documents + Key-Import aus S3_*-Env + Rechte).
  • App-Code: ensureBucket() in adapter.ts + backup-store.ts nur noch verifizierend (HeadBucket), kein S3-CreateBucket mehr (Garage kann das nicht); fehlender Bucket → sprechender Konfigfehler statt stiller Heilung. CreateBucketCommand-Imports entfernt.
  • Test/Doku: scripts/test-garage-storage.ts (skippt ohne S3_ENDPOINT, echter E2E mit gesetzten S3_*), Runbook in docs/DEPLOY-COOLIFY.md.
  • Gate grün: tsc, lint, build, Storage-Smoke-Test.
  • Deploy-Hinweise: Coolify-Env S3_ENDPOINT=http://garage:3900, S3_REGION=us-east-1, GARAGE_RPC_SECRET/GARAGE_ADMIN_TOKEN literal setzen (Interpolationsfalle); minio-Service erst nach Abnahme entfernen (Rollback-Netz).

Hotfix Garage-Deploy: garage.toml ins Image backen (Coolify-Bind-Mount-Falle)

  • Symptom: garage-Container crasht ~2s nach Start → unhealthy → Deploy bricht ab. Log: Error: IO error: Is a directory (os error 21) nach „Loading configuration…".
  • Ursache: Coolify legt die Quelle des relativen Bind-Mounts ./deploy/garage.toml als Verzeichnis an (Storage-Behandlung) → Garage bekommt /etc/garage.toml als Ordner.
  • Fix: Neue Dockerfile-Stage garage (FROM dxflrs/garage:v1.2.0 + COPY deploy/garage.toml /etc/garage.toml); docker-compose.coolify.yml nutzt build: target garage statt image: + Bind-Mount. Secrets bleiben zur Laufzeit aus GARAGE_RPC_SECRET/GARAGE_ADMIN_TOKEN. Lokales docker-compose.yml behält den Bind-Mount (auf normalem Docker unkritisch).
  • Verifiziert: docker build --target garage + Start mit gültigem Secret → Daemon läuft, /garage status Exit 0.

Merge: Framework-Erweiterung — ISO 27001 neben TISAX (AP1–AP5 + B1)

  • Kumulativer Merge von feature/framework-assessment (enthielt alle Framework-Lanes: iso27001-framework-mapping, framework-core, ap2, ap3-soa, ap4-mgmt, ap5-doccontrol, assessment) → dev (--no-ff, a747b57). 150 Dateien.
  • AP1 Framework-Dimension (TenantFramework, PolicyTemplateVersion.framework), AP2 Provisionierung & Framework-Flags + framework-fähiger Vorlagen-Editor, AP3 SoA-Modul (ISO-Anwendbarkeitserklärung, 93 Annex-A-Zeilen), AP4 Managementklauseln (9.1/9.3/10.2, CAPA + Wirksamkeitsprüfung), AP5 Dokumentenlenkung (Prüfzyklen, Versionshistorie, Lesebestätigungen), A1–A4/B2/B3 ISO-Inhalte, B1 Assessment-/Readiness-Strategie-Schicht.
  • Variante A (Konzept D4): ein Dokumentensatz, zwei Mappings — docs/FRAMEWORK-MAPPING-ISO27001.md, docs/KONZEPT-framework-iso27001.md.
  • Gate grün: tsc, lint, build. Neue Tests grün: test-framework-{core,templates,provision,assessment,dryrun}, test-{assessment-iso,soa,doc-control,review}. TISAX-Snapshot-Regression: 0 Abweichungen (45 Controls, AL2) — TISAX-Verhalten bit-genau erhalten.

Fix: Normen (Frameworks) je Mandant nachträglich umschaltbar

  • cb2bc0b Admin-Action + UI (admin/[id]/page.tsx, actions/admin.ts, i18n de/en): ISO/TISAX pro Mandant nachträglich aktivieren/deaktivieren. 1475193 Abnahmetest-Fix: „wiedererkannt" zählt reaktivierte Dokumente mit.
  • Neuer Test scripts/test-framework-toggle.ts (Aktivieren/Deaktivieren + Zustand wiederherstellen). Gate grün: tsc/lint/build, test-framework-toggle/-dryrun, TISAX-Snapshot 0 Abweichungen.

BIA-Prozessübersicht: Prozesshaus-Ansicht (Standard) + Tabellen-Umschalter

  • /processes (src/app/(app)/processes/page.tsx) zeigt statt der flachen Tabelle standardmäßig ein Prozesshaus: Bahnen nach Kategorie (Management/Kern/Support), Hauptprozesse als aufklappbare Karten (native <details>), Teilprozesse eingerückt (Baumkonnektor). Je Hauptprozess BIA-Rollup aus den Teilprozessen: Kritikalität = Maximum, RTO/RPO/MTD = schärfster (kleinster) Wert; Farbcode + Statuspunkt nach biaStatus; Schnittstellen (Process.interfaces) als Chip. Umschalter „Prozesshaus ⇄ Tabelle“ über ?view=tabelle (Prozesshaus = Default); Tabellen-Ansicht unverändert.
  • Kein Datenmodell-Umbau — nutzt vorhandene Felder (parentId, category, biaStatus, BiaEntry). KPIs: Prozesse gesamt / im Scope / BIA vollständig / hohe Kritikalität (≥3). Modals (Detail/Anlegen/Bearbeiten) unverändert. Neue i18n-Keys unter processes (de/en). Gate grün: tsc/lint/build. Konzept-Mockup: docs/MOCKUP-bia-prozessuebersicht.html.
  • Nachtrag — jetzt umgesetzt: strukturierte Prozess-zu-Prozess-Abhängigkeiten (siehe nächster Abschnitt); der frühere Freitext interfaces bleibt zusätzlich erhalten.

Prozess-Abhängigkeiten (strukturiert: „benötigt" / „wird benötigt von")

  • Neues Modell ProcessDependency (source benötigt target, optionale note), Migration 20260907084110_add_process_dependencies inkl. RLS (tenant_isolation + FORCE), Unique (source, target), FK-Cascade beim Prozess-Löschen; in TENANT_MODELS aufgenommen. Auswahl innerhalb des Mandanten.
  • Server-Actions in actions/processes.ts: addProcessDependency (idempotenter Upsert, Selbstbezug ausgeschlossen, beide Prozesse müssen existieren) und removeProcessDependency; deleteProcess löst Kanten in beide Richtungen. Beide bia:write-gegated + Audit-Log.
  • UI: Bearbeiten-Modal neuer Abschnitt „Abhängigkeiten" (Chips + Entfernen, Auswahl-Form „benötigt: [Prozess] + Notiz", plus read-only „wird benötigt von"); Detail-Modal zeigt beide Richtungen; Prozesshaus zeigt „↳ benötigt: …"-Chips und „▲ N Prozesse hängen hiervon ab" (Teilprozesse kompakt inline) + Link zum Abhängigkeits-Graph. Neue i18n-Keys deps* (de/en). Gate grün: tsc/lint/build, Modul-Guard-Check 45 Dateien ok.
  • Netz-/Graph-Darstellung: buildDependencyGraph (src/server/dependency-graph.ts) um Prozess→Prozess-Kanten (ProcessDependency, Label „benötigt von", Flussrichtung Abhängigkeit→Nutzer) erweitert; sie erscheinen im bestehenden Graphen /dependencies (React Flow + dagre) und fließen in Analyse/kritischen Pfad ein. SPOF-Erkennung jetzt auch für Prozesse (gemeinsam benötigte Prozesse wie „IT-Betrieb", von denen mehrere kritische Prozesse abhängen). Neuer Client-Filter „Nur Prozesse" in dependency-graph.tsx (blendet Assets aus → reine Prozess-Abhängigkeitskarte). Verifiziert am demo-Mandanten: IT-Betrieb als SPOF (3) korrekt erkannt.

Datenimport (Excel) — zurückgezogen

  • Das zuvor auf dev ergänzte Excel-Datenimport-Feature (geteilte Logik src/server/import/, UI /settings/import, Ops-Skript, Tabelle ImportRef/Migration 20260904081701_add_import_refs, Konzept KONZEPT-datenimport.md) wurde vollständig entfernt (nie deployt, daher ohne DB-Auswirkung). Bestandsdaten werden weiterhin über die Modul-Formulare bzw. den Onboarding-Wizard erfasst.
  • docs/HANDBUCH-KUNDENBETREUUNG.md bleibt als produkt-/supportorientiertes Einstiegshandbuch für die Kundenbetreuung (Zugang/Rollen, Provisionierung, Framework-Wahl, Module, Onboarding, Support-Fälle, Doku-Verweise) — die Datenimport-Abschnitte wurden herausgenommen.

Fix: Risikokriterien 5×5 vervollständigt (Matrix ↔ Einstellungen konsistent)

  • Bug: Risiko-Bewertung (Formular-Skala 1–5, Matrix 5×5, Score-Schwellen bis 25) war 5×5, aber die Kriterien-Daten nur 4-stufig geseedet (EW_LEVELS=4, Schadensdimensionen 1–4) → 5. Stufe ohne Definition.
  • Entscheidung (PO): 5×5 — Kriterien ergänzen (Bewertung/Matrix/Score bleiben unverändert).
  • Seed prisma/import-managed.ts: 5. EW-Stufe („Nahezu sicher") + 5. Stufe je Schadensdimension.
  • Editor onboarding/steps/criteria/criteria-editor.tsx (Settings + Wizard geteilt): Typ/Update/Neuanlage/Rendering auf 1–5; actions.ts zod-Schema um „5"; settings/risk-criteria/page.tsx + onboarding/steps/criteria/step.tsx editorDims um „5".
  • Backfill scripts/backfill-risk-5x5.ts (idempotent): ergänzt EW-Stufe 5 + Schadensstufe 5 für Bestandsmandanten. Für Test/Prod nach Redeploy je Instanz einmal ausführen (demo, gefim).
  • Gate grün (tsc/lint/build); Backfill lokal verifiziert.