Feature: Globales „Aufgaben"-Panel (Task-Center) für benutzergetriggerte Hintergrund-Prozesse #155

Closed
opened 2026-06-22 13:45:12 +00:00 by chinux · 0 comments
Owner

Ziel

Ein dauerhaft sichtbares, andockbares Aufgaben-Panel am unteren Rand des Dashboards — wie das
Proxmox-„Tasks"-Panel. Es zeigt laufende und vergangene vom Benutzer angestoßene
Hintergrund-Prozesse mit Live-Status, Fortschritt und Log-Ausgabe, app-weit auf jeder Seite.

Erfasste Prozesse (v1):

  1. Bulk-Update (VM/CT)
  2. VM-Agent-Scan (bulk-vm-agent-update-stream)
  3. QEMU-Scan (qemu-scan-stream)
  4. Security/CVE-Scan
  5. Port-Scan
  6. Node-Agent-Update (Node-Agent-Binary aktualisieren)

Ausgangslage im Code

Zwei Gruppen — und genau deshalb eine zentrale Tabelle statt reiner Aggregation:

Prozess Trigger (Endpoint) Persistenz heute
Bulk-Update POST /api/update/bulk-job (+ _run_bulk_job) BulkRun + UpdateLog
Security/CVE POST /api/security/.../cve-scan VMCveScan + VMCveReport
Port-Scan POST /api/security/port-scan/bulk-bg (+ _bulk_scan_worker) VMPortSnapshot + scan-state
VM-Agent-Scan GET /api/nodes/{n}/vms/bulk-vm-agent-update-stream (SSE) kein Lauf-Record
QEMU-Scan GET /api/nodes/{n}/qemu-scan-stream (SSE) kein Lauf-Record
Node-Agent-Update POST /api/nodes/{n}/agent-update (force_agent_update, admin_router) kein Lauf-Record

Vorhandene Bausteine zum Wiederverwenden: TailHub (In-Memory-Pubsub, services/log_tail_hub.py),
SSE-Muster (EventSource im Frontend, z.B. UpdatesTab), der globale bulkUpdate-Store
(localStorage-persistiert), UI-Komponenten (Card, Badge, Btn, Terminal/LogTailViewer).
App-Shell: frontend/src/routes/(app)/+layout.svelte (<main>{@render children()}</main>).

Architektur (festgelegt)

Schlanke zentrale tasks-Tabelle + Task-Hub. Jeder der 5 Trigger:

  1. legt beim Start eine task-Zeile an (kind, Scope, User, status=running),
  2. streamt Log-Zeilen in einen Per-Task-Puffer (Hub, SSE an Clients),
  3. finalisiert am Ende (status, finished_at, gekappter log_text).

Fachliche Ergebnisse bleiben in ihren Tabellen (UpdateLog, VMPortSnapshot, VMCveScan/Report).
tasks ist nur der vereinheitlichende Index + Log-Kanal. Eine spätere Aggregation/Verknüpfung
über ref_id bleibt möglich.

Datenmodell (neu: server/models/task.py, Migration)

tasks
  id              UUID  PK
  kind            String  -- bulk_update | vm_agent_scan | qemu_scan | cve_scan | port_scan | node_agent_update
  title           String  -- menschenlesbare Beschreibung
  node_name       String  nullable
  vmid            Integer nullable
  tenant_id       UUID    nullable  -- für Tenant-Scope
  started_by_user_id UUID nullable
  started_by_name String  nullable
  status          String  -- running | ok | error | cancelled
  total           Integer nullable  -- Fortschritt (Bulk)
  done            Integer nullable
  failed          Integer nullable
  started_at      DateTime
  finished_at     DateTime nullable
  summary         Text    nullable  -- Kurzergebnis
  error           Text    nullable
  log_text        Text    nullable  -- gekappter Volllog (z.B. max 256 KB) zum Wiederaufrufen
  ref_id          String  nullable  -- Verweis auf fachlichen Record (z.B. bulk_run.id, job_id)
  index: (status), (kind), (tenant_id), (started_at desc)

