Schema-Aenderungen als eigene Migration nachziehen

Die erste Migration wurde nachtraeglich mehrfach erweitert, statt Aenderungen
anzuhaengen. Auf einer bestehenden Installation gilt sie als angewendet und
wird uebersprungen - die seither hinzugekommenen Tabellen fehlten dort also
schlicht, ohne dass beim Start etwas auffiel. Die Antragsseite lief dadurch
in einen internen Fehler.

Die neue Migration ergaenzt alles Fehlende und ist durchgehend mit
IF NOT EXISTS geschrieben, weil bestehende Datenbanken je nach Zeitpunkt der
Einrichtung unterschiedliche Staende haben. Geprueft gegen eine frische
Datenbank, gegen eine auf altem Stand und auf mehrfaches Anwenden.

Der Testharness wendet jetzt alle Migrationen der Reihe nach an statt nur der
ersten - sonst faellt so etwas beim naechsten Mal wieder nicht auf.

Ausserdem scheiterte das Buchen komplett, wenn eine Bestellung zwischenzeitlich
ueber einen anderen Import gebucht worden war: die eindeutige Bestell-ID kippte
die gesamte Transaktion. Solche Zeilen werden jetzt uebersprungen und gezaehlt,
die uebrigen laufen durch.

Dazu fehlten in der Oberflaeche die Wege zum Bearbeiten und Loeschen eines
Spielers, obwohl es die Endpunkte gab. Beides ist jetzt auf der Spielerseite
erreichbar; das Loeschen verlangt den Namen als Bestaetigung und benennt
vorher, was mit verschwindet.
This commit is contained in:
2026-09-18 17:43:25 +02:00
parent 664a0fd5ee
commit 751f8bfe8e
6 changed files with 374 additions and 11 deletions
@@ -0,0 +1,103 @@
-- Ergaenzt alles, was nach der ersten Fassung dazugekommen ist.
--
-- Diese Migration ist bewusst durchgehend mit IF NOT EXISTS geschrieben: die
-- erste Migration wurde zwischenzeitlich nachtraeglich erweitert, weshalb
-- bestehende Installationen je nach Zeitpunkt der Einrichtung einen anderen
-- Stand haben. So laeuft sie auf einer frischen wie auf einer aelteren
-- Datenbank durch und legt nur an, was tatsaechlich fehlt.
-- --- Enums ---
DO $$ BEGIN
CREATE TYPE "ForumBoard" AS ENUM ('CUSTOM_CHARACTERS', 'AKTIVE_CCS', 'CC_ARCHIV');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE "ForumClassification" AS ENUM ('NEW_CC', 'REDESIGN', 'REJECTED', 'IGNORE');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
-- --- Klartext-Grund einer Deaktivierung ---
ALTER TABLE "Character" ADD COLUMN IF NOT EXISTS "inactiveNote" TEXT;
-- --- GExtension-Abgleich ---
ALTER TABLE "Player" ADD COLUMN IF NOT EXISTS "gextensionUsage" INTEGER;
ALTER TABLE "Player" ADD COLUMN IF NOT EXISTS "gextensionSyncedAt" TIMESTAMP(3);
CREATE TABLE IF NOT EXISTS "UnmatchedPackage" (
"id" SERIAL NOT NULL,
"externalId" TEXT NOT NULL,
"playerId" INTEGER,
"steamId" TEXT NOT NULL,
"rawTitle" TEXT NOT NULL,
"rawTag" TEXT NOT NULL,
"amount" TEXT,
"purchasedAt" TIMESTAMP(3),
"scrapedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"resolved" BOOLEAN NOT NULL DEFAULT false,
"resolvedAs" TEXT,
"resolvedById" INTEGER,
"resolvedAt" TIMESTAMP(3),
CONSTRAINT "UnmatchedPackage_pkey" PRIMARY KEY ("id")
);
CREATE UNIQUE INDEX IF NOT EXISTS "UnmatchedPackage_externalId_key" ON "UnmatchedPackage"("externalId");
CREATE INDEX IF NOT EXISTS "UnmatchedPackage_resolved_idx" ON "UnmatchedPackage"("resolved");
CREATE INDEX IF NOT EXISTS "UnmatchedPackage_playerId_idx" ON "UnmatchedPackage"("playerId");
DO $$ BEGIN
ALTER TABLE "UnmatchedPackage" ADD CONSTRAINT "UnmatchedPackage_playerId_fkey"
FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE CASCADE ON UPDATE CASCADE;
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
-- --- Forums-Antraege ---
CREATE TABLE IF NOT EXISTS "ForumThread" (
"threadId" INTEGER NOT NULL,
"title" TEXT NOT NULL,
"url" TEXT NOT NULL,
"authorName" TEXT,
"authorForumId" INTEGER,
"playerId" INTEGER,
"currentBoard" "ForumBoard" NOT NULL,
"firstSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"lastBoardChangeAt" TIMESTAMP(3),
"classification" "ForumClassification",
"needsClassification" BOOLEAN NOT NULL DEFAULT true,
"classifiedById" INTEGER,
"classifiedAt" TIMESTAMP(3),
"linkedCharacterId" INTEGER,
"boardChangeNotice" BOOLEAN NOT NULL DEFAULT false,
CONSTRAINT "ForumThread_pkey" PRIMARY KEY ("threadId")
);
CREATE INDEX IF NOT EXISTS "ForumThread_needsClassification_idx" ON "ForumThread"("needsClassification");
CREATE INDEX IF NOT EXISTS "ForumThread_playerId_idx" ON "ForumThread"("playerId");
CREATE INDEX IF NOT EXISTS "ForumThread_currentBoard_idx" ON "ForumThread"("currentBoard");
DO $$ BEGIN
ALTER TABLE "ForumThread" ADD CONSTRAINT "ForumThread_playerId_fkey"
FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE SET NULL ON UPDATE CASCADE;
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
ALTER TABLE "ForumThread" ADD CONSTRAINT "ForumThread_linkedCharacterId_fkey"
FOREIGN KEY ("linkedCharacterId") REFERENCES "Character"("id") ON DELETE SET NULL ON UPDATE CASCADE;
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
CREATE TABLE IF NOT EXISTS "ForumThreadBoard" (
"id" SERIAL NOT NULL,
"threadId" INTEGER NOT NULL,
"board" "ForumBoard" NOT NULL,
"observedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "ForumThreadBoard_pkey" PRIMARY KEY ("id")
);
CREATE INDEX IF NOT EXISTS "ForumThreadBoard_threadId_idx" ON "ForumThreadBoard"("threadId");
DO $$ BEGIN
ALTER TABLE "ForumThreadBoard" ADD CONSTRAINT "ForumThreadBoard_threadId_fkey"
FOREIGN KEY ("threadId") REFERENCES "ForumThread"("threadId") ON DELETE CASCADE ON UPDATE CASCADE;
EXCEPTION WHEN duplicate_object THEN NULL; END $$;