Commit graph

30 commits

Author SHA1 Message Date
74f71f7a58 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
54213cac64 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
3320aaaa85 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
91992ac4b0 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
0bec71ffa5 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
3940d462d9 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
6cb7b79dae 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
7d03deddb1 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
0618080e02 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
6a7483e805 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
7dbc238bdb 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
57afcab3b9 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
f87c470a0b 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
eaae1e66bc 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
9bce9afe0b 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
64311392db 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
46d7ae3c60 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
fec2148ebb 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
265d1fde53 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
42b42887b7 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
512057cbfd 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
f28b698c8d 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
55d974f9e8 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
ce5d6c98e1 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
234772be9f Doku-Abschluss 12.06.: README-Stand, weiteres/-Index, Next Steps (Phase-2/Magic-Link, Duplicate-Content)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:24:28 +00:00
4052225199 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
ced39dd371 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
5ca76c7d8d 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
1f31e108d0 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
ad75886929 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