From 2598656f1c1fd51ee716a15b12caf04d89798baf Mon Sep 17 00:00:00 2001 From: Meleki Date: Fri, 6 Mar 2026 15:51:47 +0100 Subject: [PATCH] docs: ARCHITECTURE.md + ARCHITECTURE_QUICK.md aktualisiert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Chat: POST /api/chat/stop Endpoint + Stop-Mechanismus (zwei Ebenen) dokumentiert - StreamingTracker: CancellationTokenSource pro Session beschrieben - Auth: GET /api/auth/autologin, GET /api/images/file/* ohne Auth - Admin: POST login-link Endpoint + Login-Link-Sektion - Krea: Thumb-Endpoint, Status-Endpoint, öffentliches Bild-Serving - Frontend: buildAgentCard(), buildSessionCard() UI-Helpers + Picker-Modals - ui.js in Verzeichnisstruktur ergänzt --- ARCHITECTURE.md | 60 +++++++++++++++++++++++++++++++++---------- ARCHITECTURE_QUICK.md | 20 +++++++++------ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index a76c79d..8b3bb1b 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -124,7 +124,7 @@ gott/ │ ├── CronjobService.cs # BackgroundService für Cron-Tasks │ ├── KreaService.cs # Krea Image Generation API │ ├── ImageService.cs # Bild-Resize (Avatar, Session-Image) -│ ├── StreamingTracker.cs # Concurrent Tracking aktiver Streams +│ ├── StreamingTracker.cs # Tracking aktiver Streams + CancellationTokenSource für Stop │ └── WorkspaceHelper.cs # Workspace-Pfad-Auflösung (relativ → absolut) │ ├── Endpoints/ # HTTP API (Minimal API) @@ -336,7 +336,7 @@ AuthService → DatabaseService → EnsureDefaultUser | `CronjobService` | Background | Minütlicher Check auf fällige Cronjobs, Ausführung via Claude | | `KreaService` | Singleton | Krea API für Bildgenerierung, Job-Polling, Image-Download | | `ImageService` | Singleton | Bild-Resize (max 512px) für Avatare und Session-Bilder | -| `StreamingTracker` | Singleton | ConcurrentDictionary – trackt welche Sessions gerade streamen | +| `StreamingTracker` | Singleton | Trackt aktive Streams + CancellationTokenSource pro Session für Stop-Button | ### Endpoints (API) @@ -344,16 +344,16 @@ Alle Endpoints folgen dem **Minimal API**-Pattern mit Extension Methods (`MapXxx | Gruppe | Basis-Route | Methoden | |---------------|----------------------------|---------------------------------------------| -| **Auth** | `/api/auth/` | `POST login`, `POST logout`, `GET me` | -| **Chat** | `/api/chat` | `POST` (SSE Streaming) | +| **Auth** | `/api/auth/` | `POST login`, `POST logout`, `GET me`, `GET autologin` | +| **Chat** | `/api/chat` | `POST` (SSE Streaming), `POST stop` | | **History** | `/api/history` | `GET history`, `GET poll`, `POST archive`, `GET archives`, `GET archive/{id}`, `GET attachments/{id}`, `PUT messages/{id}/mark`, `PUT messages/{id}/delete`, `GET chains/{id}` | | **Sessions** | `/api/sessions/` | CRUD + `GET system-prompt`, `GET system-prompt-blocks`, `GET streaming`, `POST exec`, `GET git-status` | | **Agents** | `/api/agents/` | CRUD | -| **Admin** | `/api/admin/` | `GET users`, `POST users`, `PUT users/{id}`, `PUT users/{id}/password`, `DELETE users/{id}`, `POST users/{id}/impersonate` (Admin-only) | +| **Admin** | `/api/admin/` | `GET users`, `POST users`, `PUT users/{id}`, `PUT users/{id}/password`, `DELETE users/{id}`, `POST users/{id}/impersonate`, `POST users/{id}/login-link` (Admin-only) | | **Workspace** | `/api/workspace/` | `GET tree`, `GET/PUT file`, `GET browse`, `POST mkdir`, `DELETE dir`, `POST browse/mkdir`, `GET agent/tree`, `GET/PUT agent/file`, `POST agent/mkdir`, `GET raw` | | **Telegram** | `/api/telegram/` | `POST webhook/{sessionId}` (unauthenticated), Session-Config CRUD, Webhook-Management | | **Cronjobs** | `/api/cronjobs/` | CRUD + `POST toggle`, `POST run` | -| **Krea** | `/api/images/` | `POST generate`, `GET list`, `GET file/{name}`, `GET status` | +| **Krea** | `/api/images/` | `POST generate`, `GET list`, `GET file/{name}`, `GET file/{name}/thumb`, `GET status` | | **Skills** | `/api/skills` | `GET list`, `GET/PUT agent skills`, Output-Files + Thumbnails | | **Profile** | `/api/profile` | `GET`, `PUT`, `PUT password` | | **Settings** | `/api/settings` | `GET`, `PUT` | @@ -371,6 +371,7 @@ Ausnahmen (kein Auth nötig): - `GET /api/auth/autologin` (Token-basierter Autologin via Link) - `POST /api/telegram/webhook/{sessionId}` (authentifiziert via Secret-Header) - `GET /api/shared/{token}` (öffentlicher Zugriff auf geteilte Nachrichten) +- `GET /api/images/file/*` (Krea-Bilder und Thumbnails, öffentlich) **API-Key Auth** (ohne User-Kontext): - `/api/images/*`-Routen akzeptieren einen `X-Api-Key`-Header. Wenn der Key mit `KreaApiKey` aus der Config übereinstimmt, wird der Request ohne User-Authentifizierung durchgelassen. Normaler Cookie-Auth funktioniert weiterhin als Fallback. @@ -422,13 +423,19 @@ Das Frontend ist eine **Single-Page Application** ohne Build-Step, komplett in V - **app.js** – Initialisierung, Auth-Check, globale Event-Handler - **api.js** – Zentraler API-Client mit `fetch()`-Wrapper, Auth-Redirect bei 401 -- **ui.js** – UI-Utilities (Modals, Toasts, Confirmations, etc.) +- **ui.js** – UI-Utilities (Modals, Toasts, Confirmations), Card-Builder (`buildAgentCard()`, `buildSessionCard()`), Markdown-Rendering-Helpers (`esc()`, `prettyModelName()`) - **chat.js** – SSE-Stream-Handling, Markdown-Rendering (mit KaTeX), Tool-Output-Darstellung - **history.js** – Chat-History laden, paginieren, rendern - **session.js** – Session-State-Management - **file-explorer.js** – Workspace File-Explorer Panel (Dateien, Ordner erstellen/löschen, Folder-Browser) - **avatar-editor.js** – Wiederverwendbares Avatar-Editor-Modal (Upload, Paste, AI-Generate, Scale) - **commands-ui.js** – Custom-Commands UI-Komponente + +### Wiederverwendbare Card-Builder (ui.js) + +- **`buildAgentCard(agent, skills)`** – Erzeugt ein `.card` DOM-Element für einen Agent (Avatar, Name, Model-Badge, Feature-Badges: toolChoice, autoCommit, useSoul, useIdentity, useUserInfo, useMemory, webSearch, Skills). Wird im Dashboard und im Agent-Picker-Modal (Session-Formular) verwendet. +- **`buildSessionCard(session, agent)`** – Erzeugt ein `.card` DOM-Element für eine Session (Avatar, Name, Badges: Agent, Kontext, Telegram, Meta: Nachrichten/Archiv/Workspace). Wird im Dashboard und im Session-Picker-Modal (Cronjob-Formular) verwendet. +- **Picker-Modals** – Agent- und Session-Auswahl in Formularen (Session-/Cronjob-Seiten) erfolgt über modale Dialoge mit den Card-Buildern statt über Dropdowns. - **emoji.js** – Emoji-Picker mit Kategorien und Suche - **tooltip.js** – Tooltip-System für Hover-Infos - **title.js** – Dynamisches Tab-Titel-Management @@ -482,12 +489,23 @@ Der Chat-Flow von User-Input bis zur gerenderten Antwort: ### Abbruch (Stop-Button) -Das `CancellationToken` wird durchgängig propagiert: -1. Frontend: `AbortController.abort()` → SSE-Fetch abgebrochen -2. ASP.NET: `RequestAborted` Token wird gecancelled +Der Stop-Mechanismus arbeitet auf zwei Ebenen: + +**1. Expliziter Stop-Endpoint (`POST /api/chat/stop`):** +- Frontend ruft `apiStopChat(sessionId)` auf +- `StreamingTracker` hält pro Session einen `CancellationTokenSource` +- `StreamingTracker.Cancel(sessionId)` cancelt den Token sofort +- Der Chat-Handler verknüpft den Stop-Token mit dem Request-Token via `CreateLinkedTokenSource` + +**2. CancellationToken-Propagierung:** +1. Frontend: `AbortController.abort()` → SSE-Fetch abgebrochen + `POST /api/chat/stop` +2. `StreamingTracker.Cancel()` → CancellationTokenSource wird gecancelled 3. `AnthropicService`: `ThrowIfCancellationRequested()` am Loop-Anfang, vor/nach Tool-Execution -4. `WriteSseEvent()`: Alle SSE-Writes mit CancellationToken → sofortiger Abbruch bei Client-Disconnect -5. Chain wird mit `StopReason = "client_disconnected"` finalisiert +4. `ToolService.ExecuteTool()`: CancellationToken wird durchgereicht → bei `execute` wird der Prozess gekillt +5. `WriteSseEvent()`: Alle SSE-Writes mit CancellationToken → sofortiger Abbruch +6. Chain wird mit `StopReason = "client_disconnected"` finalisiert + +**Warum zwei Ebenen?** Kestrel erkennt einen Client-Disconnect erst beim nächsten Write auf den Response-Stream. Wenn das Backend in einer langen Tool-Ausführung steckt, wird nichts geschrieben – der explizite Stop-Endpoint garantiert sofortigen Abbruch. ### Streaming vs Non-Streaming @@ -781,7 +799,11 @@ chatgpt-image, runway-gen-4 ### Bild-Serving - `GET /api/images` – Liste aller generierten Bilder (aus Metadaten-JSON) -- `GET /api/images/file/{filename}` – Einzelnes Bild ausliefern +- `GET /api/images/file/{filename}` – Einzelnes Bild ausliefern (ohne Auth) +- `GET /api/images/file/{filename}/thumb` – Thumbnail (320px WebP, gecacht in `data/cache/images/`, ohne Auth) +- `GET /api/images/status` – Generierungsstatus abfragen + +Bild-Dateien und Thumbnails sind **ohne Authentifizierung** abrufbar (für externe Einbindung). --- @@ -837,6 +859,7 @@ Admins können alle User verwalten über `AdminEndpoint.cs` (alle Endpoints erfo | `PUT` | `/api/admin/users/{id}/password` | Passwort zurücksetzen | | `DELETE` | `/api/admin/users/{id}` | User löschen (+ Tokens, Shared Messages) | | `POST` | `/api/admin/users/{id}/impersonate` | Als anderer User einloggen (Login-as-User) | +| `POST` | `/api/admin/users/{id}/login-link` | Autologin-Token generieren → URL zurückgeben | ### Impersonate (Login-as-User) @@ -845,11 +868,20 @@ Admins können sich als beliebiger User einloggen ohne dessen Passwort zu kennen 2. Setzt neuen `gott_token`-Cookie → Admin-Session wird zum Zieluser 3. `location.reload()` → Frontend lädt mit neuem User-Kontext +### Login-Link generieren + +Admins können für jeden User einen **Autologin-Link** generieren – z.B. für Setup oder Support: +1. `POST /api/admin/users/{id}/login-link` → Erstellt Token, gibt `{ token }` zurück +2. Frontend baut URL: `{window.location.origin}/api/auth/autologin?token={token}` +3. Link wird im Modal angezeigt mit Copy-Button +4. `GET /api/auth/autologin?token={token}` → Setzt Cookie + Redirect zu `/` (ohne Auth, wie Login) + ### Frontend (`admin-page.js`) - Erreichbar über Dashboard-Link "Benutzerverwaltung" (nur für Admins sichtbar) -- User-Liste als Cards mit Edit/Delete/Impersonate-Buttons +- User-Liste als Cards mit Edit/Delete/Login-Link-Buttons - Inline-Formular für Create/Edit +- Login-Link-Modal mit Copy-Funktion - Sich selbst löschen ist nicht möglich --- diff --git a/ARCHITECTURE_QUICK.md b/ARCHITECTURE_QUICK.md index 9ba6312..0b7cd05 100644 --- a/ARCHITECTURE_QUICK.md +++ b/ARCHITECTURE_QUICK.md @@ -26,6 +26,7 @@ gott/ │ ├── js/router.js # Hash-basiertes SPA-Routing │ ├── js/api.js # fetch()-Wrapper │ ├── js/chat.js # SSE-Stream, Markdown-Rendering +│ ├── js/ui.js # UI-Helpers, buildAgentCard(), buildSessionCard() │ ├── js/pages/ # Seiten-Komponenten │ └── css/ # Styles (theme.css = CSS Variables) ├── WindowsApp/ # WPF + WebView2 Desktop Client @@ -70,16 +71,16 @@ User 1──* Agent 1──* Session 1──* Chain 1──* Message 1──* At | Gruppe | Route | Wichtigstes | |--------|-------|-------------| -| Auth | `/api/auth/` | `POST login`, `POST logout`, `GET me` | -| Chat | `/api/chat` | `POST` → SSE Stream | +| Auth | `/api/auth/` | `POST login`, `POST logout`, `GET me`, `GET autologin` | +| Chat | `/api/chat` | `POST` → SSE Stream, `POST stop` | | History | `/api/history` | GET history, poll, archive, marks, delete | | Sessions | `/api/sessions/` | CRUD + system-prompt, exec, git-status | | Agents | `/api/agents/` | CRUD | -| Admin | `/api/admin/` | User CRUD, impersonate (Admin-only) | +| Admin | `/api/admin/` | User CRUD, impersonate, login-link (Admin-only) | | Workspace | `/api/workspace/` | tree, file read/write, mkdir, rmdir, browse, agent-files | | Telegram | `/api/telegram/` | webhook (unauth), config, registration | | Cronjobs | `/api/cronjobs/` | CRUD + toggle, manual run | -| Krea | `/api/images/` | generate, list, file-serve | +| Krea | `/api/images/` | generate, list, file-serve, thumb, status (file/* ohne Auth) | | Skills | `/api/skills` | list, agent-mapping, output-files | | Profile | `/api/profile` | GET, PUT, password | | Settings | `/api/settings` | GET, PUT (JSON blob) | @@ -106,7 +107,7 @@ User 1──* Agent 1──* Session 1──* Chain 1──* Message 1──* At | **CronjobService** | BackgroundService, minütlicher Cron-Check | | **KreaService** | Krea API Bildgenerierung + Job-Polling | | **ImageService** | Bild-Resize (ImageSharp, max 512px) | -| **StreamingTracker** | ConcurrentDict: wer streamt gerade? | +| **StreamingTracker** | Tracking aktiver Streams + CancellationTokenSource pro Session für Stop | --- @@ -123,7 +124,9 @@ User-Input → POST /api/chat (SSE) → Token-für-Token an Client streamen → Bei tool_use → ToolService.Execute() → Ergebnis zurück → neuer API Call → Loop bis end_turn oder max_iterations (100) - → CancellationToken bei Stop-Button → client_disconnected + → Stop-Button: POST /api/chat/stop → StreamingTracker.Cancel() + → CancellationToken durchgereicht bis ToolService → Prozess-Kill + → client_disconnected → Chain + Messages in DB speichern ``` @@ -194,10 +197,11 @@ User-Input → POST /api/chat (SSE) 1. `POST /api/auth/login` → Token generiert, als `gott_token` HttpOnly Cookie gesetzt 2. Jeder `/api/`-Request → `AuthMiddleware` prüft Cookie → setzt `UserId` + `IsAdmin` -3. Ausnahmen: Login, Telegram-Webhook, `GET /api/shared/{token}` und Autologin brauchen kein Auth +3. Ausnahmen: Login, Autologin, Telegram-Webhook, `GET /api/shared/{token}`, `GET /api/images/file/*` brauchen kein Auth 4. **Krea API-Key**: `/api/images/`-Routen akzeptieren `X-Api-Key`-Header (Config: `KreaApiKey`) für Automation ohne User-Kontext 5. **Impersonate**: Admin kann via `POST /api/admin/users/{id}/impersonate` als anderer User einloggen -6. **DefaultPath**: Pro User ein Basis-Ordner (nur vom Admin setzbar), Session-Workspaces sind relativ dazu +6. **Login-Link**: Admin generiert via `POST /api/admin/users/{id}/login-link` einen Autologin-Link (Token-basiert, `GET /api/auth/autologin?token=xxx`) +7. **DefaultPath**: Pro User ein Basis-Ordner (nur vom Admin setzbar), Session-Workspaces sind relativ dazu ---