- dev/roadmap.md neu: alle offenen Punkte aus Plänen, Audits und Protokollen, gegen Code und Git abgeglichen (Stand v1.7.0) - Abgeschlossenes ins Archiv: 2026-09-01 → archive/2026-09-nutzergewinnung, 2026-09-11-audit → archive/2026-09-audit, lagacy-rechnungen → archive/legacy-rechnungen, Deploy-Protokoll v1.1.0, Umami-Snippets, Go-Live-Roadmap vom 20.07. - Aktiv bleiben eigene Ordner bildrechte/ (Plan Fassung 2, Decision-Update) und changelog/ (Decision-Update Changelog) - dev/README.md als Ordnerkarte neu, Verweise und zwei Code-Kommentare auf die neuen Pfade Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
316 lines
18 KiB
Markdown
316 lines
18 KiB
Markdown
# Betriebsüberwachung, Bedienbarkeit, Nutzungsstatistik — Plan
|
||
|
||
**Stand:** 05.10.2026 · **Phase 1 live seit 05.10.2026 (v1.1.0)**
|
||
|
||
Ziel: Fehler fallen auf, bevor Kunden sie melden — Serverfehler aus der
|
||
Programmierung ebenso wie Bedienungs- und Usability-Probleme. Dazu eine
|
||
Nutzungsstatistik, aus der sich ablesen lässt, wer was tut und wo Arbeit
|
||
aufhört.
|
||
|
||
## Entscheidungen (Betreiber, 02.10.2026)
|
||
|
||
| Nr. | Frage | Entscheidung |
|
||
|---|---|---|
|
||
| M1 | Fehlerwerkzeug | **GlitchTip, selbst gehostet** (wie Umami auf sys.adametz.media), angebunden über die offiziellen Sentry-SDKs (`sentry/sentry-laravel`, `@sentry/browser`) |
|
||
| M2 | Umami im Portal | **ja, mit Zuordnung zum Nutzer** (`umami.identify` mit der internen User-ID, keine E-Mail, keine Namen) |
|
||
| M3 | Alarmweg | **Mail bleibt**, zusätzlich **ntfy** (HTTP-POST, JSON) |
|
||
|
||
Bei der Umsetzung getroffen (Bestätigung offen):
|
||
|
||
| Nr. | Frage | Entscheidung |
|
||
|---|---|---|
|
||
| M4 | Personenbezug in GlitchTip | Nur die interne User-ID, `send_default_pii` aus, Request-Bodys nie (`max_request_body_size = never`) |
|
||
| M5 | Browserfehler-SDK | Wird erst beim ersten Fehler nachgeladen (dynamischer Import) — kein Ladegewicht auf fehlerfreien Seiten, dafür ohne Breadcrumbs |
|
||
| M6 | Umami-Schalter | Getrennt: `UMAMI_ENABLED` (Webseiten), `UMAMI_PORTAL_ENABLED` (Kundenbereich), `UMAMI_IDENTIFY_USERS` (Zuordnung). Portal und Zuordnung erst nach DSE-Anpassung einschalten |
|
||
| M7 | Umami im Admin, unter Impersonation, auf Auth-Seiten | Nicht getrackt: Admin-Nutzung verfälscht die Kundenstatistik, Impersonation würde Admin-Klicks dem Kunden zuschreiben, Auth-Seiten tragen Tokens im Pfad (`/reset-password/{token}`) |
|
||
| M8 | Query-Parameter an Umami | Nur `utm_*`, `src`, `ref`, `q`, `page` gehen raus; alles andere (Signaturen, Tokens) filtert `data-before-send` — gilt auch für die Webseiten |
|
||
| M9 | Fehlgeschlagene Logins | Im Verlauf mit User-Bezug (falls Konto existiert) und gekürztem HMAC der IP statt Klartext-IP |
|
||
|
||
## Phase 1 — Fehler fallen sofort auf
|
||
|
||
| Schritt | Inhalt | Stand |
|
||
|---|---|---|
|
||
| 1.1 | GlitchTip-Anbindung Server: `sentry/sentry-laravel`, `Integration::handles()` in `bootstrap/app.php`, Release aus `SENTRY_RELEASE`, User-ID als einziger Personenbezug | erledigt |
|
||
| 1.2 | Browserfehler (JS-Fehler, unbehandelte Promises) auf Webseiten, Auth-Seiten und Portal; eigener Vite-Eintrag `resources/js/error-reporting.js`, SDK erst beim ersten Fehler | erledigt |
|
||
| 1.3 | Fehler ohne Exception als GlitchTip-Warnung: 404 mit Referrer der eigenen Domain (kaputte interne Links), 403 und 429 für angemeldete Nutzer, 419 (Seite abgelaufen, Arbeit verloren). Je Signal gedrosselt | erledigt |
|
||
| 1.4 | Scheduler-Herzschlag (`monitoring:heartbeat`, minütlich) und Check im Systemstatus | erledigt |
|
||
| 1.5 | Tiefer Health-Endpunkt `/health` mit Token: DB, Cache, Queue-Rückstau, Scheduler-Herzschlag, Plattenplatz → 200/503 JSON, für Uptime Kuma bzw. Ploi | erledigt |
|
||
| 1.6 | ntfy als zweiter Alarmweg in `OperationalAlert` | erledigt |
|
||
| 1.7 | Fehlgeschlagene Logins, Login-Sperren und 2FA-Fehler im Aktivitäts-Verlauf | erledigt |
|
||
| 1.8 | `queue:prune-failed` (30 Tage) im Scheduler | erledigt |
|
||
| 1.9 | Umami: Portal (Kundenbereich) mit `identify`, Query-Filter, Web Vitals; Schalter getrennt (M6) | erledigt |
|
||
|
||
Signale, die **nicht** im Browser erfasst werden, weil der Server sie schon
|
||
sieht: fehlgeschlagene Livewire-Requests mit 5xx (Exception in GlitchTip) und
|
||
419 (Schritt 1.3).
|
||
|
||
## Phase 2 — Bedienprobleme sichtbar machen
|
||
|
||
- Validierungsfehler zentral zählen: Formular/Komponente × Feld × Regel, nie der Wert.
|
||
- Schritt-Tracking für die Kernabläufe (Registrierung, Newsroom anlegen,
|
||
PM erstellen/einreichen, Checkout, Bildbestätigung): `step_viewed` /
|
||
`step_completed`, pseudonymer Ablauf-Schlüssel, eigene kleine Tabelle,
|
||
Schreiben per `defer()`.
|
||
- Benannte Umami-Events (`data-umami-event`) an den Kern-Buttons.
|
||
- „Problem melden“ im Portal: URL, Browser, letzte GlitchTip-Event-ID, Freitext.
|
||
- Geschäftstrichter aus vorhandenen Daten (Registrierung → erste PM →
|
||
eingereicht → bezahlt → veröffentlicht → zweite PM), ohne neues Tracking.
|
||
|
||
## Phase 3 — Rückgänge und Abwanderung erkennen
|
||
|
||
- Tägliche Kennzahlen-Tabelle (Datum × Kennzahl × Dimension → Anzahl), nächtlich verdichtet.
|
||
- Alarme bei ausbleibender Aktivität: Einlieferer ohne Einlieferung, Tage
|
||
ohne Registrierung/Login/Zahlung, Funktionen deutlich unter dem 4-Wochen-Mittel.
|
||
- Überfällig-Liste je Kunde (übliches PM-Intervall × 2).
|
||
- Admin-Seite „Betrieb & Nutzung“; `conversion:funnel` und `api:usage-report` mit Oberfläche.
|
||
- Morgendliche Sammelmail.
|
||
- Löschfristen für `activity_events` und `api_usage_logs` (Vorschlag 395 Tage).
|
||
|
||
## Datenschutz (Betreiber/Anwalt, vor dem Einschalten)
|
||
|
||
- DSE §5 (Umami): Portal-Nutzung mit Zuordnung zur Nutzer-ID ist personenbezogen
|
||
(pseudonym) — Abschnitt ergänzen, bevor `UMAMI_PORTAL_ENABLED`/`UMAMI_IDENTIFY_USERS` an.
|
||
- Neuer Abschnitt Fehlerprotokollierung (GlitchTip, selbst gehostet; User-ID,
|
||
URL, Browser, Fehlermeldung; Frist = GlitchTip-Aufbewahrung, Vorschlag 90 Tage).
|
||
- Aktivitäts-Verlauf mit fehlgeschlagenen Anmeldungen (IP nur als gekürzter HMAC).
|
||
- Unabhängig davon offen: `activity_events`/`api_usage_logs` ohne Löschfrist und ohne DSE-Erwähnung.
|
||
|
||
## Live-Schritte Phase 1
|
||
|
||
Ausgeführt mit Deploy v1.1.0 — vollständiger Ablauf in [`deploy-v1.1.0.md`](../archive/betrieb/deploy-v1.1.0.md).
|
||
|
||
**Infrastruktur (einmalig)**
|
||
|
||
1. GlitchTip auf sys.adametz.media (Docker Compose: web, worker, Postgres,
|
||
Redis; `GLITCHTIP_RETENTION_DAYS=90`, vor GlitchTip 6 `GLITCHTIP_MAX_EVENT_LIFE_DAYS`). Zwei Projekte anlegen:
|
||
`pressekonto-server` (PHP/Laravel) und `pressekonto-browser` (JavaScript).
|
||
Alert-Regel je Projekt: Mail an das Ops-Postfach bei neuem Fehlertyp.
|
||
2. ntfy: Server (ntfy.sh oder selbst gehostet), Topic mit Zugriffsschutz,
|
||
Token anlegen. Optional GlitchTip-Webhook an ntfy über dessen
|
||
Template-Funktion.
|
||
3. Uptime Kuma (oder Ploi-Monitor) auf `https://pressekonto.com/health` mit
|
||
Header `Authorization: Bearer <MONITORING_HEALTH_TOKEN>`, Intervall 1 min,
|
||
Benachrichtigung über ntfy und Mail.
|
||
|
||
**`.env` auf Live**
|
||
|
||
```
|
||
SENTRY_LARAVEL_DSN=… # Projekt pressekonto-server
|
||
SENTRY_ENVIRONMENT=production
|
||
SENTRY_RELEASE= # leer lassen, siehe RELEASE-Datei unten
|
||
SENTRY_BROWSER_DSN=… # Projekt pressekonto-browser
|
||
MONITORING_HEALTH_TOKEN=<zufällig, ≥ 32 Zeichen>
|
||
MONITORING_NTFY_URL=https://push.adametz.media
|
||
MONITORING_NTFY_TOPIC=pressekonto-ops
|
||
MONITORING_NTFY_TOKEN=…
|
||
UMAMI_ENABLED=true # Webseiten
|
||
UMAMI_PORTAL_ENABLED=false # erst nach DSE-Anpassung
|
||
UMAMI_IDENTIFY_USERS=false # erst nach DSE-Anpassung
|
||
```
|
||
|
||
Danach `config:cache`, `npm run build`, `queue:restart`.
|
||
|
||
**Bei jedem Deploy (SFTP/SSH, solange es kein Git-Deploy gibt):** lokal vor
|
||
dem Upload `git describe --tags --always --dirty > RELEASE` und die Datei `RELEASE`
|
||
mit hochladen, danach auf dem Server `php artisan config:cache`. GlitchTip
|
||
ordnet Fehler so dem Stand zu (`…-dirty` = mit nicht committeten Änderungen
|
||
deployt). Beim späteren Git-Deploy schreibt das Deploy-Skript dieselbe Datei.
|
||
|
||
GlitchTip-Instanz: `errors.adametz.media`, Projekt 1 = Server, Projekt 2 = Browser.
|
||
Umgebungen: `production` (Live), `local` (Entwicklung).
|
||
|
||
## Umsetzungsprotokoll
|
||
|
||
### 02.10.2026 — Phase 1 umgesetzt (Branch `technik/monitoring-phase-1`)
|
||
|
||
Neue Abhängigkeiten: `sentry/sentry-laravel` ^4.28 (Composer, nur neue
|
||
Pakete), `@sentry/browser` ^11.3 (npm).
|
||
|
||
| Schritt | Dateien |
|
||
|---|---|
|
||
| 1.1 | `config/sentry.php` (veröffentlicht, gehärtet), `app/Support/Monitoring/ErrorReportScrubber.php`, `bootstrap/app.php` (`Integration::handles`) |
|
||
| 1.2 | `resources/js/error-reporting.js` + `error-reporting-sdk.js` (Chunk 32 kB gzip, nur bei Fehler), `resources/views/components/monitoring/browser-errors.blade.php`, eingebunden in `partials/head` (Portal), `web/layouts/web-master`, `components/layouts/auth/pressekonto`; Vite-Einträge in beiden Configs |
|
||
| 1.3 | `app/Support/Monitoring/ErrorSignal.php`, `app/Http/Middleware/ReportErrorSignals.php` (global) |
|
||
| 1.4 | `app/Console/Commands/MonitoringHeartbeat.php`, Scheduler minütlich, Check `scheduler` im Systemstatus |
|
||
| 1.5 | `app/Services/Monitoring/HealthProbe.php`, `app/Http/Controllers/HealthController.php`, Route `/health` (ohne Gruppe, throttle 30/min), Basic-Auth-Ausnahme; Check `disk` im Systemstatus |
|
||
| 1.6 | `app/Support/OperationalAlert.php` (Mail und ntfy unabhängig, beide Best-Effort) |
|
||
| 1.7 | `ActivityType::LoginFailed/LoginLockout/TwoFactorFailed`, `RecordAuthActivity` (Grund `unknown_account`/`no_password`/`wrong_password`, `ip_hash`), Login-Komponente feuert `Failed` und `Lockout` mit Adresse |
|
||
| 1.8 | `queue:prune-failed --hours=720` täglich 03:55 |
|
||
| 1.9 | `components/web/umami.blade.php` (Web + Portal, `data-tag`, `data-before-send`, `data-performance`, `identify('user-<id>')`), `config/services.php` (`portal_enabled`, `identify_users`) |
|
||
|
||
Nebenbefund: Das Umami-Snippet der Webseiten schickte bisher die volle Query
|
||
mit — signierte Claim-Links (`?signature=…`) landeten so in Umami. Der Filter
|
||
(M8) gilt jetzt auch dort.
|
||
|
||
Tests: `tests/Feature/Monitoring/*` (neu), `tests/Feature/Auth/FailedLoginActivityTest.php`
|
||
(neu), `OperationalAlertTest` und `UmamiSnippetTest` erweitert. Gesamtsuite
|
||
2312 grün (1 übersprungen), Larastan ohne Meldung, Pint sauber.
|
||
|
||
Nicht im Browser geprüft (kein GlitchTip/ntfy angebunden): das tatsächliche
|
||
Einliefern an GlitchTip und die Darstellung dort. Erster Test nach dem
|
||
Aufsetzen: im Browser `setTimeout(() => { throw new Error('GlitchTip-Test') })`
|
||
auf einer Portalseite, serverseitig `php artisan tinker --execute 'report(new RuntimeException("GlitchTip-Test"));'`.
|
||
|
||
### 05.10.2026 — Composer-Update
|
||
|
||
`composer update` innerhalb der bestehenden Grenzen (48 Updates, u. a.
|
||
Laravel 12.69.3, Livewire 4.4.7, Flux 2.20.1, Fortify 1.40.0); damit sind die
|
||
beiden `league/commonmark`-Advisories behoben (2.10.3), `composer audit` sauber.
|
||
|
||
- Livewire 4.4.7 rendert `ModelNotFoundException` im Testhelfer als 404,
|
||
statt sie zu werfen — zwei Tests auf `assertNotFound()` umgestellt
|
||
(`CustomerCompanyContextTest`, `ContactAccessTest`). Laufzeitverhalten unverändert.
|
||
- **Deploy:** Liegt auf Live `public/vendor/livewire/` (veröffentlichte Assets),
|
||
nach `composer install` `php artisan vendor:publish --tag=livewire:assets --force`
|
||
ausführen — sonst läuft ein altes `livewire.js` gegen das neue Backend.
|
||
Lokal war die Kopie schon vor dem Update veraltet (Hash 3dabe98a statt 8ea5922c).
|
||
|
||
### 05.10.2026 — GlitchTip angebunden (lokal)
|
||
|
||
DSNs eingetragen (errors.adametz.media, Projekte 1 und 2), lokal
|
||
`SENTRY_ENVIRONMENT=local`. Release-Kennung ohne Git auf dem Server:
|
||
`App\Support\Monitoring\Release` liest `SENTRY_RELEASE`, sonst die beim
|
||
Deploy hochgeladene Datei `RELEASE` (in `.gitignore`). Test-Events lokal
|
||
abgeschickt: Server-Exception (`report()`), toter interner Link per HTTP.
|
||
|
||
### 05.10.2026 — ntfy angebunden (lokal)
|
||
|
||
ntfy auf `push.adametz.media` (gleicher Server wie GlitchTip),
|
||
`auth-default-access: deny-all` (anonymes Lesen → 403 geprüft). Eigener
|
||
Benutzer `pressekonto-alerts` mit `write-only` auf `pressekonto-ops`, Token in
|
||
`MONITORING_NTFY_TOKEN`; Lesen über den persönlichen Benutzer in der App.
|
||
Test-Alert aus `OperationalAlert` ohne Fehler angenommen.
|
||
|
||
### 05.10.2026 — Versionsnummer
|
||
|
||
Versionen sind Git-Tags nach SemVer (`v1.0.0` Go-Live 20.07., nächster Deploy
|
||
`v1.1.0`). `config('app.version')` = `APP_VERSION` oder Datei `RELEASE`
|
||
(`git describe --tags --always --dirty`); dieselbe Kennung als GlitchTip-Release,
|
||
in `/health` (`version`), im Admin-Systemstatus und in `php artisan about`.
|
||
Grundlage für die spätere Changelog-Seite.
|
||
|
||
### 05.10.2026 — Phase 1 live (v1.1.0)
|
||
|
||
Mit Deploy v1.1.0 ausgeliefert ([`deploy-v1.1.0.md`](../archive/betrieb/deploy-v1.1.0.md)).
|
||
GlitchTip (`production`), ntfy und Scheduler-Herzschlag auf Live aktiv.
|
||
Offen aus Phase 1: externer Monitor auf `/health`; DSE-Absätze, danach
|
||
`UMAMI_PORTAL_ENABLED`/`UMAMI_IDENTIFY_USERS`.
|
||
|
||
### 06.10.2026 — Erste Auswertung von GlitchTip
|
||
|
||
Lesezugriff per API eingerichtet; Arbeitsanleitung, Regeln und Protokoll der
|
||
Einträge in [`../glitch-tip/README.md`](../glitch-tip/README.md). Befunde:
|
||
Testsuite meldete an die echte DSN (behoben, `2f02acc`), Search-Console-Lauf
|
||
robuster (`a90f24a`), Registrierung mit Alpine-Fehler, Promise-Ablehnungen
|
||
lesbar, Tippfehler bei artisan nicht mehr gemeldet (`16af374`).
|
||
|
||
### 06.10.2026 — Nachtrag 1.7: fehlgeschlagene Anmeldungen
|
||
|
||
Befund auf Live (05.10. 15:26 – 06.10. 16:25): rund 250 Fehlversuche aus
|
||
53 Quellen, **alle** `unknown_account`, kein falsches Passwort, keine Sperre,
|
||
gleichmäßig auch nachts — verteiltes, langsames Durchprobieren fremder
|
||
Zugangsdaten („low and slow“, jede Quelle bleibt unter der Sperre von
|
||
5/Minute). Kein Konto betroffen. Die Einträge verdeckten im Verlauf die
|
||
relevanten Fälle. Das Nginx-Zugriffsprotokoll der Site ist bei Ploi aus,
|
||
der Einstieg ließ sich so nicht klären.
|
||
|
||
Umgesetzt:
|
||
|
||
- `meta.entry` an jedem Fehlversuch, jeder Sperre und jedem 2FA-Fehler:
|
||
`livewire` (Formular), `fortify` (`POST /login`, alle Domains, auch JSON),
|
||
`two-factor`, sonst `other`.
|
||
- Unbekannte Adressen nicht mehr im Verlauf, sondern in `failed_login_tallies`
|
||
(Tag × Einstieg × IP-Hash → Versuche, erster/letzter Zeitpunkt). Löschfrist
|
||
90 Tage über `model:prune` (täglich 04:05).
|
||
- Systemstatus-Kachel „Anmeldeversuche mit unbekannter Adresse“ (heute/gestern,
|
||
Versuche und Quellen); `warn` ab `MONITORING_FAILED_LOGIN_WARN_PER_DAY` (1000).
|
||
|
||
Auswertung auf Live (nach dem Deploy):
|
||
|
||
```bash
|
||
php artisan tinker --execute '
|
||
DB::table("failed_login_tallies")
|
||
->where("day", ">=", now()->subDays(7)->toDateString())
|
||
->selectRaw("day, entry, count(*) as quellen, sum(attempts) as versuche")
|
||
->groupBy("day", "entry")->orderBy("day")->orderBy("entry")
|
||
->get()
|
||
->each(fn ($r) => print(sprintf("%s %-10s %4d Quellen %5d Versuche\n", $r->day, $r->entry, $r->quellen, $r->versuche)));
|
||
'
|
||
```
|
||
|
||
Danach entscheiden: überwiegend `fortify` → `POST /login` auf den Hub
|
||
beschränken bzw. je IP drosseln (vorher klären, wer den JSON-Login nutzt);
|
||
überwiegend `livewire` → Honeypot/Turnstile im Formular.
|
||
|
||
### Externer Monitor auf `/health` — Einrichtung (erledigt 06.10.2026, status.adametz.media)
|
||
|
||
Ziel: Ausfälle melden, die die App selbst nicht melden kann (Server weg,
|
||
PHP-FPM hängt, Scheduler steht, Platte voll). **Uptime Kuma** auf dem
|
||
GlitchTip-Server (`178.105.154.106`); die App läuft auf `178.105.240.70` —
|
||
ein anderer Server, also echte Außensicht. ntfy liegt auf demselben Server
|
||
wie Uptime Kuma; fällt dieser aus, kommt kein Push (siehe Schritt 6).
|
||
|
||
1. **Installation** (Docker, neben GlitchTip, hinter demselben Reverse Proxy,
|
||
z. B. `status.adametz.media`):
|
||
|
||
```yaml
|
||
services:
|
||
uptime-kuma:
|
||
image: louislam/uptime-kuma:1
|
||
restart: unless-stopped
|
||
volumes:
|
||
- ./uptime-kuma:/app/data
|
||
ports:
|
||
- "127.0.0.1:3001:3001"
|
||
```
|
||
|
||
Admin-Konto beim ersten Aufruf anlegen, 2FA in den Einstellungen aktivieren.
|
||
2. **Benachrichtigung** (Settings ▸ Notifications ▸ ntfy): Server
|
||
`https://push.adametz.media`, Topic `pressekonto-ops`, Priorität 4,
|
||
Authentifizierung „Access Token“ mit dem Token von `pressekonto-alerts`.
|
||
Zusätzlich SMTP-Mail an das Ops-Postfach.
|
||
3. **Monitor „pressekonto /health“**: Typ HTTP(s), URL
|
||
`https://pressekonto.com/health`, Methode GET, Header (JSON)
|
||
`{"Authorization": "Bearer <MONITORING_HEALTH_TOKEN aus der Live-.env>"}`,
|
||
Intervall 60 s, Wiederholungen 2 (Retry-Intervall 60 s), akzeptierte
|
||
Statuscodes `200-299`. 503 = mindestens ein Check kritisch, Details in der
|
||
JSON-Antwort.
|
||
4. **Monitore „Domains“** ohne Token, Typ HTTP(s) - Keyword oder HTTP(s):
|
||
`https://presseecho.de/up`, `https://businessportal24.com/up`,
|
||
`https://pressekonto.com/up` — prüft Nginx/SSL/PHP je Domain, Intervall 5 min.
|
||
Zertifikatsablauf-Warnung aktivieren (Settings ▸ „Certificate Expiry Notification“, 14 Tage).
|
||
5. **Test:** Einen zweiten Monitor mit absichtlich falschem Token anlegen —
|
||
`/health` antwortet dann 404, der Alarm muss auf dem Handy und per Mail
|
||
ankommen. Danach diesen Test-Monitor löschen. Beim nächsten Deploy zeigt
|
||
der echte Monitor die Wartungsphase (`down` → 503) als kurzen Ausfall.
|
||
6. **Zweite Ebene (optional, empfohlen):** ein kostenloser externer Dienst
|
||
(z. B. UptimeRobot) mit einem einfachen Monitor auf `https://pressekonto.com/up`
|
||
und Mail-Benachrichtigung. Er meldet, wenn der Monitoring-Server selbst
|
||
ausfällt oder beide Server gemeinsam nicht erreichbar sind.
|
||
|
||
Nach der Einrichtung: Punkt 29 in `../archive/betrieb/deploy-v1.1.0.md` und Phase 1 hier als erledigt eintragen.
|
||
|
||
### 06.10.2026 — Worker-Ausfall und Folgen (v1.3.2)
|
||
|
||
Nach dem Deploy von `v1.3.0` (16:51) lief über eine Stunde kein Queue-Worker:
|
||
Supervisor war gestoppt, `queue:restart` beendete den Worker, niemand startete
|
||
ihn neu. Sichtbar war es nur in der Systemstatus-Kachel; einen Alarm gab es
|
||
nicht — `/health` hätte 503 geliefert, der externe Monitor war noch nicht
|
||
eingerichtet. Beim Abarbeiten scheiterten drei Veröffentlichungsmails vom
|
||
03./08.09., die erneut eingestellt worden waren (GlitchTip #23, alte
|
||
Serialisierung ohne `$viaSyndication`) — entfernt, nicht nachgesendet.
|
||
|
||
- **Externer Monitor** läuft seit 06.10.2026 (`status.adametz.media`, Uptime
|
||
Kuma). Er deckt einen stehenden Worker ab: `/health` meldet `queue`
|
||
kritisch ab 5 Minuten Wartezeit. Ein zusätzlicher Alarm aus dem Scheduler
|
||
wurde deshalb **bewusst nicht** gebaut (wäre doppelt).
|
||
- **Worker-Prüfung im Deploy** (`monitoring:queue-probe`, Ende von
|
||
`deploy.sh`, Exit 3 ohne Worker).
|
||
- **Runbook:** kein pauschales `queue:retry all` mehr; Vorgehen bei stehendem Worker.
|
||
|
||
### 07.10.2026 — Allgemeine Fassung für andere Projekte
|
||
|
||
Git-Deploy und Betriebsüberwachung als übertragbarer Baukasten mit Vorlagen
|
||
(Laravel-Dateien, `deploy.sh`, Docker-Compose für GlitchTip/ntfy/Uptime Kuma):
|
||
[`../git-deploy-monitoring/`](../git-deploy-monitoring/README.md). In einem
|
||
frischen Laravel 12 eingebaut und getestet.
|