13 KiB
Batchmaker Newsfeed Backend Implementation Plan
For Hermes: Use subagent-driven-development skill to implement this plan task-by-task.
Goal: Einen kleinen, dauerhaft betriebenen Update-Feed für Batchmaker und Batchmaker Standalone bauen, der von beiden Produkten und dem Portfolio gelesen werden kann.
Architecture: Separater, schlanker updates-api-Service statt Newsdaten im Next.js-Build oder in der Portfolio-App. Der Service bietet eine öffentliche, read-only JSON-/RSS-Schnittstelle und einen geschützten Admin-Schreibpfad. SQLite ist für die geringe erwartete Änderungsfrequenz ausreichend, wird aber auf einem persistenten Docker-Volume betrieben und regelmäßig gesichert. Das Portfolio und beide Batchmaker-Oberflächen bleiben Clients; kein Produkt greift direkt auf die Datenbank zu.
Tech Stack: Node.js 22, TypeScript, native node:sqlite, kleiner HTTP-Server ohne neues Framework sofern die vorhandene Runtime das zulässt, Docker Compose, SQLite WAL, Bearer-Token aus Secret/Environment, Next.js Server Component oder Route-Proxy für das Portfolio.
1. Ist-Zustand und Integrationsgrenzen verifizieren
Objective: Vor der Implementierung die realen Repositories, Deployment-Ziele und vorhandenen Batchmaker-Backend-Konventionen festhalten.
Read-only checks:
find /home/eldov-ryzen5/workspace/Coding -maxdepth 3 -type f \( -name package.json -o -name docker-compose.yml -o -name Dockerfile \)
rg -n "express|node:sqlite|sqlite|health|PORT|docker" /home/eldov-ryzen5/workspace/Coding/Batchmaker
Festhalten:
- Welches Repository ist die kanonische Quelle für
Batchmaker? - Wo läuft
Batchmaker Standalonetatsächlich? - Soll der Feed auf
free-warez.winoder am selben Host wie das Portfolio betrieben werden? - Existiert bereits ein Secret-/Backup-Verfahren, das wiederverwendet werden muss?
- Welche Produkt-URLs sollen aus einem Update verlinkt werden?
Gate: Keine Codeänderung, bevor Host, Repo-Pfade und Deployment-SSOT eindeutig sind.
2. Datenmodell und API-Vertrag als kleine, stabile Oberfläche definieren
Objective: Ein minimales Schema schaffen, das sowohl öffentliche Updates als auch spätere redaktionelle Pflege trägt.
Proposed entity updates:
id INTEGER PRIMARY KEY
slug TEXT NOT NULL UNIQUE
product TEXT NOT NULL CHECK (product IN ('batchmaker', 'standalone'))
title TEXT NOT NULL
summary TEXT NOT NULL
body_markdown TEXT NOT NULL DEFAULT ''
status TEXT NOT NULL CHECK (status IN ('draft', 'published', 'archived'))
published_at TEXT NULL
created_at TEXT NOT NULL
updated_at TEXT NOT NULL
link_url TEXT NULL
Indexes: (product, status, published_at DESC) und slug.
Public API:
GET /healthz→{ "status": "ok" }, ohne Datenbankdetails.GET /v1/updates?product=batchmaker|standalone&limit=1..50&cursor=...→ nurpublishedundpublished_at <= now, newest first.GET /v1/updates/:slug→ ein veröffentlichtes Update.GET /feed.xml?product=...→ RSS 2.0 oder Atom; für Browser/Feed-Reader und SEO.
Admin API:
POST /v1/admin/updatesPATCH /v1/admin/updates/:idPOST /v1/admin/updates/:id/publishPOST /v1/admin/updates/:id/archive
Admin-Endpunkte verlangen Authorization: Bearer ...; kein Token in URLs, Logs oder Frontend-Code. Schreibdaten werden serverseitig validiert; slug, product, Titel, Status, Limits und Datumswerte sind keine vertrauenswürdigen Eingaben.
Entscheidungen: Cursor-Pagination nur, wenn sie mit vertretbarem Aufwand sauber umgesetzt wird; sonst zunächst limit mit hartem Maximum. Kein Login-System, kein CMS und keine Datei-Uploads in v1.
3. Backend als eigenständigen Service anlegen
Likely files:
- Create:
services/updates-api/package.json - Create:
services/updates-api/tsconfig.json - Create:
services/updates-api/src/server.ts - Create:
services/updates-api/src/db.ts - Create:
services/updates-api/src/validation.ts - Create:
services/updates-api/src/feed.ts - Create:
services/updates-api/migrations/001_initial.sql - Create:
services/updates-api/Dockerfile - Create:
services/updates-api/.env.example
Implementation constraints:
- Native Node APIs und
node:sqlitezuerst; keine neue ORM-Abhängigkeit. - DB-Verzeichnis per
UPDATES_DB_PATH, Standard lokal unterdata/updates.sqlite. - Beim Start Migrationen idempotent ausführen, WAL und foreign keys aktivieren.
- JSON-Fehlerformat stabil halten:
{ "error": { "code": "...", "message": "..." } }. - Request body und Content-Length begrenzen, damit der Admin-Endpunkt kein unkontrollierter Speicher-/Disk-Sink wird.
Cache-Controlfür öffentliche Antworten setzen; Admin-Antworten nicht cachen.- Logs ohne Authorization-Header und ohne vollständigen Markdown-Body.
- HTML-Escaping/Content-Type beim RSS-Generator korrekt behandeln; Markdown nicht ungefiltert als HTML ausgeben.
4. Tests zuerst für die Invarianten schreiben
Test target: services/updates-api/test/updates.test.ts
Abdecken:
- Drafts erscheinen niemals in öffentlichen Listen.
- Zukünftige
published_at-Einträge erscheinen erst nach ihrem Veröffentlichungszeitpunkt. productakzeptiert nurbatchmakerundstandalone.limitwird auf den erlaubten Bereich begrenzt oder mit 400 abgewiesen.- Fehlendes/falsches Bearer-Token blockiert alle Admin-Schreibpfade.
- Publish setzt
statusundpublished_atatomar. - Archivierte Einträge verschwinden aus Public API und RSS.
- RSS enthält keine ungefilterten/kaputten XML-Zeichen.
/healthzprüft die DB-Verbindung, gibt aber keine internen Pfade preis.
Run:
node --test --import tsx services/updates-api/test/updates.test.ts
Falls tsx nicht bereits verfügbar ist: nicht blind eine Dependency hinzufügen; zuerst prüfen, ob TypeScript-Tests über den vorhandenen Build/Node-Mechanismus laufen. Nur dann die kleinste notwendige devDependency ergänzen.
5. Öffentliche Clients anbinden
Portfolio
Likely files:
- Modify:
src/app/page.tsxoder neuesrc/components/updates-feed.tsx - Modify:
src/app/layout.tsxnur falls Metadata/Feed-Link benötigt wird - Modify:
docker-compose.ymlnur für URL-/Netzwerk-Konfiguration - Modify:
.env.exampleoder Runtime-Dokumentation
Serverseitig vom Next.js-Server abrufen, nicht per Browser direkt gegen eine private interne URL. Bei Feed-Ausfall darf die Portfolio-Seite nicht failen: leerer Zustand bzw. „Updates momentan nicht verfügbar“, mit serverseitigem Timeout. Produktfilter sichtbar machen: „Batchmaker“ / „Standalone“ / „Alle“. Keine Admin-Funktion im öffentlichen Portfolio.
Batchmaker und Standalone
Je Produkt eine kleine, vorhandene UI-Integration verwenden; keine gemeinsame UI-Bibliothek nur für drei Karten einführen. Die Clients konsumieren denselben Public API-Vertrag und zeigen maximal die letzten drei Updates plus Link „Alle Updates“. Die Feed-API-URL wird konfiguriert, nicht hart codiert.
6. Deployment- und Persistenzpfad definieren
Likely files:
- Modify/create: Compose-Datei des Zielhosts bzw. eines dedizierten
updates-api-Stacks - Create:
services/updates-api/backup.shoder vorhandenes Backup-Verfahren erweitern - Modify: Traefik dynamic config/labels, falls öffentliches Routing dort erfolgt
Deployment design:
- Service intern auf Port 8080.
- Traefik-Router z. B.
updates.w-make.comoder ein eindeutig festgelegter Pfad; Entscheidung erst nach Hostprobe. - SQLite unter
/data/updates.sqliteauf named volume, nicht im Container-Layer. - Admin-Token ausschließlich über Secret/Environment auf dem Host.
/healthzals Container-Healthcheck.- DB-Backup vor jedem Deployment und per täglichem, atomarem
sqlite3 .backup/Copy-Verfahren; Restore-Test in temporärem Verzeichnis. - Keine Docker-Socket-Berechtigung für den Newsfeed-Service.
Gate: Erst deployen, wenn Traefik-Docker-Socket-Zugriff und Router-Konfiguration live geprüft sind; kein blindes 404-Debugging.
7. Redaktions- und Betriebsworkflow festlegen
V1: Updates werden per dokumentiertem CLI-Skript oder curl aus einer sicheren Admin-Umgebung angelegt/publiziert. Kein browserbasiertes Admin-Panel, solange nicht mehrere Autoren oder regelmäßige Redaktionsarbeit nachgewiesen sind.
Create: services/updates-api/README.md mit:
- lokalem Start
- Beispiel für Draft → Publish
- Token-Handling ohne Credential-Beispiele
- Backup/Restore
- Rollback
- Public API examples
Optional später: kleines Admin-Formular hinter Auth, wenn der CLI-Workflow nachweislich hinderlich ist.
8. Ende-zu-Ende-Verifikation
Local gates:
npm run lint
npm run build
node --test --import tsx services/updates-api/test/updates.test.ts
curl -fsS http://127.0.0.1:8080/healthz
curl -fsS 'http://127.0.0.1:8080/v1/updates?product=standalone&limit=3'
Integration checks:
- Ein Test-Draft je Produkt anlegen.
- Sicherstellen, dass Public API beide Drafts nicht zeigt.
- Beide veröffentlichen und Responses/RSS prüfen.
- Portfolio und beide Produkte laden; Feed-Karten und Deep-Link prüfen.
- API absichtlich stoppen: Clients bleiben renderbar und zeigen Fallback.
- Falsches Admin-Token, übergroßer Body und ungültiges Produkt testen.
Production gates:
curlüber den finalen HTTPS-Host → 200 für/healthz,/v1/updates,/feed.xml.- Traefik-Router trifft den richtigen Service; keine 404/502.
- Container-Restart: Test-Update bleibt vorhanden.
- Backup erstellen und in temporäre SQLite-Datei zurücklesen.
- Logs enthalten keine Secrets.
- Erst danach echte News veröffentlichen.
Risiken und Trade-offs
- SQLite vs. PostgreSQL: SQLite ist für seltene redaktionelle Writes und wenige Leser ausreichend und reduziert Ops deutlich. Bei mehreren Autoren, hoher Schreiblast oder bestehender PostgreSQL-SSOT migrieren; API-Vertrag bleibt gleich.
- Separate API vs. Next Route Handler: Separate API verhindert Kopplung von Persistenz und Portfolio-Build und kann von beiden Batchmaker-Produkten genutzt werden. Mehr Deployment-Artefakt, aber sauberere Verantwortungsgrenze.
- Token vs. Auth-System: Ein einzelnes Admin-Token ist für v1 klein und ausreichend, solange es nur server-/CLI-seitig genutzt wird. Bei mehreren Autoren oder Browser-Admin auf OIDC wechseln.
- Markdown vs. rich HTML: Markdown als gespeicherter Inhalt bleibt diff-/backup-freundlich; Ausgabe zunächst plain text bzw. strikt sanitised rendern. Kein raw HTML in v1.
- Public cache: CDN-/Traefik-Caching kann Updates verzögern. Bei Veröffentlichung
Cache-Controlkurz halten oder gezielt invalidieren; keine clientseitige Dauer-Cacheschicht einführen.
Offene Entscheidungen für den Session-Start
- Finaler API-Host bzw. Pfad und Zielhost.
- Sind
BatchmakerundStandalonebeide öffentlich erreichbar und in welchen Repositories liegen sie? - Soll der öffentliche Feed vollständig anonym sein oder nur über die Produktseiten erreichbar sein?
- Reicht CLI/
curlals Redaktionsworkflow für v1? Default: ja. - Welche Pflichtfelder braucht ein Update redaktionell: nur Titel/Summary/Body oder auch Release-Version und CTA-Link?
- Gibt es bereits einen PostgreSQL-Service, der als SSOT genutzt werden muss? Default: nein; nicht aus Gründen der vermeintlichen Zukunftssicherheit einführen.
Definition of Done
- Ein eigenständiger, health-checkbarer Updates-Service läuft reproduzierbar lokal und im Ziel-Compose.
- Beide Produktwerte werden korrekt getrennt, Draft/Published/Archived sind invariant.
- Public JSON und RSS funktionieren; Admin-Schreibpfad ist authentifiziert und validiert.
- Portfolio, Batchmaker und Standalone konsumieren denselben Vertrag mit Graceful Fallback.
- SQLite liegt persistent, Backup und Restore sind real getestet.
- Lint, Build, Unit-/Integrationstests und HTTPS-Smoke-Tests sind grün.
- Keine Credentials, Produktionsdaten oder Formeln im Repository.
Nicht in v1
- Kein vollständiges CMS.
- Kein User-/Role-System.
- Keine Kommentare, Likes, Suche oder Analytics.
- Keine Webhooks/Event-Sourcing-Struktur.
- Kein PostgreSQL/Redis/Kafka ohne gemessenen Bedarf.
- Keine direkte Kopplung an Batchmaker-interne Datenbanktabellen.
ponytail: SQLite + separater API-Service ist die kleinste belastbare Grenze. Auf PostgreSQL/OIDC migrieren, sobald Multi-Author-Redaktion, hohe Write-Last oder vorhandene DB-Governance das rechtfertigt.
Session handoff: Start mit Abschnitt 1, dann Architektur-Gate vor dem ersten Code. Nach jeder implementierten Invariante Tests ausführen; Deployment erst nach Persistenz- und Traefik-Probe.
Constitution note: Die geladene batchmaker-Constitution beschränkt Repo-Operationen auf /home/eldov-ryzen5/workspace/Coding/Batchmaker/; dieses Portfolio-Repository liegt außerhalb. Für die nächste Session muss die zuständige Portfolio-/CEO-Freigabe bzw. der korrekte Projektkontext geklärt werden, bevor Batchmaker-Repositories verändert werden.
Created: 2026-08-16 Status: Proposed No implementation performed.