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>
10 KiB
10 KiB
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 enablescheitert auf diesem Rechner an fehlenden Schreibrechten inC:\Program Files\nodejs. Stattdessennpm install -g pnpm@10; pnpm liegt unter%APPDATA%\npmund 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 buildunter Windows scheitert mitEPERM … symlink: Der Standalone-Output legt Symlinks in.next/standalonean, wofür Windows den Entwicklermodus oder administrative Rechte braucht. Der Docker-Build unter Linux ist davon nicht betroffen; lokal prüft man mitdocker 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 ziehtcnundradix-uials Pakete;clsxundtailwind-mergewerden dadurch nicht mehr direkt gebraucht und wurden wieder entfernt. Die Voreinstellungen sind auf Desktop-Dichte ausgelegt (Buttonsh-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 durchgehendsnake_caseverwenden. - Drizzle: Selbstbezügliche Fremdschlüssel (
parent_theme_id) brauchenAnySQLiteColumnals Rückgabetyp, nichtAnyColumn. - 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.shmit CRLF scheitert im Container mit dem irreführendenexec /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) rufenrequire()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
ChunkLoadErrorbeziehungsweiseUnexpected end of JSON inputab. 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-onlyin Tests: Das Paket wirft beim Import ausserhalb einer Server-Komponente, wodurch sich Servermodule nicht testen liessen. Invitest.config.mtsist 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, dasssrc/env.tsbei einem leeren Wert abbrach statt auf den Standard zurückzufallen – behoben, denn einBASE_URL=in der.envist 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
ERSETZENals 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.tsstarten – 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
isPublickommt aus einer Checkbox und fiel beim programmatischen Anlegen auffalse. 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 imrequireddes 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 eigenesdata-set-card.