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.
Eingaben werden mit zod validiert, jede aendernde Aktion schreibt ins
Audit-Log. Beim ersten Start entsteht ein Administrator samt Startwerten fuer
die Produkterkennung; solange ein Erstpasswort gilt, bleiben schreibende Wege
bis auf den Passwortwechsel gesperrt.
Nicht-API-Pfade fallen auf die SPA zurueck, damit Deep-Links funktionieren.
Die beiden zentralen Regeln stehen jeweils an genau einer Stelle:
Ein CC-Paket erzeugt immer CC +1 und REDESIGN_PAID +1. Die Zeilen dafuer baut
buildPackageRows, das sowohl die manuelle Eingabe als auch der Import nutzen -
so koennen beide Wege nicht auseinanderlaufen.
Ein CC kommt nur dann gratis zurueck, wenn er wegen Spieler-Inaktivitaet
entfernt wurde. Ein reworkter CC existiert im Original nicht mehr und kostet
deshalb ein Redesign- oder CC-Guthaben.
Ueberzogene Toepfe werden zugelassen statt blockiert; die Aktion meldet das
ueber ein overdrawn-Flag zurueck. Storniert wird per Gegenbuchung, nie durch
Loeschen. Der Import berechnet den Plan vorab und dedupliziert ueber die
Bestell-ID, sowohl gegen bereits gebuchte als auch innerhalb einer Datei.
Passwoerter mit Argon2id, im Cookie steht nur ein Token und in der Datenbank
dessen Hash. Das CSRF-Token wird per HMAC aus dem Sitzungstoken abgeleitet
statt separat gespeichert - ohne das httpOnly-Cookie ist es nicht herstellbar.
TOTP ist optional und wird erst nach einem bestaetigten Code scharf geschaltet,
damit sich niemand bei der Einrichtung aussperrt.
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.
Fastify mit Prisma im Server-Workspace, React mit Vite im Web-Workspace.
Das Frontend baut direkt nach server/public, damit am Ende ein einzelnes
Image API und Oberflaeche ausliefert.