Vollstaendige Erklaerung des Session-Lifecycle: Wann wird ein User abgemeldet, wann greift der Remember-Token, wie bleiben Frontend und Server synchron.
## Session-Lifecycle (Uebersicht)
```
Login (Passwort / SSO)
│
├─ $_SESSION['session_started_at'] = time()
├─ $_SESSION['session_last_activity'] = time()
└─ Optional: Remember-Token (Cookie, 30 Tage)
│
▼
Jeder Request (web/index.php)
│
├─ Session vorhanden?
│ ├─ JA → Idle-Check + Absolute-Check
│ └─ NEIN → Remember-Cookie vorhanden?
│ ├─ JA → Auto-Login (Token validieren + rotieren)
│ └─ NEIN → Redirect /login
│
├─ authz_version geaendert? → Permissions neu laden
- Throttled auf 30s (kein Overhead bei schnellem Scrollen)
- Setzt nur den JS-Timer zurueck, nicht den Server-Timer
### Background-Keepalive
Problem ohne Keepalive: User scrollt 29 Min auf einer Seite → JS zeigt "aktiv", Server sagt "idle".
Loesung: Alle 5 Minuten prueft ein Intervall ob seit dem letzten Sync Interaktion stattfand. Falls ja → `POST /admin/session-ping/data` → Server-Timer zurueckgesetzt.
| Szenario | Keepalive-Ping? |
|----------|-----------------|
| User aktiv (Maus, Scroll, Klick) | Ja, alle 5 Min |
| User wirklich idle | Nein |
| Warning-Dialog offen | Nein |
| Tab im Hintergrund | Nein (keine Events) |
### Warning-Dialog
- Erscheint 2 Min vor Idle-Timeout
- Nur bei Idle-Timeout >= 3 Min
- Kann nicht per ESC oder Backdrop geschlossen werden
- Zwei Optionen: **Session verlaengern** (POST Ping) oder **Abmelden** (Redirect /logout)
Solange der Remember-Token lebt (Default 30 Tage), bekommt der User nach Ablauf des Absolute-Timeout automatisch eine neue Session. Der Uebergang ist nahtlos (kein Flash, kein Login-Screen).
Das bedeutet: Mit aktivem Remember-Token ist die effektive Session-Dauer nicht 8 Stunden, sondern bis zu 30 Tage. Das ist by-design, sollte aber bei Compliance-Anforderungen (z. B. echte Re-Authentifizierung nach X Stunden) beruecksichtigt werden.
## Cookie-Attribute
| Attribut | Wert | Grund |
|----------|------|-------|
| `httponly` | `true` | Kein JS-Zugriff (XSS-Schutz) |
| `samesite` | `Lax` | CSRF-Schutz bei Cross-Site-Navigation |
| `secure` | dynamisch | `true` bei HTTPS, `false` bei HTTP (Dev) |
| `path` | `/` | Gueltig fuer gesamte Domain |
Das Secure-Flag wird automatisch anhand des Protokolls gesetzt (`RequestRuntime::isSecure()`). In Produktion muss HTTPS ueber Nginx erzwungen werden (Redirect 80→443 + HSTS).