Plattform-Admin-Konsole (Superadmin) + Kunden-Einstellungsbereich: - Datenmodell: TenantSettings (Quelle der ISMS-Template-Variablen), TenantModule (Feature-Toggles je Mandant), Tenant += short/sector, TenantStatus += ARCHIVED, AuditLog += scope (tenant|platform); RLS für die neuen Tenant-Tabellen. - Wiederverwendbare Provisionierung (server/provision.ts): Rollen+Permissions, erster Admin-User, Einstellungen, alle Module, optional Richtlinienpaket-Seed + TISAX-Default; idempotent + Audit (§3.7). syncPolicyVariablesFromSettings mappt Stammdaten → ISMS-Variablen (ORG_NAME, ISMS_SCOPE, ROLE_* …). - Admin-Konsole /admin (Guard isPlatformAdmin): Mandantenliste, „Neuer Kunde" (anlegen + provisionieren), Detailseite mit Modul-Toggles, Lebenszyklus (aktiv/gesperrt/archiviert), Nutzerliste. Aktionen im Plattform-Audit-Log. - Kunden-Einstellungen /settings (Guard tenant:manage): Unternehmensdaten, verantwortliche Rollen, Branding/Regionales, TISAX-Level — Stammdaten speisen die ISMS-Variablen (eine Pflegestelle). Modul-Übersicht. - Modul-Gating der Navigation (deaktivierte Module ausgeblendet); Login bereits für gesperrte/archivierte Mandanten blockiert (auth.authorize). - Seed: Demo-Mandant mit Einstellungen, 12 aktiven Modulen; admin@demo.example = Superadmin. Verifiziert: tsc/lint/build grün; Seed rollt Einstellungen/Module/Superadmin aus. (Browser-Verifikation diese Sitzung nicht möglich — Preview-Tools getrennt.) Offen (Phase 2): separater Superadmin-Store + eigener Login + MFA-Pflicht; Impersonation (zeitlich begrenzt, protokolliert); Plan/Limits; Logo-Upload/ Objektspeicher; SMTP/Benachrichtigungen; per-Route-Modul-Enforcement (serverseitig); Datenexport/Löschung/Retention (DSGVO); SSO. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
79 lines
2.5 KiB
SQL
79 lines
2.5 KiB
SQL
-- AlterEnum
|
|
ALTER TYPE "TenantStatus" ADD VALUE 'ARCHIVED';
|
|
|
|
-- AlterTable
|
|
ALTER TABLE "audit_logs" ADD COLUMN "scope" TEXT NOT NULL DEFAULT 'tenant';
|
|
|
|
-- AlterTable
|
|
ALTER TABLE "tenants" ADD COLUMN "sector" TEXT,
|
|
ADD COLUMN "short" TEXT;
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "tenant_settings" (
|
|
"id" TEXT NOT NULL,
|
|
"tenant_id" TEXT NOT NULL,
|
|
"org_name" TEXT NOT NULL,
|
|
"org_short" TEXT,
|
|
"address" TEXT,
|
|
"sector" TEXT,
|
|
"duns" TEXT,
|
|
"isms_scope" TEXT,
|
|
"isms_scope_description" TEXT,
|
|
"role_management" TEXT,
|
|
"role_isb" TEXT,
|
|
"role_it_lead" TEXT,
|
|
"role_dpo" TEXT,
|
|
"logo_key" TEXT,
|
|
"accent" TEXT,
|
|
"locale" TEXT NOT NULL DEFAULT 'de',
|
|
"timezone" TEXT NOT NULL DEFAULT 'Europe/Berlin',
|
|
"tisax_level" TEXT NOT NULL DEFAULT 'AL2',
|
|
"security_policy" JSONB NOT NULL DEFAULT '{}',
|
|
"smtp" JSONB NOT NULL DEFAULT '{}',
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "tenant_settings_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "tenant_modules" (
|
|
"id" TEXT NOT NULL,
|
|
"tenant_id" TEXT NOT NULL,
|
|
"module_key" TEXT NOT NULL,
|
|
"enabled" BOOLEAN NOT NULL DEFAULT true,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "tenant_modules_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "tenant_settings_tenant_id_key" ON "tenant_settings"("tenant_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "tenant_settings_tenant_id_idx" ON "tenant_settings"("tenant_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "tenant_modules_tenant_id_idx" ON "tenant_modules"("tenant_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "tenant_modules_tenant_id_module_key_key" ON "tenant_modules"("tenant_id", "module_key");
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "tenant_settings" ADD CONSTRAINT "tenant_settings_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "tenant_modules" ADD CONSTRAINT "tenant_modules_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
|
|
-- RLS für die neuen mandantenbezogenen Tabellen
|
|
DO $$
|
|
DECLARE t text;
|
|
BEGIN
|
|
FOREACH t IN ARRAY ARRAY['tenant_settings','tenant_modules'] LOOP
|
|
EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', t);
|
|
EXECUTE format('CREATE POLICY tenant_isolation ON %I USING (tenant_id = current_setting(''app.tenant_id'', true))', t);
|
|
END LOOP;
|
|
END $$;
|