- Auth.js v5 mit Credentials-Provider: Argon2id-Verifikation, JWT-Session mit Mandanten-Kontext, Rollen und Permissions; Login-/Logout-Flow (deutsch) - RBAC-Katalog (28 Permissions, 5 Rollen-Blueprints) mit serverseitigem requirePermission; Seed legt Demo-Mandant und 4 Demo-Nutzer an - Route-Gate über Next-16-proxy.ts (UX-Ebene), autoritative Prüfung serverseitig via requireSession/requirePermission - Prisma-Migrationen: init + Row-Level-Security-Policies (zweite Verteidigungslinie, Scharfschaltung in Härtungs-Iteration dokumentiert) - i18n-Gerüst mit next-intl (de aktiv, en vorbereitet), Audit-Log-Helper - Login/Logout end-to-end im Browser verifiziert; Build/Lint/Typecheck grün Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
132 lines
4.0 KiB
SQL
132 lines
4.0 KiB
SQL
-- CreateExtension
|
|
CREATE EXTENSION IF NOT EXISTS "vector";
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "TenantStatus" AS ENUM ('ACTIVE', 'SUSPENDED');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "UserStatus" AS ENUM ('ACTIVE', 'INVITED', 'LOCKED', 'DEACTIVATED');
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "tenants" (
|
|
"id" TEXT NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
"slug" TEXT NOT NULL,
|
|
"status" "TenantStatus" NOT NULL DEFAULT 'ACTIVE',
|
|
"config" JSONB NOT NULL DEFAULT '{}',
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "tenants_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "users" (
|
|
"id" TEXT NOT NULL,
|
|
"tenant_id" TEXT NOT NULL,
|
|
"email" TEXT NOT NULL,
|
|
"password_hash" TEXT NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
"status" "UserStatus" NOT NULL DEFAULT 'ACTIVE',
|
|
"mfa_secret" TEXT,
|
|
"is_platform_admin" BOOLEAN NOT NULL DEFAULT false,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "roles" (
|
|
"id" TEXT NOT NULL,
|
|
"tenant_id" TEXT NOT NULL,
|
|
"key" TEXT NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
|
|
CONSTRAINT "roles_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "permissions" (
|
|
"id" TEXT NOT NULL,
|
|
"key" TEXT NOT NULL,
|
|
|
|
CONSTRAINT "permissions_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "user_roles" (
|
|
"user_id" TEXT NOT NULL,
|
|
"role_id" TEXT NOT NULL,
|
|
|
|
CONSTRAINT "user_roles_pkey" PRIMARY KEY ("user_id","role_id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "role_permissions" (
|
|
"role_id" TEXT NOT NULL,
|
|
"permission_id" TEXT NOT NULL,
|
|
|
|
CONSTRAINT "role_permissions_pkey" PRIMARY KEY ("role_id","permission_id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "audit_logs" (
|
|
"id" TEXT NOT NULL,
|
|
"tenant_id" TEXT NOT NULL,
|
|
"actor_id" TEXT,
|
|
"action" TEXT NOT NULL,
|
|
"entity" TEXT NOT NULL,
|
|
"entity_id" TEXT,
|
|
"before" JSONB,
|
|
"after" JSONB,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "audit_logs_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "tenants_slug_key" ON "tenants"("slug");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "users_tenant_id_idx" ON "users"("tenant_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "users_tenant_id_email_key" ON "users"("tenant_id", "email");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "roles_tenant_id_idx" ON "roles"("tenant_id");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "roles_tenant_id_key_key" ON "roles"("tenant_id", "key");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "permissions_key_key" ON "permissions"("key");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "audit_logs_tenant_id_entity_entity_id_idx" ON "audit_logs"("tenant_id", "entity", "entity_id");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "audit_logs_tenant_id_created_at_idx" ON "audit_logs"("tenant_id", "created_at");
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "users" ADD CONSTRAINT "users_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "roles" ADD CONSTRAINT "roles_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_permission_id_fkey" FOREIGN KEY ("permission_id") REFERENCES "permissions"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "audit_logs" ADD CONSTRAINT "audit_logs_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|