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;
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "debian-openssl-3.0.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum Role {
|
||||
ADMIN
|
||||
EDITOR
|
||||
VIEWER
|
||||
}
|
||||
|
||||
enum CreditKind {
|
||||
CC
|
||||
REDESIGN_PAID
|
||||
REDESIGN_KULANZ
|
||||
}
|
||||
|
||||
enum CreditSource {
|
||||
CC_PACKAGE
|
||||
REDESIGN_PACKAGE
|
||||
KULANZ
|
||||
ADJUSTMENT
|
||||
CONSUME
|
||||
REVERSAL
|
||||
}
|
||||
|
||||
enum CharacterStatus {
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
}
|
||||
|
||||
enum InactiveReason {
|
||||
PLAYER_INACTIVITY
|
||||
REWORKED
|
||||
OTHER
|
||||
}
|
||||
|
||||
enum ProductTarget {
|
||||
CC_PACKAGE
|
||||
REDESIGN_PACKAGE
|
||||
IGNORE
|
||||
}
|
||||
|
||||
enum ImportStatus {
|
||||
PENDING
|
||||
COMMITTED
|
||||
DISCARDED
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique
|
||||
passwordHash String
|
||||
role Role @default(EDITOR)
|
||||
totpSecret String?
|
||||
totpEnabled Boolean @default(false)
|
||||
isActive Boolean @default(true)
|
||||
mustChangePassword Boolean @default(false)
|
||||
lastLoginAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
sessions Session[]
|
||||
auditEntries AuditLog[]
|
||||
ledgerEntries CreditLedger[] @relation("LedgerCreatedBy")
|
||||
charactersCreated Character[] @relation("CharacterCreatedBy")
|
||||
imports Import[]
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(uuid())
|
||||
tokenHash String @unique
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
expiresAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
lastSeenAt DateTime @default(now())
|
||||
ip String?
|
||||
userAgent String?
|
||||
|
||||
@@index([userId])
|
||||
@@index([expiresAt])
|
||||
}
|
||||
|
||||
model Player {
|
||||
id Int @id @default(autoincrement())
|
||||
displayName String
|
||||
steamId String? @unique
|
||||
forumName String?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
ledger CreditLedger[]
|
||||
characters Character[]
|
||||
orders ImportedOrder[]
|
||||
|
||||
@@index([displayName])
|
||||
}
|
||||
|
||||
/// Kontobuch: jede Guthaben-Bewegung ist eine Zeile (+1 Zugang, -1 Verbrauch).
|
||||
/// Der offene Stand eines Topfes ist die Summe der amounts je kind.
|
||||
model CreditLedger {
|
||||
id Int @id @default(autoincrement())
|
||||
player Player @relation(fields: [playerId], references: [id], onDelete: Cascade)
|
||||
|
||||
playerId Int
|
||||
kind CreditKind
|
||||
amount Int
|
||||
source CreditSource
|
||||
|
||||
/// Klammert zusammengehoerige Zeilen: ein CC-Paket schreibt zwei Zeilen
|
||||
/// mit derselben groupId, damit ein Storno beide zurueckholt.
|
||||
groupId String @default(uuid())
|
||||
|
||||
characterId Int?
|
||||
character Character? @relation(fields: [characterId], references: [id], onDelete: SetNull)
|
||||
|
||||
importId Int?
|
||||
import Import? @relation(fields: [importId], references: [id], onDelete: SetNull)
|
||||
|
||||
note String?
|
||||
|
||||
/// Storno erfolgt als Gegenbuchung, nicht als Loeschung. Das @unique
|
||||
/// verhindert, dass eine Zeile zweimal storniert wird.
|
||||
reversalOfId Int? @unique
|
||||
reversalOf CreditLedger? @relation("LedgerReversal", fields: [reversalOfId], references: [id], onDelete: NoAction, onUpdate: NoAction)
|
||||
reversedBy CreditLedger? @relation("LedgerReversal")
|
||||
|
||||
createdById Int?
|
||||
createdBy User? @relation("LedgerCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([playerId])
|
||||
@@index([playerId, kind])
|
||||
@@index([groupId])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
model Character {
|
||||
id Int @id @default(autoincrement())
|
||||
playerId Int
|
||||
player Player @relation(fields: [playerId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
loreText String?
|
||||
status CharacterStatus @default(ACTIVE)
|
||||
inactiveReason InactiveReason?
|
||||
|
||||
/// Alle CCs einer Redesign-Kette teilen sich die lineageId.
|
||||
lineageId String @default(uuid())
|
||||
predecessorId Int?
|
||||
predecessor Character? @relation("CharacterLineage", fields: [predecessorId], references: [id], onDelete: NoAction, onUpdate: NoAction)
|
||||
successors Character[] @relation("CharacterLineage")
|
||||
|
||||
ledgerEntries CreditLedger[]
|
||||
|
||||
createdById Int?
|
||||
createdBy User? @relation("CharacterCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([playerId])
|
||||
@@index([playerId, status])
|
||||
@@index([lineageId])
|
||||
}
|
||||
|
||||
model Import {
|
||||
id Int @id @default(autoincrement())
|
||||
filename String
|
||||
status ImportStatus @default(PENDING)
|
||||
rowCount Int @default(0)
|
||||
bookedCount Int @default(0)
|
||||
mapping Json?
|
||||
createdAt DateTime @default(now())
|
||||
committedAt DateTime?
|
||||
|
||||
importedById Int?
|
||||
importedBy User? @relation(fields: [importedById], references: [id], onDelete: SetNull)
|
||||
|
||||
rows ImportRow[]
|
||||
orders ImportedOrder[]
|
||||
ledgerEntries CreditLedger[]
|
||||
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model ImportRow {
|
||||
id Int @id @default(autoincrement())
|
||||
importId Int
|
||||
import Import @relation(fields: [importId], references: [id], onDelete: Cascade)
|
||||
|
||||
lineNo Int
|
||||
externalId String?
|
||||
playerKey String?
|
||||
playerName String?
|
||||
productName String?
|
||||
purchasedAt DateTime?
|
||||
|
||||
target ProductTarget?
|
||||
resolvedPlayerId Int?
|
||||
|
||||
/// Was beim Buchen passieren wuerde: BOOK, CREATE_PLAYER_AND_BOOK,
|
||||
/// SKIP_DUPLICATE, SKIP_IGNORED, SKIP_UNMAPPED, SKIP_NO_PLAYER
|
||||
plan String
|
||||
raw Json
|
||||
|
||||
@@index([importId])
|
||||
}
|
||||
|
||||
/// Dedup-Anker: eine bereits gebuchte Bestell-ID wird nie ein zweites Mal gebucht.
|
||||
model ImportedOrder {
|
||||
id Int @id @default(autoincrement())
|
||||
externalId String @unique
|
||||
importId Int
|
||||
import Import @relation(fields: [importId], references: [id], onDelete: Cascade)
|
||||
playerId Int
|
||||
player Player @relation(fields: [playerId], references: [id], onDelete: Cascade)
|
||||
target ProductTarget
|
||||
groupId String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([playerId])
|
||||
}
|
||||
|
||||
model ProductMapping {
|
||||
id Int @id @default(autoincrement())
|
||||
matchPattern String
|
||||
target ProductTarget
|
||||
priority Int @default(100)
|
||||
isActive Boolean @default(true)
|
||||
note String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([priority])
|
||||
}
|
||||
|
||||
model AuditLog {
|
||||
id Int @id @default(autoincrement())
|
||||
actorUserId Int?
|
||||
actor User? @relation(fields: [actorUserId], references: [id], onDelete: SetNull)
|
||||
/// Name wird mitgeschrieben, damit der Eintrag lesbar bleibt, wenn der Account weg ist.
|
||||
actorName String?
|
||||
action String
|
||||
targetType String
|
||||
targetId String?
|
||||
details Json?
|
||||
ip String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([createdAt])
|
||||
@@index([targetType, targetId])
|
||||
@@index([actorUserId])
|
||||
}
|
||||
Reference in New Issue
Block a user