Commit Graph
10 Commits
Author SHA1 Message Date
msolarczekandClaude Opus 4.8 cc8d48698f Feat: Prod-Bootstrap (Erst-Superadmin) + Contabo-Runbook
- scripts/bootstrap-admin.ts: legt ersten Plattform-Admin + Mandant via
  provisionTenant(isPlatformAdmin) an; idempotent, per Env gesteuert. Ersetzt in
  Prod den Demo-Seed. tsx-@/-Auflösung lokal verifiziert.
- docker-compose.coolify.yml: migrate-Job führt bei BOOTSTRAP_ADMIN=true das Skript
  nach der Migration aus; BOOTSTRAP_*-Vars durchgereicht.
- .env.prod.example: Prod-Env-Referenz (HTTPS, kein Demo-Seed, Bootstrap-Vars).
- docs/DEPLOY-PROD-CONTABO.md: Runbook (VPS-Härtung/Swap, Coolify+Gitea, DNS/TLS
  app.certvia.de, Deploy, Bootstrap, Backups, Go-Live-Checkliste).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 13:44:34 +02:00
msolarczekandClaude Opus 4.8 9b479abb0f Software und Projekte als Assets + Auto-Sicht kritische Dienste
Software (Lieferantenmodul):
- Neuer Tab „Software" mit Popups (Detail/Anlegen/Bearbeiten) analog IT-Services,
  Anbieter-Verknüpfung, Freigabestatus, Version, Review; Server-Actions
  createSoftware/updateSoftware/deleteSoftware.

Projekte (Assetinventar):
- AssetType PROJECT als Filter, Popup mit Kritikalität (C/I/A), Projektleitung,
  IS-Klassifizierung, Status, ISB-Einbindung; Risiko-Verknüpfung über die
  bestehende RiskAsset-Logik; Server-Actions createProject/updateProject/
  deleteProject. Kontextabhängiger „Neu"-Button je Filter.

Kritische IT-Dienste:
- Schreibgeschützte Auto-Sicht (/assets?view=critical), abgeleitet aus
  Verfügbarkeit und BIA; RTO/RPO aus den verknüpften Prozessen (strengster
  Wert), Abhängigkeiten aus Asset-Relationen.

Software-/Projekt-Cockpits werden auch auf der Asset-Seite gerendert
(backHref=/assets). i18n (de/en) und Modul-Guard-Registrierung ergänzt;
alle Editierfunktionen als Popup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 10:13:19 +02:00
msolarczekandClaude Opus 4.8 bd56a478fc GAP WP3.0: Generisches, editierbares Register-Datenmodell + Editor
Verwaltete Register (GAP-Report §5.2) sind nicht mehr nur benannte Dokumente,
sondern editierbare Register mit Pflichtspalten und Cross-Links.

- Schema: ManagedRegister (code, title, columns JSON, reviewCycle, responsible,
  supplierLink/assetLink) + RegisterRow (values JSON, supplierRef, assetRef).
  Migration + RLS; in TENANT_MODELS.
- import-managed.ts: 7 generische Register (REG-PROJECTS, -SENS-ROLES, -AUDIT-PLAN,
  -EXT-SERVICES, -SW-WHITELIST, -CRIT-SERVICES, -NET) mit definierten Pflichtspalten
  + Cross-Link-Flags; legt Register-Dokument (Bibliothek/Link) UND ManagedRegister-
  Definition idempotent an (RegisterRow bleibt bei Re-Import erhalten).
- actions/register.ts: addRegisterRow/updateRegisterRow/deleteRegisterRow
  (Modul policies, policy:write; Werte gegen die Pflichtspalten, optional Lieferant/Asset).
- components/generic-register.tsx: editierbare Zeilen-Tabelle + Cross-Link-Selects
  (Lieferant = Asset SUPPLIER/IT_SERVICE, Asset = alle); in /policies/[code] eingebunden.

