Files
bricktrack/docs/DEVLOG.md
T
unknownandClaude Opus 5 e52557b4bf docs: anleitung, changelog 0.3.0 und roadmap zu phase 3
Vier neue Kapitel in der Anleitung (mehrere Sammler, Preise,
Erinnerungen, Dubletten) mit vier automatisch erzeugten Bildern,
Changelog 0.3.0 samt der bewusst weggelassenen BrickLink-Anbindung,
Roadmap abgehakt und um einen offenen Ausblick ergaenzt, Devlog mit
Zeiten und Stolpersteinen.

Dazu zwei Korrekturen aus dem Testlauf:

Der Zeitplan fuer Erinnerungen liess sich nicht aus Next'
instrumentation.ts starten - die Datei wird auch fuer die Edge-Runtime
uebersetzt, und das native SQLite-Modul bricht dort den Build. Er
startet jetzt aus dem Healthcheck heraus, den der Container ohnehin alle
30 Sekunden aufruft, und zusaetzlich aus dem App-Layout; der Aufruf ist
idempotent.

Der Screenshot-Lauf waehlte ploetzlich die falschen Kacheln aus: Der
neue Sammler-Umschalter benutzt ebenfalls aria-pressed. Die
Auswahlkacheln tragen jetzt ein eigenes data-set-card.

Ausserdem raeumen die Testskripte einen Container weg, den ein
abgebrochener Lauf zurueckgelassen hat - sonst blockiert er den Port.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 10:11:40 +02:00

10 KiB
Raw Blame History

Devlog

Zeiterfassung und Nachvollziehbarkeit der Entwicklung. Eine Zeile je abgeschlossenem Arbeitsschritt, Zeiten in HH:mm (Europe/Berlin). Die Commit-Spalte verweist auf den Stand am Ende des Schritts.

Phase 1 – MVP (v0.1.0)

06.09.2026

Von Bis Dauer Schritt Ergebnis Commit
22:06 22:12 0:06 Planung Phase-1-Plan und Drizzle-Schema zur Freigabe vorgelegt; fünf Entscheidungsfragen geklärt (Cent statt Float, Migrator statt drizzle-kit im Image, Bilder öffentlich / PDFs geschützt, Token gehasht, Branch pro Phase) –
22:12 22:20 0:08 Scaffold pnpm installiert, Next 15.5.25 + Tailwind 4 + shadcn/ui (radix-nova) mit 20 Komponenten, Touch-Größen auf 44 px angehoben 0de49a9
22:20 22:25 0:05 Datenmodell 19 Tabellen in Drizzle, CHECK-Constraints, Unique-Index (wishlist_id, set_id), Migration erzeugt und angewendet, WAL verifiziert 06268bc
22:25 22:26 0:01 Dokumentation CLAUDE.md, Roadmap, Changelog, Devlog b74cecb
22:26 22:40 0:14 Auth und App-Shell better-auth mit Passwort und Passkeys, erster Nutzer wird Admin, Rate-Limit in der Datenbank, Konto-Seite, Bottom-Navigation, /api/health 4c78c56
22:40 22:46 0:06 Stammdaten CRUD für Hersteller, Themen und Standorte über eine gemeinsame CrudSection; zod-Schemata, ActionResult, Slug, Geld- und Datumshelfer af0ae03
22:46 22:59 0:13 Katalog Kachelliste mit Suche und vier Filtern, Besitzlogik in ownership.ts, Set-Formular, Detailseite, Upload-Pipeline mit Magic-Byte-Prüfung, pdf.js-Viewer, Seed-Skript 856800b
22:59 23:06 0:07 Wunschlisten und Sammlung Mehrfachauswahl mit Dubletten-Skip, Wunschlisten-Verwaltung, Teilen, Überraschungsmodus, öffentliche Ansicht mit Reservierung und Storno, Sammlungsübersicht mit Statistik 79b0133
23:06 23:31 0:25 Tests 50 Vitest-Unit-Tests, Playwright-Smoke-Test über den ganzen Weg bis zur Reservierung durch einen Besucher ohne Konto b0152b8

07.09.2026

Von Bis Dauer Schritt Ergebnis Commit
23:31 00:09 0:38 Docker Multi-Stage-Build, Entrypoint mit Rechteprüfung und Migration, Compose-Stack, Healthcheck, update.sh mit Rollback; Image gebaut und Container verifiziert 61b1249
00:09 00:50 0:41 Dokumentation und Screenshots README, QUICKSTART mit Nginx-Proxy-Manager-Konfiguration, bebilderte Anleitung, 16 automatisiert erzeugte Screenshots, Changelog 0.1.0 folgt

