Live-Prüfung 08.10.2026: nginx beantwortet die Anfragen direkt (kein CDN,
kein vorgeschalteter Proxy), die App vertraute aber jedem Proxy
(trustProxies at '*'). Jeder Client konnte per X-Forwarded-For seine IP
vorgeben und damit IP-Limits bei Login und Passwort-Reset umgehen sowie
IP-Protokolle fälschen. Jetzt steuert config/trustedproxy.php das Vertrauen:
lokal (Traefik) weiterhin '*', sonst keinem Proxy; ein späteres CDN kommt
über TRUSTED_PROXIES dazu.
HSTS fehlte auf Live. SecurityHeaders setzt Strict-Transport-Security auf
HTTPS-Antworten, standardmäßig nur in Produktion (max-age 1 Jahr, bewusst
ohne includeSubDomains/preload).
phpunit.xml leert MONITORING_NTFY_*, damit Testläufe keine echten
Push-Nachrichten mehr auslösen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Auf Live meldete memberships:resync-auto nach v1.4.0 „vorher 19607, nachher 9":
syncMembershipsForEmail() entzog Konten ohne email_verified_at alle
automatischen Rechte, und 19.597 davon gehören Bestandskonten aus dem
Altsystem. Jetzt wird nur entzogen, was keine E-Mail-Grundlage mehr hat —
unabhängig vom Kontostatus (S-03 bleibt wirksam); neue Rechte weiterhin nur
für aktive, verifizierte Konten (F01).
memberships:resync-auto läuft in einer Transaktion, kennt --dry-run und rollt
zurück, wenn mehr als 5 % (mindestens 50) der Rechte wegfallen würden
(--force zum Erzwingen). Probelauf gegen die Live-Kopie: 19.607 → 19.316.
Wiederherstellung: storage/app/private/restore-company-user-auto-2026-10-07.sql
(nicht versioniert, INSERT IGNORE, idempotent).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Audit: dev/sicherheit/SICHERHEITSAUDIT-2026-10-07.md, Plan und Entscheidungen:
dev/sicherheit/ENTWICKLUNGSPLAN-SICHERHEIT-2026-10-07.md.
- S-01 Legacy-Rechnungen fremder Kunden nur mit billing:manage (auch Kundenroute).
- S-02 Kontaktzuordnung auf der Firmenanzeige verlangt companies:write, $id gesperrt.
- S-03 CompanyMembershipObserver: automatische Firmenrechte werden bei jeder
Adress-/Zuordnungsänderung sofort neu bewertet; memberships:resync-auto.
- S-04 Passwortwechsel beendet alle anderen Sessions (PasswordChanger), Reset
alle Sessions und offene Login-Links; Fortify PUT /user/password abgeschaltet.
API-Tokens bleiben bestehen.
- S-05 Google: email_verified Pflicht, feste Bindung über die Provider-ID;
Erstverknüpfung bestehender Konten außerhalb gmail/hd nur per Bestätigungslink
in derselben Browser-Session.
- S-06 Frischer Identitätsnachweis (Passwort, App-Code, E-Mail-Code oder
Passkey) vor E-Mail-Wechsel, erster 2FA-Einrichtung und Token-Erzeugung;
Hinweis-Mails an die (bisherige) Kontoadresse.
- Entscheidung 5: Passkeys (Fortify, @laravel/passkeys) für alle; Super-Admins
und Admins bestätigen die Session für den Admin-Bereich per Passkey oder
App-Code (EnsureStrongAdminAuthentication, Notfallschalter
AUTH_REQUIRE_STRONG_ADMIN); Reset des zweiten Faktors durch Super-Admins.
Neue Migration: create_passkeys_table. Suite 2.403 grün (1 übersprungen),
Larastan ohne Meldung.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Am 07.10.2026 hat das RefreshDatabase eines frischen Demo-Projekts (Test der
Vorlagen aus dev/git-deploy-monitoring) die lokale Datenbank `pressekonto` auf
global-mysql vollständig geleert (Binärlog binlog.000009, Pos. 566161486).
Ursache: docker-compose.yml setzte DB_* als Container-Umgebungsvariablen, die
in Laravel Vorrang vor jeder .env haben; die phpunit.xml des Demo-Projekts
erzwang kein SQLite. Die eigene Suite war nicht beteiligt (force="true" und
Guard in tests/TestCase.php greifen; Gegenprobe mit MySQL-Variablen grün).
- docker-compose.yml: DB_* entfernt (Werte identisch in .env), wirksam nach
Neuerstellen des Containers.
- Baukasten: „Testdatenbank absichern" (phpunit.xml mit force, Guard,
Gegenprobe) als Pflicht vor RefreshDatabase.
- .ai/rules/general.md und CLAUDE.md: fremde/frische Laravel-Projekte nur mit
SQLite :memory: testen; migrate hier erst nach migrate:status.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vorlagen in einem frischen Laravel 12 eingebaut (30 Tests grün), deploy.sh
gegen ein simuliertes Repository durchgespielt (Deploy, Abbruch bei
Migrationen, Drift, Rollback, fehlender Worker). GlitchTip-Aufbewahrung heißt
seit Version 6 GLITCHTIP_RETENTION_DAYS — in der Projekt-Doku korrigiert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Anlass 06.10.2026: Nach dem Deploy von v1.3.0 hat queue:restart den Worker
beendet, Supervisor lief nicht, über eine Stunde blieben KI-Prüfungen und
Mails liegen, ohne dass es auffiel.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Auf Live kamen seit dem 05.10. rund 250 Versuche am Tag aus über 50 Quellen,
alle mit unbekannter Adresse — verteiltes Durchprobieren fremder
Zugangsdaten, das im Verlauf die relevanten Einträge verdeckte. Neue Tabelle
failed_login_tallies (Tag × Einstieg × IP-Hash), model:prune täglich 04:05.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Kundenwunsch 06.10.2026: Ein Kunde kam über die Stripe-Rechnungsseite nicht
an seine Rechnung und fragte nach Belegen und einer Rechnungs-E-Mail.
- Profil ▸ Rechnungsadresse ▸ Rechnungsversand: Schalter „Rechnungs-PDF an
die Konto-E-Mail" (Standard an), optionale „E-Mail für Rechnungen" mit
Schalter „Rechnungen als PDF an diese Adresse senden" (Standard an).
Neue Spalten an billing_addresses (klein, ohne FULLTEXT).
- InvoiceDelivery entscheidet Empfänger und Anhang; gleiche Adresse wie das
Konto ergibt eine Mail mit PDF.
- Zahlungsbestätigung (STR) und Bestandskunden-Rechnung/-Erinnerung (MAN)
folgen der Einstellung; die Fassung an die Rechnungs-E-Mail nennt das
Konto, ohne Blindkopie und ohne Login-Button.
- StripeInvoicePdf holt das Stripe-PDF einmal und legt es lokal ab
(storage/app/private/invoices/stripe); Mailversand wiederholt bei
Stripe-Ausfall (5 Versuche).
- Rechnungsseite: „PDF öffnen" aus pressekonto, „Beleg bei Stripe" für den
Zahlungsbeleg auf der Stripe-Seite.
Suite 2.340 grün, einer übersprungen; Larastan und Pint ohne Meldung.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die vier Icons (u. a. chevrons-up-down in der Sidebar) lagen nur lokal und
auf Live; ein frischer Checkout hätte sie nicht. Das Muster trifft jetzt nur
noch die macOS-Datei Icon\r. Beim Umstellen von Live auf Git-Deploy
aufgefallen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Am 06.10.2026 hing die URL Inspection API zeitweise: 28 Zeitüberschreitungen
und 4 × 500, jede einzeln als Fehler gemeldet, der Lauf zog sich über 1¾
Stunden. Neu: SearchConsoleUnavailable für Timeout/5xx/429 (Warnung, Meldung
bleibt fällig), echte Fehler (401/403/400) weiter über report(); FAILURE —
und damit ein Betriebs-Alert — nur bei Abbruch oder ≥ 50 % Fehlern.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Seit der lokalen DSN landeten absichtlich provozierte Fehler aus den Tests
(„Queue weg“, „Datenbank nicht erreichbar“, SQLite „no such table“,
fehlende Rolle `customer`, Wasserstandsmarke) als Issues in GlitchTip.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- deploy.sh: bricht ohne Änderung ab bei Abweichung im Checkout oder neuen
Migrationen ohne --migrations; down, Checkout, RELEASE, Composer, Caches,
queue:restart, FPM, up; Rollback = derselbe Aufruf mit dem vorherigen Tag
- git-deploy.md: Forgejo-Zugang, Umwandlung von ~/pressekonto.com in einen
Checkout von v1.1.0 ohne Dateiänderung, Release lokal, Prüfungen, Rollback
- Assets werden lokal gebaut und committet, auf dem Server kein Node
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Dateien bleiben in der Historie und im Vault; git rm --cached, nichts
auf der Platte gelöscht.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der Schlüssel stand seit Mai im Repository und auf origin; er bleibt in der
Historie und muss bei Context7 rotiert werden.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- GlitchTip über die Sentry-SDKs; Datenschutzfilter (nur User-ID, keine
Request-Bodys, Tokens aus URL/Query/Referer, E-Mails aus Meldungen).
Browser-SDK erst beim ersten Fehler nachgeladen.
- ReportErrorSignals: tote interne Links (404 mit eigenem Referrer), 403/429
für Angemeldete, 419 als gedrosselte Warnung.
- /health (Bearer-Token): DB, Cache, Queue-Rückstau, Scheduler-Herzschlag,
Plattenplatz → 200/503; Scheduler und Plattenplatz auch im Systemstatus.
- OperationalAlert zusätzlich per ntfy (JSON-POST), unabhängig von der Mail.
- Verlauf: login_failed (Grund unbekannt/kein Passwort/falsch),
login_lockout, two_factor_failed; IP nur als gekürzter HMAC.
- Umami: Kundenbereich mit eigenem Schalter und identify('user-<id>'),
nie im Admin/bei Impersonation; Query-Filter auch auf den Webseiten
(signierte Links gingen bisher an Umami).
- queue:prune-failed nach 30 Tagen.
- Versionsnummer: config('app.version') aus APP_VERSION oder Datei RELEASE
(git describe --tags), in GlitchTip, /health, Systemstatus, artisan about.
Plan: dev/betrieb/monitoring-plan.md (Entscheidungen M1–M9).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Livewire 4.4.7 rendert ModelNotFoundException im Testhelfer als 404 statt
sie zu werfen — zwei Tests auf assertNotFound() umgestellt, Laufzeitverhalten
unverändert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- UMSETZUNGSAUDIT-2026-09-29.md (Bestandsaufnahme) und -2026-10-02.md
- ENTWICKLUNGSPLAN.md: Block 9 und 10, Entscheidungen E19–E34 vom Betreiber
am 02.10.2026 bestätigt (E25 revidiert), Deploy-Plan A–E, Protokoll
- deploy-runbook.md: vollständige Scheduler-Tabelle, Restore-Schritte mit
--accept-unsigned/--without-export, Zugangsdaten aus Abschnitt 7 entfernt
(stehen weiter in der Historie — Passwort wird rotiert)
- Bildplan-Protokoll mit Korrektur zu „Altbestand geschützt" (A-05)
- dev/README.md und dev/roadmap.md verweisen auf den aktuellen Stand
- .env.example: neue Schlüssel aus Block 9/10
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- B-01/B-02: Startseiten-Feed, Card-Helfer und Nachweis-PDF nur mit
isPubliclyDeliverable()
- B-03: Livewire-Temp-Upload 16 MiB
- N09: Snapshot je Bytes- und Metadaten-Hash inkl. OG-Variante, put()
geprüft, alle Fassungen ins Archiv
- O03: published_ever_at in der Freigabetransaktion
(markPublishedIfNowPublic) — Kundenbestätigung, Vorab-Sichtung, Korrektur
- B-04/B-14: Bestätigung an Bild-ID und SHA gebunden, unter Sperre
- B-05/B-06: Entfernen unter Sperre mit frischem Stand und Archivauftrag;
Korrektur archiviert über den Auftrag, Nacharbeiten abgesichert
- B-07: precheck_withheld_at getrennt von withheld_at (Migration + Übernahme)
- B-08, B-09, B-11, B-12: published_ever_at nur bei Status published,
Admin-Eigentümer mit Kundenregel, Sweep verwaister Originale,
Verarbeitungsfehler als Formularmeldung
- K-02-Teil: nach Kundenbestätigung erneut routen
- OPT-3 bis OPT-5: pingImage für JPEG, Hash durchgereicht, erstes Frame
Admin-PM-Detailseite enthält zusätzlich K-06 (Autorisierung) und A-08
(Nachweis per POST), weil die Datei ungeteilt committet ist.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A-01/A-02/A-04: archive_pending_jobs je Vorgang (ArchivePendingQueue),
Depublikationsstand am Auftrag festgehalten, Nachholer ohne Schlüssel
FAILURE; archive_pending_at nur noch Sammelmarker
- O07: Direktweg und Nachholer beanspruchen den Auftrag unter Zeilensperre
- O08: fehlende Snapshot-Datei → Verweis auf den image_removed-Eintrag oder
offener Auftrag, nie ein still unvollständiger Nachweis
- A-03/A-06: Sweep verschiebt in die Quarantäne, Pause beim Restore,
archive:reregister; Restore-Abgleich löscht Anwendungskopien erneut
- O04/O05: Restore ordnet über den Payload-Pfad zu; unsignierte Exporte nur
mit --accept-unsigned, reregister bricht bei ungültigem/fehlendem Export ab
- A-05, A-07 bis A-15: Altbestand als möglicherweise veröffentlicht, Hold-
Historie, Zweck per POST, Nachweise gelöschter Bilder nur mit
compliance:manage, Anhänge auf ihrer Disk, Schlüssel-ID und
ARCHIVE_PREVIOUS_KEYS, HMAC per HKDF, archive:verify-export
- 5.1 d: Depublikation im Meldeverfahren trägt legal_request_id
PressReleaseService.php enthält zusätzlich K-01 (Prüfung im Publish-Lock),
N19 (archive() gibt Kopien frei) und N09 (markImagesPublished nur für
auslieferbare Bilder), weil die Datei ungeteilt committet ist.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- K-01: publish-scheduled filtert manual_review_required_at; publish() prüft
für ki/scheduler unter der Sperre (ManualReviewRequiredException)
- K-02: Kontingent- und Bildsperre sind fachliche Ausgänge (Exit 0, einmaliger
Verlaufseintrag); KI-Job ohne Retry bei Bildsperre
- O06: Kandidaten per Cursor (scheduled_at, id), Limit zählt bearbeitete
Meldungen, Blockaden nur ein Scan-Budget
- K-05: KI-Job lädt vor dem Routing neu, überholter Status ohne Retry; backoff
- K-06: Admin-Aktionen mit Permission-Prüfung und Fehlermeldung statt 500
- K-09: withoutOverlapping() mit kurzer Sperrdauer, purge-events 03:50,
neuer Wochenlauf press-release-images:sweep-orphan-originals (So 04:45)
- E9: NEWSLETTER_SENDING_ENABLED (Standard aus) sperrt Start, Resume und Job
- OPT-9: ExpireGrandfathering prüft die Queue-Voraussetzung aus E18
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- R-02/K-03: Aufrufaggregation und Merge ändern updated_at nicht mehr; neue
Spalte press_releases.content_changed_at (INSTANT), contentModifiedAt()
für Sitemap-lastmod, dateModified und article:modified_time
- R-03: Sitemap und Legacy-view_url mit /en/ für englische Meldungen
- R-04/O01: X-Pk-Ref je Empfänger per HMAC signiert; auf eine Sperre zählt —
hart wie weich — nur ein gültig signierter Rückläufer, unsignierte
standardmäßig nur zur Sichtung (BOUNCE_UNSIGNED_KIND=policy)
- R-05/R-06: Unmerge setzt nur unveränderte Füllwerte zurück
(company_merge_moves.merged_value), Canonical-Neubewertung nach Merge und
Unmerge, assignAll setzt veraltete Verweise zurück
- R-07 bis R-11: Crawler zählen nicht als Aufruf, Mail-Klick gedrosselt und
verzögert geschrieben, Claim-Zähler erst nach Versand, email_bounces nach
395 Tagen gelöscht, Canonical-Portal über Kategorie-ID, llms-Cache geleert,
Feed-Teaser ohne Doppel-Escaping, Merge-Ketten aufgelöst
- N17/N18: kein falsches „gelistet seit", Rollen im Indexbericht wie Sitemap
- OPT-1/OPT-2: topFeeds in SQL, purge-events löscht nach Grenz-ID
Enthält aus PressRelease.php auch die Card-Bild-Helfer (B-01) und
wasEverPublished()/neverPublished() (A-05), weil die Datei ungeteilt
committet ist.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- R-01: ApiNewsroomAssignment hängt an eine bestehende Firma nur noch Owner,
Mitglieder oder Nutzer aus NEWSROOM_API_ASSIGNMENT_USER_IDS; Pivot mit
granted_via = api; Befehl company-memberships:api-assignments (Liste,
--remove mit Vorschau)
- K-04: OAuth-Verifikation eines offenen Kontos verwirft Passwort,
remember_token und Sanctum-Tokens; SessionRevocation + Middleware
EnsureSessionIsNotRevoked widerruft alte Sessions (Redis-tauglich)
- K-08: LoginCompletion für Passwort, Magic Link und Google — last_login_at
und Anmeldemethode auch nach 2FA, Landeziel über die Challenge, Google
ohne erzwungenes remember, magic-login ohne guest für eigene Links
- B-10: eigener Magic-Link-Zweck image_confirmation (Migration)
- K-07: legalAcceptanceVersions #[Locked], Versionswechsel beim Absenden
wird abgelehnt, Gate-Abfragen je Request zwischengespeichert
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- makeCustomerForShowPhase8a() nach tests/Pest.php — die Suite läuft damit
auch parallel (--parallel) und dateiweise grün
- phpunit.xml leert DB_URL, der Guard in TestCase::setUpTraits() bricht bei
gesetzter url ab, bevor RefreshDatabase eine Verbindung öffnet
- HasUniqueSlug ohne widersprüchliche @var-Annotation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bilder (N01, N05, N07, N08): gemeinsamer Freigabezustand
PressReleaseImage::isPubliclyDeliverable() für Seiten, OG und Medienroute
(Bestand bleibt sichtbar, v2 nur mit Bestätigung, Admin-Upload bis zum
Kundenklick nicht öffentlich); eigene Ability confirmImageRights nur für den
Kontoinhaber, ohne Super-Admin-Kurzschluss, Identität und ausstehende
Bestätigung auch im Service; Status-Regel unter der PM-Sperre; Cache-Flush
nach dem Commit außerhalb der Dateibereinigung; Snapshot nach Bestätigung an
veröffentlichter PM; Bestätigungstexte an die gezeigte Kennung gebunden.
Beweisarchiv (N02, N10, N11, N12, N13, 5.1): Tombstone unter Zeilensperre mit
erneuter Hold-/Fristprüfung; Dateioperationen ausgewertet, Commands mit
FAILURE; record() über .tmp + move; Marker archive_pending_at mit
archive:retry-pending und archive:sweep-orphans; Anonymisierung entfernt Bilder
über den Remover mit Antragsbezug; Draft-Purge räumt Medien nie
veröffentlichter abgelehnter Einreichungen; App-Kopien fallen mit dem
Archiv-Tombstone; label_corrected nur für veröffentlichte Bilder;
archive_entries.legal_request_id; FileDeletion-Helfer; Systemstatus-Checks.
KI und Hintergrund (N03, N04, N14, N20, N21): Ergebnis-UPDATE und Audit in
einer Transaktion; erwarteter Hash bis in reject()/holdForManualReview();
Ablaufmail per beanspruchtem Marker in einer Transaktion; strikte
Schemaprüfung der Vision-Antwort; Fortschrittsmarke ungecacht.
Berichte und Canonical (N15–N19, 5.2): lückenlose Alterskohorten;
Feed-Identität mit Portal und Sprache; Sitemap-Rolle in der Kundenansicht;
Indexverteilung auf einer Grundgesamtheit; Kopien nach Wegfall der
Erstquelle neu bewertet; Kategorie-Admin leert Seiten-Caches; Dry-Run
zählt alle Tabellen.
Gesamtsuite: 2.122 Tests grün, einer übersprungen; Larastan und Pint sauber.
Zwei Migrationen (nullable Spalten, INSTANT). N09 offen.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Tests\TestCase prüft die Standardverbindung in setUpTraits(), also vor
RefreshDatabase — bisher erst nach dem Refresh (N22). Eigener Test.
- phpunit.xml pinnt IMAGE_RIGHTS_V2, IMAGE_PRECHECK(_STAGE) und
LEGAL_ACCEPTANCE_GATE auf die Vorgaben aus .env.example; die Suite hing
sonst an der lokalen .env (Audit Abschnitt 6).
- Zustimmungsgate: die Livewire-Komponenten tragen die beim Rendern gezeigten
Fassungen (Trait-Hook rendering); weicht die aktuelle Fassung beim Absenden
ab, wird die Annahme abgelehnt und der neue Wortlaut gezeigt. Ein fehlendes
Pflichtdokument ist bei aktivem Gate ein Konfigurationsfehler (N06).
- Audit vom 25.09., Decision-Update vom 22.09. und Plan Fassung 2 versioniert;
die Antwortkopie „…-211.md" entfernt; U10-Formulierung im Plan präzisiert.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>