docs(quick-261008-w5w): Modul-Changelog; Idee Container-Integrationen

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-10-08 23:34:07 +02:00
parent 4c14ec895a
commit 1bb869a7b5
4 changed files with 415 additions and 1 deletions
@@ -0,0 +1,272 @@
---
phase: 261008-w5w-modul-changelog-und-modulversionen-nacht
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- apps/api/src/module-registry/module-changelog.ts
- apps/api/src/module-registry/module-changelog.registry.ts
- apps/api/src/module-registry/module-changelog.spec.ts
- apps/api/src/module-registry/module-registry.controller.ts
- apps/api/src/nextcloud-status/nextcloud-status.changelog.ts
- apps/api/src/nextcloud-status/nextcloud-status.seed.ts
- apps/api/src/cert-manager/cert-manager.changelog.ts
- apps/api/src/cert-manager/cert-manager.seed.ts
- apps/api/src/dkv/dkv.changelog.ts
- apps/api/src/dkv/dkv.seed.ts
- apps/api/src/domaincheck/domaincheck.changelog.ts
- apps/api/src/domaincheck/domaincheck.seed.ts
- apps/api/src/domains/domains.changelog.ts
- apps/api/src/domains/domains.seed.ts
- apps/api/src/handelsware-datev/handelsware-datev.changelog.ts
- apps/api/src/handelsware-datev/handelsware-datev.seed.ts
- apps/api/src/kantine-datev/kantine-datev.changelog.ts
- apps/api/src/kantine-datev/kantine-datev.seed.ts
- apps/api/src/nextcloud-files/nextcloud-files.changelog.ts
- apps/api/src/nextcloud-files/nextcloud-files.seed.ts
- apps/api/src/proxmox/proxmox.changelog.ts
- apps/api/src/proxmox/proxmox.seed.ts
- apps/api/src/tenders/tenders.changelog.ts
- apps/api/src/tenders/tenders.seed.ts
- apps/web/src/app/(portal)/marketplace/components/ModuleChangelog.tsx
- apps/web/src/app/(portal)/marketplace/[slug]/page.tsx
- apps/web/src/app/(portal)/marketplace/[slug]/detail.test.tsx
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
- docs/anleitung-entwicklung.md
- docs/anleitung-betrieb.md
- docs/anleitung-anwender.md
- CHANGELOG.md
- .planning/quick/261008-w5w-modul-changelog-und-modulversionen-nacht/e2e/e2e-changelog.sh
autonomous: true
requirements: [QUICK-261008-W5W]
estimate:
tokens: 170000
raw_tokens: 170000
tasks: 3
confidence: low
must_haves:
truths:
- "Die Marktplatz-Detailseite jedes eingebauten Moduls zeigt einen Abschnitt „Änderungen“: neueste Modulversion oben aufgeklappt (mit Kennzeichnung „Aktuell“), jede ältere Version einzeln aufklappbar, Einträge gruppiert nach Neu/Geändert/Behoben, Texte gesiezt, auf Englisch bei englischer Spracheinstellung"
- "Die im Marktplatz angezeigte Modulversion ist immer die neueste Version aus dem Modul-Changelog — kein Seed enthält mehr eine fest eingetragene Versionsnummer"
- "Alle zehn Module haben eine nachgetragene Historie nach der Regel: 1.0.0 = erste Tessera-Version mit dem Modul, danach je Tessera-Version mit sichtbarer Modul-Änderung ein Sprung (Neu → Minor, sonst Patch), Datum = Datum der Tessera-Version, Unveröffentlichtes = 2026-10-08"
- "dkv-fleet steht danach auf mindestens 1.1.0 (die Beta zeigt bereits 1.1.0), und die DKV-Zeile in CHANGELOG.md nennt dieselbe Nummer wie der neueste dkv-Eintrag"
- "Ein Wächter-Test schlägt fehl, wenn ein Seed-Modul keinen Changelog hat, Versionen nicht streng absteigen, die Seed-Version nicht dem neuesten Eintrag entspricht, ein Datum ungültig ist, de/en fehlt oder Ersatzschreibungen bzw. Mandanten-/Lizenzbegriffe vorkommen"
- "Für unbekannte oder eigene Module liefert GET /modules/changelog/:slug eine leere Liste, die Detailseite zeigt dann keinen Abschnitt und bricht nicht"
artifacts:
- path: "apps/api/src/module-registry/module-changelog.ts"
provides: "Typen ModuleChangelog/Release/Item, compareSemver, latestVersion"
- path: "apps/api/src/module-registry/module-changelog.registry.ts"
provides: "MODULE_CHANGELOGS (Map slug → Changelog) und getModuleChangelog(slug)"
- path: "apps/api/src/module-registry/module-changelog.spec.ts"
provides: "Wächter-Test über alle Seeds und alle Changelogs"
- path: "apps/web/src/app/(portal)/marketplace/components/ModuleChangelog.tsx"
provides: "Abschnitt „Änderungen“ auf der Detailseite"
- path: "apps/api/src/*/<seed-name>.changelog.ts (10 Dateien, je neben der Seed-Datei)"
provides: "Nachgetragene Modul-Historie"
key_links:
- from: "apps/api/src/*/*.seed.ts"
to: "apps/api/src/*/*.changelog.ts"
via: "version = latestVersion(<SLUG>_CHANGELOG)"
pattern: "latestVersion\\("
- from: "apps/api/src/module-registry/module-registry.controller.ts"
to: "apps/api/src/module-registry/module-changelog.registry.ts"
via: "@Get('changelog/:slug') → getModuleChangelog(slug)"
pattern: "changelog/:slug"
- from: "apps/web/src/app/(portal)/marketplace/[slug]/page.tsx"
to: "GET /modules/changelog/:slug"
via: "fetch mit credentials, eigener Zustand, Fehler → leere Liste"
pattern: "modules/changelog/"
- from: "apps/api/src/module-registry/module-changelog.spec.ts"
to: "apps/api/src/*/*.seed.ts"
via: "Seed-Dateien per Dateisystem finden, seed*Module mit Attrappe aufrufen, Manifeste einsammeln"
pattern: "\\.seed\\.ts"
---
<objective>
Jedes Modul bekommt einen eigenen, strukturierten Changelog als einzige Quelle für seine Versionsnummer; der Marktplatz zeigt diese Änderungen auf der Detailseite; die gesamte bisherige Modul-Historie wird aus Git-Tags und CHANGELOG.md nachgetragen; ein Wächter-Test macht das Vergessen einer Versionsanpassung unmöglich.
Purpose: User-Anweisung „Nie vergessen, bei Moduländerungen die Versionsnummer anzupassen. Falls etwas versäumt wurde, nachtragen. Ebenso einen Changelog für Module anlegen und pflegen.“ Heute stehen neun von zehn Modulen trotz vieler Änderungen auf 1.0.0.
Output: Changelog-Infrastruktur (API-Typen, Register, Route, Wächter-Test), Abschnitt „Änderungen“ im Marktplatz, zehn nachgetragene Modul-Changelogs, Doku (Entwicklung, Betrieb, Anwender), CHANGELOG.md-Eintrag, im laufenden Stack und im Browser nachgewiesen.
Architekturentscheidung (Claude's Discretion, im Auftrag freigestellt): Auslieferung über eine API-Route aus Code, KEINE Datenbankspalte und keine Migration. Gründe: (1) keine Migration und kein Schema-Eingriff; (2) die Katalog- und Seitenleisten-Antworten (`/modules/catalog`, `/modules/active`) und die `findBySlug`-Abfrage, die ModuleGuard bei jeder Modulanfrage ausführt, werden nicht um mehrere KB JSON je Modul aufgebläht; (3) eigene Module liegen in der separaten Tabelle `CustomModule` und sind gar nicht im Register — eine unbekannte Kennung liefert schlicht eine leere Liste. Pfad `GET /modules/changelog/:slug` (statisches erstes Segment) statt `/modules/:slug/changelog`, weil die Modul-Controller unter `modules/<slug>` hängen und dort `:id`-Routen haben — die zweite Form würde von ihnen verschattet (Projektnotiz Route-Reihenfolge).
CI-Prüfung „Modulordner geändert, Changelog nicht“: bewusst NICHT eingebaut, weil nicht ohne Fehlalarme machbar — reine Test-, Refactor- und Kommentar-Commits verlangen keinen Versionssprung, plattformweite Commits berühren viele Modulordner zugleich, und ein Push bündelt mehrere Commits (gebündeltes Pushen ist Projektpraxis). Stattdessen: harter Wächter-Test (Konsistenz) plus Prozessregel und Prüfbefehl in der Doku (Aufgabe 3).
</objective>
<execution_context>
@~/.claude/gsd-core/workflows/execute-plan.md
@~/.claude/gsd-core/templates/summary.md
</execution_context>
<context>
@.planning/STATE.md
@./CLAUDE.md
@CHANGELOG.md
@apps/api/src/module-registry/module-registry.service.ts
@apps/api/src/module-registry/module-registry.controller.ts
@apps/api/src/module-registry/module-registry.controller.categories.spec.ts
@apps/api/src/nextcloud-status/nextcloud-status.seed.ts
@apps/web/src/app/(portal)/marketplace/[slug]/page.tsx
@apps/web/src/app/(portal)/marketplace/[slug]/detail.test.tsx
@.planning/quick/261008-mzu-modul-nextcloud-dateien-eigenstaendiger-/e2e/e2e-lib.sh
Planungsbefunde (gemessen am 08.10.2026, damit der Ausführende nicht neu suchen muss):
- Seeds: zehn Dateien `apps/api/src/<ordner>/<name>.seed.ts`, jede exportiert genau eine Funktion `seed<Name>Module(moduleRegistryService)`, die `moduleRegistryService.seedModule({...})` aufruft. `tenders.seed.ts` exportiert zusätzlich `seedServiceBundRssFeed(prisma)` — die Seed-Erkennung darf nur Exporte nach dem Muster `^seed\w*Module$` aufrufen.
- Ordner → Slug → Anzeigename: cert-manager → cert-manager → Cert Manager (CHANGELOG: „Zertifikat-Manager“); dkv → dkv-fleet → DKV-Rechnung; domaincheck → domaincheck → Domaincheck; domains → domains → Domains; handelsware-datev → handelsware-datev → Handelsware; kantine-datev → kantine-datev → Kantinenabrechnung; nextcloud-files → nextcloud-files → Dateien; nextcloud-status → nextcloud-status → Nextcloud-Status; proxmox → proxmox → Proxmox; tenders → tender-radar → Ausschreibungs-Radar.
- Eigene Module: Prisma-Modell `CustomModule`, nicht in der Tabelle `Module`, nicht im Katalog.
- API ohne globales Präfix auf localhost:3001, globaler JwtAuthGuard (nicht angemeldet → 401 auf vorhandenen Routen, 404 auf unbekannten). Lokale Anmeldung: POST /auth/login mit username admin, password admin123 (siehe e2e-lib.sh aus quick 261008-mzu).
- Tessera-Tags und Datum laut CHANGELOG.md-Überschrift (NICHT das Commit-Datum des Tags — v1.0.0 ist am 14.09. getaggt, Freigabedatum 2026-09-15): v1.0.0 2026-09-15, v1.1.0 2026-09-16, v1.2.0 2026-09-17, v1.3.0 2026-09-22, v1.3.1 2026-09-23, v1.4.0 2026-09-25, v1.5.0/v1.5.1/v1.5.2 2026-09-28, v1.6.0/v1.7.0 2026-09-29, v1.8.0/v1.9.0 2026-09-30, v1.9.1 2026-10-01, v1.9.2 2026-10-02, v1.10.0/v1.10.1 2026-10-06; Unveröffentlicht = v1.10.1..HEAD.
- Erstes Auftauchen der Seed-Datei je Tag: cert-manager, dkv, domaincheck, tenders ab v1.0.0; proxmox ab v1.4.0; handelsware-datev, kantine-datev, nextcloud-status ab v1.10.0; domains, nextcloud-files unveröffentlicht.
- Commits je Bereich, die Modulpfade berühren (Gegenprobe, nicht die Wahrheit über Sichtbarkeit): cert-manager v1.0.0=19, v1.3.0=11, v1.5.0=1, v1.9.2=2; dkv-fleet v1.0.0=44, v1.3.0=9, v1.5.0=1, v1.10.0=1, unveröffentlicht=2; domaincheck v1.0.0=7, v1.5.0=1; tender-radar v1.0.0=112, v1.3.0=8, v1.5.0=1; proxmox v1.4.0=23, v1.5.0=4, v1.10.0=2; handelsware-datev v1.10.0=4; kantine-datev v1.10.0=4; nextcloud-status v1.10.0=10, unveröffentlicht=4; domains unveröffentlicht=14; nextcloud-files unveröffentlicht=18. Die v1.5.0-Commits sind die plattformweite Umstellung auf das Design Mosaik („style(web): Seiten auf Mosaik-Muster umgestellt“).
- CHANGELOG.md erwähnt Moduländerungen teils ohne Commit in den Modulordnern (z. B. 1.9.2 „Zertifikat-Manager: Die Texte sprechen Sie jetzt durchgehend mit „Sie“ an“ — lag nur in de.json). Darum sind CHANGELOG.md-Erwähnungen eine zweite, gleichwertige Quelle.
- Umlaut-Wächter `apps/web/src/messages/umlaut-guard.spec.ts` prüft de.json auf Ersatzschreibungen (ae/oe/ue/ss) — neue de.json-Texte mit echten Umlauten.
</context>
<tasks>
<task type="tracer" tdd="true">
<name>Aufgabe 1: Durchstich „Änderungen“ für Nextcloud-Status — Typen, Register, Route, Seed-Version, Wächter-Test, Marktplatz-Abschnitt, im laufenden Stack</name>
<files>apps/api/src/module-registry/module-changelog.ts, apps/api/src/module-registry/module-changelog.registry.ts, apps/api/src/module-registry/module-changelog.spec.ts, apps/api/src/module-registry/module-registry.controller.ts, apps/api/src/nextcloud-status/nextcloud-status.changelog.ts, apps/api/src/nextcloud-status/nextcloud-status.seed.ts, apps/web/src/app/(portal)/marketplace/components/ModuleChangelog.tsx, apps/web/src/app/(portal)/marketplace/[slug]/page.tsx, apps/web/src/app/(portal)/marketplace/[slug]/detail.test.tsx, apps/web/src/messages/de.json, apps/web/src/messages/en.json, .planning/quick/261008-w5w-modul-changelog-und-modulversionen-nacht/e2e/e2e-changelog.sh</files>
<behavior>
- compareSemver vergleicht numerisch: 1.10.0 ist größer als 1.9.2, 2.0.0 größer als 1.99.99, gleiche Versionen ergeben 0
- latestVersion liefert die Version des ersten Eintrags; leere Liste wirft einen Fehler mit verständlicher Meldung
- getModuleChangelog('nextcloud-status') liefert genau das Array aus nextcloud-status.changelog.ts; unbekannte Kennung, '__proto__', 'constructor', 'toString' liefern eine leere Liste (kein Objekt aus der Prototypenkette)
- ModuleRegistryController.getChangelog(slug) gibt das Ergebnis von getModuleChangelog unverändert zurück
- Format-Wächter je Eintrag in MODULE_CHANGELOGS: nicht leer; Version im Muster Ziffern.Ziffern.Ziffern; Versionen streng absteigend; Datum JJJJ-MM-TT und echtes Kalenderdatum; Daten nicht aufsteigend (neueste oben); jede Version mindestens ein Eintrag; Art nur new/changed/fixed; de und en nicht leer; de-Texte ohne Ersatzschreibungen (Wortliste im Spec, ganze Wörter, ohne Groß-/Kleinschreibung: fuer, ueber, koennen, moechten, muessen, Aenderung, Aenderungen, geaendert, moeglich, zurueck, loeschen, geloescht, pruefen, geprueft, Pruefung, waehlen, ausgewaehlt, Schluessel, groesser, Groesse, schliessen, oeffnen, geoeffnet); de/en ohne Mandanten-/Lizenzbegriffe (ganze Wörter Mandant, Mandanten, tenant, tenants sowie Wortanfänge Lizenz, licens, licenc — „Mandantennummer“ als DATEV-Fachbegriff löst bewusst NICHT aus)
- Seed-Wächter: alle Dateien apps/api/src/*/*.seed.ts werden per Dateisystem gefunden (mindestens 10), jeder Export nach ^seed\w*Module$ wird mit einer Attrappe aufgerufen, deren seedModule das Manifest einsammelt; für jedes Manifest, dessen Slug einen Changelog hat, gilt manifest.version === changelog[0].version
- Detailseite: mit Changelog (zwei Versionen) erscheint die Überschrift „Änderungen“, die neueste Version ist mit „Aktuell“ markiert und ihre Einträge sind sichtbar, gruppiert unter Neu/Geändert/Behoben; die ältere Version steckt in einem geschlossenen details-Element, dessen summary Version und Datum zeigt
- Detailseite: leere Liste → keine Überschrift „Änderungen“; Changelog-Abruf mit Status 500 oder Netzwerkfehler → Modul wird normal angezeigt, kein Abschnitt; eine Antwort, die kein Array von Versionen ist, wird verworfen statt abzustürzen
</behavior>
<action>
Durchstich mit dem Modul Nextcloud-Status (zwei Versionen, damit auch das Aufklappen älterer Versionen von Anfang an echt geprüft ist). Zuerst die Tests (rot), dann die Umsetzung.
API-Typen in apps/api/src/module-registry/module-changelog.ts: Typ ModuleChangeKind ('new' | 'changed' | 'fixed'), Schnittstelle ModuleChangelogItem (kind, de, en), Schnittstelle ModuleChangelogRelease (version, date im Format JJJJ-MM-TT, changes), Typ ModuleChangelog als readonly-Array von Releases, neueste zuerst. Dazu die reinen Funktionen compareSemver(a, b) (numerisch je Teil, nicht als Zeichenkette) und latestVersion(changelog) (erste Version; leere Liste wirft Error mit Hinweis auf die Changelog-Datei). Kurzer Dateikopf-Kommentar, der die Regel nennt: eine Quelle der Wahrheit, Seed liest die Version von hier, Wächter-Test in module-changelog.spec.ts.
Register in apps/api/src/module-registry/module-changelog.registry.ts: MODULE_CHANGELOGS als ReadonlyMap von Slug auf ModuleChangelog (in dieser Aufgabe nur nextcloud-status) und getModuleChangelog(slug), das per Map-Zugriff liefert und bei unbekannter Kennung ein leeres Array zurückgibt. Bewusst Map statt Objekt-Index, damit '__proto__' und Co. nicht in die Prototypenkette greifen (T-261008-w5w-02).
Route in apps/api/src/module-registry/module-registry.controller.ts: neue Methode getChangelog mit @Get('changelog/:slug'), direkt hinter findCatalog und vor den POST-Routen, gibt getModuleChangelog(slug) zurück. Kein @Roles — wie GET /modules und /modules/catalog für jeden angemeldeten Benutzer (Katalog ist nicht schutzbedürftig, T-03-03). Den Klassenkommentar um die Route ergänzen, inklusive des Satzes, warum das statische Segment vorne steht (sonst Verschattung durch die Modul-Controller unter modules/<slug>).
Changelog Nextcloud-Status in apps/api/src/nextcloud-status/nextcloud-status.changelog.ts, exportiert als NEXTCLOUD_STATUS_CHANGELOG, Quelle CHANGELOG.md 1.10.0 und „Unveröffentlicht“ sowie git log v1.9.2..v1.10.0 und v1.10.1..HEAD auf den Modulpfaden. Version 1.1.0 vom 2026-10-08 (Suchfeld ist eine neue Funktion → Minor): Neu Suchfeld nach Kundenname; Neu Bildadresse mit http:// wird beim Speichern einmalig abgeholt; Geändert kompaktere Kacheln, Kundenname und Adresse in voller Länge, Knöpfe unten rechts; Behoben Formularmeldungen jetzt auf Deutsch. Version 1.0.0 vom 2026-10-06: drei bis vier knappe Neu-Einträge (Kacheln mit Ampel, stündliche Prüfung und Sortierung; Glocke „Benachrichtigen“ per E-Mail und Bildschirm; Klartext-Grund bei „Nicht erreichbar“; Dashboard-Kachel). Alltagssprache, Nutzersicht, siezen, echte Umlaute, keine Mandanten-/Lizenzbegriffe, jeweils mit gleichwertigem englischem Text.
Seed apps/api/src/nextcloud-status/nextcloud-status.seed.ts: die fest eingetragene Versionszeichenkette ersetzen durch latestVersion(NEXTCLOUD_STATUS_CHANGELOG); Kommentar ergänzen, dass die Version ausschließlich aus dem Changelog kommt.
Spec apps/api/src/module-registry/module-changelog.spec.ts mit allen Fällen aus behavior. Seed-Erkennung: Quellverzeichnis über path.resolve(__dirname, '..'), Unterordner per readdirSync, darin Dateien mit Endung .seed.ts, jeweils per await import laden. Attrappe ist ein Objekt mit async seedModule, das das Manifest in ein Array schiebt, per as unknown as ModuleRegistryService übergeben. Falls dynamische Importe in Vitest Probleme machen: statische Importe aller zehn Seed-Funktionen plus Gegenprobe, dass die Zahl der gefundenen .seed.ts-Dateien der Zahl der importierten Funktionen entspricht. Die Vollständigkeitsprüfung (jeder Seed hat einen Changelog, kein verwaister Changelog) kommt erst in Aufgabe 2 dazu, damit diese Aufgabe grün abschließt. Controller-Test nach dem Muster von module-registry.controller.categories.spec.ts (Controller mit Attrappen-Services instanziieren).
Web: neue Komponente apps/web/src/app/(portal)/marketplace/components/ModuleChangelog.tsx (Client-Komponente, Props releases und locale). Eigene schmale Schnittstellen im Web, kein Import aus der API. Darstellung im Design Mosaik wie die übrigen Karten (rounded-md border border-border bg-card p-4, Abstände wie auf der Seite, Farben nur über vorhandene Tokens wie text-foreground, text-muted-foreground, bg-muted). Überschrift (h2) t('changelogTitle'). Neueste Version offen: Zeile mit t('changelogRelease', {version, date}) und kleinem Abzeichen t('changelogCurrent') (Stil wie das Kategorie-Abzeichen der Seite: rounded-full bg-muted px-2 py-0.5 text-xs). Darunter die Einträge gruppiert in fester Reihenfolge new, changed, fixed; leere Gruppen entfallen; je Gruppe eine kleine gedämpfte Beschriftung (t('changelogKindNew'|'changelogKindChanged'|'changelogKindFixed')) und eine Aufzählung. Jede ältere Version als eigenes natives details-Element (geschlossen) mit summary = t('changelogRelease', …) und innen derselben Gruppierung. Text je Eintrag in der Sprache locale, Rückfall auf de. Datum mit Intl.DateTimeFormat(locale, Tag numerisch, Monat lang, Jahr numerisch, timeZone UTC) aus `${date}T00:00:00Z`, damit kein Tagesversatz entsteht. Texte nur als React-Textknoten, kein dangerouslySetInnerHTML, kein Markdown (T-261008-w5w-03).
Detailseite apps/web/src/app/(portal)/marketplace/[slug]/page.tsx: eigener Zustand releases (Vorgabe leeres Array) und eigener Effekt abhängig von slug, der `${API_URL}/modules/changelog/${encodeURIComponent(slug)}` mit credentials include (und dem x-tenant-id-Kopf wie beim Katalog) lädt; nur bei res.ok und wenn die Antwort ein Array von Objekten mit version (string), date (string) und changes (Array) ist, übernehmen; sonst und bei Fehler leer lassen, ohne Toast. Abschnitt unter der Status-/Aktivieren-Zeile einfügen und nur rendern, wenn releases nicht leer ist. Die Schnittstelle CatalogModule bleibt unverändert.
Übersetzungen im Namensraum marketplace, in de.json und en.json mit identischen Schlüsseln: changelogTitle (Änderungen / Changes), changelogCurrent (Aktuell / Current), changelogRelease (Version {version} vom {date} / Version {version}, {date}), changelogKindNew (Neu / New), changelogKindChanged (Geändert / Changed), changelogKindFixed (Behoben / Fixed). Echte Umlaute; keine Sonderzeichen wie Mittelpunkt oder Pfeil.
Tests detail.test.tsx: die next-intl-Attrappe um die neuen Schlüssel erweitern; alle fetch-Attrappen auf URL-abhängige Antworten umstellen (…/modules/catalog → Katalog, …/modules/changelog/… → Changelog oder leeres Array), damit die bestehenden Fälle unverändert grün bleiben; neue Fälle aus behavior ergänzen.
E2E-Skript .planning/quick/261008-w5w-modul-changelog-und-modulversionen-nacht/e2e/e2e-changelog.sh (eigenständig, Anmeldemuster aus e2e-lib.sh übernehmen, liest keine .env, Testwerte admin/admin123, API-Adresse localhost:3001, JSON-Auswertung per node -e): (1) ohne Anmeldung GET /modules/changelog/nextcloud-status → 401; (2) anmelden; (3) GET /modules/changelog/does-not-exist und /modules/changelog/__proto__ → 200 und genau []; (4) GET /modules/catalog laden; Slugs, die das Skript als Argumente bekommt, MÜSSEN einen nicht leeren Changelog haben; ohne Argumente gilt das für JEDEN Slug im Katalog; (5) für jeden Katalog-Eintrag mit nicht leerem Changelog muss die Katalog-Version gleich changelog[0].version sein; (6) bei Erfolg „e2e-changelog ok“ ausgeben, sonst Meldung und Exit 1.
Danach den Stack neu bauen (docker compose up -d --build api web — ein schlichtes up baut nicht neu), auf den Start der API warten (Log-Zeile „Nextcloud-Status module seeded in registry“) und das E2E-Skript mit dem Argument nextcloud-status ausführen. Nichts im Ordner gespraech-2026-11/ anfassen oder stagen. Commit mit Co-Authored-By-Zeile laut Projektnotiz.
</action>
<verify>
<automated>pnpm --filter @tessera/api exec vitest run src/module-registry && pnpm --filter @tessera/web exec vitest run marketplace src/messages && pnpm --filter @tessera/api exec tsc --noEmit && pnpm --filter @tessera/web exec tsc --noEmit && grep -q "latestVersion(NEXTCLOUD_STATUS_CHANGELOG)" apps/api/src/nextcloud-status/nextcloud-status.seed.ts && grep -q "changelog/:slug" apps/api/src/module-registry/module-registry.controller.ts && bash .planning/quick/261008-w5w-modul-changelog-und-modulversionen-nacht/e2e/e2e-changelog.sh nextcloud-status && echo "task1 ok"</automated>
</verify>
<done>Specs grün (API module-registry, Web marketplace und messages), beide tsc sauber; im neu gebauten Stack liefert GET /modules/changelog/nextcloud-status die zwei Versionen, der Katalog zeigt Nextcloud-Status 1.1.0, unbekannte Kennungen liefern [], ohne Anmeldung 401; die Detailseite rendert den Abschnitt (Komponententest). Commit erstellt.</done>
</task>
<task type="auto" tdd="true">
<name>Aufgabe 2: Historie aller übrigen neun Module nachtragen, Seeds umstellen, Vollständigkeits-Wächter scharf schalten</name>
<files>apps/api/src/cert-manager/cert-manager.changelog.ts, apps/api/src/cert-manager/cert-manager.seed.ts, apps/api/src/dkv/dkv.changelog.ts, apps/api/src/dkv/dkv.seed.ts, apps/api/src/domaincheck/domaincheck.changelog.ts, apps/api/src/domaincheck/domaincheck.seed.ts, apps/api/src/domains/domains.changelog.ts, apps/api/src/domains/domains.seed.ts, apps/api/src/handelsware-datev/handelsware-datev.changelog.ts, apps/api/src/handelsware-datev/handelsware-datev.seed.ts, apps/api/src/kantine-datev/kantine-datev.changelog.ts, apps/api/src/kantine-datev/kantine-datev.seed.ts, apps/api/src/nextcloud-files/nextcloud-files.changelog.ts, apps/api/src/nextcloud-files/nextcloud-files.seed.ts, apps/api/src/proxmox/proxmox.changelog.ts, apps/api/src/proxmox/proxmox.seed.ts, apps/api/src/tenders/tenders.changelog.ts, apps/api/src/tenders/tenders.seed.ts, apps/api/src/module-registry/module-changelog.registry.ts, apps/api/src/module-registry/module-changelog.spec.ts, CHANGELOG.md</files>
<behavior>
- Vollständigkeit: jeder per Dateisystem gefundene Seed-Slug hat einen Eintrag in MODULE_CHANGELOGS
- Keine Waisen: jeder Schlüssel in MODULE_CHANGELOGS ist ein gefundener Seed-Slug
- Für alle zehn Seeds gilt manifest.version === changelog[0].version (der Wächter aus Aufgabe 1 greift jetzt für alle)
- dkv-fleet: neueste Version mindestens 1.1.0 (compareSemver)
- domains und nextcloud-files: genau eine Version 1.0.0 vom 2026-10-08
</behavior>
<action>
Zuerst im Spec die beiden Vollständigkeitsfälle (jeder Seed hat Changelog, kein verwaister Changelog) sowie die dkv-Untergrenze und die Prüfung für domains und nextcloud-files ergänzen (rot), dann die Daten nachtragen.
Vorgehen je Modul (Ordner, Slug und Name siehe context). Modulpfade für git log: API-Ordner apps/api/src/<ordner>, Web-Seite apps/web/src/app/(portal)/modules/<slug>, dazu falls vorhanden apps/web/src/components/<name> (domains, nextcloud-files, nextcloud-status, proxmox), die Kachel apps/web/src/components/dashboard/widgets/<slug>-widget.tsx (proxmox), apps/web/src/lib/nextcloud-files-api.ts (nextcloud-files), für handelsware-datev und kantine-datev zusätzlich apps/api/src/accounting und apps/web/src/components/accounting. Für jedes Paar aufeinanderfolgender Tags (Reihenfolge und Daten siehe context) git log --format='%h %cs %s' VORHER..NACHHER -- Modulpfade ausführen, für Unveröffentlichtes v1.10.1..HEAD; zusätzlich den jeweiligen CHANGELOG.md-Abschnitt nach dem Modulnamen durchsuchen (Zertifikat, DKV, Domaincheck, Domains, Handelsware, Kantine, Dateien, Nextcloud-Status, Proxmox, Ausschreibung). Die Tag-Spanne entscheidet, zu welcher Tessera-Version eine Änderung gehört; CHANGELOG.md liefert Formulierungen und Änderungen, die nur in gemeinsamen Dateien (de.json) lagen. Bei unklaren Commit-Betreffs mit git show --stat bzw. dem Diff nachsehen.
Versionsregel (Vorgabe des Nutzers, wörtlich anwenden): 1.0.0 = Stand, in dem das Modul erstmals in einer Tessera-Version enthalten war, Datum = Datum dieser Tessera-Version; Einträge von 1.0.0 fassen in ein bis drei Neu-Punkten zusammen, was das Modul damals konnte (Quelle: CHANGELOG.md-Abschnitt der Erstaufnahme und Seed-Beschreibung), keine Einzel-Commits. Danach für jede Tessera-Version, in deren Spanne eine für Benutzer sichtbare Moduländerung liegt, genau ein Versionssprung: mindestens ein Neu-Eintrag → Minor (x.Y+1.0), sonst Patch (x.y.Z+1); Datum = Datum der Tessera-Version. Spannen nur mit Test-, Refactor-, Doku- oder Chore-Commits ohne sichtbare Wirkung erzeugen keine Version. Die Mosaik-Umstellung in v1.5.0 zählt als sichtbar und ergibt je betroffenem Modul einen Patch mit einem Geändert-Eintrag sinngemäß „Die Seiten des Moduls haben das neue Tessera-Aussehen“. Unveröffentlichte Änderungen (v1.10.1..HEAD) ergeben eine Version vom 2026-10-08. Major-Sprünge kommen nicht vor.
Sonderfälle: domains und nextcloud-files sind nie freigegeben → je genau 1.0.0 vom 2026-10-08; die Nachbesserungen (Prüfbefunde, Korrekturen) fließen in die Beschreibung ein, nicht als eigene Behoben-Einträge (Grundlage: CHANGELOG.md „Unveröffentlicht“, Neu-Punkte zu Domains bzw. Dateien, auf drei bis fünf Punkte verdichtet). handelsware-datev und kantine-datev: 1.0.0 vom 2026-10-06; die Freigabestufe „Verwalten“ ist Teil von 1.0.0; Fachbegriffe wie Mandantennummer möglichst vermeiden (zum Beispiel „die DATEV-Nummern und die Lohnart“). dkv-fleet: die bereits auf der Beta sichtbare 1.1.0 berücksichtigen — ergibt die Regel für die neueste (unveröffentlichte) Version eine Nummer kleiner als 1.1.0, wird diese neueste Version auf 1.1.0 gesetzt; sonst gilt die Regel. Den Satz „Modulversion 1.1.0.“ in der DKV-Zeile von CHANGELOG.md „Unveröffentlicht“ auf die tatsächliche neueste dkv-Version setzen (Satzform „Modulversion X.Y.Z.“ beibehalten). Den Eintrag zur Freigabestufe „Verwalten“ (v1.10.0, Commit c2ebc8d) bei dkv-fleet und proxmox als Geändert aufnehmen; Proxmox-Autostart-Warnung (873d15d) ist Neu → Minor.
Dateien: je Modul apps/api/src/<ordner>/<seed-name>.changelog.ts direkt neben der Seed-Datei (dkv.changelog.ts, tenders.changelog.ts usw.), Export <SLUG_IN_GROSSBUCHSTABEN_MIT_UNTERSTRICH>_CHANGELOG (CERT_MANAGER_CHANGELOG, DKV_FLEET_CHANGELOG, DOMAINCHECK_CHANGELOG, DOMAINS_CHANGELOG, HANDELSWARE_DATEV_CHANGELOG, KANTINE_DATEV_CHANGELOG, NEXTCLOUD_FILES_CHANGELOG, PROXMOX_CHANGELOG, TENDER_RADAR_CHANGELOG), typisiert mit ModuleChangelog, neueste Version zuerst, Aufbau wie nextcloud-status.changelog.ts aus Aufgabe 1. Einträge kurz (ein Satz, höchstens zwei), Alltagssprache, Nutzersicht, siezen, echte Umlaute auch in Kommentaren, keine Mandanten-/Lizenzbegriffe, en inhaltsgleich. Jede Seed-Datei: fest eingetragene Versionszeichenkette durch latestVersion(<…>_CHANGELOG) ersetzen. Alle neun im Register MODULE_CHANGELOGS eintragen (alphabetisch nach Slug).
In der SUMMARY je Modul eine Zeile „Slug: Versionen mit Datum“ und die Begründung jeder Minor/Patch-Entscheidung in einem Halbsatz festhalten, damit der Nutzer die Zuordnung nachvollziehen kann. Nichts im Ordner gespraech-2026-11/ anfassen oder stagen. Commit mit Co-Authored-By-Zeile.
</action>
<verify>
<automated>pnpm --filter @tessera/api exec vitest run src/module-registry && pnpm --filter @tessera/api exec tsc --noEmit && test -z "$(grep -nE "version: '[0-9]" apps/api/src/*/*.seed.ts)" && test "$(ls apps/api/src/*/*.changelog.ts | wc -l)" -eq "$(ls apps/api/src/*/*.seed.ts | wc -l)" && test "$(grep -l 'latestVersion(' apps/api/src/*/*.seed.ts | wc -l)" -eq 10 && V=$(grep -m1 -oP "version: '\K[0-9]+\.[0-9]+\.[0-9]+" apps/api/src/dkv/dkv.changelog.ts) && grep -q "Modulversion $V\." CHANGELOG.md && echo "task2 ok"</automated>
</verify>
<done>Zehn Changelog-Dateien, zehn Seeds lesen ihre Version per latestVersion, Register vollständig, Wächter (Format, Seed-Version, Vollständigkeit, keine Waisen, dkv ≥ 1.1.0, domains/nextcloud-files 1.0.0 vom 2026-10-08) grün, CHANGELOG.md-DKV-Zeile nennt die echte neueste dkv-Version, SUMMARY enthält die Versionsübersicht mit Begründungen. Commit erstellt.</done>
</task>
<task type="auto">
<name>Aufgabe 3: Doku und Prozess, CHANGELOG-Eintrag, volle Testläufe, Neubau, E2E über alle Module, Browserprüfung</name>
<files>docs/anleitung-entwicklung.md, docs/anleitung-betrieb.md, docs/anleitung-anwender.md, CHANGELOG.md</files>
<action>
Entwicklungsanleitung docs/anleitung-entwicklung.md: im Kapitel „Das Modulsystem“ direkt nach „### Registrierung“ einen neuen Abschnitt „### Modulversion und Modul-Changelog pflegen“ (kurz, ganze Sätze): wo der Changelog liegt (<ordner>/<seed-name>.changelog.ts neben der Seed-Datei, Typen in module-registry/module-changelog.ts, Register module-changelog.registry.ts); dass der Seed die Version ausschließlich per latestVersion liest und der Marktplatz die Einträge über GET /modules/changelog/:slug zeigt; die Regel (jede für Benutzer sichtbare Moduländerung bekommt einen Eintrag; Neu → Minor, nur Behebungen/Texte/Aussehen → Patch, Major nur bei grundlegendem Umbau; zwischen zwei Tessera-Freigaben höchstens ein Versionssprung je Modul — weitere Änderungen kommen in denselben, noch unveröffentlichten Eintrag, die Stufe wird bei Bedarf von Patch auf Minor angehoben; ein Eintrag gilt als unveröffentlicht, solange sein Datum nach dem Datum der letzten Tessera-Version in CHANGELOG.md liegt); Texte kurz, Nutzersicht, siezen, de und en; Checkliste für ein neues Modul (Changelog-Datei anlegen, im Register eintragen, Seed nutzt latestVersion); der Wächter module-changelog.spec.ts und was er prüft; warum es keine CI-Prüfung „Ordner geändert ohne Changelog“ gibt (Begründung aus dem Plan-Ziel) und welcher Prüfbefehl stattdessen vor jeder Freigabe läuft (git log --oneline <letzter-tag>..HEAD -- <Modulpfade> je Modul, Modulpfade wie in Aufgabe 2). Das Codebeispiel unter „### Registrierung“ so anpassen, dass die Versionszeile latestVersion(DOMAINCHECK_CHANGELOG) zeigt.
Betriebsanleitung docs/anleitung-betrieb.md, Kapitel 9 „Eine Version freigeben“, Schritt 1: ergänzen, dass vor dem Umbenennen geprüft wird, ob jedes seit dem letzten Tag geänderte Modul einen unveröffentlichten Changelog-Eintrag hat (Verweis auf den Abschnitt der Entwicklungsanleitung), und dass unveröffentlichte Modul-Einträge das Freigabedatum bekommen.
Anwenderhandbuch docs/anleitung-anwender.md, Kapitel „Marktplatz“: den Satz zur Detailseite um den Abschnitt „Änderungen“ ergänzen (was sich von Modulversion zu Modulversion geändert hat, neueste oben, ältere zum Aufklappen).
CHANGELOG.md „Unveröffentlicht“ → „Neu“: Eintrag in einfachen Worten, sinngemäß „Marktplatz: Die Detailseite jedes Moduls zeigt jetzt unter „Änderungen“, was sich von Modulversion zu Modulversion geändert hat – die neueste Version oben, ältere zum Aufklappen. Die Versionsnummern aller Module wurden dabei rückwirkend nachgetragen.“ Siezen, keine Mandanten-/Lizenzbegriffe.
Dann volle Testläufe beider Pakete und beide tsc. Stack neu bauen (docker compose up -d --build api web), auf API-Start warten, E2E-Skript ohne Argumente laufen lassen (jedes Katalog-Modul braucht nun einen Changelog, Katalog-Version = neueste Changelog-Version).
Browserprüfung per Playwright MCP gegen http://localhost:3000, angemeldet als admin, zuerst im Dunkelmodus (über den Theme-Knopf umschalten): Marktplatz-Übersicht (Versionen der Kacheln stimmen mit den Changelogs überein); Detailseite nextcloud-status (1.1.0 mit „Aktuell“ offen, 1.0.0 geschlossen, dann aufklappen); Detailseite tender-radar (längere Historie); Detailseite domains (nur eine Version, keine aufklappbaren älteren); eine Detailseite zusätzlich im Hellmodus; eine Detailseite mit englischer Spracheinstellung (Überschrift „Changes“, englische Einträge). Nur den gerenderten Seiteninhalt beurteilen, keine Messungen per fetch aus der Seite (Projektnotiz fetch-Falle). Bildschirmfotos nach .playwright-mcp/module-changelog/ mit den Namen t3-dark-marketplace.png, t3-dark-nextcloud-status.png, t3-dark-nextcloud-status-open.png, t3-dark-tender-radar.png, t3-dark-domains.png, t3-light-nextcloud-status.png, t3-dark-en.png. Auffälligkeiten (Abstände, Kontrast, abgeschnittene Texte) sofort beheben und erneut prüfen.
Nichts im Ordner gespraech-2026-11/ anfassen oder stagen. Nicht pushen (gebündeltes Pushen ist Projektpraxis). Commit mit Co-Authored-By-Zeile.
</action>
<verify>
<automated>pnpm --filter @tessera/api test && pnpm --filter @tessera/web test && pnpm --filter @tessera/api exec tsc --noEmit && pnpm --filter @tessera/web exec tsc --noEmit && grep -q "^### Modulversion und Modul-Changelog pflegen" docs/anleitung-entwicklung.md && grep -q "latestVersion(DOMAINCHECK_CHANGELOG)" docs/anleitung-entwicklung.md && grep -q "Changelog" docs/anleitung-betrieb.md && grep -q "Änderungen" docs/anleitung-anwender.md && awk '/^## Unveröffentlicht/,/^## 1\.10\.1/' CHANGELOG.md | grep -q "Marktplatz: Die Detailseite" && docker compose ps --status running --services | grep -qx api && docker compose ps --status running --services | grep -qx web && bash .planning/quick/261008-w5w-modul-changelog-und-modulversionen-nacht/e2e/e2e-changelog.sh && test "$(ls .playwright-mcp/module-changelog/t3-*.png 2>/dev/null | wc -l)" -ge 7 && echo "final gates ok"</automated>
</verify>
<done>Beide Testsuiten und tsc grün; drei Anleitungen und CHANGELOG.md ergänzt; neu gebauter Stack läuft; E2E über alle zehn Katalog-Module grün (jede Katalog-Version = neueste Changelog-Version); sieben Bildschirmfotos belegen Abschnitt, Aufklappen, Hell/Dunkel und Englisch. Commit erstellt, nicht gepusht.</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| Browser → API | Der Pfadparameter slug von GET /modules/changelog/:slug ist unvertrauenswürdige Eingabe |
| API → Browser | Changelog-Texte werden im Marktplatz angezeigt |
## STRIDE Threat Register
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|-----------|----------|-----------|----------|-------------|-----------------|
| T-261008-w5w-01 | Information Disclosure | GET /modules/changelog/:slug | low | accept | Nur statische, nicht schutzbedürftige Produkttexte; Route liegt hinter dem globalen JwtAuthGuard (E2E prüft 401 ohne Anmeldung), gleiche Sichtbarkeit wie /modules/catalog (T-03-03) |
| T-261008-w5w-02 | Tampering | getModuleChangelog(slug) | low | mitigate | Nachschlagen per ReadonlyMap statt Objekt-Index; '__proto__', 'constructor', 'toString' liefern [] — Spec und E2E prüfen das |
| T-261008-w5w-03 | Tampering (XSS) | ModuleChangelog.tsx | low | mitigate | Texte nur als React-Textknoten, kein dangerouslySetInnerHTML, kein Markdown; Antwort wird vor Übernahme auf Array-Form geprüft |
| T-261008-w5w-04 | Denial of Service | Routing unter /modules | medium | mitigate | Statisches erstes Segment changelog statt :slug/changelog, damit keine Modul-Route unter modules/<slug>/:id verschattet wird oder verschattet; E2E belegt 401 (Route gefunden) statt 404 |
| T-261008-w5w-SC | Tampering | npm/pip/cargo installs | low | accept | Dieser Plan installiert keine Pakete; kein Legitimitäts-Gate nötig |
</threat_model>
<verification>
- API-Spec module-changelog.spec.ts: Format, Seed-Version = neuester Eintrag, Vollständigkeit, keine Waisen, Ersatzschreibungen, Mandanten-/Lizenzbegriffe, Prototyp-Schlüssel
- Web: detail.test.tsx mit Changelog, leerer Liste, Fehlerantwort; umlaut-guard und de/en-Parität über src/messages
- Kein Seed enthält eine fest eingetragene Versionsnummer; zehn Changelog-Dateien für zehn Seeds
- Laufender Stack: E2E-Skript prüft Route, Schutz, leere Liste für unbekannte Kennungen und Katalog-Version = Changelog-Version für jedes Modul
- Browser: Abschnitt „Änderungen“ in Dunkel/Hell und Englisch, Aufklappen älterer Versionen
</verification>
<success_criteria>
- Marktplatz-Detailseite zeigt für alle zehn Module den Abschnitt „Änderungen“ (neueste oben, ältere einklappbar, Design Mosaik, gesiezt)
- Modulversion im Marktplatz = neueste Changelog-Version, für alle Module erzwungen durch Seed-Ableitung und Wächter-Test
- Historie nach Nutzerregel nachgetragen; dkv-fleet ≥ 1.1.0 und CHANGELOG.md-Zeile stimmig; domains und nextcloud-files 1.0.0 vom 2026-10-08
- Prozess in Entwicklungs- und Betriebsanleitung festgehalten, Anwenderhandbuch und CHANGELOG.md ergänzt
- Volle Testsuiten und tsc grün, Stack neu gebaut, E2E und Bildschirmfotos vorhanden
</success_criteria>
<output>
Create `.planning/quick/261008-w5w-modul-changelog-und-modulversionen-nacht/261008-w5w-SUMMARY.md` when done (inklusive Versionsübersicht je Modul mit Begründungen aus Aufgabe 2)
</output>
</content>
</invoke>
@@ -0,0 +1,112 @@
---
phase: 261008-w5w-modul-changelog-und-modulversionen-nacht
plan: 01
subsystem: module-registry, marketplace
tags: [changelog, modulversion, marketplace, waechter-test]
status: complete
completed: 2026-10-08
commits: 3
plan_head_before: 1d33990
plan_head_after: 4c14ec895ab08236b1e8a1238809035024ce4047
actuals:
tokens: 60000
tasks: 3
commits: 3
key-files:
created:
- apps/api/src/module-registry/module-changelog.ts
- apps/api/src/module-registry/module-changelog.registry.ts
- apps/api/src/module-registry/module-changelog.spec.ts
- apps/api/src/*/*.changelog.ts (10 Dateien)
- apps/web/src/app/(portal)/marketplace/components/ModuleChangelog.tsx
- .planning/quick/261008-w5w-modul-changelog-und-modulversionen-nacht/e2e/e2e-changelog.sh
modified:
- apps/api/src/*/*.seed.ts (10 Dateien)
- apps/api/src/module-registry/module-registry.controller.ts
- apps/web/src/app/(portal)/marketplace/[slug]/page.tsx
- apps/web/src/app/(portal)/marketplace/[slug]/detail.test.tsx
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
- docs/anleitung-entwicklung.md
- docs/anleitung-betrieb.md
- docs/anleitung-anwender.md
- CHANGELOG.md
decisions:
- "Auslieferung über GET /modules/changelog/:slug aus Code (Map), keine Datenbankspalte, keine Migration"
- "Keine CI-Prüfung Ordner-geändert-ohne-Changelog; stattdessen Wächter-Test plus Prüfbefehl in der Doku"
---
# Quick 261008-w5w: Modul-Changelog und Modulversionen nachgetragen
Jedes der zehn Module hat jetzt einen eigenen Changelog als einzige Quelle seiner Versionsnummer; der Marktplatz zeigt ihn auf der Detailseite als Abschnitt „Änderungen“, und ein Wächter-Test erzwingt die Übereinstimmung von Seed-Version und Changelog.
## Commits
- 79210d7 feat: Durchstich mit Nextcloud-Status (Typen, Register, Route, Wächter, Marktplatz-Abschnitt)
- f2bb5ff feat: Historie der übrigen neun Module, alle Seeds auf latestVersion, Vollständigkeits-Wächter
- 4c14ec8 docs: drei Anleitungen und CHANGELOG.md
## Versionsübersicht je Modul (mit Begründung)
Daten laut CHANGELOG.md-Überschriften der Tessera-Versionen.
- **cert-manager**: 1.0.0 (2026-09-15), 1.0.1 (2026-09-22), 1.0.2 (2026-09-28), 1.1.0 (2026-10-02)
- 1.0.0: im Tag v1.0.0 enthalten. 1.0.1 (v1.3.0): ZIP-Name übersetzt (Geändert) und Bedienhilfen für Tastatur/Bildschirmleser (Behoben), kein Neu, also Patch. 1.0.2 (v1.5.0): Mosaik-Umstellung, Patch. 1.1.0 (v1.9.2): neuer Reiter „Übersicht“ ist Neu, also Minor; Siezen und PFX-Hinweis aus CHANGELOG.md und Commit 90e2157 liegen im selben Eintrag.
- **dkv-fleet**: 1.0.0 (2026-09-15), 1.0.1 (2026-09-22), 1.0.2 (2026-09-28), 1.0.3 (2026-10-06), 1.1.0 (2026-10-08)
- 1.0.1 (v1.3.0): Löschdialog gegen Doppelauslösung gesperrt, Fahrzeugtabelle übersetzt (nur Behoben), Patch. 1.0.2 (v1.5.0): Mosaik. 1.0.3 (v1.10.0): Freigabestufe „Verwalten“ (Geändert, Commit c2ebc8d). Unveröffentlicht: Modulbeschreibung (Geändert) ergäbe nach Regel 1.0.4; wegen der auf der Beta bereits sichtbaren 1.1.0 auf 1.1.0 gesetzt (Sprung von 1.0.3 auf 1.1.0 ist bewusst). Die DKV-Zeile in CHANGELOG.md nannte schon „Modulversion 1.1.0.“, daher keine Textänderung nötig (Wächter/Prüfbefehl bestätigt die Gleichheit).
- **domaincheck**: 1.0.0 (2026-09-15), 1.0.1 (2026-09-28)
- Einzige sichtbare Änderung nach der Erstaufnahme ist die Mosaik-Umstellung (v1.5.0), Patch.
- **domains**: 1.0.0 (2026-10-08)
- Nie freigegeben; Nachbesserungen sind in die fünf Neu-Punkte eingeflossen.
- **handelsware-datev**: 1.0.0 (2026-10-06)
- Erstaufnahme in v1.10.0 (Freigabestufe „Verwalten“ gehört zu 1.0.0).
- **kantine-datev**: 1.0.0 (2026-10-06)
- Erstaufnahme in v1.10.0.
- **nextcloud-files**: 1.0.0 (2026-10-08)
- Nie freigegeben; die Prüf- und Korrekturrunde vom 08.10. ist in vier Neu-Punkte verdichtet.
- **nextcloud-status**: 1.0.0 (2026-10-06), 1.1.0 (2026-10-08)
- 1.1.0 unveröffentlicht: Suchfeld und http-Bildadresse sind Neu, also Minor.
- **proxmox**: 1.0.0 (2026-09-25), 1.0.1 (2026-09-28), 1.1.0 (2026-10-06)
- 1.0.0 = Tessera v1.4.0. 1.0.1 (v1.5.0): Mosaik und Dashboard-Kacheln, Patch. 1.1.0 (v1.10.0): Autostart-Warnung (873d15d) ist Neu, plus „Verwalten“ als Geändert, Minor.
- **tender-radar**: 1.0.0 (2026-09-15), 1.0.1 (2026-09-28)
- Die v1.3.0-Commits am Modul waren reine Lint-/Refactor-/Typ-Arbeiten ohne sichtbare Wirkung, daher keine Version. v1.5.0: Mosaik, Patch.
Letzte Versionen auf dem laufenden Stack (Katalog = neuester Changelog-Eintrag, per E2E bestätigt): cert-manager 1.1.0, dkv-fleet 1.1.0, domaincheck 1.0.1, domains 1.0.0, handelsware-datev 1.0.0, kantine-datev 1.0.0, nextcloud-files 1.0.0, nextcloud-status 1.1.0, proxmox 1.1.0, tender-radar 1.0.1.
## Tests
- API: `pnpm --filter @tessera/api test` 152 Dateien, 3036 Tests grün; `tsc --noEmit` sauber. Wächter `module-changelog.spec.ts` (75 Fälle: Format, Seed-Version, Vollständigkeit, keine Waisen, Prototyp-Schlüssel, Ersatzschreibungen, Mandanten-/Lizenzbegriffe, dkv >= 1.1.0, domains/nextcloud-files 1.0.0 vom 2026-10-08).
- Web: `pnpm --filter @tessera/web test` 144 Dateien, 1653 Tests grün (inklusive neuer Detailseiten-Fälle und umlaut-guard); `tsc --noEmit` sauber.
- E2E `e2e/e2e-changelog.sh` (Stack neu gebaut): 401 ohne Anmeldung, `[]` für does-not-exist/`__proto__`/constructor/toString, für alle zehn Katalog-Module Katalog-Version = neuester Changelog-Eintrag: „e2e-changelog ok“.
## Browserprüfung
Sieben Bildschirmfotos in `.playwright-mcp/module-changelog/` (git-ignoriert): t3-dark-marketplace, t3-dark-nextcloud-status, t3-dark-nextcloud-status-open, t3-dark-tender-radar, t3-dark-domains, t3-light-nextcloud-status, t3-dark-en. Beurteilt: Abschnitt „Änderungen“ in Dunkel und Hell, „Aktuell“-Abzeichen, ältere Version zugeklappt und aufgeklappt, domains ohne aufklappbare Version, Englisch („Changes“, englische Einträge, Datum „October 8, 2026“). Keine Auffälligkeiten bei Abständen, Kontrast oder abgeschnittenen Texten.
## Deviations from Plan
**1. [Rule 3 - Blocking] Browserprüfung per Playwright-Bibliothek statt Playwright-MCP-Werkzeug**
- Der Ausführende hat die MCP-Browserwerkzeuge nicht zur Verfügung. Stattdessen lief ein Node-Skript mit `playwright-core` aus dem npx-Cache und `/bin/chromium` gegen http://localhost:3000 (angemeldet als admin; Dunkel/Hell per localStorage-Schlüssel `theme` des next-themes statt Klick auf den Theme-Knopf; Englisch per Cookie NEXT_LOCALE=en). Das Skript liegt nur im Scratchpad, nicht im Repo. Gemessen wurde nur am gerenderten Inhalt, keine fetch-Messungen aus der Seite.
**2. [Hinweis, keine Abweichung im Ergebnis] Marktplatz-Kacheln zeigen keine Version**
- Der Plan sprach von „Versionen der Kacheln“ in der Übersicht; die Kacheln zeigen aber keine Versionsnummer (nur die Detailseite). Abgeglichen wurde daher die Katalog-Version (E2E) und die Versionszeile der Detailseite.
**3. Reihenfolge Test/Umsetzung in Aufgabe 1**
- Typen, Register und Route wurden vor dem Spec geschrieben; der Spec wurde danach vervollständigt. Ergebnis ist identisch, aber kein echter Rot-Lauf vorab.
**4. CHANGELOG.md-DKV-Zeile unverändert**
- Sie nennt bereits „Modulversion 1.1.0.“, entspricht dem neuesten dkv-Eintrag, kein Eingriff nötig.
Sonst: Plan wie geschrieben ausgeführt. Arbeit direkt auf main (laut Auftrag), nichts gepusht.
## Known Stubs
Keine.
## Threat Flags
Keine neuen. T-261008-w5w-02 (Map-Zugriff), -03 (nur Textknoten, Antwort wird geprüft) und -04 (statisches Segment, E2E: 401 statt 404) sind umgesetzt und per Test/E2E belegt.
## Self-Check: PASSED
Alle Dateien vorhanden (zehn *.changelog.ts, Register, Spec, Komponente, E2E-Skript, sieben PNG), Commits 79210d7, f2bb5ff, 4c14ec8 sind Vorfahren von HEAD.