Files
hope-events/backend/prisma/migrations/20261019181608_add_impersonation/migration.sql
T
joshuaandClaude Opus 5.5 2b453b00e6 Add read-only admin impersonation
Admins (with 2FA) can view the site as a non-admin user for up to 30
minutes, with a required reason and a "Viewing as" banner. It is
strictly read-only: a guard mounted before every route refuses any
write made with an impersonation token, protect/optionalAuth check the
session is live, and GET handlers skip the price-refresh writes. Start,
end, reason and every page/API call (including blocked attempts) are
audited; optional email to the user.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CP62L9JxHomA36aYP1ekCe
2026-10-19 18:25:02 +02:00

56 lines
2.0 KiB
SQL

-- AlterEnum
-- This migration adds more than one value to an enum.
-- With PostgreSQL versions 11 and earlier, this is not possible
-- in a single migration. This can be worked around by creating
-- multiple migrations, each migration adding only one value to
-- the enum.
ALTER TYPE "AdminAuditAction" ADD VALUE 'impersonation_started';
ALTER TYPE "AdminAuditAction" ADD VALUE 'impersonation_ended';
-- CreateTable
CREATE TABLE "ImpersonationSession" (
"id" TEXT NOT NULL,
"adminId" TEXT NOT NULL,
"targetUserId" TEXT NOT NULL,
"reason" TEXT NOT NULL,
"startedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expiresAt" TIMESTAMP(3) NOT NULL,
"endedAt" TIMESTAMP(3),
"endedReason" TEXT,
CONSTRAINT "ImpersonationSession_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ImpersonationRequestLog" (
"id" TEXT NOT NULL,
"sessionId" TEXT NOT NULL,
"method" TEXT NOT NULL,
"path" TEXT NOT NULL,
"blocked" BOOLEAN NOT NULL DEFAULT false,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "ImpersonationRequestLog_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "ImpersonationSession_adminId_idx" ON "ImpersonationSession"("adminId");
-- CreateIndex
CREATE INDEX "ImpersonationSession_targetUserId_idx" ON "ImpersonationSession"("targetUserId");
-- CreateIndex
CREATE INDEX "ImpersonationRequestLog_sessionId_createdAt_idx" ON "ImpersonationRequestLog"("sessionId", "createdAt");
-- AddForeignKey
ALTER TABLE "ImpersonationSession" ADD CONSTRAINT "ImpersonationSession_adminId_fkey" FOREIGN KEY ("adminId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ImpersonationSession" ADD CONSTRAINT "ImpersonationSession_targetUserId_fkey" FOREIGN KEY ("targetUserId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ImpersonationRequestLog" ADD CONSTRAINT "ImpersonationRequestLog_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "ImpersonationSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;