pnpm-Workspace mit web/, worker/, pdf/ und packages/db. Das Datenbankpaket ist eigenständig, weil Web-App und Worker denselben Prisma-Client brauchen. Schema nach docs/04-datenmodell.md, mit drei Abweichungen, die dort begründet sind: CaseParticipant bekommt einen eigenen Schlüssel statt eines zusammengesetzten mit NULL-Spalten, die Aktenzeichen laufen über CaseCounter statt über eine Sequenz pro Jahr, und ServiceHeartbeat kommt dazu, damit /api/health den Gateway-Zustand kennt, ohne Discord zu fragen. Die zweite Migration enthält, was Prisma nicht ausdrücken kann: - kein DELETE auf CaseEntry, CaseEntryVersion und AuditLog - authorId, createdAt, caseId und type eines Eintrags sind unveränderlich - an einer Eintragsversion darf nur minClearance angehoben werden - Volltextsuche mit deutscher Konfiguration; geschwärzte Bereiche werden vor dem Indizieren entfernt, sonst verrät ein Treffer den Inhalt - pg_notify bei Rollen- und Mapping-Änderungen Acht Tests prüfen diese Regeln gegen eine echte Postgres-Instanz, nicht gegen die Anwendungslogik. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
558 lines
18 KiB
SQL
558 lines
18 KiB
SQL
-- CreateExtension
|
|
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "NotifyMode" AS ENUM ('ALL', 'OWN_CASES', 'MENTIONS', 'OFF');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "CaseStatus" AS ENUM ('DRAFT', 'OPEN', 'DORMANT', 'REVIEW', 'CLOSED', 'ARCHIVED', 'SEALED');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "EntryType" AS ENUM ('NOTE', 'INTERROGATION', 'EVIDENCE', 'STATUS_CHANGE', 'CORRECTION', 'SYSTEM');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "EditPolicy" AS ENUM ('APPEND_ONLY', 'GRACE_WINDOW', 'OPEN');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "ParticipantRole" AS ENUM ('LEAD', 'INVESTIGATOR', 'WITNESS', 'SUBJECT', 'OBSERVER');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "LinkKind" AS ENUM ('RELATED', 'SUCCESSOR', 'MERGED_INTO');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "ScanStatus" AS ENUM ('PENDING', 'CLEAN', 'BLOCKED', 'FAILED');
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "User" (
|
|
"id" TEXT NOT NULL,
|
|
"username" TEXT NOT NULL,
|
|
"displayName" TEXT NOT NULL,
|
|
"avatarHash" TEXT,
|
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
|
"firstSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"notifyMode" "NotifyMode" NOT NULL DEFAULT 'OWN_CASES',
|
|
|
|
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "UserRole" (
|
|
"userId" TEXT NOT NULL,
|
|
"discordRoleId" TEXT NOT NULL,
|
|
|
|
CONSTRAINT "UserRole_pkey" PRIMARY KEY ("userId","discordRoleId")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "RoleMapping" (
|
|
"discordRoleId" TEXT NOT NULL,
|
|
"label" TEXT NOT NULL,
|
|
"clearanceLevel" INTEGER NOT NULL DEFAULT 0,
|
|
"permissions" TEXT[],
|
|
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "RoleMapping_pkey" PRIMARY KEY ("discordRoleId")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "ClearanceLevelConfig" (
|
|
"level" INTEGER NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
"hiddenBelow" BOOLEAN NOT NULL DEFAULT false,
|
|
"colorToken" TEXT NOT NULL,
|
|
|
|
CONSTRAINT "ClearanceLevelConfig_pkey" PRIMARY KEY ("level")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "Session" (
|
|
"id" TEXT NOT NULL,
|
|
"userId" TEXT NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"expiresAt" TIMESTAMP(3) NOT NULL,
|
|
"lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"userAgent" TEXT,
|
|
|
|
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CaseTemplate" (
|
|
"id" TEXT NOT NULL,
|
|
"key" TEXT NOT NULL,
|
|
"version" INTEGER NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
"description" TEXT,
|
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
|
"fields" JSONB NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"createdById" TEXT,
|
|
|
|
CONSTRAINT "CaseTemplate_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "Case" (
|
|
"id" TEXT NOT NULL,
|
|
"caseNumber" TEXT NOT NULL,
|
|
"title" TEXT NOT NULL,
|
|
"status" "CaseStatus" NOT NULL DEFAULT 'DRAFT',
|
|
"classification" INTEGER NOT NULL DEFAULT 1,
|
|
"templateId" TEXT NOT NULL,
|
|
"templateKey" TEXT NOT NULL,
|
|
"dueAt" TIMESTAMP(3),
|
|
"closedAt" TIMESTAMP(3),
|
|
"outcome" TEXT,
|
|
"createdById" TEXT NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
"searchVector" tsvector,
|
|
|
|
CONSTRAINT "Case_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CaseCounter" (
|
|
"year" INTEGER NOT NULL,
|
|
"lastNumber" INTEGER NOT NULL DEFAULT 0,
|
|
|
|
CONSTRAINT "CaseCounter_pkey" PRIMARY KEY ("year")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CaseSection" (
|
|
"id" TEXT NOT NULL,
|
|
"caseId" TEXT NOT NULL,
|
|
"fieldKey" TEXT NOT NULL,
|
|
"minClearance" INTEGER NOT NULL DEFAULT 0,
|
|
"currentVersion" INTEGER NOT NULL DEFAULT 1,
|
|
"value" JSONB NOT NULL,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
"updatedById" TEXT NOT NULL,
|
|
|
|
CONSTRAINT "CaseSection_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CaseSectionVersion" (
|
|
"id" TEXT NOT NULL,
|
|
"sectionId" TEXT NOT NULL,
|
|
"version" INTEGER NOT NULL,
|
|
"value" JSONB NOT NULL,
|
|
"changeReason" TEXT,
|
|
"authorId" TEXT NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "CaseSectionVersion_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CaseEntry" (
|
|
"id" TEXT NOT NULL,
|
|
"caseId" TEXT NOT NULL,
|
|
"type" "EntryType" NOT NULL,
|
|
"body" TEXT NOT NULL,
|
|
"minClearance" INTEGER NOT NULL DEFAULT 0,
|
|
"authorId" TEXT NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"correctsId" TEXT,
|
|
"version" INTEGER NOT NULL DEFAULT 1,
|
|
"editedAt" TIMESTAMP(3),
|
|
"editedById" TEXT,
|
|
"editVisible" BOOLEAN NOT NULL DEFAULT false,
|
|
"retractedAt" TIMESTAMP(3),
|
|
"retractedById" TEXT,
|
|
"retractionReason" TEXT,
|
|
|
|
CONSTRAINT "CaseEntry_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CaseEntryVersion" (
|
|
"id" TEXT NOT NULL,
|
|
"entryId" TEXT NOT NULL,
|
|
"version" INTEGER NOT NULL,
|
|
"body" TEXT NOT NULL,
|
|
"minClearance" INTEGER NOT NULL,
|
|
"changeReason" TEXT,
|
|
"editedById" TEXT NOT NULL,
|
|
"editedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "CaseEntryVersion_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "AppSetting" (
|
|
"id" INTEGER NOT NULL DEFAULT 1,
|
|
"entryEditPolicy" "EditPolicy" NOT NULL DEFAULT 'GRACE_WINDOW',
|
|
"entryEditGraceMinutes" INTEGER NOT NULL DEFAULT 15,
|
|
"entryEditMarkGrace" BOOLEAN NOT NULL DEFAULT false,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
"updatedById" TEXT,
|
|
|
|
CONSTRAINT "AppSetting_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CaseParticipant" (
|
|
"id" TEXT NOT NULL,
|
|
"caseId" TEXT NOT NULL,
|
|
"userId" TEXT,
|
|
"personnelFileId" TEXT,
|
|
"role" "ParticipantRole" NOT NULL,
|
|
"addedById" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "CaseParticipant_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CaseExclusion" (
|
|
"caseId" TEXT NOT NULL,
|
|
"userId" TEXT NOT NULL,
|
|
"reason" TEXT,
|
|
"addedById" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "CaseExclusion_pkey" PRIMARY KEY ("caseId","userId")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CaseLink" (
|
|
"fromId" TEXT NOT NULL,
|
|
"toId" TEXT NOT NULL,
|
|
"kind" "LinkKind" NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "CaseLink_pkey" PRIMARY KEY ("fromId","toId","kind")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "PersonnelFile" (
|
|
"id" TEXT NOT NULL,
|
|
"userId" TEXT,
|
|
"displayName" TEXT NOT NULL,
|
|
"serviceNumber" TEXT,
|
|
"rank" TEXT,
|
|
"department" TEXT,
|
|
"status" TEXT,
|
|
"classification" INTEGER NOT NULL DEFAULT 1,
|
|
"fields" JSONB NOT NULL DEFAULT '{}',
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
"searchVector" tsvector,
|
|
|
|
CONSTRAINT "PersonnelFile_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "Attachment" (
|
|
"id" TEXT NOT NULL,
|
|
"entryId" TEXT,
|
|
"caseId" TEXT,
|
|
"originalName" TEXT NOT NULL,
|
|
"mimeType" TEXT NOT NULL,
|
|
"sizeBytes" INTEGER NOT NULL,
|
|
"sha256" TEXT NOT NULL,
|
|
"scanStatus" "ScanStatus" NOT NULL DEFAULT 'PENDING',
|
|
"scanMessage" TEXT,
|
|
"storageKey" TEXT NOT NULL,
|
|
"thumbKey" TEXT,
|
|
"blurhash" TEXT,
|
|
"uploadedById" TEXT NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "Attachment_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "Channel" (
|
|
"id" TEXT NOT NULL,
|
|
"key" TEXT NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
"description" TEXT,
|
|
"minClearance" INTEGER NOT NULL DEFAULT 0,
|
|
"isArchived" BOOLEAN NOT NULL DEFAULT false,
|
|
"createdById" TEXT NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "Channel_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "ChatMessage" (
|
|
"id" TEXT NOT NULL,
|
|
"caseId" TEXT,
|
|
"channelId" TEXT,
|
|
"authorId" TEXT NOT NULL,
|
|
"body" TEXT NOT NULL,
|
|
"replyToId" TEXT,
|
|
"editedAt" TIMESTAMP(3),
|
|
"withdrawnAt" TIMESTAMP(3),
|
|
"adoptedEntryId" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "ChatMessage_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "ChatReaction" (
|
|
"messageId" TEXT NOT NULL,
|
|
"userId" TEXT NOT NULL,
|
|
"key" TEXT NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "ChatReaction_pkey" PRIMARY KEY ("messageId","userId","key")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "ReadMarker" (
|
|
"userId" TEXT NOT NULL,
|
|
"scopeType" TEXT NOT NULL,
|
|
"scopeId" TEXT NOT NULL,
|
|
"lastReadAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "ReadMarker_pkey" PRIMARY KEY ("userId","scopeType","scopeId")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "Watch" (
|
|
"userId" TEXT NOT NULL,
|
|
"caseId" TEXT NOT NULL,
|
|
|
|
CONSTRAINT "Watch_pkey" PRIMARY KEY ("userId","caseId")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "ServiceHeartbeat" (
|
|
"service" TEXT NOT NULL,
|
|
"status" TEXT NOT NULL,
|
|
"detail" TEXT,
|
|
"at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "ServiceHeartbeat_pkey" PRIMARY KEY ("service")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "AuditLog" (
|
|
"id" BIGSERIAL NOT NULL,
|
|
"at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"actorId" TEXT NOT NULL,
|
|
"action" TEXT NOT NULL,
|
|
"targetType" TEXT NOT NULL,
|
|
"targetId" TEXT NOT NULL,
|
|
"clearanceAtTime" INTEGER NOT NULL,
|
|
"meta" JSONB,
|
|
|
|
CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "User_isActive_displayName_idx" ON "User"("isActive", "displayName");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "UserRole_discordRoleId_idx" ON "UserRole"("discordRoleId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Session_userId_idx" ON "Session"("userId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Session_expiresAt_idx" ON "Session"("expiresAt");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseTemplate_key_isActive_idx" ON "CaseTemplate"("key", "isActive");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "CaseTemplate_key_version_key" ON "CaseTemplate"("key", "version");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "Case_caseNumber_key" ON "Case"("caseNumber");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Case_status_updatedAt_idx" ON "Case"("status", "updatedAt" DESC);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Case_classification_idx" ON "Case"("classification");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Case_dueAt_idx" ON "Case"("dueAt");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Case_createdById_idx" ON "Case"("createdById");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "CaseSection_caseId_fieldKey_key" ON "CaseSection"("caseId", "fieldKey");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseSectionVersion_sectionId_version_idx" ON "CaseSectionVersion"("sectionId", "version" DESC);
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "CaseSectionVersion_sectionId_version_key" ON "CaseSectionVersion"("sectionId", "version");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseEntry_caseId_createdAt_idx" ON "CaseEntry"("caseId", "createdAt" DESC);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseEntry_caseId_editedAt_idx" ON "CaseEntry"("caseId", "editedAt" DESC);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseEntry_authorId_idx" ON "CaseEntry"("authorId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseEntry_correctsId_idx" ON "CaseEntry"("correctsId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseEntryVersion_entryId_version_idx" ON "CaseEntryVersion"("entryId", "version" DESC);
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "CaseEntryVersion_entryId_version_key" ON "CaseEntryVersion"("entryId", "version");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseParticipant_caseId_idx" ON "CaseParticipant"("caseId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseParticipant_userId_idx" ON "CaseParticipant"("userId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseParticipant_personnelFileId_idx" ON "CaseParticipant"("personnelFileId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseExclusion_userId_idx" ON "CaseExclusion"("userId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "CaseLink_toId_idx" ON "CaseLink"("toId");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "PersonnelFile_serviceNumber_key" ON "PersonnelFile"("serviceNumber");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "PersonnelFile_displayName_idx" ON "PersonnelFile"("displayName");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "PersonnelFile_userId_idx" ON "PersonnelFile"("userId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "PersonnelFile_classification_idx" ON "PersonnelFile"("classification");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Attachment_sha256_idx" ON "Attachment"("sha256");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Attachment_scanStatus_idx" ON "Attachment"("scanStatus");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Attachment_caseId_idx" ON "Attachment"("caseId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Attachment_entryId_idx" ON "Attachment"("entryId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Attachment_uploadedById_createdAt_idx" ON "Attachment"("uploadedById", "createdAt");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "Channel_key_key" ON "Channel"("key");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Channel_isArchived_name_idx" ON "Channel"("isArchived", "name");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "ChatMessage_caseId_createdAt_idx" ON "ChatMessage"("caseId", "createdAt" DESC);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "ChatMessage_channelId_createdAt_idx" ON "ChatMessage"("channelId", "createdAt" DESC);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "ChatMessage_authorId_idx" ON "ChatMessage"("authorId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "ChatMessage_replyToId_idx" ON "ChatMessage"("replyToId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Watch_caseId_idx" ON "Watch"("caseId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "AuditLog_targetType_targetId_at_idx" ON "AuditLog"("targetType", "targetId", "at" DESC);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "AuditLog_actorId_at_idx" ON "AuditLog"("actorId", "at" DESC);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "AuditLog_action_at_idx" ON "AuditLog"("action", "at" DESC);
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "UserRole" ADD CONSTRAINT "UserRole_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "Case" ADD CONSTRAINT "Case_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "CaseTemplate"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseSection" ADD CONSTRAINT "CaseSection_caseId_fkey" FOREIGN KEY ("caseId") REFERENCES "Case"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseSectionVersion" ADD CONSTRAINT "CaseSectionVersion_sectionId_fkey" FOREIGN KEY ("sectionId") REFERENCES "CaseSection"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseEntry" ADD CONSTRAINT "CaseEntry_caseId_fkey" FOREIGN KEY ("caseId") REFERENCES "Case"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseEntry" ADD CONSTRAINT "CaseEntry_correctsId_fkey" FOREIGN KEY ("correctsId") REFERENCES "CaseEntry"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseEntryVersion" ADD CONSTRAINT "CaseEntryVersion_entryId_fkey" FOREIGN KEY ("entryId") REFERENCES "CaseEntry"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseParticipant" ADD CONSTRAINT "CaseParticipant_caseId_fkey" FOREIGN KEY ("caseId") REFERENCES "Case"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseParticipant" ADD CONSTRAINT "CaseParticipant_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseParticipant" ADD CONSTRAINT "CaseParticipant_personnelFileId_fkey" FOREIGN KEY ("personnelFileId") REFERENCES "PersonnelFile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseExclusion" ADD CONSTRAINT "CaseExclusion_caseId_fkey" FOREIGN KEY ("caseId") REFERENCES "Case"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseExclusion" ADD CONSTRAINT "CaseExclusion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseLink" ADD CONSTRAINT "CaseLink_fromId_fkey" FOREIGN KEY ("fromId") REFERENCES "Case"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CaseLink" ADD CONSTRAINT "CaseLink_toId_fkey" FOREIGN KEY ("toId") REFERENCES "Case"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "PersonnelFile" ADD CONSTRAINT "PersonnelFile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_entryId_fkey" FOREIGN KEY ("entryId") REFERENCES "CaseEntry"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_caseId_fkey" FOREIGN KEY ("caseId") REFERENCES "Case"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ChatMessage" ADD CONSTRAINT "ChatMessage_caseId_fkey" FOREIGN KEY ("caseId") REFERENCES "Case"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ChatMessage" ADD CONSTRAINT "ChatMessage_channelId_fkey" FOREIGN KEY ("channelId") REFERENCES "Channel"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ChatMessage" ADD CONSTRAINT "ChatMessage_replyToId_fkey" FOREIGN KEY ("replyToId") REFERENCES "ChatMessage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ChatReaction" ADD CONSTRAINT "ChatReaction_messageId_fkey" FOREIGN KEY ("messageId") REFERENCES "ChatMessage"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ReadMarker" ADD CONSTRAINT "ReadMarker_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "Watch" ADD CONSTRAINT "Watch_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "Watch" ADD CONSTRAINT "Watch_caseId_fkey" FOREIGN KEY ("caseId") REFERENCES "Case"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|