arch-q: Public Roadmap (#378) — Datenhaltung, Auth, Schema-Validation, Deployment #437
Labels
No labels
app/archiv
app/einkaufslisten
app/imap-client
app/wissensbasis
arch-answered
arch-question
area/api
area/auth
area/infra
area/mobile
area/shared
area/ui
area/web
portfolio-status
prio/high
prio/low
prio/medium
roadmap/public
size/l
size/m
size/s
size/xl
size/xs
status/blocked
status/needs-info
type/bug
type/chore
type/docs
type/feature
type/idea
type/refactor
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
admin-mrrm/mrrmlabapp#437
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Kontext
Epic #378 (Public Roadmap + Changelog interaktiv in der App, web + mobile) ist seit 2026-05-21 offen, Phase 1 nur halb umgesetzt (
roadmap.jsonmitreleases[]für Changelog,items[]leer, Schema referenziert aber nicht existent), Phasen 2-4 komplett offen. Bevor wir Phase 1 sauber durchziehen und mit API+UI weitermachen, brauche ich Architekt-Input zu vier verschränkten Designentscheidungen, die strukturierend für alle Folge-Stories sind.Relevant: aktuelle Nutzung von
roadmap.jsonistextract-changelog.mjsim Drone-gitea-release-Step (liestreleases[].tag/summary/highlightsund erzeugt Markdown für die Release-Notes — siehe CLAUDE.md). Jedes neue Modell muss diesen Pfad weiter funktionieren lassen oder migrieren.Entscheidung 1: Datenhaltung —
roadmap.jsonim Repo vs. DBOptionen:
Constraint: Aktuell ist (a) bereits gelebt, weil der gitea-release-Step das File aus dem Checkout liest. Ein Wechsel auf (b) würde diesen Pfad neu bauen müssen.
Entscheidung 2: Auth — Public-Endpoint oder eingeloggte User?
GET /roadmap:Entscheidung 3: Schema-Validation — Zod (Runtime) + Build-Time-Check?
Optionen:
scripts/validate-roadmap.mjs): Buildtime-Fail bei Drift, kein Runtime-Check nötig.zod-to-json-schema), CI lintet, API validiert.Das
$schema-Feld in der aktuellenroadmap.jsonzeigt auf./roadmap.schema.json— Datei existiert nicht. Müssen wir entweder einlösen oder entfernen.Entscheidung 4: JSON-Deployment — Repo-Checkout im Container vs. Bundling
Falls (a) bei Entscheidung 1 (oder (c)):
roadmap.jsonwird in das API-Docker-Image kopiert (z.B.COPY roadmap.json /app/), API liest aus Container-FS. Vorteil: immutable per Release. Nachteil: neue Roadmap-Items brauchen Image-Rebuild + Deploy.scripts/sync-roadmap.mjsmacht ausroadmap.jsoneinroadmap.generated.ts, das ins Bundle eingeht. Vorteil: typsicher. Nachteil: noch ein Generator-Step.Constraints + Deadline
extract-changelog.mjsdasreleases[]-Feld direkt am Build (Drone-Step), nicht über API → das muss weiter funktionieren oder migriert werden.Was ich brauche
Konkrete Empfehlungen je Entscheidung, Begründung, plus Hinweise auf Folge-Effekte (z.B. Auswirkungen auf Auto-Sync-Phase 6, oder ob Cache-Invalidation bei (1c) trivial bleibt). Nach Antwort übersetze ich in Produkt-Entscheidung + verlinke vom Epic.
Architekt-Antwort
Alle vier Entscheidungen hängen am Skalierungsbild der Roadmap: das ist ein ~5–20 KB File, das maximal alle paar Tage vom PM editiert wird, und der bestehende
extract-changelog.mjs-Pfad funktioniert bereits. Daraus folgt ein klarer Empfehlungs-Cluster (1a + 4a + 3c + 2a) — möglichst wenig neue Infrastruktur, git als Source-of-Truth, Validierung pragmatisch und vor Deploy.Entscheidung 1: Datenhaltung → (a) JSON-File im Repo
Empfehlung: Status quo behalten —
roadmap.jsonist Single-Source-of-Truth, git übernimmt Versionierung/Diff/Revert/Blame gratis.Begründung:
Folge-Effekt: Phase 6 (Auto-Sync Gitea→
releasedAt) muss bei (a) entweder via Bot-Push committen oder das Modell später partiell auf DB migrieren. Heute nicht vorwegnehmen — Phase 6 ist optional/später, dann erneut bewerten.Entscheidung 2: Auth → (a) Public-Endpoint
Empfehlung:
GET /roadmapohne Keycloak-Guard, aber mit Rate-Limiting.Begründung:
Operativ:
@SkipAuth()- oder@Public()-Decorator auf den Controller-Endpoint (je nach NestJS-Auth-Pattern im Repo).@nestjs/throttlermit moderatem Limit (z.B. 60 req/min per IP) gegen Crawler-Misuse.Cache-Control: public, max-age=300) — bei statischem File trivial, entlastet API.Entscheidung 3: Schema-Validation → (c) Beides, Zod als Source-of-Truth
Empfehlung: Zod-Schema im API als kanonische Definition. JSON-Schema-Datei daraus generiert (via
zod-to-json-schema) — diese wird zurroadmap.schema.jsonund CI validiert.Begründung:
scripts/validate-roadmap.mjs) fängt PM-Fehler vor Deploy ab — schnelles Feedback im Drone-Build, kein produktiver Boot-Crash.$schema-Feld inroadmap.jsonzeigt damit auf eine real existierende und immer aktuelle Datei.Operativ:
apps/api/src/roadmap/roadmap.schema.tsmit Zod-Definition.scripts/sync-roadmap-schema.mjs(Pre-Commit-Hook oder CI-Step) generiertroadmap.schema.jsonaus dem Zod-Schema. Bei Drift im CI: fail.scripts/validate-roadmap.mjsvalidiertroadmap.jsongegen das Schema (ajv) als separater CI-Step (pr-convention-check-Nachbar in.drone.yml).roadmap.jsonbeim Boot,.parse()via Zod → bei Drift: API startet nicht, klares Log.Entscheidung 4: Deployment → (a) Bundling beim Build
Empfehlung:
roadmap.jsonperCOPYins API-Docker-Image, API liest aus Container-FS.Begründung:
Operativ:
apps/api/Dockerfile:COPY roadmap.json /app/roadmap.json(oder neben das Build-Output, je nach Layout).Übersehene Folge-Effekte
items[]vsreleases[]: das aktuelleroadmap.jsonhat zwei Felder mit unterschiedlicher Semantik (items= Now/Next/Done für UI,releases= Changelog für Release-Notes). Beide bleiben — sie sind komplementär:releases[]ist strukturierter Changelog (was wurde released, mit Highlights) — vomextract-changelog.mjskonsumiert.items[]ist Forward-Looking Plan (was kommt als nächstes, was läuft) — von der UI konsumiert.items[].status: "done"könnte automatisch ein passendesreleases[]-Entry triggern oder daraus abgeleitet werden — heute nicht vorwegnehmen.API-Versionierung:
GET /roadmapsollte alsGET /api/v1/roadmap(oder bestehende Convention) eingehängt werden, mit dem geparsten + ggf. transformierten Output (z.B.itemsnach Status gruppiert,releasesabsteigend sortiert) — nicht das rohe JSON 1:1 ausliefern. Das entkoppelt internes Datenmodell von der UI-API.linkedIssues-Feld: im Datenmodell-Entwurf vorhanden — bei (1a) reine Strings, kein Foreign-Key-Constraint. UI macht daraushttps://git.mrrm.de/{linkedIssues[0]}-Links. Validation prüft Format{repo}#{number}.i18n-Punkt: explizit out-of-Scope laut Body, gut. Schema sollte aber
title/summaryals plain string definieren, nicht{de: string}— falls i18n später kommt, wird das eine Migration sein, das ist OK.Phase 1.5 (vor Phase 2): empfehle separat ein kleines Issue, um die
items[]-Befüllung initial vorzunehmen (manuelles PM-Set, ~10–15 Items für Now/Next aus dem aktuellen Backlog). Das ist Inhalt, nicht Architektur — aber Phase 2-API ist ohne befüllte Daten nicht sinnvoll testbar.Beantwortet von Architekt-Hut (in dieser Session konversationell durch PM beantwortet — formaler arch-bot-Flow nicht gefahren weil keine zweite Claude-Instanz parallel läuft; bei strittigen Stellen oder größeren Folge-Entscheidungen separate arch-Konsultation in dedizierter Session anstoßen).
Beantwortet — Architekt-Empfehlungen übernommen, Decision Record am Epic #378 (Kommentar 2948). Schließe das arch-question.