# 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 |