Browser-verifiziert: REG-EXT-SERVICES rendert 7 Spalten + Lieferant/Asset-Selects;
Eintrag anlegen persistiert alle Werte. tsc + lint + build + Guard-Check grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 11:07:08 +02:00
msolarczekandClaude Opus 4.8 1d8f56343d Freigabe-Workflow + Aufgaben-Modul + Dashboard-Kachel
Konzept (abgestimmt): Beim Einreichen wählt der Einreicher einen konkreten
Freigeber; die Freigabe/Ablehnung erfolgt im neuen Aufgaben-Modul (Vier-Augen).

- Modell: generisches Task + TaskComment (Migration inkl. RLS; Task/TaskComment
  in TENANT_MODELS). Erster Typ policy_approval. Neues Modul „tasks" (lib/modules,
  Nav, i18n) — für Bestands-Tenants per Default aktiv.
- policies.ts: submitForApproval(code, formData) verlangt einen Freigeber (aktiver
  Nutzer mit policy:approve, ≠ Einreicher), setzt IN_FREIGABE und erzeugt eine
  Aufgabe; Resubmit schließt alte offene Aufgaben. Alte approvePolicy/rejectPolicy
  entfernt (wandern ins Aufgaben-Modul).
- actions/tasks.ts: approveTask/rejectTask (nur zugewiesener Freigeber, ≠ Einreicher;
  Richtlinie → FREIGEGEBEN bzw. zurück auf ENTWURF) und commentTask (nur Beteiligte);
  Kommentare/Statuswechsel historisiert, Audit.
- /tasks: Aufgaben des Nutzers (offen/erledigt) mit Freigeben/Ablehnen (Grund
  erforderlich)/Kommentieren + Verlauf. Richtlinien-Editor: Freigeber-Dropdown beim
  Einreichen, „Zur Freigabe bei …" + Link zur Aufgabe (keine Inline-Freigabe mehr).
- Dashboard: Kachel „N offene Aufgabe(n)" verlinkt auf /tasks.
- Seed: zweiter ISB „Bea Approver" als Freigeber (ermöglicht den Vier-Augen-Flow).

Browser-verifiziert: R08 eingereicht (Freigeber Bea) → Aufgabe; Dashboard-Kachel
bei Bea; Freigeben in /tasks → R08 FREIGEGEBEN, Task DONE, Kommentar-Historie
(submit+approve). tsc + lint + build + Guard-Check grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 11:41:22 +02:00
msolarczekandClaude Opus 4.8 d0821e2e10 Paket B — Mandanten-Admin: Benutzer- & Rollenverwaltung
Eigener Bereich /settings/users (verlinkt aus /settings), sichtbar nur mit
user:manage bzw. role:manage. Strikt mandantenintern (dbForTenant über die eigene
Session) — kein Cross-Tenant-Zugriff. Audit-Scope: tenant.

- actions/tenant-users.ts:
  - Benutzer (user:manage): createUser (Initial-/Einmal-Passwort, mustChangePassword),
    resetUserPassword, setUserStatus (deaktivieren/reaktivieren), setUserRoles.
  - Rollen (role:manage): createRole (+ Permissions), updateRolePermissions
    (Standardrollen schreibgeschützt), cloneRole (Standard klonbar), deleteRole
    (nur eigene, nur ohne zugewiesene Nutzer — sonst Umzug-Hinweis).
  - Lockout-Schutz: letzter aktiver Mandanten-Admin kann nicht deaktiviert werden
    und ihm kann die Admin-Rolle nicht entzogen werden.
- Komponenten tenant-users-manager.tsx (Benutzer) und role-manager.tsx (Rollen +
  gruppierter Permission-Katalog); Bestands-UI/Dark-Theme wiederverwendet.

