Files
Matthias Giesselmann b90ff252d1 Add Logbuch: project update blog with admin, media and API
Public archive with sidebar navigation, project pages, month archive,
search and entry pages with image blocks. Admin area for brands,
projects, post types, users, api clients, media and the entry editor
with drag and drop images, preview per audience, scheduling and
publish checks. Read and write API with bearer tokens, audience
scoping, idempotent creation, OpenAPI document and editorial guide.
Magic link login with configurable allowed domains, whole app behind
the session gate. 456 tests including design rule checks.
2026-07-31 21:33:42 +02:00

5.1 KiB

Logbuch Umsetzungsstand

Stand: 30.07.2026

Plan 1, Fundament: fertig, lokal, nicht in git

Nachweis Ergebnis
pnpm test 11 Dateien, 112 Tests grün
pnpm typecheck ohne Fehler
pnpm build erfolgreich, 7 Routen
Live gegen localhost:4700 Lese-API, gelesen-Status und Sichtbarkeit von Hand geprüft
Mutationsprobe an 6 Wächtern alle 6 werden von Tests gefangen

Es gibt weiterhin kein Repository. Kein git init, kein Commit, bis der Auftraggeber die laufende Anwendung lokal abgenommen hat.

Abweichungen vom Plan, unterwegs entstanden

Punkt Was war Was gilt
Postgres-Image Volume an /var/lib/postgresql/data Postgres 18 verlangt den Mount an /var/lib/postgresql, sonst startet der Container nicht
TypeScript 7.0.2 installiert Next 16.2.12 kommt mit der Compiler-API von TS 7 nicht klar und braucht experimental.useTypeScriptCli. Rückweg wäre TypeScript 6
sharp im Plan nicht erwähnt Lässt sich auf dem Rechner nicht bauen, aus onlyBuiltDependencies entfernt. Wird erst für Bildvarianten in Plan 5 gebraucht und muss dort geklärt werden
tsconfig.json im Plan mit Tabs Next schreibt die Datei beim Start selbst um, sie ist werkzeuggesteuert
findPost nur Slug und Zielgruppe zusätzlich optionale Projektbindung, weil Slugs nur pro Projekt eindeutig sind
Token-Abfrage SQL lag in src/lib/api-auth.ts verschoben nach src/data/repositories/clients.ts, damit die eigene Regel gilt: kein SQL außerhalb von src/data

Behobene Mängel aus dem Review

Fünf Prüfer mit getrennten Blickwinkeln haben 34 Funde gemeldet, 14 wurden gegnerisch geprüft, 9 bestätigt, 5 widerlegt. Vier echte Ursachen:

  1. markRead nahm fremde Beitrags-Kennungen ungeprüft an. Ein an Trakk gebundener Client konnte einen MTA360-Beitrag als gelesen melden, die Zeile landete mit falschem Projekt in der Tabelle und senkte den Zähler der fremden App. Die Zeilen werden jetzt aus der Datenbank abgeleitet, eingeschränkt auf Projekt, Status published und die für den Client sichtbaren Zielgruppen.
  2. Unbekannte Beitrags-Kennung führte zu 500. Der Fremdschlüssel schlug durch. Das war zusätzlich ein Auskunftskanal, weil existierende Kennungen 200 und unbekannte 500 ergaben. Jetzt antwortet der Endpunkt 200 mit marked: 0 und verrät nichts.
  3. Seitenaufteilung ohne eindeutige Sortierung. Bei gleichem publishAt war die Reihenfolge zufällig, Beiträge konnten auf zwei Seiten doppelt oder gar nicht erscheinen. Sortiert wird jetzt nach publish_at desc nulls last, dann nach id.
  4. Stillgelegte Projekte lieferten weiter Beiträge aus, obwohl GET /api/v1/projects sie ausblendet. listPosts, findPost und listUnread prüfen jetzt project.is_active.

Dazu Testlücken geschlossen: Projektbindung des Clients, vollständige Übergangsmatrix mit allen 25 Paaren, Zielgruppe bis zur HTTP-Antwort inklusive scope public, Form des Problem-JSON, Parametergrenzen, since als Gleichheitsgrenze, Schlagwort-Filter mit zwei Schlagworten ohne Doppelzählung, Seed-Idempotenz ohne Dubletten, 422 für Clients ohne Projektbindung.

Bewusst nicht behoben

Fund Warum nicht
Beitrags-Detail liefert keine Blöcke und Medien Plan 1 liefert genau die Listenfelder. Blöcke kommen mit dem Web-Archiv in Plan 3
Schema erlaubt einen Write-Client mit can_publish Es gibt noch keine Schreib-API. Die Sperre gehört in Plan 5, dort mit Test
Lese-Endpunkte prüfen den Client-Modus nicht Ein Write-Client darf lesen. Die Zielgruppe schützt weiterhin, der Modus ist keine zweite Schranke
Kein Index deckt die Hauptabfrage der Liste Bei dieser Datenmenge sinnlos. Gehört gemessen, nicht geraten
listUnread lädt alle ungelesenen Zeilen zum Zählen Zählt Beiträge eines Projekts, das bleibt klein. Bei Bedarf später eine Zählabfrage
Seed-Token steht im Klartext in scripts/seed.ts Reines Entwicklungs-Token für die lokale Datenbank, lb_seed_trakk_read. Darf niemals in einer erreichbaren Umgebung gelten
Zusammengesetzter Fremdschlüssel auf post_read Die Anwendung verhindert falsche Zuordnungen jetzt zuverlässig, geprüft per Mutationsprobe. Ein zusätzlicher Datenbank-Zwang wäre Tiefenverteidigung und kostet eine Migration plus zusätzlichen Index

Lokale Abnahme

cd /Volumes/M2mini/WORK/NYO/projects/logbuch
docker compose up -d
pnpm dev

Dann:

curl -s -H "Authorization: Bearer lb_seed_trakk_read" "http://localhost:4700/api/v1/posts"
curl -s -H "Authorization: Bearer lb_seed_trakk_read" "http://localhost:4700/api/v1/unread?external_user_id=u-1"
curl -s -o /dev/null -w "%{http_code}\n" "http://localhost:4700/api/v1/posts"

Erwartet: zwei Trakk-Beiträge, kein interner Beitrag, ohne Token 401.

Das Design des Web-Archivs liegt als Entwurf unter docs/design/mockup-overview.html und ist im Browser direkt öffenbar.

Nächster Schritt

Plan 2: Auth, Admin, Block-Editor, Freigabe. Offen davor: Subdomain, und ob der Admin-Login mit better-auth per Mail und Passwort startet oder auf Portal-SSO wartet.