From 8ed1d81b7ae902512f4fc6bbc48b575bea12ae8f Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Sat, 6 Jun 2026 00:33:47 +0200 Subject: [PATCH] solution design customer cases --- b-reference/platform-core/architecture.md | 126 +++++++- .../platform-core/features/commcoach.md | 178 +++++++++++ .../platform-core/json-continuation.md | 164 ++++++++++ ...026-06-CustomerCases-step1-architecture.md | 2 +- ...26-06-CustomerCases-step3-features-plan.md | 16 +- .../2026-06-automation-system-component.md | 284 ++++++++++++++++++ c-work/_CHANGELOG.md | 3 + 7 files changed, 760 insertions(+), 13 deletions(-) create mode 100644 b-reference/platform-core/features/commcoach.md create mode 100644 b-reference/platform-core/json-continuation.md create mode 100644 c-work/1-plan/2026-06-automation-system-component.md diff --git a/b-reference/platform-core/architecture.md b/b-reference/platform-core/architecture.md index 75d0ca9..c4876ba 100644 --- a/b-reference/platform-core/architecture.md +++ b/b-reference/platform-core/architecture.md @@ -1,6 +1,6 @@ - - + + # Gateway -- Architektur @@ -20,7 +20,7 @@ Unter `platform-core/modules/` (Kontext-Audit): | `datamodels/` | Pydantic-Datenmodelle (u. a. Ai, Billing, Chat, Content, Files, Knowledge, Rbac, Subscription, UiLanguage, Workflow) | | `features/` | Feature-Module (autonome Domänen): workspace, graphicalEditor, commcoach, neutralization, realEstate, trustee, teamsbot | | `interfaces/` | DB-Interfaces (App, Billing, Chat, Knowledge, Management, Subscription), AI-Objects, RBAC, Features, Messaging | -| `migration/` | Daten-Migrationen | +| `dbHelpers/` | DB-Hilfsfunktionen (Registry, Audit-Logger, FK-Resolver, Pagination, Multi-Tenant-Optimierungen) | | `routes/` | REST-API-Routen (u. a. Admin, Billing, DataFiles, DataSources, i18n, Security, Store, System) | | `security/` | RBAC (`rbac.py`, `rbacCatalog.py`), Root-Access | | `serviceCenter/` | Zentrale Service-Orchestrierung (Registry, Resolver, Kontext, Haupt-Services) | @@ -78,6 +78,103 @@ Die genannten Module kapseln die Datenbankzugriffe bzw. die zugehörigen Fachver Weitere Interface-Dateien im Ordner (z. B. Voice, Tickets, Messaging, Bootstrap) erfüllen dieselbe Normalisierungsrolle gegenüber Connectors bzw. externen APIs; die Tabelle oben entspricht der expliziten DB-/Kern-Zuordnung aus dem Kontext-Audit. +## Feature Lifecycle Hooks + +Features sind autonome Module unter `modules/features//`. Jedes Feature hat ein `main.py` mit Registrierungs- und Lifecycle-Funktionen. Die Core-Schicht ruft diese **dynamisch** via `system/registry.py` → `loadFeatureMainModules()` auf — es gibt **keine hardcodierten Feature-Imports** in den Interfaces. + +### Pflicht-Funktionen (Feature-Registrierung) + +| Funktion | Beschreibung | +|----------|-------------| +| `getFeatureDefinition() -> Dict` | Feature-Metadaten: `code`, `label`, `icon`, `autoCreateInstance` | +| `registerFeature(catalogService) -> bool` | RBAC-Objekte (UI, Resource, Data) im Katalog registrieren | +| `getUiObjects() -> List[Dict]` | UI-Objekte fuer RBAC-Sichtbarkeit | +| `getResourceObjects() -> List[Dict]` | Resource-Objekte fuer RBAC | +| `getTemplateRoles() -> List[Dict]` | Template-Rollen mit AccessRules | + +### Optionale Lifecycle Hooks + +Jedes Feature kann diese Funktionen in seinem `main.py` definieren. Die Core-Schicht ruft sie automatisch auf, wenn die entsprechende Situation eintritt: + +| Hook | Signatur | Wann aufgerufen | Wo aufgerufen | +|------|----------|-----------------|---------------| +| `onMandateDelete` | `(mandateId: str, instances: list) -> None` | Mandate wird geloescht (hard-delete) | `interfaceDbApp.py` (Cascade-Delete-Loop) | +| `onBootstrap` | `() -> None` | App-Start (nach DB-Initialisierung) | `interfaceBootstrap.py` (Boot-Sequenz) | +| `onInstanceCreate` | `(mandateId: str, instanceId: str, featureCode: str, templateWorkflows: list) -> int` | Feature-Instanz wird erstellt und das Feature hat Template-Workflows | `interfaceFeatures.py` (via graphicalEditor) | +| `onStart` | `async (eventUser) -> None` | App-Start (Feature-spezifische Hintergrund-Prozesse) | `app.py` (Startup-Event) | +| `onStop` | `async (eventUser) -> None` | App-Shutdown | `app.py` (Shutdown-Event) | +| `getTemplateWorkflows` | `() -> List[Dict]` | Bootstrap / Instance-Create (Workflow-Templates bereitstellen) | `mainGraphicalEditor.onBootstrap()` / `onInstanceCreate()` | + +### Aufruf-Pattern (Core-Seite) + +```python +from modules.system.registry import loadFeatureMainModules + +for featureCode, mod in loadFeatureMainModules().items(): + hook = getattr(mod, "onMandateDelete", None) + if hook: + try: + hook(mandateId, instances) + except Exception as e: + logger.warning(f"onMandateDelete hook for '{featureCode}' failed: {e}") +``` + +### Implementierungs-Status + +Alle Features haben `onMandateDelete` implementiert: + +| Feature | DB | `onMandateDelete` | `onBootstrap` | `onInstanceCreate` | Besonderheiten | +|---------|----|----|----|----|-----| +| graphicalEditor | poweron_graphicaleditor | Yes | Yes | Yes | Vollstaendige Hooks | +| trustee | poweron_trustee | Yes | — | — | 13 Models | +| commcoach | poweron_commcoach | Yes | — | — | Nutzt `instanceId` statt `featureInstanceId` | +| teamsbot | poweron_teamsbot | Yes | — | — | Nutzt `instanceId`; Child-Records via Session-FK | +| neutralization | poweron_neutralization | Yes | — | — | 2 Models | +| workspace | poweron_workspace | Yes | — | — | 1 Model | +| realEstate | poweron_realestate | Yes | — | — | Fallback auf `mandateId` | +| redmine | poweron_redmine | Yes | — | — | 3 Models inkl. Ticket-Mirrors | + +### Beispiel: Neues Feature mit Lifecycle + +```python +# modules/features/myFeature/mainMyFeature.py + +FEATURE_CODE = "myFeature" + +def getFeatureDefinition() -> Dict[str, Any]: + return {"code": FEATURE_CODE, "label": "My Feature", "icon": "mdi-star", "autoCreateInstance": False} + +def onMandateDelete(mandateId: str, instances: list) -> None: + """Eigene Daten aufraumen wenn ein Mandate geloescht wird.""" + # Hier: Verbindung zur eigenen DB, Records loeschen + pass + +def onBootstrap() -> None: + """Eigene System-Daten seeden beim App-Start.""" + pass +``` + +### Architektur-Prinzipien + +1. **Kein Aufwaerts-Import:** Die Core-Schicht (interfaces) importiert NIEMALS direkt aus `features/`. Alle Feature-spezifische Logik wird ueber Hooks und die Registry aufgerufen. +2. **Feature raeumt selbst auf:** Jedes Feature ist verantwortlich fuer seine eigenen Daten (eigene DB, eigene Models). Die Core-Schicht delegiert Lifecycle-Events. +3. **Fail-safe:** Hook-Fehler werden geloggt, brechen aber nicht den Boot oder die Mandate-Deletion ab. +4. **Dynamisch erweiterbar:** Neue Features muessen nur die Hook-Funktion definieren — kein Code in der Core-Schicht muss angepasst werden. + +### Workflow-Automation Models + +Die Workflow-Engine-Models leben kanonisch in `datamodels/datamodelWorkflowAutomation.py`: + +| Model | Beschreibung | DB | +|-------|-------------|-----| +| `AutoWorkflow` | Workflow-Definition (Graph, Triggers, Templates) | poweron_graphicaleditor | +| `AutoVersion` | Versionierter Graph-Snapshot | poweron_graphicaleditor | +| `AutoRun` | Laufende/abgeschlossene Ausfuehrung | poweron_graphicaleditor | +| `AutoStepLog` | Protokoll pro Knoten-Ausfuehrung | poweron_graphicaleditor | +| `AutoTask` | Human Tasks (Formulare, Approvals) | poweron_graphicaleditor | + +Die DB-Konstante `GRAPHICAL_EDITOR_DATABASE = "poweron_graphicaleditor"` ist ebenfalls dort definiert. Feature-interne Re-Exports in `features/graphicalEditor/datamodelFeatureGraphicalEditor.py` existieren fuer Backward-Kompatibilitaet. + ## Schlüssel-Dateien | Datei / Pfad | Rolle | @@ -238,11 +335,32 @@ Konsequenzen: - **Save-with-errors** ist explizit erlaubt (AC-9-Patch im `CanvasHeader`); Run wird mit `executeBlockedReason` blockiert, der Save-Toast meldet Pflicht-Fehler-Anzahl. - **DB-Hygiene** ist optional via `script_migrate_feature_instance_refs.py` (`--dry-run` standard) -- ohne Skript laufen Workflows korrekt, der Editor zeigt aber bis zum naechsten Save noch das Legacy-Format. +## Layer-Hierarchie (strikte Importrichtung) + +``` +shared (L0) → 0 ausgehende Imports +datamodels (L1) → nur shared +connectors (L2) → shared, datamodels +dbHelpers (L3) → shared, datamodels, connectors +interfaces (L4) → L0-L3 + security, system +system (L4) → L0-L3 +security (L4) → L0-L3 +auth (L4) → L0-L4 +serviceCenter (L5) → L0-L4 +workflows (L5) → L0-L4 + features (Deferred: WorkflowAutomation) +features (L5) → L0-L4 + serviceCenter, workflows +routes (L6) → L0-L5 +app (L7) → alle (Composition Root) +``` + +Jede Schicht importiert NUR von niedrigeren Schichten. Ausnahmen (z.B. workflows→features) sind dokumentiert und haben einen Refactoring-Plan. + ## Regeln / Invarianten - **Schichten:** Connectors sind anbieterspezifisch und ersetzbar; **Services hängen von Interfaces ab, nicht direkt von Connectors**. Geschäftslogik und Guardrails liegen in den Services. +- **Kein Aufwaerts-Import:** Interfaces importieren NICHT von features, routes oder serviceCenter. Feature-Interaktion laeuft ueber Lifecycle Hooks (siehe oben). - **Datenbank:** Persistenz und die genannten Domänen-Reads/Writes laufen über die **Interface**-Schicht, nicht ad hoc aus Routen heraus. - **Service Center:** Aufrufe laufen über die zentrale Auflösung (`getService` + Kontext); Workflows und Routen konsumieren dieselbe Landschaft. - **Sicherheit & Governance:** RBAC und Geheimnisse werden zentral geführt; Service-Aufrufe und Workflow-Schritte sollen nachvollziehbar sein (Audit); Kontingente und Limits pro Mandant/Service sind vorgesehen. - **HTTP-Einstieg:** Globale Middleware (CSRF, Token-Refresh unter `modules/auth/`); RBAC-Auswertung und Katalog unter `modules/security/`. -- **Code-Konventionen (Projekt):** Interne Hilfsfunktionen mit Präfix **`_`**; Bezeichner in **camelCase** für Variablen und Funktionen. +- **Code-Konventionen (Projekt):** Interne Hilfsfunktionen mit Präfix **`_`** (duerfen NICHT extern importiert werden); Bezeichner in **camelCase** für Variablen und Funktionen. diff --git a/b-reference/platform-core/features/commcoach.md b/b-reference/platform-core/features/commcoach.md new file mode 100644 index 0000000..7a8fcd0 --- /dev/null +++ b/b-reference/platform-core/features/commcoach.md @@ -0,0 +1,178 @@ +# CommCoach – Communication Coach for Leaders + +## Product Goal + +An AI coaching agent for executives that: +- Captures topics, concerns, and questions +- Asks active diagnostic follow-up questions +- Builds a continuable context per topic (Dossier) +- Conducts daily training conversations +- Makes progress visible (Gamification) +- Supports voice natively (STT/TTS, voice selection) + +## Architecture + +### Layers + +``` +Transport (REST/SSE) → routeFeatureCommcoach.py +Orchestration → serviceCommcoach.py +AI Pipeline → serviceCommcoachAi.py +Scheduler → serviceCommcoachScheduler.py +Domain / Storage → interfaceFeatureCommcoach.py +Data Models → datamodelCommcoach.py +Feature Registration → mainCommcoach.py +``` + +### Reuse from Existing Codebase + +| Component | Source | Usage | +|-----------|--------|-------| +| Feature Plug&Play | `registry.py` | Auto-discovery via `routeFeature*.py` | +| RequestContext + RBAC | `authentication.py`, `interfaceRbac.py` | Auth + ownership | +| DatabaseConnector | `connectorDbPostgre.py` | New DB `poweron_commcoach` | +| VoiceObjects (STT/TTS) | `interfaceVoiceObjects.py` | Voice pipeline | +| MessagingInterface | `interfaceMessaging.py` | Email summaries | +| SSE Pattern | workspace `routeFeatureWorkspace.py` | Chat streaming | +| PDF Renderer | `rendererPdf.py` | Dossier export (Iteration 2) | +| EventManagement | `eventManagement.py` | Scheduled reminders | + +## Domain Model + +### Entities + +``` +User (1) ──── owns ──── (N) CoachingContext + │ +CoachingContext (1) ────── (N) CoachingSession + │ +CoachingSession (1) ───── (N) CoachingMessage + │ +CoachingContext (1) ────── (N) CoachingTask +CoachingContext (1) ────── (N) CoachingScore +User (1) ──────────────── (1) CoachingUserProfile +``` + +### Status Models + +``` +CoachingContext: active → paused → active | archived → active | completed +CoachingSession: active → completed | cancelled +CoachingTask: open → in_progress → done | skipped +``` + +## API Design + +``` +PREFIX: /api/commcoach/{instanceId} + +# Contexts (Dossier) +GET /contexts +POST /contexts +GET /contexts/{contextId} +PUT /contexts/{contextId} +DELETE /contexts/{contextId} +POST /contexts/{contextId}/archive +POST /contexts/{contextId}/activate + +# Sessions +GET /contexts/{contextId}/sessions +POST /contexts/{contextId}/sessions/start +GET /sessions/{sessionId} +POST /sessions/{sessionId}/complete +POST /sessions/{sessionId}/cancel + +# Streaming Chat +POST /sessions/{sessionId}/message/stream +POST /sessions/{sessionId}/audio/stream +GET /sessions/{sessionId}/stream + +# Tasks +GET /contexts/{contextId}/tasks +POST /contexts/{contextId}/tasks +PUT /tasks/{taskId} +PUT /tasks/{taskId}/status +DELETE /tasks/{taskId} + +# Dashboard +GET /dashboard + +# User Profile +GET /profile +PUT /profile + +# Voice +GET /voice/languages +GET /voice/voices +POST /voice/tts +``` + +### SSE Event Types + +- `message` – Complete message +- `messageChunk` – Streaming token +- `sessionState` – Status update +- `taskCreated` – New task from coach +- `insightGenerated` – New insight +- `scoreUpdate` – Score change +- `status` – UI status label +- `complete` – Stream ended +- `error` – Error +- `ping` – Keepalive + +## RBAC Model + +### Ownership Rules (Critical) +- **Strict MY-only**: User sees only own contexts/sessions/messages/tasks/scores +- **SysAdmin**: Only technical monitoring, NO content access +- **No admin override** on userId filter + +### Template Roles +- `commcoach-user`: DATA=MY on all entities, UI=ALL, RESOURCE=ALL +- `commcoach-admin`: DATA=MY (intentionally not ALL), UI=ALL, RESOURCE=ALL + +### Audit Events +- `commcoach.context.created/archived` +- `commcoach.session.started/completed` +- `commcoach.export.requested` + +## Iterations + +### Iteration 1 (MVP) +- Context management (create, switch, archive) +- Chat + SSE streaming +- STT/TTS with language/voice selection +- Coaching session with active diagnostic questions +- Auto session protocol +- Tasks/Checklist per context +- Session summary via email +- RBAC + strict ownership +- Basic dashboard: continuity, competence score, goal progress +- Long-session compression: ab 25 Nachrichten wird der aeltere Verlauf per AI zusammengefasst, letzte 15 Nachrichten bleiben vollstaendig (Teamsbot-Pattern) +- Context Memory (Phasen 1-7): previousSessionSummaries im Chat, keyTopics bei completeSession, Intent-Erkennung (summarize_all, recall_session, recall_topic), Datums-Lookup, Topic-Suche, Rolling Overview, RAG-Platzhalter + +### Iteration 2 +- Roleplay personas (critical CFO, difficult employee, etc.) +- Document upload + context binding +- Exports (Markdown/PDF) +- Extended gamification (streaks, levels, badges) +- Better scoring/insights + +## Database + +- Database name: `poweron_commcoach` +- Tables auto-created from Pydantic models via `DatabaseConnector` + +## Frontend + +### Views +- `CommcoachDashboardView` – KPIs, streaks, quick start +- `CommcoachCoachingView` – Chat UI with voice + context tabs +- `CommcoachDossierView` – Dossier: timeline, tasks, scores +- `CommcoachSettingsView` – Voice, reminder, profile settings + +### UX +- Multiple active contexts as quick-switch tabs/chips +- "Daily Coach" entry point prominent +- Voice first, always with text fallback +- Dossier view: timeline, learnings, tasks, next exercise diff --git a/b-reference/platform-core/json-continuation.md b/b-reference/platform-core/json-continuation.md new file mode 100644 index 0000000..b7e93cb --- /dev/null +++ b/b-reference/platform-core/json-continuation.md @@ -0,0 +1,164 @@ +# JSON Continuation Context Module + +Ein Python-Modul zur Generierung von Kontextinformationen für abgeschnittene JSON-Strings, um AI-Modellen die Fortsetzung zu ermöglichen. + +## Problem + +Wenn eine AI-Antwort als JSON abgeschnitten wird (z.B. Token-Limit erreicht), muss die nächste Iteration wissen: +- **Wo** der JSON abgeschnitten wurde +- **Was** bereits generiert wurde +- **Was** als nächstes geliefert werden soll + +## Lösung: Drei Kontexte + +### 1. Overlap Context +- Zeigt das **innerste Objekt/Array-Element**, das den Cut-Punkt enthält +- Wird verwendet, um den abgeschnittenen Teil mit dem neuen Teil zu **mergen** +- Exakt so wie im Original-String (für String-Matching beim Merge) + +### 2. Hierarchy Context +- Zeigt die **hierarchische Struktur** vom Root bis zum Cut-Punkt +- Mit **Budget-Logik**: Näher am Cut = vollständige Werte, weiter weg = `"..."` Platzhalter +- Gibt der AI den Kontext der gesamten JSON-Struktur + +### 3. Complete Part (NEU) +- Der **vollständige, valide JSON** bis zum Cut-Punkt +- Alle offenen Strukturen werden geschlossen (`}`, `]`, `"`) +- Unvollständige Keys werden entfernt +- Kann direkt als valides JSON geparst werden + +## Installation + +```bash +# Keine externen Abhängigkeiten erforderlich +cp json_continuation.py /your/project/ +``` + +## Modulkonstanten + +```python +# Diese Konstanten können vor dem Import angepasst werden +BUDGET_LIMIT: int = 500 # Zeichen-Budget für Datenwerte +OVERLAP_MAX_CHARS: int = 1000 # Max Zeichen für Overlap Context +``` + +## Verwendung + +### Grundlegende Verwendung + +```python +from json_continuation import extract_continuation_contexts + +truncated_json = '''{"customers": [ + {"id": 1, "name": "John"}, + {"id": 2, "name": "Jane", "email": "jane@exa''' + +overlap, hierarchy, complete = extract_continuation_contexts(truncated_json) + +print("Overlap Context:") +print(overlap) +# {"id": 2, "name": "Jane", "email": "jane@exa + +print("Hierarchy Context:") +print(hierarchy) +# {"customers": [...structure with budget logic...] + +print("Complete Part (valid JSON):") +print(complete) +# {"customers": [{"id": 1, "name": "John"}, {"id": 2, "name": "Jane", "email": "jane@exa"}]} + +import json +parsed = json.loads(complete) # ✓ Funktioniert! +``` + +### Mit Dictionary-Interface + +```python +from json_continuation import get_contexts + +contexts = get_contexts(truncated_json) + +print(contexts['overlap']) +print(contexts['hierarchy']) +print(contexts['complete_part']) +``` + +### Konstanten anpassen + +```python +import json_continuation + +# Budget anpassen bevor Funktionen aufgerufen werden +json_continuation.BUDGET_LIMIT = 200 +json_continuation.OVERLAP_MAX_CHARS = 500 + +overlap, hierarchy, complete = json_continuation.extract_continuation_contexts(truncated_json) +``` + +## Rückgabewerte + +| Rückgabe | Typ | Beschreibung | +|----------|-----|--------------| +| `overlap` | str | Innerstes Element mit Cut-Punkt (für Merge) | +| `hierarchy` | str | Volle Struktur mit Budget-Logik | +| `complete_part` | str | Valides JSON mit geschlossenen Strukturen | + +## Beispiele + +### Verschachtelte Objekte + +```python +json_str = '{"user": {"profile": {"bio": "Hello Wor' + +overlap, hierarchy, complete = extract_continuation_contexts(json_str) + +# Overlap: {"bio": "Hello Wor +# Hierarchy: {"user": {"profile": {"bio": "Hello Wor +# Complete: {"user": {"profile": {"bio": "Hello Wor"}}} ← Valides JSON! +``` + +### Array von Objekten mit unvollständigem Key + +```python +json_str = '''{ + "items": [ + {"id": 1, "name": "First"}, + {"id": 2, "name": "Second"}, + {"id": 3, "name": "Third", "add''' + +overlap, hierarchy, complete = extract_continuation_contexts(json_str) + +# Complete entfernt den unvollständigen Key "add": +# {"items": [{"id": 1, ...}, {"id": 2, ...}, {"id": 3, "name": "Third"}]} +``` + +## Budget-Logik + +Die Budget-Logik funktioniert wie folgt: + +1. **Sammeln**: Alle String-Werte werden mit ihrer Position gesammelt +2. **Sortieren**: Nach Entfernung zum Cut-Punkt (näher = höhere Priorität) +3. **Zuweisen**: Budget wird von hinten nach vorne aufgebraucht +4. **Ersetzen**: Werte außerhalb des Budgets werden durch `"..."` ersetzt + +## Tests ausführen + +```bash +python -m unittest test_json_continuation -v +``` + +## API Referenz + +### `extract_continuation_contexts(truncated_json: str) -> Tuple[str, str, str]` + +Hauptfunktion. Gibt `(overlap, hierarchy, complete_part)` zurück. + +### `get_contexts(truncated_json: str) -> dict` + +Convenience-Funktion. Gibt Dictionary mit Keys `'overlap'`, `'hierarchy'`, `'complete_part'` zurück. + +### Modulkonstanten + +- `BUDGET_LIMIT`: int (default: 500) - Zeichen-Budget für Hierarchy-Context +- `OVERLAP_MAX_CHARS`: int (default: 1000) - Max Zeichen für Overlap-Context + diff --git a/c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md b/c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md index 79a40f7..cd64438 100644 --- a/c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md +++ b/c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md @@ -204,7 +204,7 @@ bereit und lässt ihn einen Graphen erzeugen → als Draft-Version speichern → ## Betroffene Module (Skizze) - **Gateway:** - - `features/graphicalEditor/` — dünnes `Solution`-Modell (`mandateId`/`workflowRef`/`runAsPrincipal`/`surfaceFeatureRef`/`settingsValues`/`instanceSelection`/`outputBinding`/`customerFacing`) + Solution-Service; `AutoWorkflow` selbst bleibt schlank (Konfiguration via `trigger.form`). **DB-Migration: ja (Greenfield, additiv).** Details: step3-features-plan A0/A1. + - `features/graphicalEditor/` — **wird zur System-Komponente `WorkflowAutomation`** umgebaut (Voraussetzung, eigener Plan `c-work/1-plan/2026-06-automation-system-component.md`); danach dünnes `Solution`-Modell (`mandateId`/`workflowRef`/`runAsPrincipal`/`surfaceFeatureRef`/`settingsValues`/`instanceSelection`/`outputBinding`/`customerFacing`) + Solution-Service; `AutoWorkflow` bleibt schlank (Konfiguration via `trigger.form`). **DB-Migration: ja.** Details: step3-features-plan A0/A1. - `workflows/scheduler/mainScheduler.py` — unverändert nutzbar (Trigger-Policy mappt auf bestehende Schedule-Logik). - `interfaces/interfaceBootstrap.py` — Use-Case-Katalog als System-Templates. - `serviceCenter/services/serviceAgent/` (Toolbox `workflow`) — Use-Case→Graph-Generierung; ggf. Prompt/Guardrails ergänzen. diff --git a/c-work/0-ideas/2026-06-CustomerCases-step3-features-plan.md b/c-work/0-ideas/2026-06-CustomerCases-step3-features-plan.md index 1e88975..007d62d 100644 --- a/c-work/0-ideas/2026-06-CustomerCases-step3-features-plan.md +++ b/c-work/0-ideas/2026-06-CustomerCases-step3-features-plan.md @@ -97,12 +97,12 @@ Solution { → Es ist «n8n in PORTA», kein Domänen-Feature wie Trustee. Vergleich: Scheduler/RBAC/`system` sind reine Infrastruktur; `neutralization` ist das echte Feature-Analogon (DATA, kein `onStart`). -**Entscheid (pragmatisch, kein Big-Bang):** +**Entscheid (vorgezogen — eigener Plan):** `graphicalEditor` wird **von einem Feature zur System-Komponente `WorkflowAutomation`** umgebaut, **bevor** die Solution-Schicht gebaut wird (sonst erbt sie den Designfehler). `graphicalEditor` ist darin nur **ein Modul** (der Editor). Details, Phasen, DB-/UI-/RBAC-Migration: **`c-work/1-plan/2026-06-automation-system-component.md`**. -- **Konzeptionell als Plattform-/System-Komponente führen** («Automation/Workflow-Plattform»), nicht als Domänen-Feature. Der **Feature-Mantel bleibt** als RBAC-Eintritt + Store-Packaging + Navigation — das ist legitime Wiederverwendung der Feature-Mechanik, kein Modellfehler. -- **Solutions nicht an einen GE-Owner hängen** (siehe A0.1): Solution = mandatsweit + Run-as-Principal; die GE-Instanz ist nur Authoring-/RBAC-Eintritt. -- **Doku/Mentales Modell schärfen:** `b-reference` soll `graphicalEditor` explizit als **«Orchestrierungs-Substrat, als Feature paketiert»** beschreiben, damit künftige Designs nicht erneut einen «Host-Feature-Owner» erfinden. -- **Roadmap (optional, nicht jetzt):** Scheduler-Boot vom Feature-`onStart` entkoppeln (echter System-Service) und GE-Instanz rein als Authoring-Surface führen. Erst ziehen, wenn es weh tut (YAGNI). +- **Eigene Top-Level-Nav-Gruppe «Workflow-Automation»** (Tab-Seiten: Editor · Vorlagen · Workflows · Läufe · Tasks), mandanten-/feature-übergreifend an einem Ort — **nicht** als Feature-Seite. +- **Scheduler-Boot** in System-Lifespan (statt Feature-`onStart`); **API mandatsweit** `/api/workflow-automation/…` (RBAC = Mandats-Mitgliedschaft + System-Rollen + `isPlatformAdmin`). +- **DB:** `AutoWorkflow.featureInstanceId` verliert RBAC-Bedeutung; `mandateId`+`runAsPrincipal` = Owner; `targetFeatureInstanceId`/per-Node-Ref bleiben (Daten-Scope). +- **Solutions hängen damit sauber an Mandant + Run-as-Principal** (A0.1), nicht an einer GE-Instanz. Die kundenseitige «Lösungen»-Surface bleibt pro Host-Feature eingebettet (Präsentation) — getrennt von der technischen WorkflowAutomation-Gruppe. > Netto (korrigiert): **A0.1** verankert Ownership an **Mandant + Run-as-Principal** (statt erfundenem Host-Owner); **A0.2** behandelt Multi-Feature/Multi-Instanz als **native** Fähigkeit und benennt die 3 echten Code-Lücken (Runtime-Mandatscheck, Read-RBAC, per-Node-Billing); **A0.3** hält «Config statt Code» mit der Versions-Invariante vereinbar; **A0.4** ordnet `graphicalEditor` als Orchestrierungs-Substrat ein. Alles auf bestehenden Mechanismen (`mandateId`-Scoping, `FeatureInstanceRef`, `runEnvelope`/`trigger.form`, `recordUsage`). @@ -229,7 +229,7 @@ Echtes Feature (eigene Modelle + opinionated UI), das die Plattform-Bausteine b | 2026-06-05 | **A0.2 (korrigiert)** Multi-Feature/Multi-Instanz ist **nativ** (per-Node `FeatureInstanceRef`); Schranke = Mandant | Code-Befund: Picker mandats-gescoped, kein Sonder-Fan-out nötig | | 2026-06-05 | **A0.2** 3 Code-Lücken schliessen: Runtime-Mandatscheck, Read-RBAC, **per-Node-Billing** | heute Billing fix auf `graphicalEditor`; Reads ohne RBAC; Mandat nur design-time geprüft | | 2026-06-05 | **A0.3** Settings als **Run-Envelope-Injektion** (`trigger.form`/DataRef), nie Graph-Mutation | hält Published-Version-Invariante; 1 Template-Graph, N Settings | -| 2026-06-05 | **A0.4** `graphicalEditor` als **Orchestrierungs-Substrat** führen (Feature-Mantel bleibt) | Code-Befund: kein DATA, eigene DB für alle Features, globaler Scheduler-Boot | +| 2026-06-05 | **A0.4 (vorgezogen)** `graphicalEditor` von Feature → System-Komponente **`WorkflowAutomation`** umbauen (eigener Plan) | Code-Befund: kein DATA, eigene DB für alle Features, globaler Scheduler-Boot; Solution-Schicht würde Designfehler erben → `c-work/1-plan/2026-06-automation-system-component.md` | | 2026-06-05 | Versand als **neuer `email.sendEmail`-Node** (heute nur `draftEmail`) | Send-Node fehlt real → Blocker für Reporting-Solutions | | 2026-06-05 | i18n: UI via `t()`, kundensichtbare Inhalte als `TextMultilingual` | `ui-nyla`-Regel; Kataloge/Settings lokalisierbar | | 2026-06-04 | Plattform-Bausteine + Solution-Schicht als **generischer Code**, nie kundenspezifisch | macht alle Solutions möglich, hält «kein Kunden-Code» real | @@ -245,7 +245,7 @@ Echtes Feature (eigene Modelle + opinionated UI), das die Plattform-Bausteine b - [ ] A0.1 **Run-as-Principal** in Engine + Scheduler (statt globalem `event`-Sysadmin) + Read-RBAC gleichziehen - [ ] A0.2 **Runtime-Mandatsvalidierung** beim `FeatureInstanceRef`-Auflösen + **per-Node-Billing** (`recordUsage` mit berührter Instanz) + Klarstellung in `feature-instance-scoping.mdc` - [ ] A0.3 Run-Envelope-Injektion aus `settingsValues` (kein Graph-Schreiben) + `settingsSchema`-Drift-Validierung + optional `pinnedVersionId` -- [ ] A0.4 `b-reference`: `graphicalEditor` als Orchestrierungs-Substrat dokumentieren (Roadmap: Scheduler-Boot entkoppeln — später) +- [ ] A0.4 **System-Komponente `WorkflowAutomation` bauen ZUERST** (eigener Plan `c-work/1-plan/2026-06-automation-system-component.md`): Scheduler-Boot entkoppeln, Nav-Gruppe «Workflow-Automation», mandatsweite API/RBAC, DB-Migration **Teil A (Enabler):** - [ ] Solution-Routes **am Host-Feature** (CRUD/Test/Activate) + Host-RBAC + `SolutionsView` (Tab-Pattern, FormGenerator, `useConfirm`/`usePrompt`, i18n) @@ -294,7 +294,7 @@ Echtes Feature (eigene Modelle + opinionated UI), das die Plattform-Bausteine b 5. **Lawyer-Connectors:** iManage/KYC/Konflikt-Check-APIs — welche mandantenspezifisch, welche generisch? 6. **Connector-Generalisierung:** wann Capability-Mixins (`AccountingCapable`/`PayrollCapable`) ziehen? 7. **`email.sendEmail`-Scope:** eigener Node vs. `email.draftEmail` + Auto-Send-Flag — und Verhältnis zu `input.emailWait`/`testMode`. -8. **`graphicalEditor`-Entkopplung:** Scheduler-Boot vom Feature-`onStart` lösen — jetzt oder als spätere Roadmap (A0.4)? +8. **`graphicalEditor`-Entkopplung:** ✅ entschieden — **jetzt**, als eigener Plan `c-work/1-plan/2026-06-automation-system-component.md` (Voraussetzung für die Solution-Schicht). ## Links diff --git a/c-work/1-plan/2026-06-automation-system-component.md b/c-work/1-plan/2026-06-automation-system-component.md new file mode 100644 index 0000000..ca4a43e --- /dev/null +++ b/c-work/1-plan/2026-06-automation-system-component.md @@ -0,0 +1,284 @@ + + + + +# WorkflowAutomation als System-Komponente — `graphicalEditor` raus aus dem Feature-Modell + +> **Treiber:** Entscheid aus `c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md` / `…-step3-features-plan.md` **A0.4**. Dort wurde die Entkopplung als Roadmap markiert; sie wird **vorgezogen**, weil sie sonst die Solution-Schicht (Ownership/RBAC/Billing) später erneut einholt. +> +> **Namens-Konvention:** Die System-Komponente heisst **`WorkflowAutomation`** (Code-Token `WorkflowAutomation`/`workflowAutomation`) — semantisch eindeutig und gut greppbar. Das generische Wort «Automation» ist im Bestand schon mehrfach belegt (`AutomationsDashboardPage`, `routeAutomationWorkspace`, `/automations`, `workflows/automation2`) und bleibt dort **unverändert**. UI-Label (kundensichtbar): **«Workflow-Automation»** / «Automatisierung». + +## Beschreibung und Kontext + +`graphicalEditor` ist heute ein **Hybrid**: formal ein Feature (Discovery, `TEMPLATE_ROLES` `graphicalEditor-*`, Store-Eintrag, `FeatureInstance` pro Mandant, per-Instanz-API `/api/workflows/{instanceId}/…`), architektonisch aber **mandanten- und feature-übergreifende Orchestrierungs-Infrastruktur**: + +- **Kein `getDataObjects()`** — keine Domänen-/Kundendaten; `AutoWorkflow`/`AutoRun` sind Orchestrierungs-Metadaten (eigene DB `poweron_graphicaleditor`). +- **Einziges Feature mit `onStart`/`onStop`** — bootet beim App-Start den **globalen** Scheduler (Email-Poller startet **on-demand** via `emailPoller.ensureRunning`, gestoppt in `onStop`). +- **Scheduler/Engine liegen ohnehin unter `modules/workflows/`** (System), nicht im Feature. +- **`getWorkflows()` filtert nur nach `mandateId`** («cross-instance»); ein Graph referenziert legitim mehrere Features/Instanzen über per-Node `FeatureInstanceRef`. +- **Cross-Mandate-Ops-Sicht existiert bereits**: `AutomationsDashboardPage` (`/automations`, Tabs Workflows/Runs/Details) ← `routeWorkflowDashboard.py` (`/api/system/workflow-runs`), RBAC über Mandats-Mitgliedschaft + Platform-Admin — **ganz ohne** GE-FeatureInstance. + +**Business-Treiber:** Die Solution-Schicht (CustomerCases) verankert Ownership an **Mandant + Run-as-Principal** (A0.1). Solange `graphicalEditor` als Feature mit per-Instanz-RBAC/Billing geführt wird, kollidiert jede Solution mit einem erfundenen «Host-Owner». Wir lösen die Wurzel: **WorkflowAutomation = System-Komponente** mit eigener Navigations-Gruppe «Workflow-Automation» (mehrere Tab-Seiten, mandanten-/feature-übergreifend strukturiert an einem Ort) und sauberem Daten-/RBAC-Modell. + +**Risiko, wenn NICHT gemacht:** doppelte Wahrheit (Feature-Instanz-RBAC vs. mandatsweite Realität), Billing fix auf `graphicalEditor` statt auf berührte Instanz, per-Instanz-URLs (`{instanceId}`) zementieren das Feature-Modell, und die Solution-Schicht erbt den Designfehler. + +## Fokus und kritische Details + +- **Kein Big-Bang.** Parallel-Pfade bauen (mandatsweite API neben `{instanceId}`-API), dann umschalten, dann Feature-Mantel entfernen. Jede Phase ist für sich lauffähig. +- **Scheduler-Boot ist fragil.** Er hängt am Feature-`onStart` (`app.py`-Lifespan iteriert alle Feature-Module). Vor dem Entfernen des Feature-Mantels **muss** der Boot in einen System-Lifespan-Hook umziehen, sonst startet der Scheduler nicht mehr. +- **`featureInstanceId` hat heute zwei Bedeutungen:** (a) GE-Owner/RBAC-Scope auf `AutoWorkflow`, (b) Daten-Scope der Ausführung (`targetFeatureInstanceId` + per-Node `FeatureInstanceRef`). Nur (a) wird abgebaut; (b) bleibt — es ist die Cross-Feature-Referenz. +- **Kaum DDL nötig (Code-verifiziert).** Tabellen werden **ohne `NOT NULL`** (ausser `id`-PK) und **ohne DB-FKs** angelegt (`connectorDbPostgre.py` `_create_table_from_model`); FKs sind app-level (`fkRegistry`, `app.py` `validateFkTargets`). Heisst: `featureInstanceId` ist **schon jetzt DB-nullable** → «nullable machen» ist nur `Optional[str]` im Pydantic-Modell (`datamodelFeatureGraphicalEditor.py`) + Query-/Code-Anpassungen, **keine Migration**. `runAsPrincipal` = additives `ADD COLUMN` (von `_ensureTableExists` abgedeckt). Echte Arbeit = Application-Logik (Routen/Queries, die `featureInstanceId` voraussetzen), nicht Schema. +- **Bestehende Daten grandfathern.** `AutoWorkflow`-Zeilen tragen `featureInstanceId`; `FeatureAccess`-Grants und per-Instanz-Rollen existieren. Datenmigration als **einmaliges Skript** (Muster: `scripts/script_migrate_feature_instance_refs.py`; Cascade-Vorbild: `routeWorkflowDashboard._cascadeDeleteAutoWorkflow`). Migration muss diese erhalten/überführen, nicht löschen. +- **RBAC-Präzedenz nutzen — aber sie deckt nur Lesen.** `routeWorkflowDashboard.py` (`_scopedWorkflowFilter`/`_getAdminMandateIds` + `isPlatformAdmin`) ist ein **Read/List/Delete**-Muster — **kein** Create/Update/Publish/Execute. Die **39** `_validateInstanceAccess`-Sites in `routeFeatureGraphicalEditor.py` sind grösstenteils Write/Execute; dafür braucht es einen **eigens entworfenen** Helper `_validateWorkflowAccess(workflow, context, action)` (read vs. write), nicht 1:1 das Dashboard-Muster. `system`-Pseudo-Feature (`instantiable=False`) ist die Vorlage für Katalog-/RBAC-Registrierung ohne Instanzen. +- **Shared Contracts statt Boundary-Leck (Code-verifiziert).** `graphicalEditor/portTypes` (`PORT_TYPE_CATALOG`) und der Node-Katalog (`STATIC_NODE_TYPES`) werden vom **geteilten** Layer + Chats genutzt (`methods/methodBase.py`, `processing/shared/parameterValidation.py`, `serviceAgent/actionToolAdapter.py`, `shared/i18nRegistry.py`) — sie dürfen **nicht** in die Komponente, sonst importiert Shared/Chat *aufwärts*. Zudem liegen zwei Helfer (`PauseForHumanTaskError`, `_coerce_document_data_to_bytes`) in `automation2.executors`, werden aber von `methods/` importiert → **vor** dem Engine-Umzug in den Shared-Layer **delaminieren**. +- **Zwei UI-Oberflächen sauber trennen** (siehe «Verhältnis zur Solution-Schicht»): die **WorkflowAutomation-Gruppe** (technische Orchestrierung, cross-mandate, für Power-User/Admins) vs. die kundenseitige **«Lösungen»-Surface** pro Host-Feature (bleibt eingebettet, Präsentation). + +## Ziel und Nicht-Ziele + +- **Ziel:** `graphicalEditor` als System-Komponente **`WorkflowAutomation`** führen — eigene Top-Level-Navigationsgruppe mit Tab-Seiten (Editor · Vorlagen · Workflows · Läufe · Tasks), mandanten-/feature-übergreifend. +- **Ziel:** Mandatsweite API + RBAC (kein `{instanceId}` als RBAC-Anker), Scheduler-Boot als System-Lifespan, DB-Scoping auf **Mandant + Principal** (statt GE-Owner-Instanz). +- **Ziel:** Bestehende Workflows/Runs/Tasks und Grants verlustfrei migrieren. +- **Ziel:** Fundament legen für die `Solution`-Schicht (A0.1) — Solutions hängen an Mandant + Run-as-Principal, nicht an einer GE-Instanz. +- **Explizit NICHT:** Graph-Format/Node-Semantik ändern (`modules/workflows/automation2/*` bleibt funktional gleich). **Ausnahme:** per-Node-Billing-Attribution (AC5) ist eine bewusste, lokal begrenzte Executor-Änderung (berührte `FeatureInstanceRef` in den `recordUsage`-Kontext threaden) — kein Graph-/Semantik-Umbau. +- **Explizit NICHT:** den geteilten **Workflow-Execution-Layer** (`workflows/methods/`, `workflows/processing/`) in die Komponente ziehen — er bleibt unter `modules/workflows/` (Chats/Agents nutzen ihn **ohne** Automation). +- **Explizit NICHT:** die kundenseitige «Lösungen»-Surface in diesem Plan bauen (→ CustomerCases-Pläne; dieser Plan liefert nur das Substrat). +- **Explizit NICHT:** per-Node `FeatureInstanceRef` / `targetFeatureInstanceId` (Daten-Scope) abschaffen. +- **Explizit NICHT:** DB-Engine/Datenbankname wechseln (`poweron_graphicaleditor` bleibt). +- **Explizit NICHT:** bestehende «Automation»-Code-Namen umbenennen (`AutomationsDashboardPage`, `routeAutomationWorkspace`, `workflows/automation2`) — nur die *neue* Komponente trägt das Token `WorkflowAutomation`. + +## Zielarchitektur (Kurz) + +``` +VORHER (Feature): + Nav: Mandant → graphicalEditor-Instanz → {editor, templates, tasks} + API: /api/workflows/{geInstanceId}/... RBAC: FeatureAccess auf GE-Instanz + DB : AutoWorkflow.featureInstanceId = GE-Owner (RBAC-Scope) + Boot: graphicalEditor.onStart → Scheduler + +NACHHER (System-Komponente WorkflowAutomation): + Nav: Top-Level-Gruppe «Workflow-Automation» (einmal) → Tabs {Editor, Vorlagen, Workflows, Läufe, Tasks} + + Mandanten-/Instanz-Picker in der Seite (cross-mandate) + API: /api/workflow-automation/... RBAC: Mandats-Mitgliedschaft + System-Rollen + isPlatformAdmin + DB : AutoWorkflow.mandateId + runAsPrincipal (Owner); featureInstanceId → entfällt als RBAC-Anker + targetFeatureInstanceId + per-Node FeatureInstanceRef bleiben (Daten-Scope) + Boot: System-Lifespan (app.py) → Scheduler +``` + +## Namensgebung & modulare Struktur + +**Name der System-Komponente: `WorkflowAutomation`** (UI-Label «Workflow-Automation» / «Automatisierung»). `graphicalEditor` ist **nicht** der Name der Komponente, sondern **ein Modul** darin (der Graph-/Flow-Editor). Begründung für `WorkflowAutomation`: semantisch eindeutig + als Token greppbar (das generische «Automation» ist im Code mehrfach belegt und bleibt). (Verworfen: «Automation» allein — mehrdeutig; «Orchestration» — neuer Begriff ohne Code-Verankerung.) + +Die Komponente bündelt die bestehenden, heute verstreuten **Automation**-Teile (`features/graphicalEditor/`, `workflows/automation2/`, `workflows/scheduler/`) **plus** die kommende L3/L4-Schicht zu **einem nachvollziehbaren, modularen System**. Den geteilten **Workflow-Execution-Layer** (`workflows/methods/`, `workflows/processing/`) bündelt sie **nicht** — der bleibt eigenständig (siehe Abgrenzung unten). Jedes Modul hat eine klare Verantwortung und mappt auf die L2–L4-Schichten der Architektur. + +| L | Modul | Verantwortung | +|---|---|---| +| L2 | **editor** (= heute `graphicalEditor` Authoring) | Graph/Flow-Authoring, Node-Registry, Adapter, Editor-UI-Backend (konsumiert Shared Contracts) | +| L2 | **engine** (= heute `workflows/automation2/`) | Graph-Ausführungs-Runtime (Graph → Run) | +| L2 | **scheduler** | Zeit-/Event-Trigger, Email-Poller | +| L3 | **solutions** | konfigurierte Workflows (Solution-Modell, Settings-Injektion) | +| L4 | **launcher** | Katalog/Vorlagen + «neue Automation» (Template/AI) + Template-Instanziierung | +| L4 | **monitoring** | Läufe, Tasks, Logs (Ops-Sicht) | + +> **NICHT Teil der Komponente (geteilt, Code-verifiziert) — Komponente *konsumiert* abwärts:** +> - **L1 Toolbox** = `workflows/methods/` (Actions) + `workflows/processing/` (ActionExecutor, methodDiscovery, modes) — von Chats/Agents genutzt. +> - **Shared Contracts** = `portTypes`/`PORT_TYPE_CATALOG` + Node-Katalog/`STATIC_NODE_TYPES` — von methods/processing/chats/i18n genutzt; bleibt im Shared-Layer (neu `workflows/workflowContracts/`). Die Komponente besitzt sie **nicht**. + +### Platform (`platform-core/modules/workflowAutomation/`) + +``` +modules/workflowAutomation/ # NEU — die Automation-Komponente +├─ mainWorkflowAutomation.py # System-Registrierung (instantiable=False) + Lifespan-Hook (Scheduler-Boot; Poller-Stop) +├─ datamodelWorkflowAutomation.py # AutoWorkflow / AutoVersion / AutoRun / AutoTask (+ Legacy-Aliase) +├─ routes/ # mandatsweite API /api/workflow-automation/{workflows,versions,runs,tasks,nodes,solutions,...} +├─ editor/ # L2 — Graph-Editor-Backend (nodeRegistry, nodeAdapter, adapterValidator) — konsumiert Shared Contracts +├─ engine/ # L2 — Graph-Ausführung (heute workflows/automation2/: executionEngine, executors, graphUtils, runEnvelope, scheduleCron) +├─ scheduler/ # L2 — Scheduler + emailPoller (heute workflows/scheduler/ + graphicalEditor/emailPoller.py) +├─ solutions/ # L3 — solutionService, datamodelSolution (Settings-Injektion, run-as-Principal) +└─ launcher/ # L4 — Katalog/Templates + AI-Erstellung + Template-Instanziierung + +modules/workflows/ # BLEIBT — geteilt (NICHT Teil der Komponente) +├─ methods/ # L1 — Actions (methodAi/Trustee/Sharepoint/Outlook/File/Context/Clickup/Jira/Redmine) +├─ processing/ # L1 — ActionExecutor, methodDiscovery, modes/adaptive, workflowProcessor +├─ workflowContracts/ (NEU) # Shared Contracts: portTypes (PORT_TYPE_CATALOG) + Node-Katalog (STATIC_NODE_TYPES) +│ # — heute in graphicalEditor/, hierher delaminieren (genutzt von methods/processing/chats/i18n) +└─ workflowManager.py # Chat-/Agent-seitige Workflow-Verarbeitung +``` + +> **Abgrenzung Komponente ↔ Contracts ↔ Execution (Code-verifiziert, korrigiert).** Drei Schichten, strikt abwärts: **Komponente → Shared Contracts → Execution-Layer.** +> - **In die Komponente:** `workflows/automation2/` (Graph-Engine) → `engine/`; `workflows/scheduler/` → `scheduler/`; `graphicalEditor/{nodeRegistry, adapterValidator, emailPoller, Editor-Backend}` → `editor/`/`scheduler/`. +> - **Bleibt geteilt unter `modules/workflows/`:** `methods/` (Actions), `processing/` (`ActionExecutor`, `methodDiscovery`, `modes/`, `adaptive/`, `workflowProcessor`) — genutzt von Chats/Agents (`serviceAgent/{actionToolAdapter,mainServiceAgent}`, `serviceAi/*`, `serviceGeneration/*`) **ohne** Automation. +> - **Shared Contracts (neu zu delaminieren):** `portTypes`/`PORT_TYPE_CATALOG` und der Node-Katalog/`STATIC_NODE_TYPES` liegen heute unter `graphicalEditor/`, werden aber von `methods/methodBase.py`, `processing/shared/parameterValidation.py`, `serviceAgent/actionToolAdapter.py` und `shared/i18nRegistry.py` genutzt → **bleiben geteilt** (`workflows/workflowContracts/`); die Komponente konsumiert sie. +> - **Korrektur eines früheren Fehlers:** «`automation2` wird von Chats nicht importiert» war **falsch**. `methods/methodFile/actions/create.py` + `methods/methodContext/actions/setContext.py` importieren `automation2.executors` (`_coerce_document_data_to_bytes`, `PauseForHumanTaskError`) top-level — geladen via `methodDiscovery` im Chat-/Agent-Pfad. **Diese zwei Helfer vor dem Engine-Umzug in den Shared-Layer extrahieren** (Delaminierung), sonst importiert Shared aufwärts in die Komponente. +> +> **Guard-Test:** sicherstellen, dass `modules.workflows.{methods,processing}` + `modules.serviceCenter` importierbar sind, **ohne** `modules.workflowAutomation.*` zu laden. Migration nur der Automation-Teile (Re-Export/Shims; ~20 Importer von `workflows.automation2`/`scheduler`). **Kein funktionaler Umbau der Engine** (Ausnahme: per-Node-Billing, AC5). + +### UI (`ui-nyla/src/`) + +``` +pages/workflowAutomation/ +├─ WorkflowAutomationHubPage.tsx # Container: Top-Level-Gruppe «Workflow-Automation», Tabs, Mandanten-/Instanz-Scope-Selector +└─ tabs/ + ├─ LauncherTab.tsx # L4 — Katalog/Neu (Vorlage oder AI) + ├─ SolutionsTab.tsx # L3 — konfigurierte Solutions (Admin/Power-User-Sicht) + ├─ EditorTab.tsx # L2 — Graph-Editor (Keep-Alive) + ├─ WorkflowsTab.tsx # alle Workflows (cross-mandate/-feature) + ├─ RunsTab.tsx # L4 — Läufe/Monitoring + └─ TasksTab.tsx # Human-Tasks +components/workflowAutomation/ +├─ FlowEditor/ # heute components/GraphicalEditor/ +├─ Launcher/ +├─ Solutions/ +└─ Monitoring/ +api/workflowAutomationApi.ts # /api/workflow-automation/... (ersetzt workflowApi {instanceId}-Pfade) +``` + +- **Eine** Top-Level-Nav-Gruppe «Workflow-Automation» (nicht pro Mandant/Instanz); Tabs via `?tab=` deeplinkbar (Muster `AutomationsDashboardPage`). +- **Abgrenzung zur kundenseitigen «Lösungen»-Surface:** Der `SolutionsTab` hier ist die **Admin/Power-User**-Sicht über alle Solutions; die kundenseitige `SolutionsView` (L4) bleibt **pro Host-Feature eingebettet** (Trustee usw.) und zeigt nur die für diesen Kontext konfigurierten Solutions. Beide nutzen `api/workflowAutomationApi.ts`. + +## Verhältnis zur Solution-Schicht (CustomerCases) + +- **WorkflowAutomation-Gruppe = Substrat-UI** (Power-User/Admin): roher Editor, Templates, alle Workflows/Läufe/Tasks über Mandanten/Features. +- **«Lösungen»-Surface = kundenseitig**, pro Host-Feature eingebettet (Trustee usw.) — konsumiert dasselbe Substrat, zeigt aber nur konfigurierbare Solutions. Bleibt wie in den CustomerCases-Plänen. +- Beide hängen am gleichen Modell: **Mandant + Run-as-Principal**, nicht an einer GE-Instanz. Dieser Plan ist die **Voraussetzung** für A0.1/A0.2. + +## Betroffene Module + +- **Gateway (platform-core):** + - `app.py` — Scheduler/Email-Poller-Boot in **System-Lifespan** (statt Feature-`onStart`). + - `modules/workflows/scheduler/mainScheduler.py` — Boot-Aufruf; `JOB_ID_PREFIX`/`_CALLBACK_NAME` (`"graphicalEditor.*"`) sind in Job-IDs persistiert → Literale behalten oder Job-IDs migrieren (in-memory APScheduler, Re-Sync beim Boot → risikoarm); `if not instanceId`-Guard entfernen (s. Phase 1); **Run-as-Principal** statt globalem `event`-Sysadmin (A0.1). + - **Delaminierung zuerst (Phase 0.5):** `PauseForHumanTaskError` + `_coerce_document_data_to_bytes` aus `automation2/executors/` in den Shared-Layer; `portTypes`/Node-Katalog (`STATIC_NODE_TYPES`) aus `graphicalEditor/` nach `workflows/workflowContracts/`. Erst dann ist der Engine-Umzug aufwärts-importfrei. + - `modules/workflows/{automation2,scheduler}/` → in die Komponente: `automation2` → `workflowAutomation/engine/`, `scheduler` → `workflowAutomation/scheduler/` (Re-Export-Shims). **`automation2` = die Graph-Engine**, kein funktionaler Umbau (Ausnahme: per-Node-Billing-Kontext, AC5). + - **`modules/workflows/{methods,processing}/` + `workflowContracts/` bleiben** geteilt — **nicht** verschieben. + - `modules/features/graphicalEditor/` → konzeptionell nach `modules/workflowAutomation/editor/` führen; `mainGraphicalEditor.py`: `getFeatureDefinition`/`TEMPLATE_ROLES`/`onStart` entfernen bzw. zu System-Registrierung umbauen (`instantiable=False`, Vorbild `mainSystem.py`). + - `modules/features/graphicalEditor/routeFeatureGraphicalEditor.py` — neue **mandatsweite** Routen `/api/workflow-automation/...`; die **39** `_validateInstanceAccess`-Sites bewusst auf einen neuen `_validateWorkflowAccess(workflow, context, action)` (read vs. write) migrieren — Read-Scoping vom Dashboard, Write/Execute eigens entworfen, `isPlatformAdmin`-Bypass. `_validateTargetInstance` zusätzlich um **Mandatsgrenze** ergänzen (AC8, heute nur `FeatureAccess`). + - `modules/routes/routeSystem.py` — GE-Hardcode in `_getFeatureUiObjects` entfernen; neuen statischen Nav-Block `workflowAutomation` ausliefern. + - `modules/system/mainSystem.py` — `NAVIGATION_SECTIONS`: Block `id="workflowAutomation"` (order ~25) + `ui.system.workflowAutomation.*`-Objekte; Store-Eintrag `resource.store.graphicalEditor` entfernen. + - `modules/interfaces/interfaceFeatures.py` — `_copyTemplateWorkflows` läuft heute bei **FeatureInstance-Erstellung** und stempelt `{{featureInstanceId}}`/`targetFeatureInstanceId` (auch für Trustee/Redmine). Ohne GE-Instanz **entfällt der Trigger** → Template-Instanziierung explizit in den `launcher/`-Flow verlagern (inkl. Demo-Bootstrap); Trustee/Redmine-Platzhalter-Vertrag beachten. + - `modules/interfaces/interfaceDbApp.py` — Mandate-Delete-Cascade für WorkflowAutomation-Daten mandatsweit (statt per GE-Instanz; Vorbild `_cascadeDeleteAutoWorkflow`). + - `modules/interfaces/interfaceRbac.py` — `TABLE_NAMESPACE` (8 Einträge: `AutoWorkflow/AutoVersion/AutoRun/AutoStepLog/AutoTask` + Legacy `Automation2*`): **Option B** — Namespace `feature.graphicalEditor` **beibehalten** + System-DATA-Objekte ergänzen. (Ein Flip auf `system.workflowAutomation` verwaist bestehende `AccessRule`/Rollen-Zeilen; nur mit zwingend gekoppeltem Migrations-Skript im selben Deploy.) + - `modules/interfaces/interfaceBootstrap.py` — Store-Grant + ggf. neue System-Rollen `workflowAutomation-*`. + - `modules/features/graphicalEditor/mainGraphicalEditor.py` `getGraphicalEditorServices` — `featureCode`/`featureInstanceId` im Hub: Billing **per-Node** auf berührte Instanz (A0.2, Executor-Change), Mandate = `mandateId`. + - `serviceCenter/.../toolboxRegistry.py` — `ToolboxDefinition(featureCode="graphicalEditor")` → `workflowAutomation`. + - **Weitere GE-Importer (oft übersehen):** `shared/i18nRegistry.py` (zieht `STATIC_NODE_TYPES`/`PORT_TYPE_CATALOG` → nach Delaminierung auf `workflowContracts` umbiegen), `routeSystem.py` (`UI_OBJECTS` + Dashboard-`_ensureTableExists`), `routeAdminFeatures.py`, `interfaceDbManagement.py`, `interfaceFeatureGraphicalEditor.getAllWorkflowsForScheduling` (Lesepfad von Scheduler **und** Dashboard — stabil halten/shimmen). +- **Frontend (ui-nyla):** + - `src/components/Navigation/MandateNavigation.tsx` — `block.id === 'workflowAutomation'` als eigene Top-Level-Gruppe rendern (analog `admin`). + - `src/App.tsx` — `/workflow-automation/*`-Routen (Hub + `?tab=` Deeplinks); Redirects der alten `/mandates/.../graphicalEditor/.../*`. + - `src/pages/AutomationsDashboardPage.tsx` → in **`WorkflowAutomationHubPage`** mit Tabs überführen (Workflows, Läufe, Editor, Vorlagen, Tasks). + - `src/pages/FeatureView.tsx` — `graphicalEditor` aus `VIEW_COMPONENTS` entfernen. + - `src/pages/views/graphicalEditor/*` — von `useInstanceId()`/`useCurrentInstance()` auf expliziten Mandanten-/Instanz-Picker (Scope-Selector) umstellen. + - `src/config/keepAliveRoutes.tsx` — Editor-Keep-Alive-Pfad auf `/workflow-automation/editor` umziehen. + - `src/config/pageRegistry.tsx` — Icons für `page.system.workflowAutomation.*`. + - `src/api/workflowApi.ts` — URLs `/api/workflows/{instanceId}/…` → `/api/workflow-automation/…`. + - Cross-Links: `TrusteeAnalyseView`/`TrusteeAbschlussView` (`/automations?tab=…`), `Store.tsx` (GE-Karte entfernen). +- **DB-Migration:** minimal — `runAsPrincipal` = additives `ADD COLUMN`; `featureInstanceId` ist **bereits DB-nullable** (kein DDL, keine DB-FK; nur Pydantic `Optional` + Code); Daten-/Grant-Backfill via Skript. **Kein** Namespace-Flip (Option B). +- **Andere:** RBAC (System-Objekte/-Rollen, FeatureAccess-Grants migrieren, GE-Feature-Rollen entfallen), Billing (per-Node-Attribution), Demo-Configs (`pwgDemo2026`/`investorDemo2026`), Tests, `.cursor/rules/*` (s. Abschluss). + +## Entscheidungen + +| Datum | Entscheidung | Begründung | +|-------|-------------|------------| +| 2026-06-05 | System-Komponente heisst **`WorkflowAutomation`** (Token `WorkflowAutomation`/`workflowAutomation`); UI-Label «Workflow-Automation» | semantisch eindeutig + greppbar; generisches «Automation» bleibt für Bestand | +| 2026-06-05 | `graphicalEditor` = **ein Modul** (editor) innerhalb von WorkflowAutomation | graphEditor ist nur das Authoring-Element | +| 2026-06-05 | **Automation ≠ Workflow-Execution.** `methods`/`processing` bleiben geteilter Layer unter `modules/workflows/`; nur `automation2` (engine) + `scheduler` + `graphicalEditor` wandern in die Komponente | Chats/Agents nutzen den Execution-Layer **ohne** Automation; Abwärts-Abhängigkeit Komponente→Execution (Code-belegt) | +| 2026-06-05 | **Shared Contracts** (`portTypes`/`PORT_TYPE_CATALOG`, Node-Katalog) bleiben geteilt (`workflows/workflowContracts/`); Komponente konsumiert | Code-Beleg: methods/processing/chats/i18n nutzen sie — Verschieben = Aufwärts-Import | +| 2026-06-05 | **Delaminierung** zweier Helfer (`PauseForHumanTaskError`, `_coerce_document_data_to_bytes`) aus `automation2.executors` **vor** Engine-Umzug | sonst importiert Shared `methods/` aufwärts in die Komponente | +| 2026-06-05 | RBAC-Namespace **Option B** (beibehalten + System-DATA-Objekte), **kein** Flip | verhindert verwaiste `AccessRule`/Rollen-Zeilen | +| 2026-06-05 | Eigener **Write-RBAC-Helper** `_validateWorkflowAccess` (read/write) für die 39 Sites; GE-Feature-Rollen entfallen, Modell = Mandats-Mitgliedschaft/-Admin + `isPlatformAdmin` | Dashboard-Muster deckt nur Lesen; `instantiable=False` ⇒ keine Feature-Instanz-Rollen mehr | +| 2026-06-05 | **Modulares System** (editor/engine/scheduler/solutions/launcher/monitoring), gemappt auf L2–L4; L1 (Actions/Execution) + Contracts bleiben geteilt | wartbar/nachvollziehbar; bündelt heute verstreute Automation-Teile + L3/L4 | +| 2026-06-05 | Code nach **`modules/workflowAutomation/`** (Platform) bzw. `pages/workflowAutomation/` + `components/workflowAutomation/` (UI); schrittweise via Re-Export-Shims | sauberer Schnitt; Imports brechen nicht | +| 2026-06-05 | `graphicalEditor` wird **System-Komponente** (Feature-Mantel entfällt) | kein DATA, eigene DB für alle Features, globaler Scheduler-Boot → ist Infrastruktur | +| 2026-06-05 | Eigene Top-Level-Nav-Gruppe **«Workflow-Automation»** mit Tab-Seiten | strukturiert an einem Ort, cross-mandate/-feature; nicht als Feature-Seite | +| 2026-06-05 | Scheduler-/Poller-Boot in **System-Lifespan** (`app.py`) statt Feature-`onStart` | Boot von der Feature-Plug-in-Mechanik lösen | +| 2026-06-05 | API mandatsweit `/api/workflow-automation/…`; RBAC = Mandats-Mitgliedschaft + System-Rollen + `isPlatformAdmin` | `{instanceId}` als RBAC-Anker abbauen; bestehende Dashboard-Muster wiederverwenden | +| 2026-06-05 | `AutoWorkflow.featureInstanceId` verliert RBAC-Bedeutung; `mandateId`+`runAsPrincipal` = Owner; `targetFeatureInstanceId`/per-Node-Ref bleiben | A0.1/A0.2; Daten-Scope bleibt funktional | +| 2026-06-05 | Migration **phasenweise, parallel** (kein Big-Bang); Bestand grandfathern | Risiko begrenzen, jederzeit lauffähig | +| 2026-06-05 | DB-Name `poweron_graphicaleditor` bleibt | YAGNI; Rename = unnötiges Risiko | + +## Umsetzungs-Checkliste + +**Phase 0 — Scheduler-Boot entkoppeln (risikoarm, zuerst):** +- [ ] Scheduler-Start in System-Lifespan (`app.py`, **nach** `setSchedulerMainLoop`; `eventUser` ist dort schon vorhanden); Poller bleibt **on-demand** (`ensureRunning`), nur `onStop`-Stop verlagern; GE-`onStart`/`onStop` entfernen +- [ ] Sicherstellen, dass das Komponenten-Modul weiter importiert wird (Routen-Registrierung) auch ohne Feature-Mantel +- [ ] Smoke: **bestehende (grandfathered)** geplante Runs feuern weiterhin, auch ohne GE-Feature-Instanz im Mandanten + +**Phase 0.5 — Delaminierung (vor jedem Code-Umzug):** +- [ ] `PauseForHumanTaskError` + `_coerce_document_data_to_bytes` aus `automation2/executors/` in den Shared-Layer ziehen (Re-Export-Shim am alten Ort) +- [ ] `portTypes`/`PORT_TYPE_CATALOG` + Node-Katalog (`STATIC_NODE_TYPES`) → `workflows/workflowContracts/`; `i18nRegistry`, `methodBase`, `parameterValidation`, `actionToolAdapter` darauf umbiegen +- [ ] Guard-Test: `modules.workflows.{methods,processing}` + `serviceCenter` importieren **ohne** `modules.workflowAutomation.*` + +**Phase 1 — Mandatsweite API + System-RBAC (parallel zur Bestands-API):** +- [ ] `AutoWorkflow.runAsPrincipal` ergänzen (additives `ADD COLUMN`, nullable) +- [ ] System-RBAC-Objekte `ui.system.workflowAutomation.*` + RESOURCE für `/api/workflow-automation/…`; DATA-Objekte unter **bestehendem** Namespace (Option B) +- [ ] Neue Routen `/api/workflow-automation/{workflows,versions,runs,tasks,nodes,…}` mandatsweit; **Write-RBAC-Helper** `_validateWorkflowAccess` (read = Dashboard-Scoping, write/execute eigens), `isPlatformAdmin`-Bypass +- [ ] Scheduler **von `featureInstanceId` entkoppeln**: `if not instanceId`-Guard (`mainScheduler.py`) entfernen, Interface/Services nicht mehr instanz-gekeyt auflösen, Ausführung über `targetFeatureInstanceId`/Mandant scopen +- [ ] Per-Node-Billing: berührte `FeatureInstanceRef` in den `recordUsage`-Kontext threaden (Executor-Change, AC5), Mandate = `mandateId` +- [ ] Run-as-Principal in Engine/Scheduler (statt globalem `event`-Sysadmin) + Read-RBAC analog Write-Pfad (A0.1) +- [ ] Runtime-Mandatsvalidierung beim `FeatureInstanceRef`-Auflösen (A0.2) + +**Phase 2 — UI «Workflow-Automation»-Gruppe:** +- [ ] Nav-Block `workflowAutomation` in `mainSystem.py` + Handling in `MandateNavigation.tsx` (Top-Level) +- [ ] `/workflow-automation/*`-Routen + Hub-Seite mit Tabs (Editor · Vorlagen · Workflows · Läufe · Tasks), `?tab=`-Deeplinks +- [ ] Mandanten-/Instanz-Scope-Selector in der Seite (kein per-Instanz-Nav) +- [ ] Editor-Komponenten von `useInstanceId()` lösen; Keep-Alive-Pfad umziehen +- [ ] Redirects alte → neue Pfade; Cross-Links (Trustee, Store) anpassen + +**Phase 3 — DB & Datenmigration:** +- [ ] `AutoWorkflow.featureInstanceId` → `Optional` (Pydantic; **kein DDL** — Spalte bereits nullable, keine DB-FK); Routen/Queries auf leeren Wert tolerant machen; `validateFkTargets` tolerant +- [ ] `Solution`-Modell vorbereiten (A0.1 — Detail in CustomerCases-features-plan) +- [ ] Migrations-Skript: `FeatureAccess`-Grants → Mandats-Mitgliedschaft/-Rollen (GE-Feature-Rollen entfallen — **Sichtbarkeitsänderung dokumentieren**); `featureInstanceId`-RBAC-Bezug auflösen (Bestand grandfathern), `targetFeatureInstanceId` erhalten +- [ ] Mandate-Delete-Cascade mandatsweit (Vorbild `_cascadeDeleteAutoWorkflow`) + +**Phase 4 — Feature-Mantel entfernen:** +- [ ] `getFeatureDefinition`/`registerFeature`/`TEMPLATE_ROLES`/`UI_OBJECTS`(feature)/Store-Eintrag entfernen; GE-Hardcode in `routeSystem.py` raus +- [ ] `FeatureView.tsx`-Eintrag + Store-Karte entfernen; Demo-Configs umstellen +- [ ] Alte `/api/workflows/{instanceId}/…`-Routen deprecaten/entfernen +- [ ] Tests grün (inkl. `tests/unit/graphicalEditor/*`, Demo-Bootstrap, Adapter-Drift) + +**Abschluss:** +- [ ] `b-reference` aktualisieren; `_CHANGELOG.md` + +## Akzeptanzkriterien + +| # | Kriterium (Given-When-Then) | Prio | +|---|---|---| +| 1 | Given ein Mandant ohne GE-FeatureInstanz, When ein **bestehender (grandfathered)** geplanter Workflow fällig ist, Then feuert der Scheduler (Boot via System-Lifespan). *(Instanz-freie Workflows: erst nach Phase-1-Scheduler-Entkopplung.)* | must | +| 2 | Given ein User mit Mandats-Mitgliedschaft, When er «Workflow-Automation» öffnet, Then sieht er eine Top-Level-Gruppe mit Tabs (Editor/Vorlagen/Workflows/Läufe/Tasks) — **nicht** pro Mandant/Instanz dupliziert | must | +| 3 | Given mehrere Mandanten/Features, When er Workflows/Läufe ansieht, Then sind sie cross-mandate/-feature gelistet, RBAC-gefiltert (Mandats-Admin/`isPlatformAdmin`) | must | +| 4 | Given Bestands-Workflows/Runs/Tasks, When migriert wurde, Then bleiben sie aufrufbar/ausführbar; `targetFeatureInstanceId` unverändert wirksam | must | +| 5 | Given ein Run über mehrere Trustee-Instanzen, When er läuft, Then bucht `recordUsage` je Node die berührte Instanz (nicht fix `graphicalEditor`) | must | +| 6 | Given kein `graphicalEditor`-Feature mehr, When der Store geöffnet wird, Then erscheint keine GE-Karte; bestehende Mandanten verlieren keine Workflows | must | +| 7 | Given ein geplanter Run, When er ausgeführt wird, Then unter definierter Automations-Identität (nicht globaler Sysadmin); Reads nur im RBAC-Umfang des Principals | must | +| 8 | Given die neue API, When ein Node eine fremd-mandatige Instanz-UUID trägt, Then Laufzeit-Fehler (Mandatsgrenze) | should | + +## Testplan + +| ID | AC | Art | Automatisiert | Repo-Pfad | Status | +|----|----|-----|--------------|-----------|--------| +| T1 | 1 | integration | ja | platform-core/tests/.../scheduler | pending | +| T2 | 3 | api | ja | platform-core/tests/.../workflowAutomation | pending | +| T3 | 4 | migration | ja | platform-core/tests/.../migration | pending | +| T4 | 5 | unit | ja | platform-core/tests/.../billing | pending | +| T5 | 2 | e2e/manual | nein | ui-nyla | pending | + +## Offene Fragen + +1. **RBAC-Granularität (grösstenteils entschieden):** Modell = Mandats-Mitgliedschaft + Mandats-Admin + `isPlatformAdmin`; GE-Feature-Rollen (`graphicalEditor-*`) entfallen. Offen nur: brauchen Power-User ohne Admin eine eigene System-Rolle `workflowAutomation-user`, oder genügt Mandats-`user`? (Feature-Instanz-Rollen sind keine Option mehr — `instantiable=False` + `rbac-role-separation.mdc`.) +2. **API-Pfad:** `/api/workflow-automation/…` neu vs. bestehendes `/api/system/workflow-runs` ausbauen — konsolidieren? +3. **Run-as-Principal-Verwaltung:** Ersteller-Identität vs. dedizierter Service-Principal (siehe CustomerCases offene Frage #1). +4. **Alt-URLs:** wie lange Redirects der `{instanceId}`-Pfade halten (Bookmarks/Deeplinks)? +5. **Datei-/Doku-Rename:** dieses Plan-Dokument ggf. auf `…-workflowautomation-system-component.md` umbenennen (aktuell `…-automation-system-component.md`) — Konsistenz vs. Referenz-Churn. + +## Links + +- Architektur/Entscheid: `c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md` (A0.4), `…-step3-features-plan.md` (A0) +- Prior Art: `c-work/4-done/2026-04-automation-unification.md`, `2026-04-automation-central-admin.md`, `2026-04-generic-graph-editor.md` +- Code (Backend): `modules/features/graphicalEditor/`, `modules/workflows/{automation2,scheduler}/`, `modules/routes/{routeWorkflowDashboard,routeAutomationWorkspace,routeSystem}.py`, `modules/system/mainSystem.py`, `app.py` +- Code (Frontend): `ui-nyla/src/pages/AutomationsDashboardPage.tsx`, `components/Navigation/MandateNavigation.tsx`, `pages/FeatureView.tsx`, `App.tsx` +- RBAC: `b-reference/platform/rbac.md`, `.cursor/rules/rbac-role-separation.mdc`, `.cursor/rules/feature-instance-scoping.mdc` + +## Abschluss + +- [ ] `b-reference/`: neue Kanon-Seite «WorkflowAutomation (System-Komponente)»; `graphicalEditor`-Feature-Seite umschreiben +- [ ] `.cursor/rules/rbac-role-separation.mdc` + `feature-instance-scoping.mdc` aktualisieren (WorkflowAutomation als dokumentierte Ausnahme; stale Globs `gateway/`/`frontend_nyla/` → `platform-core/`/`ui-nyla/` korrigieren) +- [ ] `TOPICS.md` aktualisieren (WorkflowAutomation = System-Komponente) +- [ ] Dieses Dokument → `c-work/2-build/` bei Annahme, dann `4-done/` diff --git a/c-work/_CHANGELOG.md b/c-work/_CHANGELOG.md index 6f33fc3..dc3c049 100644 --- a/c-work/_CHANGELOG.md +++ b/c-work/_CHANGELOG.md @@ -14,6 +14,9 @@ Skip: reine Refactors, Formatting, Lint, Dep-Bumps, Test-only, Wiki-Tippfehler. ## 2026-06-05 +- 2026-06-05 | docs | wiki | **WorkflowAutomation-Plan nach 2 kritischen Code-Reviews überarbeitet (+ Trennung Automation ↔ Execution)**: Zentrale Korrektur — **Automation** (Graph-Editor/Engine `automation2`/Scheduler/Solutions) und der geteilte **Workflow-Execution-Layer** (`workflows/methods`+`processing`, von reinen Chats/Agents genutzt) bleiben im Code getrennt; nur die Automation-Teile wandern in die Komponente. Frühere Aussage «`automation2` wird von Chats nicht importiert» als **falsch** korrigiert (shared `methods` importieren `automation2.executors`) → neue **Phase 0.5 Delaminierung** (`PauseForHumanTaskError`/`_coerce_document_data_to_bytes` + `portTypes`/`STATIC_NODE_TYPES` → neues geteiltes `workflows/workflowContracts/`). Weitere Review-Fixes: `featureInstanceId` ist **bereits DB-nullable** (kein DDL, keine DB-FK), Scheduler ist hart auf `featureInstanceId` gekeyt (Entkopplung als eigener Schritt), Dashboard-RBAC deckt nur Lesen → eigener Write-Helper `_validateWorkflowAccess` für 39 Sites, RBAC-Namespace **Option B** (kein Flip), Template-Instanziierungs-Trigger (`_copyTemplateWorkflows`) wandert in `launcher/`, per-Node-Billing als bewusste Executor-Ausnahme, `.cursor/rules/*` aktualisieren. (c-work: c-work/1-plan/2026-06-automation-system-component.md) +- 2026-06-05 | docs | wiki | **Plan: System-Komponente `WorkflowAutomation` (`graphicalEditor` raus aus dem Feature-Modell)**: Neuer Umsetzungsplan in `c-work/1-plan/`. Komponente heisst `WorkflowAutomation` (greppbares Token; `graphicalEditor` = ein Modul darin), modulares Layout (toolbox/editor/engine/scheduler/solutions/launcher/monitoring) gemappt auf L1–L4. Code-fundiert (Discovery/Registry, `FeatureInstance`-Lifecycle, DB `poweron_graphicaleditor`, Scheduler-Boot via Feature-`onStart`, RBAC-Präzedenz `routeWorkflowDashboard`/`routeAutomationWorkspace`, ~70 Backend-Touchpoints + UI-Navigation). Phasen 0–4: Scheduler-Boot in System-Lifespan → mandatsweite API `/api/workflow-automation/…` + System-RBAC → Top-Level-Nav-Gruppe «Workflow-Automation» mit Tab-Seiten → DB (`runAsPrincipal`, `featureInstanceId` als RBAC-Anker abbauen, Daten-Backfill) → Feature-Mantel entfernen. Vorgezogen aus A0.4, weil Voraussetzung für die Solution-Schicht. (c-work: c-work/1-plan/2026-06-automation-system-component.md) +- 2026-06-05 | docs | wiki | **CustomerCases A0.4 von Roadmap auf «jetzt» gezogen**: step1-architecture + step3-features-plan verweisen für die `graphicalEditor`→System-Komponente-Umstellung auf den neuen 1-plan; offene Frage #8 + Checkliste/Entscheidungstabelle entsprechend aktualisiert. (c-work: c-work/0-ideas/2026-06-CustomerCases-step3-features-plan.md) - 2026-06-05 | docs | wiki | **A0 Code-verifiziert korrigiert: Workflow-Ownership = Mandant + Run-as-Principal (nicht Host-Feature)**: Code-Analyse (`executionEngine.py`, `mainScheduler.py`, `routeFeatureGraphicalEditor.py`, `datamodelFeatureGraphicalEditor.py`, Trustee-Actions) zeigt, dass Workflows mandatsweit + identitätsgebunden über beliebige Feature-Instanzen laufen — kein Host-Feature-Owner. **A0.1** neu: Owner-Achse = `mandateId` + `runAsPrincipal`, RBAC = Principal-RBAC; scheduled Runs sollen unter definierter Automations-Identität statt globalem `event`-Sysadmin laufen. **A0.2** neu: Multi-Feature/Multi-Instanz ist nativ (per-Node `FeatureInstanceRef`), echte Schranke = Mandant; 3 Code-Lücken benannt (Runtime-Mandatscheck beim Ref-Auflösen, Read-RBAC analog Write, per-Node-Billing statt fix `graphicalEditor`). **A0.4** neu: `graphicalEditor` als Orchestrierungs-Substrat eingeordnet (kein DATA, eigene DB für alle Features, globaler Scheduler-Boot via `onStart`) — Feature-Mantel bleibt als RBAC-/Store-Eintritt. step1-architecture + product-summary angeglichen. (c-work: c-work/0-ideas/2026-06-CustomerCases-step3-features-plan.md) - 2026-06-05 | docs | wiki | **CustomerCases step3-Pläne überarbeitet + 3 Architektur-Leitentscheide (A0)**: Nach kritischem Review beide Pläne geschärft. Neuer Abschnitt **A0** im features-plan löst die 3 kritischen Punkte: **A0.1** Solution = `graphicalEditor`-Execution mit `hostFeatureRef` als alleinigem Owner für RBAC/Billing (Cross-Feature-Drift gelöst); **A0.2** Multi-Instanz-Fan-out nur mandatsintern über explizites `instanceSet`, instanz-genaue Billing-Attribution; **A0.3** Settings als Run-Envelope-Injektion (`trigger.form`/DataRef) statt Graph-Mutation (Published-Version-Invariante gewahrt). Zusätzlich: Node-IDs gegen `nodeDefinitions/` verifiziert (neuer `email.sendEmail`-Versand-Node + `data.writeToTable` als Blocker erkannt; `data.consolidate` vorhanden), neuer i18n-Abschnitt (A5, `t()` + `TextMultilingual`), RBAC-Items/Deletion-Cascade/Adapter-Drift ergänzt, S5 als «vorhandene Templates exponieren» (statt migrieren) korrigiert. step1-architecture + product-summary + mockup auf neue Entscheide/Node-IDs angeglichen. (c-work: c-work/0-ideas/2026-06-CustomerCases-step3-features-plan.md, 2026-06-CustomerCases-step3-solutions-plan.md)