Vier Punkte aus dem Betrieb.
Ein toter CC liess sich nicht zurueckholen. Der Knopf dafuer wurde nie
angezeigt: bei Grund "Im RP gestorben" landete die Seite im Zweig "Bezahlt
reaktivieren", den der Server zu Recht abweist - ein Toter kehrt nur durch
einen Administrator zurueck. Der Dialog dafuer war fertig gebaut und wurde
schlicht nie geoeffnet. Jetzt steht an einem toten CC "Zurueckholen", fuer
Editoren stattdessen der Hinweis, dass das ein Administrator entscheidet.
Der Abgleich eines einzelnen Spielers fragte nur dessen hinterlegte SteamID
ab. Guthaben, das unter einem frueheren Konto gekauft wurde, blieb damit
unsichtbar - obwohl das Konto hinterlegt war und der Sammellauf es beruecksichtigt
hat. Jetzt werden alle Kennungen des Spielers abgefragt.
Ein Beitritt zu einem Gruppen-CC ueber ein Redesign kostete nur das Guthaben.
Damit entstand aus einem Redesign ein zusaetzlicher CC, was die Regel gerade
nicht hergibt: ein Redesign ersetzt einen CC. Jetzt muss angegeben werden,
welcher eigene CC dafuer aufgegeben wird; ein aktiver wird dabei inaktiv
gesetzt, ein bereits inaktiver bleibt unveraendert. Ueber ein CC-Paket kommt
weiterhin ein Platz hinzu, ohne Vorgaenger. Welcher CC aufgegeben wurde, haengt
am Beitritt und bleibt nachvollziehbar.
Faelle, die sich beim Eintragen nicht klaeren lassen - ein Antrag ohne
auffindbares Paket, ein fehlender GExtension-Eintrag, widerspruechliche Angaben
- koennen als Spieler angelegt und dabei als Problem vorgemerkt werden, mit
Notiz. Auch nachtraeglich setzbar und wieder abraeumbar. Die Markierung ist
folgenlos: sie sperrt nichts und veraendert weder Guthaben noch CCs. Die
Uebersicht kennzeichnet betroffene Spieler und laesst sich darauf eingrenzen.
Nebenbei: die Spielerliste gab die Markierung nicht mit aus, aufgefallen beim
Test.
Threads ohne zuordenbaren Spieler wurden bisher verworfen. Von 502 Antraegen
im Forum kamen dadurch nur die wenigen an, deren Ersteller schon als Spieler
mit Forum-Namen erfasst war - der Rest war schlicht unsichtbar. Sie werden
jetzt erfasst und stehen unter "Ohne zugeordneten Spieler", durchsuchbar nach
Titel und Ersteller, aber ausserhalb der Arbeitsliste: ohne Spieler laesst
sich nichts buchen.
Wird spaeter ein Spieler mit passendem Forum-Namen angelegt, der Name
nachgetragen oder ein frueheres Konto ergaenzt, wandern seine wartenden
Antraege von selbst hinueber. Ein erneuter Abgleich ist dafuer nicht noetig,
und eine bereits getroffene Zuordnung bleibt unberuehrt.
Der Name eines CCs fuehrt auf der Spielerseite jetzt zum Forumsbeitrag, sofern
einer verknuepft ist.
Weitere Korrekturen am Abgleich:
- Wer sein Forumskonto geloescht hat, stand ohne Profil-Link in der Zeile und
hatte damit keinen Autor. Solche Antraege liessen sich niemandem zuordnen.
- Bei einer abgewiesenen Anfrage brach das ganze Board ab; die bis dahin
gelesenen Seiten gingen mit verloren. Jetzt wird die genannte Wartezeit
eingehalten, das Tempo fuer den Rest des Laufs gedrosselt und die Seite
erneut versucht. Was gelesen wurde, bleibt in jedem Fall erhalten.
- Derselbe Schutz im GExtension-Abgleich, der sonst den Spieler uebersprungen
haette.
- Der Board-Filter fragte nach einem Feld "board", das es nicht gibt.
Ein voller Lauf dauert rund eine halbe Minute und laenger, wenn das Forum
bremst. Er laeuft deshalb im Hintergrund weiter und meldet seinen Fortschritt,
statt an einer HTTP-Zeitgrenze zu sterben. Gelesen und geschrieben wird
gebuendelt statt Thread fuer Thread.
Bisher entschied allein das Redesign darueber, ob eine Rueckkehr etwas kostet.
Es fehlten zwei Faelle: ein Entzug ohne Anspruch auf kostenlose Rueckkehr, und
der Tod im Rollenspiel. Ein toter CC laesst sich weder gratis noch gegen
Guthaben auf dem normalen Weg zurueckholen - das entscheidet ein Administrator
ueber einen eigenen Weg, mit Pflicht-Begruendung, und waehlt dabei, ob ein
Guthaben fliesst. Schon das Eintragen des Todes verlangt eine Notiz.
Dazu koennen sich mehrere Spieler einen CC teilen. Die Zugehoerigkeit laeuft
ab jetzt durchgehend ueber eine eigene Tabelle, auch bei Einzel-CCs; die
Migration traegt bestehende CCs als erstes Mitglied ihres Erstellers nach.
Ohne das waere nach dem Update kein CC mehr beim Spieler aufgetaucht.
Fuer jeden Mitnutzer gelten dieselben Regeln wie fuer einen eigenen CC: der
Platz kostet ein eigenes Guthaben, wahlweise aus dem CC-Paket oder ueber ein
Redesign. Ein Austritt gibt nichts zurueck, denn bis dahin wurde der CC
genutzt; fuer eine Fehleingabe ist das Storno der richtige Weg. Der letzte
Nutzer laesst sich nicht austragen - dann wird der CC deaktiviert. Ein
Redesign nimmt die Gruppe mit.
Der Forums-Abgleich las von 25 Archivseiten nur zwei. WoltLab verlinkt in der
Blätterleiste nur die Nachbarseiten und führt die Gesamtzahl in einem eigenen
Element; ausgewertet wurden aber die Links. Alles jenseits von Seite zwei war
damit unsichtbar - etwa ein Antrag auf Seite vier, der deshalb nie ankam.
Die Rollen verlaufen jetzt zwischen erfassen und gewähren statt zwischen
Alltag und Verwaltung: Editoren erfassen Käufe und führen Datei-Import,
GExtension- und Forums-Abgleich samt Entscheidung über Anträge durch. Kulanz
zu vergeben bleibt Administratoren, ebenso das Auflösen unklarer Pakete, weil
dabei Kulanz entstehen kann.
Dazu lassen sich frühere Steam- und Forumskonten am Spieler hinterlegen.
Abgleich und Import prüfen sie mit, sodass ein Kontowechsel die Zuordnung
nicht abreißen lässt. Steam-Kennungen werden dabei auf dieselbe Form gebracht
wie die Hauptangabe, und eine Kennung kann nicht zwei Spielern gehören.
harle.png steht jetzt gross auf der Anmeldeseite und klein in der Fusszeile,
dazu die Zeile "Created by Harlekin | CC-Head".
Aus der Vorlage entstehen drei Groessen: das volle Bild fuer die Anzeige und
ein Ausschnitt des Kopfes fuer Favicon und Startsymbol - ganzfigurig waere die
Figur bei 32 Pixeln nicht mehr zu erkennen.
Dabei fiel auf, dass die Cache-Regel zu grob war: sie gab allem ausser HTML
ein Jahr immutable, also auch Bildern. Deren Name aendert sich beim Austausch
aber nicht, ein neues Bild waere ein Jahr lang nicht angekommen. Jetzt gilt
das lange Ablaufdatum nur fuer die gebauten Assets, die einen Inhalts-Hash im
Namen tragen; alles andere haelt einen Tag und fragt dann nach.
Sechs Ruecklaeufer aus dem ersten Praxistest:
Das Archiv reicht ueber 25 Seiten und enthaelt vieles, was kein CC-Antrag ist.
Aufgenommen werden jetzt nur Threads von Spielern, die im CC-Manager mit
passendem Forum-Namen erfasst sind. Angepinnte Ankuendigungen tragen die
Labels "Wichtig" oder "Information" und fallen darueber raus.
Der Titel wird bewusst nirgends ausgewertet - weder zum Erkennen noch zum
Aussortieren. Antraege heissen mal "CC Antrag | Name", mal "The Duke Rang
Update"; daran ist nichts abzulesen.
Eine Reaktivierung laeuft ebenfalls ueber einen Forums-Antrag und fehlte als
Entscheidung. Sie ist jetzt waehlbar und kostet nichts, solange der CC nicht
redesignt wurde - die bestehende Regel entscheidet das, nicht der Dialog.
Der Titel in der Liste verlinkt jetzt auf den Thread im Forum. Die Labels
stehen als Kontext daneben, ohne die Entscheidung vorwegzunehmen.
Wer einen Antrag von Hand eintraegt, kann beim Anlegen oder Redesignen den
Thread-Link angeben. Der Antrag gilt damit als erledigt und taucht nicht
erneut als offen auf.
Manuelle Guthaben-Buchungen fragen vorher nach: bisher buchte ein einzelner
Klick sofort, ohne zu sagen, was genau passiert. Der Dialog nennt die Wirkung
und nimmt eine Notiz entgegen.
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.
Der GExtension-Abgleich liefert die Käufe, der Verbrauch steht im Forum. Die
App liest jetzt die drei CC-Boards und sammelt die Anträge.
Gelesen wird nur die Board-Übersicht: sie führt bereits den Ersteller, nicht
nur den letzten Antwortenden. Damit bleibt ein Lauf bei wenigen Anfragen statt
einer je Thread. Unterforen und globale Kästen tragen ebenfalls Thread-Links,
deshalb liest der Parser strikt entlang der Listeneinträge - sonst landen
Changelogs und Bewerbungen in der Antragsliste.
Klassifiziert wird ausschließlich von Hand. Weder Titel noch Board sind
verlässlich genug: Threads werden nicht immer verschoben, ein genehmigter
Antrag kann weiter im Antrags-Board liegen. Das Board steht deshalb nur als
Hinweis an der Zeile.
Angenommene Anträge rufen dieselben Aktionen wie die Knöpfe auf der
Spielerseite, es gibt keinen zweiten Buchungsweg mit eigenen Regeln. Wandert
ein bereits entschiedener Thread später in ein anderes Board, erscheint das
als Hinweis zum Abhaken - der CC-Status ändert sich nie von allein.
Die Thread-ID bleibt beim Verschieben stabil und traegt deshalb die
Wiedererkennung; die Board-Historie wird mitgeschrieben. Zurückgelassene
Verweise erkennt der Parser und zählt sie nicht als eigenen Antrag.
Der Abgleich bucht bewusst nichts, sondern legt eine Vorschau zur Bestaetigung
an. Nur fuehrte von dort kein Weg weiter: die Import-Seite zeigte allein den
Datei-Upload, und die Rueckmeldung sagte lediglich "abgeglichen". Die
gefundenen Pakete lagen damit unsichtbar herum und der Knopf wirkte, als tue
er nichts.
Die Import-Seite listet jetzt alle Importe, die noch auf Bestaetigung warten,
und oeffnet sie in derselben Vorschau wie einen frischen Upload. Die Meldung
nach dem Abgleich nennt die Zahl der Funde und den naechsten Schritt.
Ausserdem beruecksichtigt der Abgleich jetzt offene Vorschauen: bisher pruefte
er nur gegen bereits gebuchte Pakete. Ein zweiter Lauf legte dieselben Zeilen
deshalb ein weiteres Mal an, und beim Buchen kollidierten beide Importe an der
eindeutigen Bestell-ID - der zweite schlug komplett fehl.
Oberflaeche, Fehlermeldungen und Kommentare schrieben durchgehend ae, oe, ue
und ss. Dafuer gab es keinen Grund - die Anwendung ist deutschsprachig und
laeuft durchgehend in UTF-8.
Betroffen waren 55 Dateien, darunter alle sichtbaren Texte: Guthaben-Zaehler,
Import, Nutzerverwaltung, Passwortwechsel und die Zwei-Faktor-Einrichtung.
Der Name einer Migration bleibt im README-Beispiel bewusst bei ASCII, weil
daraus ein Verzeichnisname wird.
Die maxAge-Option von fastify-static setzt den Cache-Header fuer jede Datei,
auch fuer die index.html. Der setHeaders-Callback, der das fuer HTML wieder
aufheben sollte, kam dagegen nicht an: ausgeliefert wurde durchgehend
public, max-age=31536000.
Damit bekam ein Browser nach einem Update weiter die alte Oberflaeche - ein
Jahr lang, ohne Fehlermeldung, obwohl der Server laengst neue Dateien hatte.
Genau so ist der Abgleich-Knopf nach dem Deploy unsichtbar geblieben.
Jetzt setzt die App beide Faelle selbst: HTML immer neu holen, Assets
unbegrenzt behalten. Deren Dateinamen enthalten einen Inhalts-Hash, sie
aendern sich bei neuem Inhalt ohnehin.
Drei Tests pruefen die Header, weil ein Fehler an dieser Stelle nirgends
auffaellt - er sieht aus, als waere das Update nicht angekommen.
Die Profilseiten sind ohne Login abrufbar und betten die Kaeufe als JSON ins
HTML ein. Gelesen wird dieses JSON statt der gerenderten Tabelle: das ist
unempfindlich gegen Layout-Aenderungen und liefert zusaetzlich Kaufdatum,
Betrag und den Storno-Status. Ein Headless-Browser ist nicht noetig.
Der Abgleich bucht nichts von sich aus. Eindeutige Treffer landen als
regulaerer Import in der bestehenden Vorschau, die per package_bought_id
dedupliziert. Titel, die nach CC klingen, sich aber keiner Guthaben-Art
sicher zuordnen lassen, gehen in eine Handpruefung statt geraten zu werden -
sichtbar als Hinweis auf der Uebersicht und als Box beim Spieler.
Beachtet werden dabei: stornierte Kaeufe werden uebersprungen, der Web-
Bereich enthaelt nie CC-Pakete, und ein Redesign-Titel zaehlt als Redesign,
auch wenn Custom Character darin vorkommt. Letzteres war auch in den
Standard-Mappings des Datei-Imports falsch herum einsortiert.
Der Lauf geht bewusst nur ueber bereits erfasste Spieler und haelt eine
Sekunde Abstand zwischen den Anfragen, da die Seite fremde Infrastruktur ist.
Voraussetzung dafuer ist, dass SteamIDs auf eine Schreibweise gebracht
werden: die Legacy-Form, die Steam3-Form und die 64-Bit-Zahl bezeichnen
dieselbe Person, wurden bisher aber als verschiedene Spieler gefuehrt.
Gespeichert wird jetzt immer die 64-Bit-Form, Eingabe und Suche akzeptieren
alle drei.
Drei Befunde aus einer Durchsicht der gespeicherten personenbezogenen Daten:
Der Import legte bisher jede Spalte der hochgeladenen Datei dauerhaft ab,
auch Mailadressen oder Rechnungsdaten, die nie zugeordnet wurden. Nach dem
Buchen oder Verwerfen bleiben jetzt nur noch die gemappten Spalten stehen.
Ein fehlgeschlagener Login protokollierte den eingetippten Benutzernamen.
Wer sein Passwort ins Namensfeld tippt, hatte es damit im Klartext im
Audit-Log. Der Name wird nur noch gespeichert, wenn das Konto existiert.
Das Loeschen eines Spielers liess Spuren in den Import-Zeilen und in den
Details frueherer Audit-Eintraege zurueck. Beides wird jetzt mit abgeraeumt;
die Vorgaenge bleiben als Eintrag bestehen, nur ohne Inhalt.
Dazu eine Aufbewahrungsfrist fuer das Audit-Log (Standard 12 Monate, ueber
AUDIT_RETENTION_DAYS einstellbar). Die Guthaben-Historie ist davon nicht
betroffen - sie bleibt die Quelle der Wahrheit fuer bezahlte Ansprueche.
Ein CC, der nicht redesignt wurde, existiert unveraendert weiter und kommt
deshalb immer gratis zurueck - egal ob der Spieler inaktiv war oder die
Einheit voruebergehend aus dem Spiel genommen wurde. Bisher kostete der Fall
OTHER ein Guthaben, was die Regel unnoetig verkompliziert hat.
Damit der zweite Fall brauchbar wird, haelt inactiveNote den Grund im Klartext
fest ("Einheit bis Maerz entfernt"); die Notiz steht an der CC-Karte und wird
beim Reaktivieren wieder geleert.
Die Tests starten Postgres per PGlite und sprechen es ueber einen lokalen Port
an, laufen also ohne Docker und ohne installierte Datenbank.
Abgedeckt sind die Guthaben-Regeln, der CC-Lebenszyklus samt Reaktivierung,
Stornos und Ruecknahmen, Anmeldung mit CSRF- und Rollenpruefung sowie der
Import mit Dedup.