Service (neu: server/services/task_hub.py)

  • SSE-Pubsub analog TailHub (Subscriber = asyncio.Queue; publish(event)).
  • async def start(db, *, kind, title, node=None, vmid=None, user=None, tenant_id=None, total=None) -> Task
    → Row anlegen, Event task_created publishen.
  • async def log(task_id, line) → Per-Task-Puffer + Event task_log; periodisch in log_text flushen (gekappt).
  • async def progress(task_id, done, total=None, failed=None) → Update + Event task_progress.
  • async def finish(task_id, status, summary=None, error=None) → Row finalisieren, log_text flushen, Event task_finished.
  • Events tragen Scope (tenant_id/node) für serverseitiges Filtern pro Subscriber.

Wrapping der 5 Trigger (minimal-invasiv)

  • Bulk-Update (update_router, _run_bulk_job): BulkRun-Lifecycle um Task ergänzen
    (ref_id = bulk_run.id), pro Item task.log + task.progress.
  • VM-Agent-Scan (deploy_router, bulk-vm-agent-update-stream): Task bei Stream-Öffnung starten,
    jede SSE-Zeile task.log, am Stream-Ende task.finish.
  • QEMU-Scan (admin_router, qemu-scan-stream): gleiches Muster.
  • CVE-Scan (security_router, _cve_scan_inner / run_security_bulk_scan): start/log/finish.
  • Port-Scan (security_router, _bulk_scan_worker + Einzel-Port-Scan): start/log/finish.
  • Node-Agent-Update (admin_router.force_agent_update, POST /nodes/{node}/agent-update): Task starten, Update-Ausgabe loggen, finish(status).

API (neu: server/routers/task_router.py)

GET  /api/tasks?limit=&kind=&status=     -> Liste (tenant/rollen-gescoped, neueste zuerst)
GET  /api/tasks/{id}                      -> Detail inkl. log_text
GET  /api/tasks/stream                    -> SSE: task_created | task_progress | task_log | task_finished
POST /api/tasks/{id}/cancel               -> best-effort (nur wo Cancel existiert, z.B. Bulk-Job)

Scope: an die bestehende Tenant-Sichtbarkeit koppeln; superadmin sieht alles. In main.py registrieren.

Frontend

  • Store frontend/src/lib/stores/tasks.svelte.ts: initiale Liste via /api/tasks, danach
    EventSource('/api/tasks/stream'); Events reaktiv in die Liste mergen. Eingeklappt/ausgeklappt +
    Höhe in localStorage.
  • Komponente frontend/src/lib/components/tasks/TaskDock.svelte, gerendert in
    (app)/+layout.svelte nach <main> (app-weit):
    • Eingeklappt: schmaler Balken — „N laufend" + Spinner + letzter abgeschlossener Task.
    • Ausgeklappt: Tabelle mit Spalten Start · Ende · Node/Scope · User · Beschreibung · Status
      (Status mit Fortschrittsbalken bei laufenden), Filter (kind/status), neueste zuerst, „mehr laden".
    • Klick auf Zeile → Log-Ansicht: live aus dem Store-Puffer wenn laufend, sonst log_text
      aus /api/tasks/{id}; im Terminal-/LogTailViewer-Stil (monospace <pre>).
  • Bestehendes BulkUpdateMode bleibt als „VMs wählen + starten"-Modal; der Fortschritt taucht
    zusätzlich global im Dock auf (vorhandenen Flow nicht brechen).