Browser-verifiziert: Mandanten-Admin sieht Benutzer + Rollen des eigenen Mandanten,
legt eine eigene Rolle „Externer Prüfer" mit ausgewählten Rechten an (asset:read,
audit:read, policy:read → korrekt gespeichert); Standardrollen als schreibgeschützt
markiert. tsc + lint + build + Guard-Check grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 09:44:28 +02:00
msolarczekandClaude Opus 4.8 908b098400 Paket A — Plattform-Admin: Benutzerverwaltung je Mandant
In der Mandanten-Detailansicht (/admin/[id]) kann der Plattform-Admin je Kunde
Benutzer anlegen und verwalten — ohne E-Mail-Flow, über Initial-/Einmal-Passwort.

- actions/platform-users.ts (Platform-Session-Guard, dbForTenant(zielTenant),
  Audit scope=platform):
  - createTenantUser: Name, E-Mail (eindeutig je Mandant), ≥1 Rolle; Initialpasswort
    selbst setzen ODER policy-konformes Einmal-Passwort erzeugen (einmalig angezeigt);
    Nutzer mit mustChangePassword=true.
  - resetTenantUserPassword: neues Einmal-Passwort + erzwungener Wechsel.
  - setTenantUserStatus: deaktivieren/reaktivieren.
  - setTenantUserRoles: Mehrfach-Rollenzuweisung.
  - Lockout-Schutz: letzter aktiver Mandanten-Admin kann nicht deaktiviert werden
    und ihm kann die Admin-Rolle nicht entzogen werden.
- components/platform-tenant-users.tsx: Anlege-Formular (useActionState, zeigt das
  Einmal-Passwort), Benutzerkarten mit Rollen-Checkboxen, Status-Toggle und Reset.
- /admin/[id] lädt Nutzer inkl. Rollen + Mandanten-Rollen und rendert die Verwaltung.
- Passwort-Generierung/-Prüfung gegen die Mandanten-Passwort-Policy.
- Zukunftssicher gekapselt: Einladungs-Flow (Paket 4) als alternative Aktivierung
  (Token statt Initialpasswort) später einhängbar.

tsc + lint + build + Guard-Check grün. Browser-E2E folgt zusammen mit Paket C.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 09:24:33 +02:00
msolarczekandClaude Opus 4.8 db36c795bd Fundament Benutzer-/Rollenverwaltung: Schema, Passwort-Policy, Force-Change
Vorbereitung für die Benutzer- & Rollenverwaltung (Pakete A–C) ohne E-Mail-Flow.

- Schema: User.mustChangePassword (erzwungener Wechsel), User.mfaEnrolledAt +
  recoveryCodes (optionale Nutzer-MFA, Paket C); neues Singleton PlatformSetting
  mit mfaRequired (Default aus → MFA optional). Migration additiv + Grant/Seed.
- RBAC: neue Permission role:manage (Rollenverwaltung), dem Mandanten-Admin
  zugewiesen; für den bestehenden Demo-Mandanten nachgezogen (neue Tenants via
  provision/seed automatisch).
- Passwort-Policy: lib/password-policy.ts (client-safe Validierung/Beschreibung,
  Defaults + Ableitung aus TenantSettings.securityPolicy) und server/password.ts
  (Argon2id-Hash + policy-konformer Einmal-Passwort-Generator).
- Force-Change-Flow: /change-password (außerhalb der (app)-Shell) + Self-Service-
  Action changeOwnPassword (policy-geprüft, Audit). (app)-Layout erzwingt den
  Wechsel autoritativ aus der DB und sperrt deaktivierte Konten (Abmelden-Screen).

tsc + lint + build + Guard-Check grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 09:18:05 +02:00
msolarczekandClaude Opus 4.8 e07dcd9f2a Nicht-destruktiver Richtlinien-Re-Import (Phase-1-Härtung Paket 3)
Der Re-Import löschte bisher alle Policy-Zeilen und legte sie neu an — das setzte
per-Dokument-Status, TISAX-Override, Freigabe/Version und nutzergepflegte
Variablenwerte zurück. Jetzt Diff/Upsert über stabile Schlüssel, verlustfrei.

