Datenmodell fuer Spieler, Guthaben-Ledger und CCs
Guthaben werden als Kontobuch gefuehrt: jede Bewegung ist eine Zeile, der Stand eines Topfes ist deren Summe. Zusammengehoerige Zeilen teilen sich eine groupId, damit ein CC-Paket als Ganzes storniert werden kann; ein unique Constraint auf reversalOfId verhindert doppelte Stornos. CCs bilden ueber lineageId und predecessorId eine Redesign-Kette. Der Grund einer Deaktivierung entscheidet spaeter ueber die Reaktivierungskosten.
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
-- CreateSchema
|
||||
CREATE SCHEMA IF NOT EXISTS "public";
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "Role" AS ENUM ('ADMIN', 'EDITOR', 'VIEWER');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CreditKind" AS ENUM ('CC', 'REDESIGN_PAID', 'REDESIGN_KULANZ');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CreditSource" AS ENUM ('CC_PACKAGE', 'REDESIGN_PACKAGE', 'KULANZ', 'ADJUSTMENT', 'CONSUME', 'REVERSAL');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CharacterStatus" AS ENUM ('ACTIVE', 'INACTIVE');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "InactiveReason" AS ENUM ('PLAYER_INACTIVITY', 'REWORKED', 'OTHER');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ProductTarget" AS ENUM ('CC_PACKAGE', 'REDESIGN_PACKAGE', 'IGNORE');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ImportStatus" AS ENUM ('PENDING', 'COMMITTED', 'DISCARDED');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"username" TEXT NOT NULL,
|
||||
"passwordHash" TEXT NOT NULL,
|
||||
"role" "Role" NOT NULL DEFAULT 'EDITOR',
|
||||
"totpSecret" TEXT,
|
||||
"totpEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"mustChangePassword" BOOLEAN NOT NULL DEFAULT false,
|
||||
"lastLoginAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Session" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tokenHash" TEXT NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"ip" TEXT,
|
||||
"userAgent" TEXT,
|
||||
|
||||
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Player" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"displayName" TEXT NOT NULL,
|
||||
"steamId" TEXT,
|
||||
"forumName" TEXT,
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Player_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "CreditLedger" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"playerId" INTEGER NOT NULL,
|
||||
"kind" "CreditKind" NOT NULL,
|
||||
"amount" INTEGER NOT NULL,
|
||||
"source" "CreditSource" NOT NULL,
|
||||
"groupId" TEXT NOT NULL,
|
||||
"characterId" INTEGER,
|
||||
"importId" INTEGER,
|
||||
"note" TEXT,
|
||||
"reversalOfId" INTEGER,
|
||||
"createdById" INTEGER,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "CreditLedger_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Character" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"playerId" INTEGER NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"loreText" TEXT,
|
||||
"status" "CharacterStatus" NOT NULL DEFAULT 'ACTIVE',
|
||||
"inactiveReason" "InactiveReason",
|
||||
"lineageId" TEXT NOT NULL,
|
||||
"predecessorId" INTEGER,
|
||||
"createdById" INTEGER,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Character_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Import" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"filename" TEXT NOT NULL,
|
||||
"status" "ImportStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"rowCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"bookedCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"mapping" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"committedAt" TIMESTAMP(3),
|
||||
"importedById" INTEGER,
|
||||
|
||||
CONSTRAINT "Import_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ImportRow" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"importId" INTEGER NOT NULL,
|
||||
"lineNo" INTEGER NOT NULL,
|
||||
"externalId" TEXT,
|
||||
"playerKey" TEXT,
|
||||
"playerName" TEXT,
|
||||
"productName" TEXT,
|
||||
"purchasedAt" TIMESTAMP(3),
|
||||
"target" "ProductTarget",
|
||||
"resolvedPlayerId" INTEGER,
|
||||
"plan" TEXT NOT NULL,
|
||||
"raw" JSONB NOT NULL,
|
||||
|
||||
CONSTRAINT "ImportRow_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ImportedOrder" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"externalId" TEXT NOT NULL,
|
||||
"importId" INTEGER NOT NULL,
|
||||
"playerId" INTEGER NOT NULL,
|
||||
"target" "ProductTarget" NOT NULL,
|
||||
"groupId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ImportedOrder_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ProductMapping" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"matchPattern" TEXT NOT NULL,
|
||||
"target" "ProductTarget" NOT NULL,
|
||||
"priority" INTEGER NOT NULL DEFAULT 100,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"note" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ProductMapping_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AuditLog" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"actorUserId" INTEGER,
|
||||
"actorName" TEXT,
|
||||
"action" TEXT NOT NULL,
|
||||
"targetType" TEXT NOT NULL,
|
||||
"targetId" TEXT,
|
||||
"details" JSONB,
|
||||
"ip" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Session_tokenHash_key" ON "Session"("tokenHash");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Session_userId_idx" ON "Session"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Session_expiresAt_idx" ON "Session"("expiresAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Player_steamId_key" ON "Player"("steamId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Player_displayName_idx" ON "Player"("displayName");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "CreditLedger_reversalOfId_key" ON "CreditLedger"("reversalOfId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CreditLedger_playerId_idx" ON "CreditLedger"("playerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CreditLedger_playerId_kind_idx" ON "CreditLedger"("playerId", "kind");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CreditLedger_groupId_idx" ON "CreditLedger"("groupId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CreditLedger_createdAt_idx" ON "CreditLedger"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Character_playerId_idx" ON "Character"("playerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Character_playerId_status_idx" ON "Character"("playerId", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Character_lineageId_idx" ON "Character"("lineageId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Import_status_idx" ON "Import"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ImportRow_importId_idx" ON "ImportRow"("importId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ImportedOrder_externalId_key" ON "ImportedOrder"("externalId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ImportedOrder_playerId_idx" ON "ImportedOrder"("playerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ProductMapping_priority_idx" ON "ProductMapping"("priority");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AuditLog_createdAt_idx" ON "AuditLog"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AuditLog_targetType_targetId_idx" ON "AuditLog"("targetType", "targetId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AuditLog_actorUserId_idx" ON "AuditLog"("actorUserId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CreditLedger" ADD CONSTRAINT "CreditLedger_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CreditLedger" ADD CONSTRAINT "CreditLedger_characterId_fkey" FOREIGN KEY ("characterId") REFERENCES "Character"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CreditLedger" ADD CONSTRAINT "CreditLedger_importId_fkey" FOREIGN KEY ("importId") REFERENCES "Import"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CreditLedger" ADD CONSTRAINT "CreditLedger_reversalOfId_fkey" FOREIGN KEY ("reversalOfId") REFERENCES "CreditLedger"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CreditLedger" ADD CONSTRAINT "CreditLedger_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Character" ADD CONSTRAINT "Character_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Character" ADD CONSTRAINT "Character_predecessorId_fkey" FOREIGN KEY ("predecessorId") REFERENCES "Character"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Character" ADD CONSTRAINT "Character_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Import" ADD CONSTRAINT "Import_importedById_fkey" FOREIGN KEY ("importedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ImportRow" ADD CONSTRAINT "ImportRow_importId_fkey" FOREIGN KEY ("importId") REFERENCES "Import"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ImportedOrder" ADD CONSTRAINT "ImportedOrder_importId_fkey" FOREIGN KEY ("importId") REFERENCES "Import"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ImportedOrder" ADD CONSTRAINT "ImportedOrder_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_actorUserId_fkey" FOREIGN KEY ("actorUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
Reference in New Issue
Block a user