Commit graph

30 commits

Author SHA1 Message Date
6f6cb13f2e docs: Audit-Protokoll, KI-Kennzeichnung & Release-Notizen
- dev/optimize/optimize-14-07-2026.md: Security-/Code-Audit inkl.
  Fix-Protokoll (Befunde gegen den Code verifiziert).
- docs/weiteres/KI-Kennzeichnung.md, Pm Tracken.md, Decision-Updates und
  Release-/Entwicklungsplan aktualisiert.

Hinweis: Der Audit-Bericht enthält keine echten Geheimnisse (nur die
öffentlichen Key-Präfixe), aber eine vollständige Befundübersicht.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:50:41 +00:00
4b7403bd4e Stripe Checkout: automatic_tax aktiviert (USt fehlte in der Session)
Cashier::calculateTaxes() greift nur bei direkter Abo-Erstellung, nicht
bei Checkout-Sessions — Stripe zeigte darum nur den Nettopreis
(QA-Befund 07.07.). Session-Optionen setzen jetzt automatic_tax +
tax_id_collection; Ad-hoc-Buchungen (Credits, Depublikation) laufen
statt ueber checkoutCharge ueber price_data mit tax_behavior=exclusive,
da automatic_tax das verlangt. Stripe Tax im Testmode eingerichtet
(Origin Bielefeld, DE-Registrierung); Live-Schritt in WS-7 ergaenzt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:25:28 +00:00
5d199f0130 Rechnungsadressen der Bestandskunden aus dem Legacy-Archiv uebernehmen
Befund 06.07.: Der MAN-Rechnungslauf ueberspringt Vereinbarungen ohne
Rechnungsadresse — der Bestandsschutz laeuft dann am Periodenende faktisch
aus. Der Grandfather-Import nahm die Adressen bisher nicht mit, weil die
Altportale sie nur als Freitext-Blob fuehren.

- legacy:import-billing-addresses: uebernimmt Adressen der grandfathered
  Kunden aus der Quell-Rechnung im Archiv (pdf_payload.billing_address),
  nie ueberschreibend, mit Dry-Run und Report der manuell nachzupflegenden
  Faelle (leere/unparsebare Blobs, unbekannte Laender)
- LegacyAddressParser: Best-Effort-Strukturierung der Blobs (mehrzeilig,
  kommasepariert, CH-PLZ-Praefix, Firmen-/Zusatzzeilen); raet nie
- Laenderaufloesung ueber die country-Tabellen der Legacy-Verbindungen
- config/countries.php: CY ergaenzt (reale Bestandskunden aus Zypern)
- WS-7- und QA-Checkliste: Import-Schritt nach dem Grandfathering

Lokal: 11 von 21 Bestandskunden importiert, 9 im Report (7 leere Blobs);
MAN-Lauf rechnet zuvor blockierte Vereinbarungen jetzt ab.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 12:19:50 +00:00
616b7847d4 Uebernahme bestehender Legacy-API-Integrationen (Keys, Auth, Pfade)
Bestehende Kunden-Integrationen der Altportale laufen nach dem Relaunch
weiter, ohne dass Kunden etwas umstellen muessen:

1. legacy:import-api-keys uebernimmt die api_keys aus den Legacy-DBs
   (sf_guard_user_profile) als Sanctum-Tokens mit identischem Secret
   (Sanctum loest Tokens ohne id|-Praefix per sha256-Hash auf) — nur
   fuer berechtigte Nutzer (aktiver Zahlungsstatus/Bestandsschutz,
   ApiAccessEligibilityService); idempotent, mit Dry-Run. Probe gegen
   die lokalen Snapshots: 406 Keys wuerden uebernommen.
2. Die Auth-Middleware uebersetzt die alten Uebergabeformen (X-ApiKey-
   Header, api_key-Parameter) fuer gueltige Keys in Bearer; unbekannte
   Keys erhalten weiterhin 410 mit Migrationshinweis.
3. Die dokumentierten /service/...-Pfade der Alt-API sind als Aliasse
   auf die v1-Controller gelegt (pressreleases inkl. Bilder, companies
   lesend); nicht uebernommene Alt-Endpoints (Pressemappen/Kontakte
   anlegen) antworten 410 mit Hinweis auf Kundenkonto und neue Doku.

