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>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "users" ADD COLUMN "mfa_enrolled_at" TIMESTAMP(3),
|
||||
ADD COLUMN "must_change_password" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "recovery_codes" JSONB NOT NULL DEFAULT '[]';
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "platform_settings" (
|
||||
"id" TEXT NOT NULL DEFAULT 'singleton',
|
||||
"mfa_required" BOOLEAN NOT NULL DEFAULT false,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "platform_settings_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
|
||||
-- platform_settings ist plattformweit (kein tenant_id) → RLS nicht aktiviert.
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON "platform_settings" TO isms_app;
|
||||
|
||||
-- Singleton-Zeile anlegen (MFA-Pflicht standardmäßig aus).
|
||||
INSERT INTO "platform_settings" ("id", "mfa_required", "updated_at")
|
||||
VALUES ('singleton', false, now())
|
||||
ON CONFLICT ("id") DO NOTHING;
|
||||
+16
-1
@@ -102,7 +102,12 @@ model User {
|
||||
passwordHash String @map("password_hash")
|
||||
name String
|
||||
status UserStatus @default(ACTIVE)
|
||||
mfaSecret String? @map("mfa_secret")
|
||||
// Erzwungener Passwortwechsel beim nächsten Login (Initial-/Reset-Passwort).
|
||||
mustChangePassword Boolean @default(false) @map("must_change_password")
|
||||
// Optionale TOTP-MFA je Nutzer (Paket C). recoveryCodes = SHA-256-Hashes.
|
||||
mfaSecret String? @map("mfa_secret")
|
||||
mfaEnrolledAt DateTime? @map("mfa_enrolled_at")
|
||||
recoveryCodes Json @default("[]") @map("recovery_codes")
|
||||
// Plattform-Admin ist mandantenübergreifend (Betreiberrolle)
|
||||
isPlatformAdmin Boolean @default(false) @map("is_platform_admin")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
@@ -187,6 +192,16 @@ model PlatformAdmin {
|
||||
@@map("platform_admins")
|
||||
}
|
||||
|
||||
// Plattformweite Betriebseinstellungen (Singleton). Steuert u. a., ob MFA für
|
||||
// Plattform-Admins verpflichtend ist (Default: aus → MFA optional, Paket C).
|
||||
model PlatformSetting {
|
||||
id String @id @default("singleton")
|
||||
mfaRequired Boolean @default(false) @map("mfa_required")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@map("platform_settings")
|
||||
}
|
||||
|
||||
// ── Assets & BIA (ein Modul, SPEC §4.1) ─────────────────────────────────────
|
||||
|
||||
enum AssetType {
|
||||
|
||||
Reference in New Issue
Block a user