Zum Inhalt springen

Changelog

aktuelle Version v1.4.3

Chronologische Dokumentation der Änderungen (neueste zuerst). Jede Zeile entspricht einem deployten Git-Commit auf main. Audit-Findings + gemeldete Bugs, die noch nicht gefixt sind, stehen als GitHub-Issue-Nummern dabei.

Versionierung: Semver über Git-Tags (vX.Y.Z). Veröffentlichte Versionen stehen unten mit ## vX.Y.Z-Überschrift; ältere Einträge (vor Einführung der Tags) sind nach Datum gruppiert. Diese Datei ist die Quelle der öffentlichen Seite /changelog.

v1.4.3 — 2026-09-09

Behoben

  • HTML-Codes in Artikel-Titeln: Titel aus WordPress zeigten Conversion Hero – Online Wiederkäufe sichern statt des Gedankenstrichs. WordPress liefert typografische Zeichen als HTML-Codes; die wurden unverändert übernommen. Betroffen waren 2.880 Titel über zehn Publikationen — alle sind korrigiert, und neue werden beim Abgleich richtig übernommen. Nebenbei behoben: eine Hilfsfunktion ersetzte solche Codes durch Leerzeichen, aus Tipps & Tricks wurde also Tipps Tricks.
  • Generierte Bilder von passwortgeschützten Seiten (#765): Bilder, die die Pipe erzeugt und nach WordPress hochgeladen hat, wurden in der Mediathek als „nicht ladbar" angezeigt. Ihre Adresse zeigt nach dem Hochladen auf WordPress — und liegt die Seite hinter einem Passwortschutz, kam auch hier eine Fehlermeldung statt des Bildes. Wird jetzt mit den hinterlegten Zugangsdaten geholt, wie die Vorschaubilder in der Artikel-Liste.

v1.4.2 — 2026-09-09

Behoben

  • Aufmacherbilder von passwortgeschützten Seiten (#765): Liegt eine WordPress-Seite hinter einem Passwort-Dialog des Webservers, sind auch ihre Bilder geschützt — der Browser schickt beim Laden eines Bildes keine Zugangsdaten mit und bekam eine Fehlermeldung statt des Bildes. Die Vorschaubilder blieben deshalb leer. Sie werden jetzt über den Server geholt, der die hinterlegten Zugangsdaten kennt. Nur für Seiten mit Passwortschutz — alle anderen laden weiter direkt.

v1.4.1 — 2026-09-09

Behoben

  • Filter und Tabs reagieren sofort (#776): Ein Klick auf ALLE/Beiträge/Seiten oder auf einen Kategorie-Filter änderte nur die Adresse — die Seite zeigte bis zur Antwort des Servers unverändert die alte Liste, ohne jedes Zeichen, dass der Klick angekommen war. Die Auswahl schaltet jetzt im selben Moment um, und ein Ladehinweis zeigt, dass gearbeitet wird.
  • Artikel-Liste deutlich schneller (#778): In der Datenbank stehen nur die Kennungen der Kategorien und Schlagwörter, nicht deren Namen — die wurden daher bei jedem Seitenaufbau von WordPress nachgeladen, mit Wartezeit, und bei jedem Filterklick erneut. Die Namen kommen jetzt beim WordPress- Abgleich mit und liegen in der eigenen Datenbank; die Liste fragt WordPress nur noch, wenn nie abgeglichen wurde. Die Abfrage selbst dauert 2,5 ms.
  • Kopfzeile verrutschte nach „Aus WordPress aktualisieren" (#777): Die Bestätigungsmeldung stand in derselben Zeile wie der Button und schob den Seitenkopf auseinander. Sie steht jetzt in einer eigenen Zeile.

v1.4.0 — 2026-09-09

Neu

  • Mitglieder entfernen und Einladungen zurückziehen (#766): Die Team-Verwaltung konnte bisher nur hinzufügen. Jetzt lässt sich pro Zeile ein Mitglied entfernen (der Zugang ist sofort weg, der Account bleibt bestehen) und eine offene Einladung zurückziehen — dabei wird der Einladungslink ungültig, nicht bloß unsichtbar. Zwei Sperren zum Schutz: niemand kann sich selbst entfernen, und der letzte Admin bleibt.
  • Sites hinter Passwortschutz anbindbar (#765): Liegt eine WordPress-Seite hinter einem Passwort-Dialog des Webservers (Staging-Boxen, Wartungsmodus), ließ sich sie bisher nicht verbinden — der Verbindungstest scheiterte an der Tür, bevor WordPress überhaupt gefragt wurde. Unter Einstellungen → WordPress lassen sich die Zugangsdaten der Tür jetzt getrennt vom WordPress-Zugang hinterlegen; die Anmeldung bei WordPress läuft dann über das Companion-Plugin.

Behoben

  • Quellen aus dem Themen-Explorer kamen im Compose-Bereich nicht an (#767): Zwei Drittel aller Quellen eines Themas wurden auf dem Weg stillschweigend verworfen — betroffen waren Verweise ohne eigene Adresse, also Bezüge auf eigene Artikel und Begründungen des Modells. Zudem standen die übergebenen Adressen nur im Eröffnungstext des Briefings und wurden nicht als Recherche-Vorgabe an die Erstellung weitergegeben. Beides behoben.
  • Irreführende Fehlermeldung bei gesperrten Seiten (#765): Ein 401 des Webservers wurde als WordPress-Anmeldefehler gemeldet und schickte damit zu den Zugangsdaten, an denen nichts falsch war. Die beiden Fälle werden jetzt unterschieden und benannt.
  • SEO-Felder erreichten Yoast/RankMath nicht (#743): Ohne Companion-Plugin nahm WordPress die SEO-Angaben stumm nicht an und antwortete trotzdem mit Erfolg. Das wird jetzt erkannt und protokolliert; die Veröffentlichung selbst bleibt davon unberührt.
  • Geplante und zur Prüfung vorgelegte Beiträge sahen wie Entwürfe aus (#743): Beim Abgleich mit WordPress wurden future, pending und private alle zu „Entwurf". Terminierte Beiträge erscheinen jetzt als „Geplant", vorgelegte als „In Prüfung".
  • Nächtlicher WordPress-Abgleich brach bei langsamen Seiten ab: Das Zeitlimit für das Abholen ganzer Beitragsseiten war zu knapp — bei mehreren Publikationen scheiterte der Abgleich jede Nacht. Limit angehoben.
  • Wissen & Fakten aufgeräumt (#718): Der Bereich stapelte sechs Blöcke untereinander. Ein doppelter Hinweis ist entfallen, „Per Chat erfassen" liegt jetzt dort, wo auch Dateien hinzugefügt werden.

v1.3.1 — 2026-09-03

Behoben

  • Translate nutzte veraltete Quellversion (#762/#763): Der Editor speicherte bei manuellen Änderungen nur die HTML-Fassung, nicht die Markdown-Fassung — Übersetzungen basierten dadurch auf einem alten Stand, obwohl online schon die überarbeitete Version stand. Beide Fassungen werden jetzt beim Speichern konsistent gehalten.
  • Interne Verlinkung bei veröffentlichten Beiträgen (#761): Gleiche Ursache — die Verlinkung suchte im veralteten Text und fand nichts. Mit dem Fix greift sie auch bei veröffentlichten Beiträgen.
  • KI-„Denk"-Text im Änderungsvorschlag (#760): Interne Reasoning-Blöcke mancher Modelle wurden im Editor-Vorschlag angezeigt. Werden jetzt zentral herausgefiltert.
  • Bild-Backfill-Werkzeug (#746): Zwei Bugs im Wartungsskript korrigiert (Rechte-Kontext + Ergebnis-Auslesen); tote Alt-Bild-URLs werden nun korrekt erkannt.

v1.3.0 — 2026-09-02

Neu

  • Öffentliche Changelog-Seite (/changelog): diese Übersicht ist jetzt ohne Login unter content-pipe.calluna.ai/changelog erreichbar. Statisch zur Build-Zeit aus dieser Datei gerendert, mit Anzeige der aktuellen Version. Versionsmanagement per Semver + Git-Tags.

2026-09-01

Deployed auf Prod (content-pipe.calluna.ai)

  • CI-Lint-Fix (fix(ci)): <a><Link> in LibraryLanguageSetting — behob den chronisch roten CI-validate-Job (no-html-link-for-pages-Error).
  • Translate: Versionshistorie + Rollback (#754) — spiegelt die Artikel- Versionierung auf translate.translations. Migration 0065 (translation_versions, Voll-Snapshot title/content/metadata/status/ccqs, FORCE RLS im 0055-Muster, GRANTs an content_pipe_rt für #738). Kanonischer Writer src/lib/translate/versioning.ts; Snapshots bei generate/translate/ edit/fix_note/rollback (Baseline v1 bei erster Generierung); Rollback-Route (Voll-Restore, append-only, 30/h); Versions-List/Detail-API; UI TranslationVersionsPanel (Label + Actor, Diff gegen Vorgänger). Von einem Implementierungs-Agenten gebaut, Migration/Rollback reviewt, 170 Tests grün.
  • #734 Translate-Retry-Doppelkosten: translateQueue attempts=1 (statt Default 3). Ein Job fährt die nicht-resumable LLM-Pipeline; BullMQ-Retry zahlte Spend 2–3× + konnte Auto-Publish doppeln. callLLM retryt transiente Fehler eh intern (#537/#493).
  • Translate SEO-Suggest-Guard: 409 wenn Übersetzungstext leer (statt verschwendetem LLM-Call + irreführender „Keine Kandidaten").

Audit-Batch (4 parallele Agenten, gebündelt deployed, e5621c9)

  • #741 Cast-Guards: CASE-Guard (regex) an 8 Runtime-Cast-Sites — malformed/ leerer metadata.wp.cmsPostId/date-Wert wird NULL statt 22P02-Throw (blockte Writes / 500te Reads über alle Tenant-Rows). Follow-up: Index-Expression in 0040.
  • #736 Entitlement-Gate: requireInsightTenant gated 11 Insight/Trends-APIs (DataForSEO/LLM-Budget) — nicht-berechtigte Tenants können sie nicht mehr direkt aufrufen (CLAUDE.md-Prinzip 7).
  • #750 Übersetzte Kategorien/Tags: Term-Namen → Zielsprache (gecacht) + im Editor angezeigt (Label + Original klein); Cross-Domain-Publish mappt auf Ziel-WP-Term-IDs (find-or-create); same_site = ID-Erhalt.
  • #740 Web-Search-Budget: Suchgebühr fließt jetzt in total_cost_centscheckBudget zählt sie mit (unterzählte sie vorher).

Sequenzieller Deploy (App→Worker) nötig — paralleler Doppel-Build OOM'te den Build-Container (23 GB Box, zwei gleichzeitige next build = Speicher-Spike).

  • #749 Wasserzeichen für WP-Mediathek-Bilder: neuer Endpoint POST /api/cms/media/[id]/label — lädt die WP-Media-Bytes (SSRF-safe via fetchMediaById + safeFetch), rendert das EU-Icon (sharp) rein und lädt es als NEUES WP-Medium hoch (Original unangetastet). Lightbox-„Gekennzeichnete Kopie erstellen" für WP-Bilder (one-shot, kein Toggle). Rate-Limit 30/h.

Bug-Batch (7 parallele Agenten, gebündelt deployed, 3367189)

  • #744 GSC-Admin-Liste: gruppiert nach Domain wie die Publikationsliste (statt pro-Tenant/aktiv-only/nach Name) — groupPublications.
  • #745 Kategorie-Namen: Browser-User-Agent im WP-Taxonomy-Fetch (reduziert WAF-403) + UI-Fallback „Kategorie #N" statt roher Zahl.
  • #747 Trends-Duplikate: ON-CONFLICT-Upsert + DISTINCT-Anzeige + Migration 0066 (Unique-Index, Dedup bestehender Rows, content_pipe_rt-GRANTs).
  • #748 „eingeladen"-Geist: Pending-Invites von bereits-Mitgliedern werden in der Team-Liste ausgeblendet.
  • #752 Translate-QA: nur echte behebbare Fehler in der Fix-Liste (Lob + quellen-bedingt raus) + Trunkierungs-Längen-Ratio-Guard. Score unverändert.
  • #753 UX: „Besprechen"-Panel scrollt beim Öffnen in den Sichtbereich.
  • #737 Rollback-Datenverlust: Text-Rollback nutzt /rollback (Voll-Snapshot inkl. contentHtml) → manuelle Formatierung bleibt erhalten. Follow-up: HTML→MD beim Editor-Save.

Wave-1-Batch (5 parallele Agenten, gebündelt deployed, b7bc6bf)

  • #756 Publish→Entwurf: 10min-Publish-Grace verhindert, dass der Status-Sync einen frisch publizierten Artikel auf draft zurücksetzt (WP-Read-Lag). →#757.
  • #738 GRANTs: Migration 0067 macht content_pipe_rt self-sufficient (public+translate, inkl. ALTER DEFAULT PRIVILEGES) — schließt die 42501-Klasse.
  • #739 CCQS-Scorer: hasProperNounSignal statt kaputter Regex (dt. Großschreibung) → concreteness/engagementHook diskriminieren wieder (Scores verschieben sich bei künftigen Bewertungen; Gate unverändert).
  • #731 Brand-Timeout: 45s Per-Call-Timeout auf /api/brand/chat + writing-chat + sauberer 504. →#758.
  • #664 Halluzinierte Statistiken: Seed-Prompt-Regel + Headline-Detektor (Slop-Weakness, Score 0). Live-DB-Prompt braucht die Regel noch via Admin.

Wave-2-Batch (4 parallele Agenten, gebündelt deployed, e77998c)

  • #735 Publish-TX: Route in 3 Phasen (Read-TX → WP-I/O ohne offene TX → Write-TX) + 20s-Timeouts → keine Pool-Exhaustion durch hängende WP-Hosts.
  • #742 Feed-Discovery: nackte Domain → robots.txt/<link rel=alternate>/ Standard-Pfade automatisch entdecken + als Feed ingesten.
  • #730 lokale-Edits-Clobber: WP-Sync überschreibt lokalen Content nicht mehr, wenn articles.updatedAt neuer als WP modified_gmt.
  • #683 unvollständige Übersetzung: input-skaliertes maxTokens + Completeness- Guard (finishReason/Ratio → Retry → status failed statt Silent-Publish).

#733 Image-Jobs → BullMQ (live, Worker→App)

Image-Generierung als echter BullMQ-Job (image-jobs-Queue + Worker-Consumer, conc. 2) statt fire-and-forget im Web-Prozess. Idempotenz (decideImageJobStart, kein Doppel-Charge), Reaper (5min-Tick, kind-scoped, 15min) gegen verwaiste running-Rows. Deploy-sicher (Job überlebt in Redis).

Wave-3-Batch (4 parallele Agenten, gebündelt deployed, 4cd341f)

  • #751 Translate-Speed: seo∥quality parallel + seo-Modell gpt-5-mini→ claude-haiku-4-5 (non-reasoning) + Config-Flags TSQS_BACK_TRANSLATE/CROSS_EXAM (default on) → kritischer Pfad 5→~4 Latenzen; off collapsed TSQS 3→1.
  • #757 pages-Status: fetchPostStatuses liest posts UND pages → publizierte Seiten nicht mehr fälschlich als „aus WP gelöscht".
  • #758 Chat-Timeouts: 45s + 504 auf voice-chat/sources-chat/seo-chat/ prompt-chat (Web-Search-Chats bei 180s).
  • #652 Tracing: rewrite + onboarding-v2 tracen mit tenantId; Prompt-Caching + Modell-Drift geprüft = kein Change nötig.

Erkenntnisse / offen

  • error-watcher existiert bereits (src/worker/errorWatcher.ts, alle 6h): scannt audit_log-Cluster, filed GitHub-Issues + Digest-Mail — gated auf GITHUB_TOKEN + GITHUB_REPO im Worker-Env. Deckt den Wunsch „Error-Logs regelmäßig → Issues" ab; nur die zwei Env-Vars fehlen ggf.
  • Social-Prod-Embed (#755): Runbook + fertige Traefik-Prod-Route hinterlegt; gated auf embedded Prod-App-Klon (Prod-Secrets). Option A verworfen (bräuchte CP-Auth-Cookie auf .calluna.ai).

2026-08-31

Deployed auf Prod (content-pipe.calluna.ai)

  • EU-KI-Kennzeichnung für Bilder (Mediathek). Offizielle EU-Icons (None/AI/AI Generated/AI Modified) werden per sharp nativ ins Bild komponiert (unten rechts, Auto-Kontrast). Original bleibt erhalten (images.ai_label, reversibel), gerendert wird beim Ausliefern (/raw, Redis-Cache pro Label) und beim WP-Upload (fetchBytes). Migration 0063. Doku: siehe CLAUDE.md → Stack → Bilder.
  • Library-Ladezeit-Fix. loadTaxonomy cachte fehlgeschlagene WP-Taxonomy- Abrufe nie → jeder Library-Load lief bis 8s in den WP-Timeout. Jetzt 90s- Negativ-Cache (Backoff) + Timeout 8s→5s.
  • Beitragsbild-Save-Fix. featuredImageUrl per z.string().url() lehnte die relative Pipe-Form (/api/images/<id>/raw) ab → „Fehler beim Speichern". Validierung akzeptiert jetzt absolute URL | data:image | /api/images//raw.
  • Versionierungs-Überarbeitung (Migration 0064):
    • article_versions.snapshot jsonb = VOLLER Zustand (title/body/metadata inkl. WP-Identität+SEO+OG, status, ccqsBreakdown). Rollback stellt jetzt ALLES her.
    • Kanonischer Writer src/lib/articles/versioning.ts ersetzt die 4 kopierten Insert-Implementierungen; Cap 10→100.
    • Coverage-Lücken geschlossen: WP-Sync sichert lokale Fassung VOR Overwrite, Soft-Delete + Pipeline-Baseline (v1) + Hero-Image-Worker versionieren jetzt.
    • UI: lesbares Label + Actor (Nutzer/KI/Pipeline), Diff = Version gegen VORGÄNGER statt gegen aktuellste. Audit: docs/audit-artikel-versionierung.md.
  • SEO-Titel-Konflikt-Fix. Client baselte die Concurrency-Prüfung auf der eigenen Wall-Clock → bei Clock-Skew falscher „jemand anderes hat geändert". PATCH gibt jetzt den echten updatedAt zurück, Client nutzt ihn.
  • Radar-Quelle-Löschen-Fix. DELETE prunte nur documents, nie workspace_settings.data.radarSources → noch-nicht-gecrawlte Feeds unlöschbar.
  • Azure-SAS-Bilder-Fix. Alte DALL·E-URLs (24h-SAS) verfielen. Guard lädt temporäre http-Provider-URLs sofort als permanente data:-URL; /raw-Proxy redirectet nicht mehr auf tote Upstream-URLs (sauberer 404). Backfill der Alt-Rows offen → #746.
  • SSRF-Fix (Sicherheit). ensureFeaturedImage nutzte rohes fetch auf die tenant-kontrollierte siteUrl und schickte das WP-App-Passwort ungeschützt → SSRF + Credential-Exfil. Jetzt safeFetch (IP-Pin, DNS-Rebinding-Schutz).
  • #732 IP-Range-Fix. isPrivateIPv4 blockte via a===192 && b===0 das ganze 192.0.0.0/16 statt nur der reservierten /24 → öffentliche Ranges (Automattic 192.0.78.x) fälschlich als privat → Sitemaps nicht hinzufügbar.
  • Publish-Credential-orderBy-Fix. Publish griff per bare .limit(1) evtl. eine token-/username-lose Alt-Row → 401 gegen Front-Door-Sites. Gleiche Ordnung wie loadWordPressCreds.
  • Translate SEO-Suggest-Guard. Keyword-Kandidaten ohne generierten Übersetzungstext → klarer 409 statt verschwendetem LLM-Call + irreführender „Keine Kandidaten"-Meldung.

Multi-Agenten-Audit (7 Agenten)

Security / Secrets / IDOR / Session-Guards = clean. Worker / WP / Pipeline / DB / API = ~20 Findings → als Issues erfasst.

GitHub-Issues angelegt

  • Critical: #733 (Image-Jobs fire-and-forget, Deploy-Verlust), #734 (Translate-Retry-Doppelkosten).
  • High: #735 (Publish-TX/Pool-Exhaustion), #736 (Insight/Trends ohne Entitlement-Gate), #737 (Editor speichert kein contentMd — Root-Cause #665/#730), #738 (GRANT-Coverage content_pipe_rt), #739 (CCQS-Scorer auf Deutsch inert).
  • Med-High: #740 (Web-Search-Budget), #741 (Cast-Guards 22P02).
  • Medium (gebündelt): #743.
  • Gemeldete Bugs: #744 (GSC-Liste), #745 (yogamitlara-Kategorien), #746 (Azure-Backfill), #747 (Trends-Duplikate), #748 (stadtlandmama „eingeladen").
  • Features/Perf: #742 (Feed-Auto-Discovery), #749 (Wasserzeichen für WP-Bilder), #750 (Translate-Taxonomie-Anzeige), #751 (Translate-Speedup).
  • Geschlossen: #732 (IP-Range, live). Kommentiert: #665, #730 → #737.