# Fortsetzungsdokument: Umsetzungsauftrag_Sonnet5.md — Teil F (Mehrere Sitzungen je Benutzer mit Seitenleiste) Stand: 2026-09-01, Stufen F1+F2+F3+F4+F5 abgeschlossen und verifiziert (F.6-Abnahme noch ausstehend, siehe Abschnitt 6). Repo: `ssh_jumphost` (FastAPI/SQLite SSH/RDP-Jumphost), erreichbar ueber die device_bash-Bridge unter `$HOME/mnt/ssh_jumphost`. **Reihenfolge des Gesamtauftrags** (verbindlich, siehe `Umsetzungsauftrag_Sonnet5.md`): Teil A/B -> Teil E -> Teil C (fertig) -> Teil D (fertig, siehe `FORTSETZUNG_Teil_D.md`) -> **Teil F (dieses Dokument, laufend)** -> Aufgabe #11 (SSH Copy-Paste + Terminal-Farben, vom Nutzer nachtraeglich hinzugefuegt). **Erledigt: Teil A, Teil B, Teil E, Teil C, Teil D** -- alle vollstaendig abgeschlossen in frueheren Sessions, hier nicht mehr relevant. Teil F siehe unten. --- ## 0) Betreiberentscheidungen fuer Teil F (Nutzerantworten dieser Session) Der Umsetzungsauftrag verlangt vor Beginn von Teil F Antworten auf drei der acht offenen Betreiberentscheidungen (Abschnitt "Offene Entscheidungen fuer den Betreiber", Punkte 6-8): 1. **#6 Obergrenze gleichzeitiger Sitzungen (Teil E.4)** -- bereits durch eine fruehere Session beantwortet und implementiert: `app/config.py` `max_sessions_per_user=6`, `max_sessions_global=100` (Env-Overrides `JUMPHOST_MAX_SESSIONS_PER_USER`/`_GLOBAL`), durchgesetzt in `app/ssh_proxy/terminal_ws.py` und `app/rdp_proxy/ws_tunnel.py` VOR jedem Ressourcenverbrauch. Keine neue Entscheidung noetig. 2. **#7 Verhalten von Hintergrundsitzungen (F.3.9)** -- Nutzerentscheidung dieser Session: **voll verbunden bleiben** (Spec-Empfehlung fuer Stufe 1). Kein Halte-/Pausenzustand, keine neue Zustandsmaschine. Die bereits vorhandene niedrige Obergrenze (Punkt 1) begrenzt den Ressourcenverbrauch. 3. **#8 Wiederanschluss nach Seiten-Reload (F.3.7)** -- Nutzerentscheidung dieser Session: **kein Wiederanschluss, klar beschriftet** (Spec-Empfehlung fuer Stufe 1). Ein Reload beendet die Sitzung wie heute; die Oberflaeche muss das ehrlich kommunizieren ("Sitzung wurde beendet, erneut verbinden"), statt es zu verschweigen. Serverseitiges Halten von SSH-Verbindung + Ausgabepuffer ueber eine Trennung hinweg ist explizit NICHT Teil dieser Umsetzung (F.3.7, Umsetzungsauftrag: "kein Nebenbei-Feature"). ## 0a) Ist-Zustand-Bestandsaufnahme (vor F1) Bereits vorhanden und fuer Teil F wiederverwendbar (nichts davon musste neu gebaut werden): * **E7 Session-Reaper** (`app/security/session_reaper.py`, in `app/main.py::lifespan` vor dem ersten Request aufgerufen) -- keine Geistersitzungen nach Neustart. * **E9 Keepalive** (`static/js/session-keepalive.js`, in terminal.html/ rdp.html eingebunden) -- haelt das Anmelde-Cookie waehrend einer offenen Sitzung per periodischem `GET /auth/me` am Leben. * **E10 Aktivitaets-basierter Idle-Timeout** (`app/ssh_proxy/terminal_ws.py` `IDLE_TIMEOUT_SECONDS`, `activity["t"]` wird sowohl bei Ein- als auch bei Ausgabe aktualisiert) -- ein `tail -f` im Hintergrund haelt die Sitzung am Leben. * **E.4 Obergrenzen + Registry** (`app/security/active_sessions.py`: `count_for_user()`, `count_total()`, prozesslokale In-Memory-Registry mit `task`/`user_id`/`watchers`) -- Grundlage fuer F.3.6 (eigene Sitzungs-API, Stufe F2). * **D4 RDP dynamische Aufloesung** (`resize-method: display-update` in `app/rdp_proxy/guacd_client.py::build_rdp_params()`, `client.sendSize()` bereits in `rdp.js` aufgerufen mit Debounce) -- F.3.3 kann direkt darauf aufbauen, keine Server-Aenderung noetig. * **GET /admin/sessions + Beenden-Logik** (`app/admin/routes.py`) als Referenzmuster fuer die in F2 zu bauende, auf `user_id=eigene` beschraenkte Variante im Katalog-Router. ## 1) Stufe F1 -- FERTIG (terminal.js/rdp.js zu instanzierbaren Bausteinen) **Ziel (F.3.1):** aus zwei Dokument-Singletons (ein Skript pro Seite, feste Element-IDs) werden zwei Klassen mit genau einer Instanz pro Sitzung: `connect()`, `dispose()`, `setActive(bool)`, ein Statusrueckruf fuer eine kuenftige Seitenleiste. Verhalten danach unveraendert (reiner Umbau). ### Umgesetzt * **`static/js/terminal.js`**: `class SshTerminalSession` -- baut ihr komplettes DOM (Toolbar, Terminal-Container, Dateitransfer-Panel) selbst per `innerHTML`-Template und `document.createElement`, referenziert intern ausschliesslich ueber Klassen (`.session-shell`, `.status`, `.ft-overlay` usw. -- keine IDs mehr fuer die interne Verdrahtung, mit Ausnahme von zwei dynamisch generierten, instanzeindeutigen IDs fuer die `