docs: ARCHITECTURE.md + ARCHITECTURE_QUICK.md aktualisiert
- 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
This commit is contained in:
1 parent
40c8fee531
commit
2598656f1c
2 files changed
+58
-22
No files matched your search
+46
-14
@@ -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
|
||||
|
||||
---
|
||||
|
||||
+12
-8
@@ -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
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user