API-Seite + OpenAPI entsprechend aktualisiert; Go-Live-Checkliste um den
Import-Schritt (nach dem Grandfathering) ergaenzt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 11:55:22 +00:00
c54c6943b7 Ablehnungskategorien live aus der DB (rejection_categories)
/richtlinien rendert jetzt alle aktiven Kategorien aus der neuen
rejection_categories-Tabelle (stabiler code als Anker, public_label/desc,
optionale Beispiele) statt der statischen K1-K6-Liste. Kategorien werden
nie geloescht, nur deaktiviert; neue Kategorien erscheinen ohne
Textaenderung und ohne neue AGB-Version (AGB par. 7 Abs. 3 verweist nicht
abschliessend). Seeder legt K1-K6 idempotent an; Versionszeile der Seite
kommt aus legal_documents. Go-Live-Checkliste um beide Seeder ergaenzt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 09:25:16 +00:00
b90e59a383 Umami-Webanalyse eingebaut, bis zum Go-Live deaktiviert
Selbst gehostetes Umami (sys.adametz.media) je Brand: Website-IDs aus
dev/release/umami.md in config/domains.php, Snippet via x-web.umami im
web-master-Layout auf allen oeffentlichen Seiten der drei Domains.
UMAMI_ENABLED=false haelt es aus, bis die Webseiten live gehen
(User-Vorgabe 06.07.; Go-Live-Checkliste WS-7 ergaenzt). Damit stimmt
Datenschutz Abschnitt 5 mit dem Code ueberein. User bestaetigt ausserdem:
Log-/Backup-Fristen und Stripe-Entitaet passen wie eingetragen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 08:56:14 +00:00
39f0af7d0b Doku: Launch-Vorbereitung 18.06. (Status-Widget, WS-8, i18n, Paket-Vorteile)
- Decision-Update: neuer Abschnitt 7 "Launch-Vorbereitung (Stand 18.06.2026)"
  dokumentiert Status-Widget, WS-8-Optimierungen, Paket-Vorteile in der DB,
  i18n-Readiness (Default-Locale de, Views __()-gewrappt, EN-Inhalt bewusst
  spaeter) sowie den Editor-Umbruch-Fix. End-to-End-QA als naechster Schritt.
- WS-7-Checkliste: add_benefits_to_plans_table in die Migrations-Liste
  aufgenommen (APP_LOCALE=de stand bereits drin).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 17:04:17 +00:00