Summe Phase 1: 2:44

Phase 2 – Komfort (v0.2.0)

07.09.2026

Von Bis Dauer Schritt Ergebnis Commit
06:50 07:01 0:11 Einladungen Admin erzeugt einmal gültige Registrierungslinks; Freigabe über AsyncLocalStorage, damit die Rolle nicht aus dem Formular kommen kann. Smoke-Test deckt den ganzen Weg ab 52d69e5
07:01 07:12 0:11 Rebrickable-Import Setnummer genügt: Metadaten, Thema und lokal gespeichertes Bild; 14 Tests gegen gestubbtes fetch inklusive aller Fehlerfälle 4e3cbb8
07:12 07:15 0:03 Barcode-Scanner EAN mit der Handykamera, Prüfziffer-Kontrolle, zxing wird erst beim Öffnen geladen baa94bf
07:15 07:18 0:03 Fehlteile Liste je Sammlungseintrag; Vollständigkeit pflegt sich daraus selbst 5c5c521
07:18 07:23 0:05 Export und Import ZIP, JSON und CSV; Import ersetzt in einer Transaktion, 10 Tests für den Rundweg 45aa8f1
07:23 07:27 0:04 PWA Manifest, Icons aus SVG-Quelle, Service Worker mit Offline-Katalog 39271f8
07:27 07:45 0:18 Verifikation und Dokumentation Smoke-Test, Docker-Build, Changelog 0.2.0, Anleitung und Roadmap folgt

Summe Phase 2: 0:55

Phase 3 – Nice to have (v0.3.0)

07.09.2026

Von Bis Dauer Schritt Ergebnis Commit
08:35 09:00 0:25 Mehrere Sammler Neue Tabelle, Migration mit Nachziehen der Bestandsdaten, Besitzlogik um eine Dimension erweitert, Umschalter in Katalog und Sammlung, Zuordnung in Sammlungseintrag und Wunschliste c23b754
09:00 09:13 0:13 Dublettenprüfung Ähnlichkeitsvergleich mit konservativer Schwelle, Warndialog mit Links, E2E-Test 87131b8
09:13 09:17 0:04 Preisbeobachtung Preisreihe je Set, Wertentwicklung gegen die UVP, Kachel „Aktueller Wert" 91fb66b
09:17 09:22 0:05 Erinnerungen SMTP optional, stündliche Prüfung, Sperrfrist je Liste, Verwaltungsseite mit Testfunktionen 0d08df0
09:22 09:50 0:28 Verifikation und Dokumentation Docker-Build, Smoke-Test, Screenshots, Changelog 0.3.0, Anleitung folgt

Summe Phase 3: 1:15


Notizen und Entscheidungen

Umgebung

  • pnpm: corepack enable scheitert auf diesem Rechner an fehlenden Schreibrechten in C:\Program Files\nodejs. Stattdessen npm install -g pnpm@10; pnpm liegt unter %APPDATA%\npm und ist im PATH.
  • Port 3000 ist auf dem Entwicklungsrechner von einer anderen Anwendung belegt. Der Dev-Server läuft deshalb lokal auf 3100, die Testläufe auf 3210 und 3220.
  • pnpm build unter Windows scheitert mit EPERM … symlink: Der Standalone-Output legt Symlinks in .next/standalone an, wofür Windows den Entwicklermodus oder administrative Rechte braucht. Der Docker-Build unter Linux ist davon nicht betroffen; lokal prüft man mit docker build -t bricktrack:test ..

Bibliotheken

  • shadcn-CLI 4.21 arbeitet mit Presets (-p nova) und Base-Libraries (-b radix) statt der früheren Style-Auswahl. Sie zieht cn und radix-ui als Pakete; clsx und tailwind-merge werden dadurch nicht mehr direkt gebraucht und wurden wieder entfernt. Die Voreinstellungen sind auf Desktop-Dichte ausgelegt (Buttons h-8) – für die Bedienung am Handy auf 44 px angehoben.
  • better-auth 1.7.3: Das Passkey-Plugin liegt nicht mehr unter better-auth/plugins/passkey, sondern im eigenen Paket @better-auth/passkey. Der Drizzle-Adapter löst Modelle über die TypeScript-Property-Namen auf, nicht über die Spaltennamen – deshalb können auch die Auth-Tabellen durchgehend snake_case verwenden.
  • Drizzle: Selbstbezügliche Fremdschlüssel (parent_theme_id) brauchen AnySQLiteColumn als Rückgabetyp, nicht AnyColumn.
  • pdf.js wird lokal gebündelt, inklusive Worker. Kein CDN, damit der Browser des Nutzers keine fremden Server kontaktiert.