Akzeptanzkriterien

  1. Starte ich einen der 5 Prozesse, erscheint sofort eine laufende Aufgabe im Dock (auf jeder Seite).
  2. Fortschritt/Status aktualisieren sich live ohne Reload (SSE).
  3. Klick auf eine Aufgabe zeigt deren Log — live bei laufenden, gespeichert bei abgeschlossenen.
  4. Abgeschlossene Aufgaben bleiben als Verlauf sichtbar (mit Start/Ende/Status), „mehr laden" lädt ältere.
  5. Spalten entsprechen dem Proxmox-Vorbild (Start, Ende, Node/Scope, User, Beschreibung, Status).
  6. Scope respektiert Tenant/Rollen; superadmin sieht alle.
  7. Eingeklappt/ausgeklappt-Zustand überlebt Navigation und Reload.
  8. SPDX-Header auf neuen Dateien; keine schweren neuen Dependencies; bestehende Flows intakt.

Prompt für Claude Code

Implementiere das globale "Aufgaben"-Panel (Task-Center) gemäß diesem Issue im Repo theProx.
Lies zuerst ARCHITECTURE.md und die wiki/*.md für Stack/Konventionen.

KONTEXT & KONVENTIONEN (zwingend):
- Backend FastAPI in server/, Router via app.include_router() in server/main.py. Async SQLAlchemy,
  Alembic-Migrationen in server/migrations/versions (nächste Nummer fortlaufend). Auth über auth.rbac
  (require_role / get_current_user), Tenant-Scope wie im Rest der App.
- Frontend SvelteKit + TS, Svelte 5 Runes ($state/$effect/$derived), API über $lib/api, UI-Komponenten
  aus $lib/components/ui wiederverwenden (Card, Badge, Btn). Dark-Theme/CSS-Variablen des Projekts.
- SPDX-Header auf JEDER neuen Datei:
    # SPDX-License-Identifier: AGPL-3.0-only
    # Copyright (C) 2026 Sebastian Serfling
- Vorbild für Pubsub: services/log_tail_hub.py (TailHub). Vorbild für SSE-Konsum im Frontend:
  components/admin-vm-modal/tabs/UpdatesTab.svelte (EventSource). Globaler Store-Stil: stores/bulkUpdate.svelte.ts.

1. MODELL + MIGRATION
   - server/models/task.py: Model Task wie im Issue (Felder, Indizes). In models/__init__.py exportieren.
   - Neue Alembic-Migration (fortlaufende Nummer) für Tabelle tasks.

2. SERVICE  server/services/task_hub.py
   - SSE-Pubsub analog TailHub (Subscriber-Queues, publish). Per-Task-Log-Puffer im Speicher.
   - start()/log()/progress()/finish() wie im Issue. log_text gekappt (z.B. 256 KB, head+tail).
   - Events tragen tenant_id/node_name fürs serverseitige Scope-Filtern.

3. ROUTER  server/routers/task_router.py  (prefix /api/tasks)
   - GET /  (Liste, tenant/rollen-gescoped, Filter kind/status, limit, neueste zuerst)
   - GET /{id}  (Detail inkl. log_text)
   - GET /stream  (SSE: task_created|task_progress|task_log|task_finished, pro Subscriber gescoped)
   - POST /{id}/cancel  (best-effort; für Bulk-Update an bestehenden cancel-item-Pfad delegieren)
   - In server/main.py registrieren.

4. WRAPPING DER 5 TRIGGER (minimal-invasiv, vorhandene Logik nicht ersetzen, nur Task-Lifecycle ergänzen)
   - Bulk-Update: update_router._run_bulk_job — Task parallel zum BulkRun (ref_id=bulk_run.id),
     pro Item task_hub.log + progress, am Ende finish(status).
   - VM-Agent-Scan: deploy_router bulk-vm-agent-update-stream — Task bei Stream-Start, jede SSE-Zeile
     loggen, am Ende finish.
   - QEMU-Scan: admin_router qemu-scan-stream — gleiches Muster.
   - CVE-Scan: security_router _cve_scan_inner / run_security_bulk_scan — start/log/finish.
   - Port-Scan: security_router _bulk_scan_worker (+ Einzel-Port-Scan) — start/log/finish.
   - Node-Agent-Update: admin_router.force_agent_update (POST /nodes/{node}/agent-update) — start/log/finish.
   - title/kind/node/vmid/user/tenant aus dem jeweiligen Request/Kontext füllen.

5. FRONTEND
   - stores/tasks.svelte.ts: initial /api/tasks, dann EventSource /api/tasks/stream; Events mergen;
     collapsed/expanded + Höhe in localStorage.
   - components/tasks/TaskDock.svelte: eingeklappter Balken (N laufend, letzter Task) ⇄ ausgeklappte
     Tabelle (Start, Ende, Node/Scope, User, Beschreibung, Status+Fortschritt; Filter kind/status; mehr laden).
     Zeilen-Klick → Log-Ansicht (live aus Store-Puffer bei running, sonst log_text via /api/tasks/{id}),
     monospace im Terminal/LogTailViewer-Stil.
   - In routes/(app)/+layout.svelte nach <main> einbinden (app-weit sichtbar).
   - BulkUpdateMode-Flow nicht brechen; Fortschritt erscheint zusätzlich im Dock.

QUALITÄT / ABSCHLUSS:
- Keine Doppel-Logik: vorhandene Worker/Streams bleiben Quelle der Wahrheit, Task-Hub nur ergänzend.
- Tenant/Rollen-Scope auf Liste UND Stream anwenden.
- Migration testen (upgrade/downgrade). Nach Implementierung geänderte/neue Dateien + manuelle
  Test-Schritte auflisten (je Prozess starten → im Dock sichtbar, live-Log, Verlauf nach Reload).

Offen / später

  • Scheduled-Jobs und Ad-hoc-Kommandos als weitere kinds aufnehmen.
  • Aufräum-Job für tasks (Retention, z.B. > 90 Tage / > N pro Tenant).
  • Desktop-Notification/Toast bei Task-Ende (Reuse bestehende Notification-Pipeline).
## Ziel Ein dauerhaft sichtbares, andockbares **Aufgaben-Panel** am unteren Rand des Dashboards — wie das Proxmox-„Tasks"-Panel. Es zeigt laufende und vergangene **vom Benutzer angestoßene** Hintergrund-Prozesse mit Live-Status, Fortschritt und Log-Ausgabe, app-weit auf jeder Seite. Erfasste Prozesse (v1): 1. **Bulk-Update** (VM/CT) 2. **VM-Agent-Scan** (bulk-vm-agent-update-stream) 3. **QEMU-Scan** (qemu-scan-stream) 4. **Security/CVE-Scan** 5. **Port-Scan** 6. **Node-Agent-Update** (Node-Agent-Binary aktualisieren) ## Ausgangslage im Code Zwei Gruppen — und genau deshalb eine zentrale Tabelle statt reiner Aggregation: | Prozess | Trigger (Endpoint) | Persistenz heute | |----------------|------------------------------------------------------|------------------| | Bulk-Update | `POST /api/update/bulk-job` (+ `_run_bulk_job`) | `BulkRun` + `UpdateLog` ✓ | | Security/CVE | `POST /api/security/.../cve-scan` | `VMCveScan` + `VMCveReport` ✓ | | Port-Scan | `POST /api/security/port-scan/bulk-bg` (+ `_bulk_scan_worker`) | `VMPortSnapshot` + `scan-state` ✓ | | VM-Agent-Scan | `GET /api/nodes/{n}/vms/bulk-vm-agent-update-stream` (SSE) | **kein Lauf-Record** | | QEMU-Scan | `GET /api/nodes/{n}/qemu-scan-stream` (SSE) | **kein Lauf-Record** | | Node-Agent-Update | `POST /api/nodes/{n}/agent-update` (`force_agent_update`, admin_router) | **kein Lauf-Record** | Vorhandene Bausteine zum Wiederverwenden: `TailHub` (In-Memory-Pubsub, `services/log_tail_hub.py`), SSE-Muster (`EventSource` im Frontend, z.B. `UpdatesTab`), der globale `bulkUpdate`-Store (localStorage-persistiert), UI-Komponenten (`Card`, `Badge`, `Btn`, `Terminal`/`LogTailViewer`). App-Shell: `frontend/src/routes/(app)/+layout.svelte` (`<main>{@render children()}</main>`). ## Architektur (festgelegt) Schlanke zentrale **`tasks`-Tabelle** + **Task-Hub**. Jeder der 5 Trigger: 1. legt beim Start eine `task`-Zeile an (`kind`, Scope, User, `status=running`), 2. streamt Log-Zeilen in einen Per-Task-Puffer (Hub, SSE an Clients), 3. finalisiert am Ende (`status`, `finished_at`, gekappter `log_text`). Fachliche Ergebnisse bleiben in ihren Tabellen (`UpdateLog`, `VMPortSnapshot`, `VMCveScan/Report`). `tasks` ist nur der vereinheitlichende Index + Log-Kanal. Eine spätere Aggregation/Verknüpfung über `ref_id` bleibt möglich. ## Datenmodell (neu: `server/models/task.py`, Migration) ``` tasks id UUID PK kind String -- bulk_update | vm_agent_scan | qemu_scan | cve_scan | port_scan | node_agent_update title String -- menschenlesbare Beschreibung node_name String nullable vmid Integer nullable tenant_id UUID nullable -- für Tenant-Scope started_by_user_id UUID nullable started_by_name String nullable status String -- running | ok | error | cancelled total Integer nullable -- Fortschritt (Bulk) done Integer nullable failed Integer nullable started_at DateTime finished_at DateTime nullable summary Text nullable -- Kurzergebnis error Text nullable log_text Text nullable -- gekappter Volllog (z.B. max 256 KB) zum Wiederaufrufen ref_id String nullable -- Verweis auf fachlichen Record (z.B. bulk_run.id, job_id) index: (status), (kind), (tenant_id), (started_at desc) ``` ## Service (neu: `server/services/task_hub.py`) - SSE-Pubsub analog `TailHub` (Subscriber = `asyncio.Queue`; `publish(event)`). - `async def start(db, *, kind, title, node=None, vmid=None, user=None, tenant_id=None, total=None) -> Task` → Row anlegen, Event `task_created` publishen. - `async def log(task_id, line)` → Per-Task-Puffer + Event `task_log`; periodisch in `log_text` flushen (gekappt). - `async def progress(task_id, done, total=None, failed=None)` → Update + Event `task_progress`. - `async def finish(task_id, status, summary=None, error=None)` → Row finalisieren, `log_text` flushen, Event `task_finished`. - Events tragen Scope (tenant_id/node) für serverseitiges Filtern pro Subscriber. ## Wrapping der 5 Trigger (minimal-invasiv) - **Bulk-Update** (`update_router`, `_run_bulk_job`): `BulkRun`-Lifecycle um Task ergänzen (`ref_id = bulk_run.id`), pro Item `task.log` + `task.progress`. - **VM-Agent-Scan** (`deploy_router`, bulk-vm-agent-update-stream): Task bei Stream-Öffnung starten, jede SSE-Zeile `task.log`, am Stream-Ende `task.finish`. - **QEMU-Scan** (`admin_router`, qemu-scan-stream): gleiches Muster. - **CVE-Scan** (`security_router`, `_cve_scan_inner` / `run_security_bulk_scan`): start/log/finish. - **Port-Scan** (`security_router`, `_bulk_scan_worker` + Einzel-Port-Scan): start/log/finish. - **Node-Agent-Update** (`admin_router.force_agent_update`, `POST /nodes/{node}/agent-update`): Task starten, Update-Ausgabe loggen, finish(status). ## API (neu: `server/routers/task_router.py`) ``` GET /api/tasks?limit=&kind=&status= -> Liste (tenant/rollen-gescoped, neueste zuerst) GET /api/tasks/{id} -> Detail inkl. log_text GET /api/tasks/stream -> SSE: task_created | task_progress | task_log | task_finished POST /api/tasks/{id}/cancel -> best-effort (nur wo Cancel existiert, z.B. Bulk-Job) ``` Scope: an die bestehende Tenant-Sichtbarkeit koppeln; superadmin sieht alles. In `main.py` registrieren. ## Frontend - **Store** `frontend/src/lib/stores/tasks.svelte.ts`: initiale Liste via `/api/tasks`, danach `EventSource('/api/tasks/stream')`; Events reaktiv in die Liste mergen. Eingeklappt/ausgeklappt + Höhe in localStorage. - **Komponente** `frontend/src/lib/components/tasks/TaskDock.svelte`, gerendert in `(app)/+layout.svelte` **nach** `<main>` (app-weit): - Eingeklappt: schmaler Balken — „N laufend" + Spinner + letzter abgeschlossener Task. - Ausgeklappt: Tabelle mit Spalten **Start · Ende · Node/Scope · User · Beschreibung · Status** (Status mit Fortschrittsbalken bei laufenden), Filter (kind/status), neueste zuerst, „mehr laden". - Klick auf Zeile → Log-Ansicht: live aus dem Store-Puffer wenn laufend, sonst `log_text` aus `/api/tasks/{id}`; im Terminal-/`LogTailViewer`-Stil (monospace `<pre>`). - Bestehendes `BulkUpdateMode` bleibt als „VMs wählen + starten"-Modal; der Fortschritt taucht zusätzlich global im Dock auf (vorhandenen Flow nicht brechen). ## Akzeptanzkriterien 1. Starte ich einen der 5 Prozesse, erscheint sofort eine laufende Aufgabe im Dock (auf jeder Seite). 2. Fortschritt/Status aktualisieren sich live ohne Reload (SSE). 3. Klick auf eine Aufgabe zeigt deren Log — live bei laufenden, gespeichert bei abgeschlossenen. 4. Abgeschlossene Aufgaben bleiben als Verlauf sichtbar (mit Start/Ende/Status), „mehr laden" lädt ältere. 5. Spalten entsprechen dem Proxmox-Vorbild (Start, Ende, Node/Scope, User, Beschreibung, Status). 6. Scope respektiert Tenant/Rollen; superadmin sieht alle. 7. Eingeklappt/ausgeklappt-Zustand überlebt Navigation und Reload. 8. SPDX-Header auf neuen Dateien; keine schweren neuen Dependencies; bestehende Flows intakt. --- ## Prompt für Claude Code ``` Implementiere das globale "Aufgaben"-Panel (Task-Center) gemäß diesem Issue im Repo theProx. Lies zuerst ARCHITECTURE.md und die wiki/*.md für Stack/Konventionen. KONTEXT & KONVENTIONEN (zwingend): - Backend FastAPI in server/, Router via app.include_router() in server/main.py. Async SQLAlchemy, Alembic-Migrationen in server/migrations/versions (nächste Nummer fortlaufend). Auth über auth.rbac (require_role / get_current_user), Tenant-Scope wie im Rest der App. - Frontend SvelteKit + TS, Svelte 5 Runes ($state/$effect/$derived), API über $lib/api, UI-Komponenten aus $lib/components/ui wiederverwenden (Card, Badge, Btn). Dark-Theme/CSS-Variablen des Projekts. - SPDX-Header auf JEDER neuen Datei: # SPDX-License-Identifier: AGPL-3.0-only # Copyright (C) 2026 Sebastian Serfling - Vorbild für Pubsub: services/log_tail_hub.py (TailHub). Vorbild für SSE-Konsum im Frontend: components/admin-vm-modal/tabs/UpdatesTab.svelte (EventSource). Globaler Store-Stil: stores/bulkUpdate.svelte.ts. 1. MODELL + MIGRATION - server/models/task.py: Model Task wie im Issue (Felder, Indizes). In models/__init__.py exportieren. - Neue Alembic-Migration (fortlaufende Nummer) für Tabelle tasks. 2. SERVICE server/services/task_hub.py - SSE-Pubsub analog TailHub (Subscriber-Queues, publish). Per-Task-Log-Puffer im Speicher. - start()/log()/progress()/finish() wie im Issue. log_text gekappt (z.B. 256 KB, head+tail). - Events tragen tenant_id/node_name fürs serverseitige Scope-Filtern. 3. ROUTER server/routers/task_router.py (prefix /api/tasks) - GET / (Liste, tenant/rollen-gescoped, Filter kind/status, limit, neueste zuerst) - GET /{id} (Detail inkl. log_text) - GET /stream (SSE: task_created|task_progress|task_log|task_finished, pro Subscriber gescoped) - POST /{id}/cancel (best-effort; für Bulk-Update an bestehenden cancel-item-Pfad delegieren) - In server/main.py registrieren. 4. WRAPPING DER 5 TRIGGER (minimal-invasiv, vorhandene Logik nicht ersetzen, nur Task-Lifecycle ergänzen) - Bulk-Update: update_router._run_bulk_job — Task parallel zum BulkRun (ref_id=bulk_run.id), pro Item task_hub.log + progress, am Ende finish(status). - VM-Agent-Scan: deploy_router bulk-vm-agent-update-stream — Task bei Stream-Start, jede SSE-Zeile loggen, am Ende finish. - QEMU-Scan: admin_router qemu-scan-stream — gleiches Muster. - CVE-Scan: security_router _cve_scan_inner / run_security_bulk_scan — start/log/finish. - Port-Scan: security_router _bulk_scan_worker (+ Einzel-Port-Scan) — start/log/finish. - Node-Agent-Update: admin_router.force_agent_update (POST /nodes/{node}/agent-update) — start/log/finish. - title/kind/node/vmid/user/tenant aus dem jeweiligen Request/Kontext füllen. 5. FRONTEND - stores/tasks.svelte.ts: initial /api/tasks, dann EventSource /api/tasks/stream; Events mergen; collapsed/expanded + Höhe in localStorage. - components/tasks/TaskDock.svelte: eingeklappter Balken (N laufend, letzter Task) ⇄ ausgeklappte Tabelle (Start, Ende, Node/Scope, User, Beschreibung, Status+Fortschritt; Filter kind/status; mehr laden). Zeilen-Klick → Log-Ansicht (live aus Store-Puffer bei running, sonst log_text via /api/tasks/{id}), monospace im Terminal/LogTailViewer-Stil. - In routes/(app)/+layout.svelte nach <main> einbinden (app-weit sichtbar). - BulkUpdateMode-Flow nicht brechen; Fortschritt erscheint zusätzlich im Dock. QUALITÄT / ABSCHLUSS: - Keine Doppel-Logik: vorhandene Worker/Streams bleiben Quelle der Wahrheit, Task-Hub nur ergänzend. - Tenant/Rollen-Scope auf Liste UND Stream anwenden. - Migration testen (upgrade/downgrade). Nach Implementierung geänderte/neue Dateien + manuelle Test-Schritte auflisten (je Prozess starten → im Dock sichtbar, live-Log, Verlauf nach Reload). ``` ## Offen / später - Scheduled-Jobs und Ad-hoc-Kommandos als weitere `kind`s aufnehmen. - Aufräum-Job für `tasks` (Retention, z.B. > 90 Tage / > N pro Tenant). - Desktop-Notification/Toast bei Task-Ende (Reuse bestehende Notification-Pipeline).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
chinux/theProx#155
No description provided.