# GlitchTip — Fehlerprotokoll von Pressekonto **Stand:** 06.10.2026 · **Gilt ab:** v1.1.0 (live seit 05.10.2026) **Für:** KI-Chats und Entwickler, die Fehler aus GlitchTip auswerten und beheben. Dieses Dokument beschreibt, **was** GlitchTip hier ist, **wie** Fehler dorthin gelangen, **was zu tun ist**, wenn jemand sagt „schau mal in GlitchTip“, und welche Regeln dabei nicht verletzt werden dürfen. Hintergrund und Entscheidungen: [`../betrieb/monitoring-plan.md`](../betrieb/monitoring-plan.md) (Phase 1, Entscheidungen M1–M9). --- ## 1. Überblick | Was | Wert | |---|---| | Instanz | `https://errors.adametz.media` (selbst gehostet, Sentry-kompatibel) | | Organisation (Slug) | `adametz-media` | | Projekt 1 | `server-pressekonto` — PHP/Laravel: Exceptions und Fehlersignale | | Projekt 2 | `browser-pressekonto` — JavaScript-Fehler aus dem Browser | | Umgebungen | `production` (Live), `local` (Entwicklung). Nur `production` ist Betrieb | | Release | Git-Tag aus der Datei `RELEASE` (z. B. `v1.1.0`), siehe Abschnitt 6 | | Aufbewahrung | 90 Tage (`GLITCHTIP_RETENTION_DAYS` auf dem GlitchTip-Server; ältere Versionen: `GLITCHTIP_MAX_EVENT_LIFE_DAYS`) | | Alarmierung | GlitchTip-Alert-Regel: Mail bei neuem Fehlertyp. Betriebs-Alerts der App (fehlgeschlagene Jobs/Tasks) laufen getrennt über Mail + ntfy (`push.adametz.media`, Topic `pressekonto-ops`) | GlitchTip ist **nicht** das einzige Signal. Daneben: `/health` (externer Monitor), Admin ▸ Reports ▸ Betriebsüberwachung, `storage/logs/*.log`. --- ## 2. Wie Fehler nach GlitchTip gelangen ### Server (Projekt 1) | Weg | Datei | Was | |---|---|---| | Gemeldete Exceptions | `bootstrap/app.php` → `Integration::handles($exceptions)` | Alles, was Laravel über `report()` meldet — unbehandelte Exceptions in Requests, Jobs, Commands | | Fehlersignale ohne Exception | `app/Http/Middleware/ReportErrorSignals.php`, `app/Support/Monitoring/ErrorSignal.php` | Warnungen: 404 mit eigenem Referrer („Toter interner Link“), 403/429 für Angemeldete, 419 („Seite abgelaufen“). Je Signal und Ort höchstens 5 Meldungen in 10 Minuten | | Konfiguration | `config/sentry.php` | DSN, Release, Datenschutz-Optionen | | Datenschutzfilter | `app/Support/Monitoring/ErrorReportScrubber.php` (`before_send`) | Nur User-ID, Tokens/Signaturen aus URL/Query/Referer, E-Mails aus Meldungen | **Bewusst nicht gemeldet:** - Laravels Standard-`dontReport`: 404, Validierung, Authentifizierung, 419 als Exception (419 kommt als Fehlersignal). - `CommandNotFoundException` — vertippte `artisan`-Befehle (`bootstrap/app.php`). - `App\Services\SearchConsole\SearchConsoleUnavailable` — Google hängt vorübergehend; nur `Log::warning`, der Lauf alarmiert erst bei Abbruch oder ≥ 50 % Fehlern. ### Browser (Projekt 2) | Datei | Was | |---|---| | `resources/js/error-reporting.js` | Hört auf `error` und `unhandledrejection`; lädt das SDK erst beim ersten Fehler; filtert URLs/E-Mails; Ablehnungen ohne `Error` werden mit Typ und Inhalt beschrieben | | `resources/js/error-reporting-sdk.js` | Re-Export der benötigten SDK-Funktionen (Tree-Shaking) | | `resources/views/components/monitoring/browser-errors.blade.php` | `` mit DSN, Release, User-ID, Bereich; nur mit `SENTRY_BROWSER_DSN` | | Eingebunden in | `partials/head` (Portal, `area: portal`), `web/layouts/web-master` (`area: web`), `components/layouts/auth/pressekonto` (`area: auth`) | Fehlgeschlagene Livewire-Requests (5xx, 419) meldet der **Server**, nicht der Browser. ### Tests melden nie an GlitchTip `phpunit.xml` leert `SENTRY_LARAVEL_DSN`, `SENTRY_DSN`, `SENTRY_BROWSER_DSN`. Wächtertest: `tests/Feature/Monitoring/ErrorReportingTest.php` („the test suite never reports to the real glitchtip“). Tests, die Sentry-Ereignisse prüfen, benutzen `Tests\Support\FakeGlitchTip::install()`. **Erkennungszeichen für Test-Rauschen** in GlitchTip: Umgebung `local` und Texte wie „Queue weg“, „Datenbank nicht erreichbar“, SQLite-Fehler („General error: 1 no such table“ — Live ist MySQL), „no role named `customer`“. Bis 06.10.2026 kamen solche Einträge aus Testläufen mit lokaler DSN. --- ## 3. Zugriff per API (lesend) Token: `GLITCHTIP_API_TOKEN` in der lokalen `.env` — **nur lesen** (`project:read`, `event:read`). Kein `org:read` (Organisationsliste → 403), kein Schreiben (Auflösen → 403). Den Token nie ausgeben, nie committen. Alle Befehle aus dem Projektverzeichnis: ```bash T=$(grep -E "^GLITCHTIP_API_TOKEN=" .env | cut -d= -f2- | tr -d "'\"") B=https://errors.adametz.media/api/0 ``` **Offene Einträge eines Projekts** (Projekt 1 = Server, 2 = Browser; `environment=production` für Live, weglassen für alle): ```bash curl -s -H "Authorization: Bearer $T" \ "$B/organizations/adametz-media/issues/?project=1&query=is:unresolved&environment=production&limit=100" \ | python3 -c " import json,sys for i in json.load(sys.stdin): print(i['id'], i['level'], i['count'], i['firstSeen'][:16], i['lastSeen'][:16], '|', (i['title'] or '')[:100])" ``` **Letztes Ereignis eines Eintrags** mit Umgebung, Release, URL und Stacktrace: ```bash curl -s -H "Authorization: Bearer $T" "$B/issues//events/latest/" | python3 -c " import json,sys e=json.load(sys.stdin); tags={t['key']:t['value'] for t in e.get('tags',[])} print('env:',tags.get('environment'),'| release:',tags.get('release'),'| area:',tags.get('area'),'| browser:',tags.get('browser')) for en in e.get('entries',[]): if en['type']=='exception': for v in en['data'].get('values',[]): print('EXC',v.get('type'),':',(v.get('value') or '')[:300]) for f in ((v.get('stacktrace') or {}).get('frames') or [])[-8:]: print(' ',f.get('filename') or f.get('absPath'),f.get('function'),f.get('lineNo'),f.get('colNo')) if en['type']=='request': print('REQ',en['data'].get('url'))" ``` **Mehrere Ereignisse eines Eintrags:** `$B/issues//events/?limit=10`. **Projekte:** `$B/projects/`. Weboberfläche: `https://errors.adametz.media/adametz-media/issues?project=1`. --- ## 4. Aufgabe: GlitchTip auswerten und Fehler beheben Wenn der Auftrag lautet „schau in GlitchTip“, „was sagt GlitchTip“ o. Ä.: 1. **Abrufen.** Offene Einträge beider Projekte, zuerst `environment=production`, dann ohne Filter. 2. **Einordnen** — jeder Eintrag in genau eine Klasse: | Klasse | Erkennen | Vorgehen | |---|---|---| | Test-/Entwicklungsrauschen | Umgebung `local`, Texte aus Tests (Abschnitt 2) | Nichts am Code; Betreiber markiert „Resolved“. Taucht es mit `production` auf → echter Fehler | | Bedienfehler am Server | z. B. `CommandNotFoundException` | In `dontReport` aufnehmen, falls wiederkehrend | | Externer Dienst vorübergehend | Timeouts/5xx von Google, OpenAI, Stripe … | Retry + Warnung statt `report()`, Abbruch- und Zeitbudget; Muster: `SearchConsoleClient` + `SearchConsoleUnavailable` | | Echter Bug | Stacktrace in `app/`, `resources/`, Browserfehler mit eigener Datei/URL | Schritte 3–6 | | Unklar | z. B. `Error: [object Object]` | Erfassung verbessern (mehr Kontext, keine personenbezogenen Daten), auf das nächste Auftreten warten | 3. **Code finden.** Stacktrace (`filename`, `function`, `lineNo`), `culprit`, URL (`REQ`), Bereich (`area`). Bei Browserfehlern zeigen die Frames oft nur `livewire.min.js` — der Hinweis steckt dann im Funktionsnamen (z. B. `[Alpine] __('…')` = Alpine-Ausdruck) → in `resources/views` nach dem Ausdruck suchen. 4. **Reproduzieren mit rotem Test**, dann Fix (Projektregel: jede Änderung mit Test). Ist der Fehler ein Muster, das wieder auftreten kann, einen **Wächtertest** über alle Dateien schreiben (Beispiele: `BladePhpBlockGuardTest`, `BladeAlpineTranslationGuardTest`). 5. **Qualitätsgates:** betroffene Tests, dann `php artisan test --compact --parallel`, `vendor/bin/phpstan analyse --memory-limit=2G`, `vendor/bin/pint --dirty --format agent`; bei JS `npm run build`. 6. **Dokumentieren:** Eintrag in Abschnitt 7 (ID, Klasse, Ursache, Fix, Commit). Commit-Nachricht nennt die GlitchTip-ID. 7. **Ausliefern** über den nächsten Deploy (Hotfix: letzte Versionsstelle erhöhen). Ablauf seit `v1.1.3`: Git-Deploy per Tag, [`../betrieb/git-deploy.md`](../betrieb/git-deploy.md) Abschnitte C und D (Assets bauen und committen, Tag, Push, auf dem Server `deploy.sh`). 8. **Auflösen** in GlitchTip macht der Betreiber (Token ist nur lesend) — erst nach dem Deploy. Kommt der Fehler mit neuem Release wieder, öffnet GlitchTip den Eintrag erneut. --- ## 5. Regeln, die nicht verletzt werden dürfen - **Datenschutz (M4):** `send_default_pii` bleibt `false`, `max_request_body_size` bleibt `never`, Log- und Cache-Breadcrumbs bleiben aus, `ErrorReportScrubber` bleibt in `before_send` und entfernt die Daten aller Breadcrumbs; Livewire-Breadcrumbs bleiben aus (sie tragen Formularwerte und Properties, Roadmap 4.9). Kein Name, keine E-Mail, keine IP an GlitchTip — nur die interne User-ID. Neue Query-Parameter, die mitgehen sollen, nur über `ErrorReportScrubber::AllowedQueryParameters` (und dieselbe Liste in `error-reporting.js` / Umami-Filter). - **Keine variablen Zahlen in Fehlermeldungen**, wenn sie gruppiert werden sollen: GlitchTip gruppiert nach Text. `…after 20002 ms` und `…after 20001 ms` wurden drei getrennte Einträge (Issues 11, 13, 14). Variable Werte in den Kontext, nicht in die Meldung — oder einen Fingerprint setzen wie `ErrorSignal`. - **Vorübergehende Fremdfehler nicht einzeln melden.** Sonst flutet ein Google-Ausfall GlitchTip und verdeckt echte Fehler. - **Tests melden nie an GlitchTip** (Abschnitt 2). Neue Sentry-Tests nur mit `FakeGlitchTip`. - **Token nur lesend.** Für Schreibrechte (Auflösen per API) erst mit dem Betreiber sprechen. --- ## 6. Konfiguration | Variable | Wo | Wert | |---|---|---| | `SENTRY_LARAVEL_DSN` | `.env` | DSN Projekt 1 | | `SENTRY_BROWSER_DSN` | `.env` | DSN Projekt 2 (öffentlich, steht im HTML) | | `SENTRY_ENVIRONMENT` | `.env` | `production` (Live) bzw. `local` | | `SENTRY_RELEASE` / `APP_VERSION` | `.env` | leer lassen — kommt aus der Datei `RELEASE` | | `GLITCHTIP_API_TOKEN` | nur lokale `.env` | Lese-Token für Abschnitt 3 | **Release:** `App\Support\Monitoring\Release::current()` liest `APP_VERSION` bzw. `SENTRY_RELEASE`, sonst die Datei `RELEASE` im Projektwurzelverzeichnis. Seit dem Git-Deploy schreibt `dev/betrieb/deploy.sh` sie beim Deploy (`echo "$tag" > RELEASE`), GlitchTip zeigt also genau den ausgelieferten Tag. Bei den SFTP-Deploys bis `v1.1.0` wurde sie von Hand erzeugt; daher stammen Releases wie `v1.1.0-3-gb1cec16` in älteren Einträgen. Nach Änderung: `php artisan config:cache`. --- ## 7. Protokoll der Einträge Stand 06.10.2026 (Abruf per API). „Fix“ = im Code behoben; ausgeliefert mit dem nächsten Deploy. | ID | Projekt | Umgebung | Eintrag | Klasse | Ursache / Maßnahme | Stand | |---|---|---|---|---|---|---| | 1 | Server | local | GlitchTip-Test Server | Test | Anbindungstest 05.10. | auflösen | | 8 | Server | production | Deploy-Test v1.1.0 | Test | Deploy-Prüfung 05.10. | auflösen | | 3, 16 | Server | local | Queue weg | Test-Rauschen | `ExpireGrandfatheringTest` meldete an echte DSN | Fix `2f02acc`, auflösen | | 5, 17 | Server | local | Datenbank nicht erreichbar | Test-Rauschen | `PressReleaseSchedulingTest` | Fix `2f02acc`, auflösen | | 4 | Server | local | no such table: conversion_events | Test-Rauschen | SQLite im Test | Fix `2f02acc`, auflösen | | 6 | Server | local | Wasserstandsmarke steht auf 1 statt 0 | Test-Rauschen | Konkurrenztest der Aufruf-Aggregation | Fix `2f02acc`, auflösen | | 7 | Server | local | no role named `customer` | Test-Rauschen | Tests ohne Rollen-Seeder | Fix `2f02acc`, auflösen | | 9 | Server | production | Command "config:cachels" is not defined | Bedienfehler | Tippfehler auf dem Server | `dontReport` (16af374); auflösen | | 11, 13, 14 | Server | production | cURL error 28 … searchconsole.googleapis.com | Extern | Google URL Inspection hing; jeder Timeout einzeln gemeldet, Lauf 1¾ h | Fix a90f24a: Retry, Warnung statt Meldung, Abbruch nach 5 in Folge, 40-min-Budget; nach Deploy auflösen | | 12 | Server | production | URL Inspection API antwortet mit 500 | Extern | Google-interner Fehler | wie 11 | | 15 | Browser | production | ReferenceError: __ is not defined | **Bug** | `/register`: `:placeholder="__('…')"` an `` → Alpine wertet PHP-Helfer im Browser aus | Fix 16af374: `placeholder="{{ __('…') }}"`, Wächtertest `BladeAlpineTranslationGuardTest`; nach Deploy auflösen | | 10 | Browser | production | Error: [object Object] | Unklar | Promise-Ablehnung mit Objekt auf `businessportal24.com/de` | Erfassung verbessert (16af374, Typ + Inhalt); nach Deploy neues Auftreten abwarten |