Stolpersteine

  • CRLF im Entrypoint: Eine unter Windows geschriebene entrypoint.sh mit CRLF scheitert im Container mit dem irreführenden exec /app/entrypoint.sh: no such file or directory – der Kernel sucht dann /bin/sh\r. Behoben mit einer .gitattributes, die für Shell-Skripte LF erzwingt.
  • Migrations-Bundle: Der mit esbuild als ESM gebündelte Migrations-Runner scheiterte an Dynamic require of "fs" is not supported – mitgebündelte CJS-Abhängigkeiten (dotenv) rufen require() für Node-Builtins auf. Als CommonJS gebündelt läuft es.
  • Playwright und Reihenfolge: Playwright startet den Web-Server vor dem globalSetup. Das Löschen des Testdatenverzeichnisses im globalSetup scheiterte deshalb unter Windows an der bereits geöffneten SQLite-Datei; das Aufräumen läuft jetzt im npm-Skript davor.
  • Screenshots gegen den Dev-Server waren nicht reproduzierbar: unter Last brach der Stream mit ChunkLoadError beziehungsweise Unexpected end of JSON input ab. Die Bilder entstehen jetzt gegen das Produktions-Image im Container – verlässlich und zugleich näher an dem, was Nutzer wirklich sehen.

Phase 2

  • server-only in Tests: Das Paket wirft beim Import ausserhalb einer Server-Komponente, wodurch sich Servermodule nicht testen liessen. In vitest.config.mts ist es jetzt auf einen leeren Stub gemappt – der Import ist eine Build-Zeit-Absicherung, kein Verhalten.
  • Namenskonflikt BASE_URL: Vite benutzt genau diesen Namen für seinen Public-Base-Path und setzt ihn auf /. Die Tests überschreiben ihn deshalb ausdrücklich. Dabei ist aufgefallen, dass src/env.ts bei einem leeren Wert abbrach statt auf den Standard zurückzufallen – behoben, denn ein BASE_URL= in der .env ist ein realistischer Tippfehler.
  • Rebrickable und Anleitungen: Die API v3 stellt keine Anleitungsdateien bereit. Statt das zu verschleiern, legt der Import einen externen Link auf die LEGO-Serviceseite zur Setnummer an.
  • Import statt Zusammenführen: Zwei Sammlungen zu mischen bräuchte Konfliktregeln für jede Tabelle und wäre im Ergebnis nicht vorhersagbar. Der Import ersetzt deshalb – dafür mit getipptem ERSETZEN als Bremse.

Phase 3

  • Migration mit Bestandsdaten: Die generierte SQL-Datei wurde von Hand um drei Anweisungen ergänzt, die einen Sammler anlegen und alles Vorhandene zuordnen. Ohne das wären nach dem Update alle Sammlungseinträge ohne Besitzer gewesen.
  • Instrumentation und native Module: Der Zeitplan für Erinnerungen liess sich nicht aus Next' instrumentation.ts starten – die Datei wird auch für die Edge-Runtime übersetzt, und das native SQLite-Modul bricht dort den Build. Der Zeitplan startet jetzt aus dem Healthcheck heraus, den der Container ohnehin alle 30 Sekunden aufruft.
  • BrickLink bewusst weggelassen: OAuth1 mit einer pro Nutzer registrierten Anwendung ist viel Apparat für eine Zahl, die man in zehn Sekunden eintippt. Im Plan war der Punkt als optional vermerkt.

Beim Testen gefunden und behoben

  • Eine spontan aus dem Katalog angelegte Wunschliste war nicht teilbar: Das Feld isPublic kommt aus einer Checkbox und fiel beim programmatischen Anlegen auf false. Die Schnellanlage setzt es jetzt ausdrücklich.
  • Das Sternchen an Pflichtfeldern gehörte zum zugänglichen Namen des Feldes („Name *"). Jetzt aria-hidden – der Pflichtstatus steckt ohnehin im required des Eingabefeldes.
  • In der Mehrfachauswahl verdeckte die Aktionsleiste die letzte Kachelreihe; das Raster bekommt im Auswahlmodus zusätzliches Polster nach unten.
  • Die Sperrfrist der Erinnerungen rechnete mit umgedrehtem Vorzeichen und hätte jede Erinnerung dauerhaft unterdrückt. Der Test dafür war zuerst da.
  • Der Screenshot-Lauf wählte plötzlich die falschen Kacheln aus: Der neue Sammler-Umschalter benutzt ebenfalls aria-pressed. Die Auswahlkacheln tragen jetzt ein eigenes data-set-card.