- Schema: PolicyDocument.archivedAt + PolicyRequirement.archivedAt (Lifecycle,
  orthogonal zum Freigabe-status). Migration additiv/nullable.
- import-policies.ts komplett auf Reconcile umgebaut:
  - Dokumente (code): neu→anlegen; vorhanden→nur Inhaltsfelder aktualisieren,
    Status/Version/Owner/Freigabe/Override bleiben; fehlend→archivedAt setzen
    (deaktivieren, nicht löschen); Wiederauftauchen→reaktivieren.
  - Anforderungen (reqId): analog inkl. Deaktivierung entfernter Anforderungen.
  - Variablen (key): Metadaten aktualisieren, aber value NIE überschreiben
    (Kundenpflege); fehlende bleiben bestehen (als obsolet ausgewiesen).
  - Baseline (blId) und Nachweise (nr): Upsert; fehlende bleiben erhalten.
  - Deaktivierung greift nur im Paket-Namensraum (L00/R*/VA-*/BASELINE/NACHWEIS)
    — verwaltete Register aus import-managed (CRYPTO/RISKMATRIX/CLASSIFICATION/
    HANDBUCH) werden nicht angetastet.
- Änderungsreport (added/updated/archived/reactivated/unchanged/obsolete) wird
  zurückgegeben und ins Audit-Log geschrieben (Entity policy_package). Option
  { dryRun: true } liefert die Vorschau ohne Schreibzugriff. Idempotent.
- Aktive Ansichten (Bibliothek/Coverage, Dokument-Detail) filtern archivedAt: null;
  Historie bleibt per Direktlink erreichbar.

Akzeptanztest scripts/test-reimport.ts: Status/Override/Einreicher + Variablenwert
bleiben nach Re-Import erhalten, entfernte Anforderung wird deaktiviert (nicht
gelöscht), verwaltete Register unberührt, zweiter Lauf idempotent. Browser: /policies
rendert unverändert (30 Dokumente). tsc + lint + build + Guard-Check grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 13:46:42 +02:00
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
msolarczekandClaude Opus 4.8 8348764c99 API-seitige Modul-Durchsetzung vervollständigt (§3.4, Phase-1-Härtung Paket 1)
Der requireModule-Guard war bislang nur exemplarisch in den Policy-Actions
gesetzt. Jetzt läuft jede mutierende Server-Action eines gegateten Moduls über
einen zentralen, modul- und rechteprüfenden Guard — ein für den Mandanten
deaktiviertes Modul weist damit auch Writes serverseitig ab (nicht nur Reads
über die Route-Layouts).

- action-guard.ts: moduleGuard("<key>") erzeugt je Modul einen guard(...perms),
  der Session → Modul-Aktivierung → RBAC prüft und {session, db} zurückgibt.
- modules.ts: assertModuleEnabled(session, key) wirft (statt Redirect) bei
  Deaktivierung und protokolliert die Verweigerung (Audit-Aktion "denied").
- audit.ts: Audit-Aktion "denied" + optionaler scope-Parameter.
- Alle gegateten Action-Dateien umgestellt: assets→assets, processes→bia,
  risks→risk, measures→measures, suppliers/services→suppliers, policies→policies.
  Freigabe/Ablehnung der Richtlinien laufen jetzt ebenfalls über den Modul-Guard.
- Vollständigkeitscheck scripts/check-module-guards.ts (Registry Action→Modul):
  schlägt fehl bei nicht zugeordneter Datei, fehlendem moduleGuard oder einer
  Action ohne guard(...). Als prebuild verdrahtet ⇒ Build failt bei vergessenem
  Endpoint. admin/tenant-settings sind als EXEMPT (eigene Auth) markiert.

Verifiziert: tsc sauber, lint sauber, Guard-Check grün (9 Dateien), Negativ-Probe
(ungemappte Action-Datei) failt den Check wie erwartet.

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