58b427fcd0 i18n: Default-Locale auf Deutsch umstellen (Basis fuer EN-Umschaltung)
APP_LOCALE/APP_FALLBACK_LOCALE auf 'de'. Das Backend nutzt durchgaengig
__('Deutscher Text') als Schluessel; mit Default-Locale 'en' wurden zwar
(mangels en.json) ebenfalls die deutschen Schluessel ausgegeben, aber eine
spaeter ergaenzte en.json haette die App bei Locale 'en' ungewollt teilweise
auf Englisch umgestellt. Mit 'de' rendert Deutsch nativ und 'en' wird zum
bewussten Umschalter. Frontend bleibt unveraendert (URL-Prefix /de|/en via
SetEdition + strukturierte lang/de|en/*.php-Keys).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 16:31:55 +00:00
82abdf6bd6 Doku: Umsetzungsstand der Credit-Oekonomie im Decision-Update
Abschnitt 6 'Umsetzungsstand 17.06.2026': Fundament (Wallet/Ledger/Tier/Topup),
Launch-Funktionen (Extra-PM/Boost/Nachweis/UI/Gate), Phase-2-vorbereitet
(Pruefzaehler, Pfade C/D/G), offene Punkte. Nachzug zu dd5a937 (Dateiname
mit NFD-Umlaut wurde beim ersten Commit verfehlt).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:02:24 +00:00
dd5a937b1b Doku: Credit-Oekonomie in WS-7-Checkliste + Umsetzungsstand im Decision-Update
- WS-7: Credit-Migrationen (wallets/transactions/review_checks/boosts/topups)
  in die Pflichtliste; Hinweis dass Credit-Pakete keine Stripe-Preis-IDs
  brauchen (checkoutCharge, config/credits.php); Webhook erfuellt credit_topup_id
  idempotent; Post-Deploy-Checks fuer Wallet-Topup + Gate-Datenschutz
- Decision-Update: Abschnitt 'Umsetzungsstand 17.06.2026' (Fundament,
  Launch-Funktionen, Phase-2-vorbereitet, offene Punkte)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:01:24 +00:00
a2ff47e44e WS-7: Live-Deployment-Checkliste + WS-6/WS-7 als erledigt dokumentiert
Kompakte Go-Live-Checkliste (Live-.env, Migrationen, einmalige Setups,
Stripe-Webhook, Cache-Warmup, Scheduler/Worker, Post-Deploy-Kontrollen).
WS-6 (Auth/Verifizierung/Google) und WS-7 im Detailplan als erledigt
markiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 13:32:35 +00:00
a0547208d3 WS-5: Buchungs-Gate launch-ready – proaktiver Dashboard-Hinweis
Das Abo-/Bestandsschutz-Gate (User::hasActiveBooking, BookingRequiredException,
Submit-Modal, API 402/422) war bereits implementiert und getestet. Ergänzt wird
die proaktive Block-UX:

- Kunden-Dashboard zeigt bei scharfem Gate (billing.enforce_booking=true) und
  fehlender aktiver Buchung einen Banner "Buchung erforderlich, um zu
  veröffentlichen" mit Link zur Buchungsseite. Bestandskunden (grandfathered)
  sehen den Hinweis nicht; bei offenem Gate bleibt er unsichtbar.
- Tests: Banner aus (Gate offen) / an (Gate scharf, keine Buchung) /
  Ausnahme für grandfathered.

Launch-Flip bleibt env-gesteuert (BILLING_ENFORCE_BOOKING), Dev-Default false –
.env.example und Detailplan (WS-5 ✅) dokumentieren den Schalter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 16:37:16 +00:00
be7d1799a5 WS-4: Bestandsschutz-Abrechnung – gekoppelte Kündigung + Admin-Sichtbarkeit
M1 (portalübergreifend) und M5 (04:30-Worker) verifiziert; M2 + M3 umgesetzt.

- M2 (Entscheidung: getrennte Rechnungen, gekoppelte Kündigung): neuer
  LegacySubscriptionService::cancelBundleFor() kündigt das gesamte
  Bestandsschutz-Bündel eines Kunden gemeinsam – keine Einzelkündigung. Kein
  Rechnungs-Schema-Umbau (jede Kondition behält ihre MAN-Rechnung).
- M3: Admin-Payments-Ansicht zeigt eine "Bestandsschutz-Posten"-Tabelle
  (Badge, Portal, Netto, nächste Fälligkeit, "Bündel (N)") + Bündel-Kündigung
  mit Bestätigungsmodal.
- Tests: tests/Feature/Billing/LegacyBundleTest.php (M1 cross-portal, M2 Bündel-
  Kündigung + Gate, M3 Admin-Liste + Kündigung). Detailplan WS-4 dokumentiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 15:20:18 +00:00
6668f492ad WS-3 abgeschlossen dokumentiert: B abgedeckt, A nach Phase 2 verschoben
E/F/Melden/Queue erledigt (95007da); B über WS-2-Firmen-Scope abgedeckt;
A (Tippfehler an veröffentlichten PMs) bewusst nach Phase 2/Pfad C zurückgestellt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 15:03:16 +00:00
95007da826 WS-3: Recht & Compliance – Rechts-Kern (DSGVO/Persönlichkeitsrecht/Melden + Queue)
Launch-pflichtiger Compliance-Slice: öffentliche Anfrage zu einer PM speist eine
manuelle Admin-Queue (keine KI).

- Migration legal_requests + Model + Enums (Type: dsgvo/personal_rights/report,
  Status: open/in_progress/resolved/rejected) + Factory.
- Öffentliches Formular /release/{slug}/rechtliches (LegalRequestController +
  web/legal-request.blade.php): typ-abhängiger Hinweistext (Alpine), E-Mail bei
  DSGVO/Persönlichkeitsrecht erforderlich, zwei versteckte Honeypot-Felder,
  Rate-Limit + Bremse "1 offene Anfrage pro PM/Typ". Regeltexte als Entwurf mit
  TODO für rechtliche Finalisierung markiert.
- Routen bewusst in eigener routes/legal.php (entkoppelt vom laufenden Web-Umbau),
  host-agnostisch via domains.php eingebunden.
- Admin-Bereich "Recht & Compliance": Sidebar-Nav mit Offen-Zähler, Volt-Queue
  index/show (in Bearbeitung/erledigt/abgelehnt/wieder öffnen + interne Notiz).
- Tests: je Typ, Honeypots (Dataset), Bremse, Admin-Queue + Status-Übergänge.
- Doku: Detailplan WS-3-Status + Deployment-Migrationsreihenfolge ergänzt.

Hinweis: Der "Melden"-/E&F-Button auf der PM-Detailseite (release-detail.blade.php)
wird mit dem separaten Web-Frontend-Commit verdrahtet; Ziel ist legal-request.create.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 14:20:05 +00:00
2a622044f3 WS-6: Google-Redirect-URI auf Live-Domain pressekonto.com korrigiert
Live-Portal-Domain ist pressekonto.com (nicht .de) – Callback-URL in
.env.example und Deployment-Doku entsprechend gesetzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 13:33:07 +00:00
fe10adb657 WS-6: Google-Redirect-URI klargestellt (Portal-Domain, .de) + lokaler Testhinweis
- .env.example: GOOGLE_REDIRECT_URI explizit auf die Portal-Callback-URL statt
  ${APP_URL}; Hinweis, dass Google keine .test-Domains akzeptiert.
- Deployment-Doku (§6c): exakte Prod-Callback-URL (pressekonto.de, nicht .com),
  lokaler Round-Trip via localhost/https-Tunnel, sonst über gemockte Tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 13:29:29 +00:00
6c6b9e0f26 WS-2: Magic-Link für Firmen & Pressekontakte vereinheitlicht + Schreibzugriff
Magic-Link und Pressekontakt-Zugang zu einer Seite (/anmeldelink) zusammengeführt;
altes Login-Modal entfernt, /pressekontakt-zugang leitet weiter.

- ContactAccessService deckt jetzt Firmen-E-Mail UND Pressekontakt-E-Mail ab,
  portalübergreifend (ohne PortalScope). Eine E-Mail mehrfach hinterlegt → genau
  ein Account, dem alle Firmen + Kontakte zugeordnet werden.
- Zugeordnete Firmen erhalten Pivot-Rolle 'responsible' (Schreibzugriff auf
  Stammdaten, Kontakte, Pressemitteilungen) statt nur 'member'; bestehende
  Lese-Pivots werden hochgestuft, Owner bleiben unangetastet.
- Neuer Login-Listener (SyncCompanyMembershipsOnLogin) frischt die Zuordnungen
  bei JEDEM Login (Magic-Link, Passwort, Google) auf – auch nachträglich (API)
  hinzugekommene Firmen/Kontakte mit gleicher E-Mail greifen.
- Auth-Bereich erzwingt Hellmodus: aus dem Portal übernommene .dark-Klasse wird
  am <html> entfernt (Login war im Dark Mode hängengeblieben).
- Tests: Firmen-E-Mail-Login, Multi-Firmen-Aggregation, Schreibzugriff/Upgrade,
  Per-Login-Re-Sync, Auth-Hellmodus. Sicherheits-Doku aktualisiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 12:55:49 +00:00
068a5a4b49 WS-6: Google-Login via Laravel Socialite
- Socialite installiert; oauth_provider/oauth_provider_id an users (Migration).
- GoogleController (redirect/callback) + SocialAuthService: De-Dup über E-Mail,
  neuer User aktiv + verifiziert + customer (Verifizierung über den Google-
  Kanal), offener Selbst-Registrierer wird onboardet, deaktivierter Account wird
  NICHT reaktiviert. Abschluss über die gemeinsame LoginRedirect-Logik
  (rollengerecht, 403-sicher).
- Routen /auth/google/redirect + /auth/google/callback (guest), "Mit Google
  anmelden/registrieren"-Buttons auf Login und Register.
- config/services.php google + .env.example-Keys; Sicherheits-/Deployment-Doku
  ergänzt (Keys, Redirect-URI, Migration).

Tests: neuer User, De-Dup bestehender User, deaktivierter Account blockiert,
unverifizierter Registrierer onboardet, fehlgeschlagener Callback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 10:39:19 +00:00
ae79d5bee4 Security: JSON-Login durchläuft die is_active-/Verifizierungschecks
RoleAwareLoginResponse gab bei wantsJson() sofort 204 zurück – VOR den
Sicherheitschecks. Ein XHR/JSON-Login eines verifiziert-inaktiven Accounts
erhielt damit eine Session ohne Logout. Checks laufen jetzt zuerst:
verifiziert-inaktiv → Logout + Session-Invalidate + 403 (JSON) bzw. Login mit
Fehler (HTML); unverifiziert → 204 (JSON) bzw. Notice (HTML); danach der
Erfolgsfall.

Tests: JSON-Login eines inaktiven Accounts (403, guest), JSON-Login eines
aktiven Users (204, authentifiziert).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 10:19:32 +00:00
f4ca452c6b Security: 2FA-Bypass beheben & Login-Pfade konsolidieren
Befund (Review 16.06.): Der Volt-Login machte direkt Auth::attempt() und umging
Fortifys 2FA-Pipeline (2FA-Bypass); zusätzlich existierte der Fortify-POST /login
parallel mit schwächeren Post-Login-Regeln.

Fix (Volt-nativ):
- Volt-Login prüft Credentials ohne sofortiges Login; bei aktivem 2FA wird der
  Session-Vertrag login.id/login.remember gesetzt und auf eine neue Volt-
  2FA-Challenge-Seite (/two-factor-challenge) geleitet, die an Fortifys
  bestehenden Controller postet (TOTP + Recovery-Code).
- Gemeinsame Post-Login-Logik in App\Support\LoginRedirect (rollengerechtes
  Home + 403-sicherer intended-Redirect), genutzt von Volt-Login UND Response.
- RoleAwareLoginResponse implementiert jetzt LoginResponse UND
  TwoFactorLoginResponse und erzwingt einheitlich: unverifiziert → Notice,
  verifiziert-inaktiv → Logout+Fehler, sonst 403-sicherer Redirect. Damit ist
  auch der direkte Fortify-POST-Pfad gehärtet.

Tests: 2FA-Übergabe, Challenge-Guard, voller TOTP-Flow, Fortify-POST blockt
inaktive User und hält Customer aus dem Admin-Bereich.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 10:00:15 +00:00
d98d297524 Security-Härtung Login & Magic-Link (Review 16.06.)
- Magic-Link-Versand im Login rate-limited (E-Mail+IP 3/h und IP-only 15/h);
  verhindert Mail-Fluten und das Entwerten aktiver Links.
- Inaktive (aber verifizierte) User werden beim Passwort-Login zentral
  blockiert (Auth::logout + Fehler) – sichert nur-auth/verified-Routen ab.
- Rollensicherer Login-Redirect: gemerkte intended-Admin-URLs schicken einen
  Customer nicht mehr in den 403, sondern auf das rollengerechte Ziel.
- ContactAccess prüft is_active vor jeder Mutation: deaktivierte Bestands-
  Accounts werden durch eine Anfrage weder verändert noch angemailt.
- Magic-Link-Verbrauch atomar (UPDATE … whereNull(consumed_at)) – Single-Use
  auch bei parallelen Requests.
- Sicherheits-Doku um diese Härtungen + Captcha-Empfehlung ergänzt.

Tests: Rate-Limit, intended-Admin-URL für Customer, inaktiver Login,
ContactAccess ohne Mutation inaktiver Accounts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 09:33:44 +00:00
84f7eb3aab Doku: Sicherheits- & Deployment-Hinweise (Auth, Rollen, Verifizierung)
Dokumentiert die deployment-kritischen und sicherheitsrelevanten Punkte der
Auth-Phase: Reihenfolge der Migrationen (Verifizierungs-Backfill gegen Lockout,
Legacy-editor→customer-Downgrade), der Sicherheits-Fix der Editor-Über-
berechtigung (65.950 Legacy-User hatten Admin-Zugriff), die Firmen-Scope-
Verhaltensänderung bei PMs und der Magic-Link-Kontaktzugang. PROGRESS-Log-
Eintrag (16.06.) und README-Index ergänzt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 08:35:04 +00:00
ec4aa1dc3d Detailplan Umsetzungsphase: Launch-Slice aus Decision-Updates + Merkliste
Bündelt die Launch-Anteile der beiden Decision-Updates (Phase-2/Magic-Link,
Duplicate-Content) mit den Merkliste-Notizen zu einem Plan (WS-1 bis WS-8) inkl.
empfohlener Reihenfolge und Anti-Zombie-Check. Verbindliche Entscheidungen
(15.06.): Legacy-Posten bleiben ungemappt, Pflicht-E-Mail-Verifizierung bei
Registrierung (Ausnahme Magic-Link/Google), Laravel Socialite freigegeben.
README-Index um den Plan ergänzt; Merkliste (Wochenend-Notizen) als Quelle
mit aufgenommen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-15 10:03:05 +00:00
ad741331ee Doku-Abschluss 12.06.: README-Stand, weiteres/-Index, Next Steps (Phase-2/Magic-Link, Duplicate-Content)
Some checks failed
tests / ci (push) Has been cancelled
linter / quality (push) Has been cancelled
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:24:28 +00:00
970b4909fa PM-Vorschau: Firmen-Kachel im Stil der Firmenübersicht
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:20:23 +00:00
cc7b3c3379 KI-generierte Bilder: eigener Lizenztyp, Anbieter-Bestätigung, Kennzeichnung
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:04:12 +00:00
6e0b2b1814 Titelbild: Bildnachweis als Pflichtfeld, Lizenzdetail-Reset bei Typwechsel
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 15:44:52 +00:00
25ea91d85b Verlinkung & Backlinks: systemseitige rel-Auszeichnung (Decision-Update 11.06.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 15:24:20 +00:00
5a8da0c1f4 PM-Vorschau: Workflow oben + farbig, Metadaten, saubere Inhalts-Typografie
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 15:16:52 +00:00