455 lines
188 KiB
Markdown
455 lines
188 KiB
Markdown
<!-- status: canonical -->
|
||
<!-- lastReviewed: 2026-05-23 -->
|
||
|
||
|
||
# Changelog (c-work)
|
||
|
||
Eine Zeile pro Change, NEUESTE EINTRAEGE ZUOBERST. Begruendungen gehoeren ins zugehoerige
|
||
`c-work/<phase>/<feature>.md` oder die PR-Beschreibung.
|
||
|
||
Format: `- YYYY-MM-DD | <type> | <scope> | <Kurzbeschreibung> [(c-work: <relPfad>)] [(PR: #123)]`
|
||
type: `feat` `fix` `refactor` `docs` `test` `chore` `build` · scope: `platform-core` `ui-nyla` `service-llm-private` `service-preprocessing` `teams-bot` `wiki` `infra` `*`
|
||
|
||
Skip: reine Refactors, Formatting, Lint, Dep-Bumps, Test-only, Wiki-Tippfehler.
|
||
|
||
## 2026-06-05
|
||
|
||
- 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)
|
||
|
||
## 2026-06-04
|
||
|
||
- 2026-06-04 | docs | wiki | **CustomerCases-Doks auf einheitliche Naming-Convention umbenannt**: `2026-06-STEP*`-Dateien → `2026-06-CustomerCases-stepN-*` (step1=architecture, step2=communication [product-summary md/pdf + mockup html], step3=solutions-plan/features-plan). Alle Cross-Referenzen in den Dokumenten + Changelog-Pfade angepasst. (c-work: c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md u. a.)
|
||
- 2026-06-04 | docs | wiki | **STEP2-Pläne neu strukturiert: Solutions vs. Features**: Die drei bisherigen STEP2-Docs (lawyer-feature, pm-consolidated-customer-requirements, umsystem-integration) durch zwei architektur-konforme Pläne ersetzt. `step3-solutions-plan.md` = alle konfigurierten Use Cases als Solutions (S1 SelectLine→RMA, S2 Pling-Reporting, S3 PWG-Mietzins, S4 Beleg-Import, S5 Finanz-Analysen, S6 Notification) mit Trigger/Bausteine/Settings/Output je Solution + Klassifikationstabelle. `step3-features-plan.md` = der Code dahinter (Teil A Plattform-Enabler: Solution-Schicht L3/L4, generische Nodes rbac.queryUsersByRole/testMode/integration.*, Connectors; Teil B vertikale Features: lawyer, commcoach, trustee-core). (c-work: c-work/0-ideas/2026-06-CustomerCases-step3-solutions-plan.md, 2026-06-CustomerCases-step3-features-plan.md)
|
||
- 2026-06-04 | docs | wiki | **Konzept: Solution-Schicht (Customer Workflows) + Pling-Use-Case**: Architektur-Idee fuer generische L3/L4-Solution-Schicht ueber dem Workflow-Stack (Use Case → konfigurierter Workflow, kein Kunden-Code). Pling «Kaffee-Klatsch» Monatsreporting als staerkstes Validierungsbeispiel eingearbeitet (Multi-Instanz-Fan-out, rollenbasierte Verteilung). Plus generische Product-Summary und klickbares HTML-Mockup im ui-nyla-Look. (c-work: c-work/0-ideas/2026-06-CustomerCases-step1-architecture.md, 2026-06-CustomerCases-step2-communication-product-summary.md, 2026-06-CustomerCases-step2-communication-mockup.html)
|
||
- 2026-06-04 | docs | wiki | **Plan: Umsystem-Integration (Connectors + Workflows + Datenquellen-Seiten)**: Arbeitsdokument fuer generische Umsystem-Anbindung (SelectLine→RMA als Pilot). Trennung generische Bausteine (Connectors/kanonische Modelle/Workflow-Nodes) vs. kundenspezifische Logik (Workflow-Graph + Config). UI-Muster «Datenquelle = Seite» pro Kategorie (Buchhaltung existiert, Saläre als Idee). (c-work: c-work/1-plan/2026-06-umsystem-integration-connectors-und-datenquellen-seiten.md)
|
||
|
||
## 2026-06-03
|
||
|
||
- 2026-06-03 | fix | platform-core | **Image MIME-Type Pre-Validation in Extraction Pipeline**: Unsupported Bild-Formate (image/bmp, image/tiff, image/x-icon etc.) werden jetzt VOR dem Failover-Loop erkannt und uebersprungen. Magic-Bytes-Sniffing korrigiert falsche MIME-Types. Verhindert 6000+ Error-Storm bei EML-Verarbeitung (vorher: jedes unsupported Bild x 10+ Models = 30+ API-Errors). Safety-Net auch in aicorePluginAnthropic.
|
||
- 2026-06-03 | fix | platform-core | **App Shutdown: ResilientHttp Sessions + EventManager Tasks**: `closeAllResilientHttp()` schliesst alle shared aiohttp-Sessions beim Shutdown. `EventManager.shutdown()` cancelt pending Cleanup-Tasks. Behebt 30s+ Shutdown-Hang.
|
||
- 2026-06-03 | fix | ui-nyla | **Data-Source Chip UUID-Fix**: Race Condition in WorkspaceInput behoben -- `refreshDataSources()` gibt jetzt Promise zurueck, `_handleDataSourceDrop` wartet darauf bevor `pendingAttachDsId` gesetzt wird. Lokaler Label-Cache als Fallback. Verhindert UUID-Anzeige in Chips.
|
||
- 2026-06-03 | fix | platform-core | **Model Selector: totalTokens statt promptTokens**: Filter in `aicoreModelSelector.py` prueft jetzt `totalTokens` (prompt+context) statt nur `promptTokens` gegen 80%-Limit. Verhindert Auswahl von Modellen mit zu kleinem Context-Window bei grossen Dokumenten.
|
||
- 2026-06-03 | fix | platform-core | **simpleMode an Chunking-Pipeline angebunden**: `process.py` simpleMode nutzt jetzt `_resolve_file_refs_to_content_parts` / `_action_docs_to_content_parts` statt roher Bytes-Konkatenation. Dokumente fliessen durch die existierende Extraction+Chunking-Pipeline, oversized Prompts (4M+ Tokens) werden vermieden.
|
||
- 2026-06-03 | fix | platform-core | **Image-Element-Normalisierung**: `_normalizeImageElement` in `subStructureFilling.py` stellt sicher, dass AI-generierte Image-Elemente immer das `content`-Dict-Format haben. Behebt Crash in rendererMarkdown wenn AI flache Keys liefert.
|
||
- 2026-06-03 | fix | platform-core | **Pre-Flight Guard in callWithTextContext**: Defense-in-depth in `interfaceAiObjects.py` -- lehnt Payloads ab die >95% des besten Modell-Context-Windows ueberschreiten, bevor die Failover-Schleife startet.
|
||
- 2026-06-03 | fix | platform-core | **PPTX Tabellen-Positionierung**: `_renderSlideContentWithFrames` in rendererPptx.py umgebaut auf sequenzielles Y-Tracking. Textboxen werden mit geschaetzter Hoehe statt full-height erstellt, Tabellen und Code-Blocks erhalten explizite `top`-Positionen. Behebt Bug wo Tabellen unterhalb des sichtbaren Slide-Bereichs erschienen.
|
||
- 2026-06-03 | feat | platform-core | **HTTP Resilience Mixin fuer Connectors**: Neues `_httpResilience.py` mit `ResilientHttp`-Klasse (Shared aiohttp.ClientSession, asyncio.Semaphore, Retry mit Backoff bei 429/502/503/504, Retry-After Header). Integriert in Google, MSFT und Infomaniak Connectors. Eliminiert 429-Storms durch Concurrency-Limit (Google 8, MSFT 10, Infomaniak 6).
|
||
- 2026-06-03 | feat | platform-core | **Sandbox readFileBytes + SafeZipFile**: `sandboxExecutor.py` erweitert um `readFileBytes(fileId)` Builtin (rohe Bytes, 50MB-Limit) und `SafeZipFile` Wrapper (read-only, in-memory, kein extract/write). Ermoeglicht ZIP/XLSX/DOCX-Strukturanalyse im Agent-Sandbox ohne Dateisystem-Zugriff.
|
||
- 2026-06-03 | refactor | platform-core | **Style-System Overhaul: THEME_PRESETS + documentTheme entfernt, AI-Enhancement aktiviert**: `THEME_PRESETS`, `resolveTheme()` und `documentTheme`-Parameter end-to-end entfernt (styleDefaults, mainServiceGeneration, _mediaTools, methodAi, generateDocument, documentPath, mainServiceAi, mainTrustee). Statische Presets ersetzt durch AI-getriebene Style-Enhancement (`_enhanceStyleWithAi` in mainServiceGeneration); DEFAULT_STYLE auf Cursor/VS-Code-Aesthetik modernisiert (Calibri, GitHub-Farben, subtile Rahmen). Dead Code aus allen 5 Renderern entfernt (_getStyleSet, _enhanceStylesWithAI, _getDefaultStyleSet, _validateStylesContrast etc.). (c-work: c-work/4-done/2026-06-style-system-overhaul-smart-tables.md)
|
||
- 2026-06-03 | fix | platform-core | **Style-Chain-Luecken geschlossen**: AI-Enhancement-Prompt bekommt jetzt das vollstaendige Style-Set (~920 Bytes) statt nur fonts/colors/table (3 von 12 Sektionen). `_convertUnifiedStyleToInternal` erweitert um page, image, table font sizes, borderWidth, codeBlock.borderColor, coverPage, caption, table_banding, table_padding, fonts, colors. Fallback-Farben an DEFAULT_STYLE angeglichen (#1F3864->#24292e, lineSpacing 1.15->1.5). Heading-Key-Mismatch in XLSX/PPTX behoben (heading->heading{level}); DOCX h3/h4 Styles registriert.
|
||
- 2026-06-03 | feat | platform-core | **Smart Table Styling**: Per-Table Style-Overrides via `content.tableStyle` im JSON-Block (deep-merge mit globalem Table-Style). Neue Style-Keys: `borderStyle` (grid/horizontal/none), `bandingEnabled` (Toggle), `cellPaddingPt`. Automatische Spaltenausrichtung (`_inferColumnAlignments`: Zahlen rechts, Daten zentriert, Text links) oder explizit via `columnAlignments`. Neue Schema-Sektionen `coverPage` und `caption` in DEFAULT_STYLE. Alle 5 Renderer (PDF/DOCX/PPTX/XLSX/HTML) implementieren borderStyle-Varianten, banding-Toggle und columnAlignments.
|
||
- 2026-06-03 | refactor | platform-core | **HTML-Renderer Legacy-Pfad entfernt**: `_getStyleSet`, `_getDefaultStyleSet` und zugehoerige Legacy-AI-Styling-Logik aus rendererHtml.py entfernt. Nur noch der Unified-Style-Pfad ueber `_convertUnifiedStyleToInternal` + `_generateCssFromUnifiedStyle` ist aktiv.
|
||
- 2026-06-03 | docs | wiki | **Kanonische Referenzseite Dokumenten-Rendering**: Neue `b-reference/platform-core/document-rendering.md` dokumentiert die vollstaendige Style-Resolution-Pipeline (DEFAULT_STYLE -> Agent-Overrides -> AI-Enhancement -> Per-Element-Overrides), Table-Rendering-Modell, Renderer-Architektur, Font-Resolution, AI-Style-Enhancement-Prompt. TOPICS.md ergaenzt. ADR- und PO-Cleanup-Docs nachgefuehrt.
|
||
- 2026-06-03 | refactor | * | **Scope von DataSource entfernt (Datenschutz)**: Scope-Flag, -Icon und -Funktionalitaet komplett aus der UDB (Sources-Tab) entfernt — persoenliche Datenquellen duerfen nicht gescoped werden. DB-Spalte `DataSource.scope` bleibt als deprecated, wird nicht mehr gelesen/geschrieben. UDB-Backend (`udbNodes.py`, `_inheritFlags.py`, `routeUdb.py`), Frontend (`UdbSourcesProvider.tsx`), Ingest (`subConnectorIngestConsumer.py`), Auth (`routeDataSources.py`) bereinigt. Scope existiert nur noch bei Files (folder-files). Wiki (`unified-data-bar.md`) aktualisiert. Tests angepasst.
|
||
|
||
## 2026-06-02
|
||
|
||
- 2026-06-02 | fix | service-llm-private | **Private-LLM-Pricing byte-basiert statt Pauschale**: `aicorePluginPrivateLlm` rechnete Text/Vision/Reasoning pauschal pro Call ab (CHF 0.01/0.10/0.05, `costPer1kTokens=0`, Bytes ignoriert) -> faktisch fast gratis. Neu byte-/tokenbasiert via `_calcPrivatePriceCHF` mit `PRICE_INPUT_PER_1K=0.0075` / `PRICE_OUTPUT_PER_1K=0.0375`; `costPer1kTokens` der bepreisten Modelle entsprechend gesetzt. Embedding via `_calcPrivateEmbedPriceCHF` (`PRICE_EMBED_PER_1K=0.0005`, nur Input) statt gratis. Hintergrund: Depoformance-Angebot (privates CH-Modell muss teurer sein als oeffentliche Modelle).
|
||
- 2026-06-02 | feat | platform-core | **Grossdokument: Lazy File-Ref-Bilder (A3/AC15, Schritt 1)**: Block-Bilder koennen jetzt nur eine `fileId` tragen; `renderReport(imageResolver=fileId->bytes)` setzt einen Per-Render-Resolver am Renderer (`BaseRenderer._lazyResolveImageBase64`), den PDF/DOCX `_renderJsonImage` on-demand nutzen. `renderDocument`-Tool haelt fuer pdf/docx Bilder als Referenz (kein base64 mehr im JSON) und uebergibt den Resolver; HTML/Inline/uebrige Formate unveraendert (rueckwaertskompatibel). DOCX bekommt damit echten Ein-Bild-Speicher (python-docx kopiert Bytes sofort ins Package); PDF vermeidet base64-Overhead/JSON-Retention (voll-streamendes PDF via Temp-File-Bilder bleibt als Schritt 2). Tests: tests/serviceGeneration/test_large_document_render.py. (c-work: c-work/1-plan/2026-06-po-cleanup-neutralization-docgen.md)
|
||
- 2026-06-02 | feat | platform-core | **documentTheme end-to-end + Preset-Bibliothek (A3)**: `styleDefaults.py` bekommt `THEME_PRESETS` (general/finance/legal/technical/hr/marketing) + `resolveTheme`; `resolveStyle(style, documentTheme)` mergt `DEFAULT_STYLE <- Preset <- explizites style` (explizit gewinnt). `documentTheme` ist jetzt durchverkabelt: `ai.generateDocument` Action -> `callAiContent` -> `_handleDocumentGeneration` -> `documentPath.generateDocument` -> `renderResult` -> `renderReport(documentTheme=...)`; ausserdem im `renderDocument`-Tool (neues `documentTheme`-Schema-Property) und in `methodAi.py` (Param an `ai.generateDocument`, Optionen um `marketing` ergaenzt). Reconciliation mit ADR 2026-04 (Presets als agent-ueberschreibbare Defaults, kein Hard-Mandate). Tests in tests/serviceGeneration/test_style_resolver.py. **Offen:** Grossdokument-Pfad (File-Ref-Bilder + Chunked-Render, AC15) — Entscheidung/Scope siehe Plan. (c-work: c-work/1-plan/2026-06-po-cleanup-neutralization-docgen.md)
|
||
- 2026-06-02 | feat | platform-core | **Typ-/vererbungsbewusste Feld-Neutralisierung (A2)**: `FeatureDataProvider` neutralisiert Quelldaten jetzt regelbasiert via `finalizeRowsAsync`/`_neutralizeAndSerializeRows`: Strings substring-neutralisiert wenn effektiv (explizit ODER geerbt, Feldname als Typ-Hint, async+dedupe ueber die lokale Engine), Binary gedroppt, andere Skalare nur bei explizitem Feld-Flag; IDs/System-Spalten ausgenommen, Engine-Ausfall = [REDACTED]. Policy aus `_featureSubAgentTools` via `resolveEffectiveForFds`; RAG-Bootstrap (`subFeatureBootstrap`) nutzt dieselbe Policy (Query-/Index-Paritaet). Unit-Tests in tests/unit/serviceAgent/test_field_neutralization.py (c-work: c-work/1-plan/2026-06-po-cleanup-neutralization-docgen.md)
|
||
- 2026-06-02 | feat | * | **Sichere De-Neutralisierung fuer Download (revealDocument)**: Neuer read-only Agent-Tool `revealDocument` loest Platzhalter [typ.uuid] ausschliesslich ueber das private lokale Mapping (resolveText, kein externes LLM) auf und liefert den Klartext als transienten Einmal-Download via SSE-SideEvent `revealDownload`; Klartext wird NICHT gespeichert, indexiert oder in der Chat-Historie abgelegt (persistiertes ToolResult enthaelt nur eine Bestaetigung). Toter `_rehydrateResponse` (nie aufgerufen) aus serviceAi entfernt und callAi/callAiStream-Docstrings korrigiert (keine Rueck-Hydration in Speicher). UI: sseClient + useWorkspace onRevealDownload (base64->Blob->Download->revoke) (c-work: c-work/1-plan/2026-06-po-cleanup-neutralization-docgen.md)
|
||
- 2026-06-02 | refactor | * | **Chatbot-Feature komplett entfernt**: Backend (features/chatbot, methodChatbot, Routen, Interfaces, RBAC-Namespaces, datamodelChat WORKFLOW_CHATBOT, DB-/Script-Referenzen) und UI (chatbotApi, useChatbot, views/chatbot, ChatbotConfigSection, Routing, FeatureView, pageRegistry, Stores/Hooks/DEBUG-Logs) entfernt (c-work: c-work/1-plan/2026-06-po-cleanup-neutralization-docgen.md)
|
||
- 2026-06-02 | refactor | platform-core | **LangChain/LangGraph entfernt**: ChatStreamingHelper (langchain_core) geloescht; BZO-Extraktion (realEstate) von LangGraph-StateGraph auf direkte sequentielle Funktionsaufrufe migriert (bzoExtractionLangGraph.py -> bzoExtraction.py); langchain/langchain-core/langgraph/langchain-tavily/nest-asyncio aus requirements.txt entfernt (requirements.lock muss via pip-compile neu generiert werden)
|
||
- 2026-06-02 | docs | wiki | **Chatbot/LangGraph aus aktiver Doku entfernt**: README, product.md, b-reference (architecture/workflow/diagrams/database), e-compliance/security-overview, a-strategy/roadmap nachgefuehrt (z-archive unveraendert)
|
||
- 2026-06-02 | feat | platform-core | **Agent data-source search-first guidance**: Sharpened searchDataSource/browseDataSource tool descriptions (per-service query syntax, anti mass-download) and added a search-first rule to buildDataSourceContext so the agent queries server-side instead of downloading whole sources
|
||
- 2026-06-02 | fix | platform-core | **SharePoint/OneDrive/Drive search scoping + pagination**: SharePoint and OneDrive search now scope to the attached folder and follow @odata.nextLink; OneDrive browse paginates; Google Drive search uses fullText contains (name+content) with pageToken pagination and URL-encoded queries
|
||
- 2026-06-02 | feat | platform-core | **Outlook mail metadata + date filter**: browse/search expose sender+date inline in the agent tool, browse supports a date-range filter via Graph $filter, and search scopes to the attached folder
|
||
- 2026-06-02 | fix | platform-core | **Gmail search metadata + label scoping**: search returns real Subject/From/Date (was 'Message {id}'), scopes to the attached label, and resolves message metadata concurrently to cut the sequential N+1
|
||
- 2026-06-02 | feat | platform-core | **Google Calendar date-range fetch**: browse/search use timeMin/timeMax when a date range is given, avoiding full multi-year event listings
|
||
- 2026-06-02 | feat | platform-core | **Contacts metadata inline (MSFT/Google/Infomaniak)**: agent tool shows email/phone/company per contact so vCards are only downloaded when the full record is needed
|
||
- 2026-06-02 | feat | platform-core | **ClickUp task metadata inline**: agent tool shows status/assignee/due-date per task instead of requiring a JSON download
|
||
- 2026-06-02 | feat | platform-core | **Infomaniak Calendar date filter**: events honour an agent-supplied date range (clamped to the vendor <3 month limit) instead of a fixed 90-day window
|
||
|
||
## 2026-05-31
|
||
|
||
- 2026-05-31 | fix | ui-nyla | **UDB Sources panel compact**: Reduced tree indent from 24px to 16px, shrunk compact row height to 28px, smaller chevrons/icons/action buttons in compact mode for better label visibility
|
||
- 2026-05-31 | fix | ui-nyla | **Mobile FormGeneratorTable/Controls**: Controls stay horizontal (row wrap) on mobile instead of going vertical, reduced padding/gap/font-size on mobile for table cells and pagination
|
||
- 2026-05-31 | fix | ui-nyla | **Chat DataSource attach sends DataSource ID**: SourcesTab now resolves DataSource UUID via ensureDataSourceId before attaching (was incorrectly sending connectionId)
|
||
- 2026-05-31 | fix | platform-core | **TEXT to VECTOR schema migration**: Added auto-migration for TEXT->VECTOR columns in PostgreSQL connector, fixing broken semantic search on databases created before pgvector was declared
|
||
- 2026-05-31 | fix | platform-core | **ChatDocument DB fallback**: getChatDocumentsFromDocumentList now queries ChatDocument table directly when in-memory workflow lookup fails, preventing orphaned document references
|
||
- 2026-05-31 | fix | platform-core | **Table section string content normalization**: subStructureFilling validates table elements after AI JSON parse; string content (CSV/markdown/pipe) is parsed into {headers, rows} instead of crashing rendererMarkdown
|
||
|
||
## 2026-05-30
|
||
|
||
- 2026-05-30 | docs | wiki | **Depoformance Property Match — Backend ueber PORTA (Idee)**: 0-ideas-Dokument, das die Backend-Wuensche aus ihrer Techdoku (Kap. 11) in PORTA-Faehigkeiten uebersetzt statt Schlagworte woertlich zu nehmen. Mapping: 18 Provider-Interfaces -> generische RBAC-CRUD-Schicht; OpenRouter-Proxy -> unser AI-Gateway (serviceAi, kein OpenRouter); JWT-Felder -> PORTA Auth+RBAC (organizationId=mandateId); offene Punkte (Realtime/Upload/Mail/i18n/CI-CD) -> bereits PORTA-Plattformfunktionen; Security-Gate weitgehend abgedeckt. Keine Neutralisierung, CH-Residenz. Architektur: dedizierter Partner-Router (`/api/v1/depoformance/*`), der ihre Endpunkte durchschleift. Pricing: einmalig CHF 24'000 + API-Grundgebuehr CHF 600/Mo (inkl. 100k Calls) + AI pay-as-you-go. (c-work: 0-ideas/2026-05-depoformance-api-integration.md)
|
||
|
||
## 2026-05-29
|
||
|
||
- 2026-05-29 | docs | wiki | **Repo-Namen auf git.poweron.swiss/PowerOn migriert**: Wiki-weit alte Repo-/Pfad-Namen ersetzt (`frontend_nyla`/`frontend-nyla`→`ui-nyla`, `gateway`→`platform-core`, `private-llm`→`service-llm-private`). b-reference-Ordner umbenannt (gateway/ui-nyla/service-llm-private), README+product Komponenten-Tabellen aktualisiert, `service-preprocessing` ergaenzt, Changelog-Scope-Legende angepasst. Konzeptionelle Prosa-Begriffe (Gateway, Private-LLM) und z-archive/Changelog-Historie bewusst belassen.
|
||
- 2026-05-29 | feat | platform-core | **Anthropic Claude Opus 4.8 hinzugefuegt**: `aicorePluginAnthropic.py` um Opus 4.8 (`claude-opus-4-8`) erweitert -- Basic- + Vision-Variante, 1M Context, 128K max output, gleiche Preise wie 4.7 ($5/$25 pro M Tokens). `_supportsCustomTemperature` erkennt 4.8 als Extended-Thinking-Modell (sendet kein `temperature`).
|
||
- 2026-05-29 | feat | platform-core | **Private-LLM Next-Gen Modelle vorbereitet**: `aicorePluginPrivateLlm.py` um 3 neue Modell-Definitionen erweitert (deepseek-r1:70b Reasoning, llama4:scout Vision, nomic-embed-text Embedding). Werden automatisch aktiv wenn in Ollama verfuegbar -- kein Impact auf laufenden Betrieb.
|
||
- 2026-05-29 | feat | private-llm | **Config fuer GPU-Migration vorbereitet**: `config.py` Next-Gen MODEL_MAPPING als kommentierter Block, `_isVisionModel` um llama4/scout erweitert.
|
||
- 2026-05-29 | docs | wiki | **Private-LLM Architektur-Seite aktualisiert**: Migrations-Plan Infomaniak→FireStorm, geplante Modelle, Kostenvergleich dokumentiert.
|
||
- 2026-05-29 | feat | ui-nyla | **SourcesTab sendToChat fuer Mobile**: Chat-Icon (💬) im Sources-Tab reaktiviert -- `onSendToChat_FeatureSource` und `onAttachDataSource` an FormGeneratorTree durchgereicht. Mobile-User koennen nun Source-Objekte per Tap in den Chat senden.
|
||
- 2026-05-29 | fix | infra | **Gateway Workers auf 2 erhoeht** (prod+int): Single-Worker-Bottleneck behoben -- RAG-Indexierung blockierte User-Requests nicht mehr.
|
||
|
||
## 2026-05-28
|
||
|
||
- 2026-05-28 | fix | platform-core | **RAG ragLimits Vererbung**: `ragLimits` (z.B. `maxBytes`) auf der Connection-Root-DataSource (path `/`) wurden nicht an Kind-DataSources vererbt -- Walker fielen immer auf den 200 MB Default zurueck. Fix: `_loadRagEnabledDataSources` propagiert `settings.ragLimits` vom Connection-Root auf Kinder ohne eigene Werte. `_finalizeResult` in allen 4 Walkern (SharePoint, GDrive, kDrive, ClickUp) zeigt nun effektive Limits statt hartkodierter Defaults.
|
||
- 2026-05-28 | feat | platform-core+ui-nyla | **DB Migration Streaming Import**: Import grosser JSON-Dateien (>1 GB) lief bisher komplett im RAM (`json.load()`), was OOM verursachte. Neuer Two-Pass-Ansatz mit `ijson` fuer speicher-effizientes Parsen: Pass 1 validiert + extrahiert Metadaten, Pass 2 splittet in per-Table JSONL-Dateien. Neuer `GET /process-import-stream` Endpoint mit `StreamingResponse` (ndjson) fuer Echtzeit-Fortschritt waehrend Validierung und Split. Frontend zeigt dynamischen Progress (Phase, DB, Tabelle, Datensatzzahl).
|
||
- 2026-05-28 | feat | platform-core+ui-nyla | **DB Migration Streaming Export**: Export lief bisher client-seitig (`JSON.stringify`) und schlug bei grossen DBs fehl (`RangeError: Invalid string length`). Neuer `GET /export-stream` Endpoint streamt die gesamte Export-JSON inkrementell via `StreamingResponse`. Frontend nutzt `fetch()` + `ReadableStream` + File System Access API fuer direktes Streaming-to-Disk. Fortschrittslog zeigt aktuelle DB x/n mit MB-Angabe.
|
||
- 2026-05-28 | fix | private-llm+infra | **LLM-Server Recovery**: Ollama-Modelle (`qwen2.5:7b`, `qwen2.5vl:7b`, `granite3.2-vision`) auf Infomaniak GPU-Server neu installiert (waren nach Instanz-Neustart verloren). NVIDIA-Treiber-Mismatch per Reboot behoben. pgvector Extension auf prod+int DB-Servern installiert (OS-Package + CREATE EXTENSION). Doku aktualisiert: `setupserver.md`, `README.md`, `infrastructure.md` (DB-Setup-Anleitung fuer neue Installationen).
|
||
|
||
## 2026-05-27
|
||
|
||
- 2026-05-27 | fix | platform-core | UDB DS Auto-Create: Virtuelle DataSource-Nodes (Browse-Folder ohne DB-Record) auf eigener Connection koennen jetzt getoggelt werden. `canEdit` prueft Connection-Ownership via `UserConnection.userId`; `setFlag` erstellt automatisch einen DataSource-Stub-Record analog zu `_findOrCreateTableFds`. Behebt 403-Errors beim Toggling von Browse-Foldern. 4 neue Tests (`test_udbNodes.py`).
|
||
- 2026-05-27 | refactor | platform-core | UDB neutralizeFields-Handling von generischer Infrastruktur in polymorphe Node-Klassen verschoben: `_inheritFlags.cascadeResetDescendantsFds` ist wieder rein generisch (keine `neutralizeFields`-Logik); `_FdsFamilyNode.setFlag` bietet generischen `_onSetFlag`-Hook; `FdsTableNode._onSetFlag` wipe-t eigene `neutralizeFields` bei explizitem neutralize-Toggle; `FdsWorkspaceNode._onSetFlag` wipe-t `neutralizeFields` auf allen Descendant-Tables. `FdsFieldNode.getEffectiveFlag` erbt korrekt vom Table (Zwei-Quellen-Modell). 122/122 Tests gruen. Wiki `unified-data-bar.md` (Cascade-Reset-Abschnitt) aktualisiert.
|
||
|
||
## 2026-05-26
|
||
|
||
- 2026-05-26 | fix | gateway+frontend-nyla | UDB Toggle Spec Recovery: virtuelle Coordinates nutzen neu aggregate-Pfad (mixed moeglich ohne DB-Record); sechs redundante Aggregatoren + Parallel-Endpoint tree/attributes + Frontend refreshAttributes-Pfad entfernt; eine Pipeline, ein Resolver, immer refetch nach Toggle (Spec 2026-05-18 wiederhergestellt) (c-work: 3-validate/2026-05-udb-toggle-spec-recovery.md)
|
||
|
||
## 2026-05-24
|
||
|
||
- 2026-05-24 | docs | infra | **Deployment-Infrastruktur Doku** -- Neue kanonische Seite `b-reference/platform/infrastructure.md`: Infomaniak-Projektstruktur (Porta, LLM, Teamsbot), Naming Convention (`{bereich}-{env}-{komponente}`), VM-Instanzenliste, Deploy-Patterns. TOPICS.md ergaenzt.
|
||
|
||
## 2026-05-23
|
||
|
||
- 2026-05-23 | refactor | platform-core+ui-nyla+wiki | UDB Polymorphic Refactor: neue `UdbNode`-Klassenhierarchie (`udbNodes.py`), generischer Router `routeUdb.py` mit `POST /api/udb/tree/children` + `POST /api/udb/node/{key}/flag/{flag}`, Hart-Cut der 4 PATCH-Routen + altem `/api/workspace/{id}/tree/children`. FDS-Schema entschlackt (kein `userId`, kein `workspaceInstanceId`, kein `scope` mehr — feature-owned, RBAC-gated via `roleLabel.endswith('-admin')`). Neue kanonische Doku `b-reference/platform/unified-data-bar.md`; Updates auf `neutralization.md`, `rbac.md`, `TOPICS.md`. Tests: neu `test_udbNodes.py`, angepasst `test_buildTree.py` + `test_inheritFlags.py` + `UdbSourcesProvider.test.ts` (alle gruen) (c-work: 3-validate/2026-05-udb-polymorphic-refactor.md)
|
||
- 2026-05-23 | feat | gateway+frontend | DB Migration Progress: Export und Import laufen per-DB sequentiell mit Echtzeit-Fortschrittslog (Timestamp, DB-Name, Tabellen-/Datensatzzahl, Fehler); neuer export-single Endpoint; Import via prepare-import + import-single (server-seitiger Payload-Cache mit Token); Export-Dateiname enthaelt Instanzlabel + full/partial (z.B. db_backup_main_full_2026-05-23T06-20-54.json)
|
||
- 2026-05-23 | feat | gateway+frontend-nyla | **DB Migration Backup/Restore** — Neuer Tab "Migration" auf der Datenbank-Gesundheit-Seite (SysAdmin). Backup: dynamische DB-Auswahl via Registry, Export als JSON. Restore: JSON-Upload, Validierung, Import mit Modus "Neu" (replace) oder "Zusammenfuehren" (merge). System-Objekte (Root-Mandant, Admin-User, Event-User) werden nie geloescht; ihre IDs werden beim Import automatisch auf die Live-IDs remapped. Neue Dateien: `databaseMigration.py`, 4 API-Endpoints unter `/api/admin/database-health/migration/`, MigrationTab in `AdminDatabaseHealthPage.tsx`.
|
||
|
||
## 2026-05-22
|
||
|
||
- 2026-05-22 | fix | frontend-nyla | **UDB FormGeneratorTree: RAG-Icon + Mixed-Symbol nach Merge-Konflikt-Verlust restauriert** — In Commit `9488a7d` ("build errors") wurden bei einer Merge-Auflösung die RAG-Konstanten (`_RAG_ON_EMOJI` 🧠, `_RAG_OFF_EMOJI`), `_MIXED_SYMBOL` (◩), `_OFF_STATE_STYLE` sowie der RAG-Button-JSX-Block und die Mixed-/Spinner-Branches in Scope/Neutralize entfernt. Surgical Restore: alle Stellen wieder eingebaut, Idas Neutralize-On/Off-Emoji-Distinction und `hideRowActionButtons`/`dragDropEnabled`-Refactor beibehalten. Auch verlorenes Auto-Expand-`useEffect` für `defaultExpanded` Nodes wiederhergestellt (Test grün: 53/53).
|
||
- 2026-05-22 | refactor | gateway+frontend-nyla | **RAG Cost-Estimate Währung USD→CHF** — `_costEstimate.estimateBootstrapCost()` liefert nun `estimatedChf` (statt `estimatedUsd`); Konstante `EMBEDDING_CHF_PER_MTOKEN` (Wert 0.02, Projekt-Konvention: Anbieter-Listenpreise werden direkt als CHF behandelt, identisch zu `calculatepriceCHF` in `aicorePluginOpenai.py`). Mit-aktualisiert: `routeDataSources.py` Docstring, `test_costEstimate.py` (6/6 grün), FE `CostEstimate`-Type, `DataSourceSettingsModal` Anzeige. Wiki: `b-reference/gateway/ai-agent.md` Endpoint-Doku, `TOPICS.md`, `c-work/2-build` + `4-done/2026-05-udb-datasource-settings.md`.
|
||
|
||
## 2026-05-19
|
||
|
||
- 2026-05-19 | fix | gateway | RAG Inventory /mandate: ImportError UserMandate behoben (war in datamodelUam statt datamodelMembership); refactored zu getUserMandatesByMandate(); RBAC membership-Check hinzugefuegt (verhindert Zugriff auf fremde Mandate via X-Mandate-Id)
|
||
- 2026-05-19 | fix | gateway+frontend | RAG Inventory Mandate-Dropdown: neuer Endpunkt GET /api/rag/inventory/my-mandates liefert nur Mandate mit aktiver Mitgliedschaft; Frontend nutzt diesen statt /api/mandates/ (admin-only Route)
|
||
- 2026-05-19 | feat | gateway+frontend | RAG Inventory Feature-Daten: featureInstances-Array mit Datei-/Chunk-Zaehler, Status-Breakdown (indexed/pending/failed), FeatureDataSource-Details mit ragIndexEnabled-Flag, RAG-Aktiv-Indikator; Frontend zeigt Sync-Status-Banner, Datenquellen pro Instanz, RAG-Hinweis wenn inaktiv; leere Instanzen werden ausgefiltert
|
||
- 2026-05-19 | feat | gateway+frontend | Feature-Daten RAG-Sync: neuer Background-Job-Handler feature.bootstrap (subFeatureBootstrap.py) indexiert FeatureDataSource-Tabellendaten via FeatureDataProvider+requestIngestion; Handler-Registrierung in registerKnowledgeIngestionConsumer; neuer Endpoint POST /api/rag/inventory/reindex-feature/{workspaceInstanceId} mit FeatureAccess-Check; _buildFeatureInstanceInventory liefert runningJobs/lastSuccess/lastError; Frontend: Job-basierte Sync-Status-Banner + Reindex-Button fuer Feature-Instanzen (analog zu Connection-Sync)
|
||
- 2026-05-19 | fix | gateway | FeatureDataProvider: alle DB-Zugriffe (getActualColumns, browseTable, aggregateTable, queryTable, _resolveInstanceColumn) von deprecated db.connection.cursor() auf db.borrowCursor() migriert (Pool-API-Kompatibilitaet nach Pooling-Refactoring)
|
||
- 2026-05-19 | fix | gateway | Trustee Budget-Vergleich: _exportAccountingData liefert neu eine accountSummary (1 Zeile/Konto mit closingBalance + Q1-Q4) statt 5590 rohe Balance-Records (26/Konto); AI-Prompt praezisiert Datenquelle; reduziert Payload von 355KB auf 25KB und verhindert Faktor-100-Abweichungen durch versehentliches Summieren
|
||
- 2026-05-19 | fix | frontend-nyla+gateway | **RAG-Inventar Mandate-Scope 403 + SQL-Fehler** — Zwei Bugs: (1) Frontend sendete `mandateId` als Query-Parameter statt `X-Mandate-Id`-Header → `context.mandateId=None` → 403. Fix: Header wird gesetzt. (2) Backend `routeRagInventory._getInventoryMandate` filterte `UserConnection` mit `recordFilter={"mandateId": ...}`, aber `UserConnection` hat kein `mandateId`-Feld → SQL-Error. Fix: Mandate-Members via `UserMandate`-Junction holen, dann deren `getUserConnections(userId)` aggregieren.
|
||
- 2026-05-19 | refactor | gateway+frontend-nyla | **UDB Toggle Refresh: Visible-IDs Pattern** -- After a toggle, FE sends all visible node IDs in one POST request; backend returns correct attribute values (incl. mixed) for exactly those IDs. No full-tree reload, no optimistic updates. New endpoints: `POST /api/files/attributes` (FilesTab) and `POST /api/workspace/{id}/tree/attributes` (SourcesTab). `TreeNodeProvider.refreshAttributes(ids)` added to interface. Collapse now removes children from FE state (always fresh on re-expand). Removed `_enrichFoldersWithMixed` and `_refetchAllExpanded`.
|
||
|
||
## 2026-05-18
|
||
|
||
- 2026-05-18 | feat | gateway+frontend | UDB Resolve Endpoint: neuer POST /datasources/resolve-flags Bulk-Endpoint liefert effective-Werte (neutralize, scope, ragIndexEnabled) fuer beliebige Pfade auch ohne eigenen DB-Record; Frontend entfernt client-seitige Vererbungslogik (_findCoveringDs), nutzt ausschliesslich Backend-Daten via resolvedFlags Map
|
||
- 2026-05-18 | fix+feat | gateway+frontend-nyla | **UDB Sources Recovery -- Zweite Smoke-Test-Runde (H1-H10)** (`c-work/3-validate/2026-05-udb-sources-recovery.md`). (H1) Logik-Audit aller drei Flags zusammengefasst: `'mixed'` ist Backend-Aggregate-Anzeige, niemals persistiert; FE-Handler mappen `'mixed'` immer auf konkreten Wert (`'personal'`/`false`); Cascade-PATCH setzt alle Nachkommen auf `NULL` und dann den Master, deshalb kann aggregate nach einem User-Toggle nicht `'mixed'` bleiben. (H2/H8) Initial-Render-Bug: sequentieller `for ... await` im Auto-Expand-Effekt loeste Cancellation-Race aus -- erstes `setNodes` triggerte cleanup, weitere defaultExpanded-Knoten blieben "expanded ohne Children". Fix: `Promise.all(...)` parallel + atomares Single-`setNodes`. Zusaetzlich `autoExpandedRef.current.clear()` in `_loadRoot` (StrictMode-Doppelmount + manuelle Refresh tauglich). (H3) `PUT /api/files/{id}` 404: Route hatte keinen `RequestContext`, `interfaceDbManagement.getInterface(currentUser)` ohne mandate/featureInstance scope -> RBAC-Filter excludiert File. Fix: Context-Dep + scope-pass-through bei `update_file` und `delete_file`; `move_folder` akzeptiert sowohl `parentId` als auch `targetParentId` aus dem Body. (H4) Neuer Folder erschien initial auf Legacy-Top-Level: `FolderFileProvider.createChild(parentId=null, ...)` setzt jetzt `parentId = _SYNTH_ROOT_ID('own')` damit der neue Folder unter `/` rendert. (H5) `+`-Button pro Folder im FormGeneratorTree: neue `onCreateChild?: (parentId: string) => void`-Prop in TreeNodeRow + verdrahtetem `_createFolderAt(parentId)` Handler in der Hauptkomponente; sichtbar im Hover-Action-Slot fuer alle Folders mit `provider.createChild` && `provider.canCreate(id)`. (H6) FilesTab neutralize partly broken: Diagnose plausibel mit H2-Fix erledigt (Optimistic-Update verfehlte Knoten, deren Children durch das Cancellation-Race nicht im FE-State waren). (H7) Hardcoded `[Persoenliche Quellen]`: Source-String hatte `oe`-Encoding, `t()` returned key fuer DE -> sichtbar mit fake-Umlaut. Fix: `resolveTextSafe("Persoenliche Quellen")` -> `resolveTextSafe("Persönliche Quellen")` (echter Umlaut). (H9) FDS-Neutralize ging nicht: `POST /api/workspace/{instanceId}/feature-datasources` 403te Cross-Mandate-Erstellung (Workspace mandate A, Feature mandate B beides user-zugaenglich), `_ensureRecord` schluckte den Fehler still. Fix: Cross-Mandate-Block entfernt, statt dessen `getFeatureAccess(userId, body.featureInstanceId)`-Validierung; `mandateId` der neuen FDS = `wsMandateId` (= Workspace-Tenancy, konsistent mit Tree-Filter). (H10 = G5) Persistenter Expand-State umgesetzt: `WorkspaceUserSettings.uiTreeExpansion: Dict[str, List[str]]` Backend-Field; neue Routen `GET/PUT /api/workspace/{instanceId}/ui-tree-expansion/{scope}`; FE-Hook `useTreeExpansion(instanceId, scope)` mit 600 ms Debounce-PUT; `FormGeneratorTree` Props `expandedIds?: string[] | null` + `onExpandedIdsChange?: (ids) => void` (controlled mode); `SourcesTab` (scope `'sources'`), `FilesTab` (scopes `'filesOwn'` + `'filesShared'`) verdrahtet. Bei `null` (kein Record) Default-Verhalten + erster Toggle erstellt den Settings-Record; bei Array gewinnt persistierte Liste ueber Backend-`defaultExpanded`-Hints. Tests: Backend `services+routes` 107/107 gruen, Frontend UDB+FormGen 69/69 gruen.
|
||
- 2026-05-18 | fix+feat | gateway+frontend-nyla | **UDB Sources Recovery -- Smoke-Test-Followups (G1-G5)** (`c-work/3-validate/2026-05-udb-sources-recovery.md`). (G1) `tsconfig.json` referenziert jetzt auch `tsconfig.test.json`; Testfile bekam expliziten `import React`, `afterEach`, `@testing-library/jest-dom/vitest`. 139 -> 0 Lints; Tests 50/50 weiterhin gruen. (G2) Off-State der `neutralize`/`ragIndexEnabled`-Buttons: `filter: grayscale(1); opacity: .45` im OFF-Zustand -- offenes Schloss + greyed-Brain klar als "deaktiviert" lesbar. (G3a) Bug `_browseChildren`: Childs erbten `parentKey=ds|...|/` statt des aufgerufenen `svc|...`; Children erschienen daher nie im FE-Tree. Fix: `parentKey` als optionaler Parameter durchgereicht; Dispatcher uebergibt den asked-for-Key. (G3b) Per-Field-Neutralize fuer Feature-Tabellen: `fdsTable.hasChildren=True` bei vorhandener `meta.fields`-Liste; neuer Knoten-Typ `fdsField` (Dispatcher `fdstbl|fi|table` -> `_featureTableFields`). Effektiver Field-Neutralize = `parent.neutralize OR field IN parent.neutralizeFields`. Toggle: `UdbSourcesProvider.patchNeutralize` splittet die Batch nach Kind und ruft fuer fdsField `PATCH /api/datasources/{id}/neutralize-fields` mit der mutierten Liste; `neutralizeFields` ist im Tree-Payload mitgesendet -- kein Extra-GET. Scope/RAG auf Feldebene bewusst nicht editierbar. +3 neue Backend-Tests in `TestFeatureTableFields`. (G4) FilesTab synthetischer "/"-Root pro Ownership: Provider mappt `parentId=null` auf `[__filesRoot:<own|shared>]` (`defaultExpanded=true`); reale Top-Level-Items werden Children. `moveNodes` mit Synth-Root-Ziel re-mapt auf `parentId/folderId=null` (= Drop auf "/"); `patchScope`/`patchNeutralize` mit Synth-Root-Id materialisieren ueber API alle Top-Level-Folders+Files und setzen pro Folder `cascadeChildren=true` -- globaler Toggle ohne Backend-Aenderung. Tests: Backend 19/19 gruen, Frontend UDB+FormGen 69/69 gruen.
|
||
- 2026-05-18 | refactor | gateway+frontend-nyla | **UDB Sources Recovery -- Folge-UX-Iteration** (`c-work/3-validate/2026-05-udb-sources-recovery.md`). Auf das User-Feedback nach Phase 1-3: (a) **Visual cascade fuer `neutralize` und `ragIndexEnabled`** wieder klar erkennbar -- vorher *gleiches Symbol* fuer on/off (nur Opacity), Cascade unsichtbar. Distinct emojis: `_NEUTRALIZE_ON_EMOJI=closed lock` / `_NEUTRALIZE_OFF_EMOJI=open lock`, `_RAG_ON_EMOJI=brain` / `_RAG_OFF_EMOJI=thought-bubble`. Backend-Cascade war korrekt (parametrisch in `cascadeResetDescendants(rec, flag)`); rein UI-Issue. (b) **Top-Level-Layout flach**: synthetische Wrapper `srcRoot` + `mandateRoot` entfernt. `_topLevel` emittiert direkt `[personalRoot, mgrp|m1, mgrp|m2, ...]`. Mandate-Groups haben nun `parentKey=None`. (c) **`TreeNode.defaultExpanded?: boolean`** als generisches Tree-Feature (one-shot pro Node-Id ueber `autoExpandedRef`); BE markiert `personalRoot` und alle Mandate-Groups mit `defaultExpanded=True` -- UI oeffnet bis zur Datenquellen-Ebene ohne User-Klick. (d) **Icon-Reihenfolge** in `FormGeneratorTree` (rechtsbuendig, von rechts nach links): neutralize, scope, sendToChat, rag, settings. Settings (`extraActions`) jetzt linksbuendig. (e) **Settings-Icon nur auf Daten-Quellen-Root** (`kind in {connection, featureNode}`), aber dort *immer* sichtbar, auch ohne `dataSourceId`; Klick triggert lazy `_ensureRecord` -> `onOpenSettings`. (f) **`SourcesTab`** setzt `title={t('Datenquellen')}` als Section-Header. Tests: Backend `test_buildTree.py` 16/16 + `test_inheritFlags.py` 72/72 -> 88/88 gruen. Frontend `FormGeneratorTree.test.tsx` 50/50 (+`defaultExpanded`-Tests) + `UdbSourcesProvider.test.ts` 16/16 (+settings-on-root + defaultExpanded-passthrough). TypeScript clean.
|
||
- 2026-05-18 | refactor | gateway+frontend-nyla | **UDB Sources Recovery: SourcesTab nutzt FormGeneratorTree** (`c-work/3-validate/2026-05-udb-sources-recovery.md`). Behebt das Folge-Problem aus dem Generic-Tree-Refactor vom selben Tag, dass der Sources-Tab nur "Lade Datenquellen..." zeigte, weil der ad-hoc `_TreeNodeView`-Renderer in `SourcesTab.tsx` an einem State-Race (StrictMode-Doppelmount × `mountedRef`-Frueh-Abort × paralleler `expansionSignature`-useEffect, vier sichtbare POSTs) erstickte. Diagnose via temporaerem `_buildTree.getChildrenForParents`-INFO-Log: Backend liefert sauber `counts={'__root__': 6}` -- Bug war ausschliesslich auf der ad-hoc-Renderer-Seite. **Backend** (`_buildTree.py`): synthetische Container `srcRoot` (Top-Level), `personalRoot`, `mandateRoot` mit neuem `_syntheticNode` Helper und `displayOrder`-Sort-Hint; `_topLevel` schrumpft auf `[srcRoot]`, `_srcRootChildren` emittiert `[personalRoot, mandateRoot]`, `_personalRootChildren` und `_mandateRootChildren` enthalten die alte Connections-/Mandate-Logik mit korrigierten `parentKey`. Dispatcher in `getChildrenForParents` matcht `parentKey == _KEY_*_ROOT` vor dem Decode-Pfad. +7 neue `TestSyntheticRoots` Tests, Service-Suite 89/89 gruen. **FormGeneratorTree** (generisch erweitert, kein UDB-Vokabular): `TreeNode.ragIndexEnabled?: boolean | 'mixed'`, `TreeNode.displayOrder?: number`, `TreeNodeProvider.patchRagIndex?` + `canPatchRagIndex?`, `FormGeneratorTreeProps.refreshAfterAction?: boolean`. Sort-Comparator setzt `displayOrder` vor folder-first. Dritter Flag-Button (`_RAG_EMOJI`, `_ACTION_RAG`) rendert nur wenn `ragIndexEnabled !== undefined`. `_runAction` ruft `_refetchAllExpanded` automatisch auf wenn `refreshAfterAction=true`; optimistic-Update-Pfad fuer FilesTab unveraendert. +10 neue Tests, Tree-Suite 51/51 gruen. **Frontend SourcesTab**: ad-hoc-Renderer mit `_TreeNodeView`, `_FlagButton`, eigenem `pendingToggles`-State, eigenem `_fetchVisible`-Pfad komplett geloescht. Neuer `UdbSourcesProvider.tsx` mappt Backend-`UdbBackendNode` auf generischen `TreeNode<T>` (Synthese-Container ohne Flag-Felder); haelt internen `nodeCache: Map<key, UdbBackendNode>` fuer Patch-Pfade; `_ensureRecord` POSTet `/datasources` oder `/feature-datasources` je nach `kind`; danach PATCH `/api/datasources/{id}/{scope|neutralize|rag-index}`. Neue `SourcesTab.tsx` ist 75 LOC duenner Wrapper: `useMemo` Provider + `<FormGeneratorTree compact selectable={false} allowCreateFolder={false} refreshAfterAction />` + Settings-Modal-Anbindung ueber `extraActions`. +14 neue Provider-Tests, Tree+Provider-Suite 65/65 gruen.
|
||
- 2026-05-18 | fix | gateway | PostgreSQL `recordCreate`/`_save_record`: Zeichenketten-Parameter mit eingebetteten NUL-Bytes (`\\x00`) werden vor dem Bind gestriped — behebt `ingestion.failed` / `ContentChunk`-Insert (psycopg2: „A string literal cannot contain NUL“), z. B. bei indexierten `.sql`/Dump-Dateien.
|
||
- 2026-05-18 | refactor | gateway+frontend-nyla | **UDB Generic Tree Refactor: Backend autoritativ, FE pure Renderer, RAG fuer FDS** (`c-work/4-done/2026-05-udb-generic-tree-refactor.md`). Schliesst die ueber mehrere Iterationen verschleppte UI-Inkonsistenz, dass Toggles unter bestimmten Bedingungen keinen UI-Effekt hatten. Root-Cause: parallele Logik im Frontend (`_resolveFdsFlags`, optimistic Updates, `_findCoveringDs`) widersprach den vom Backend gelieferten Werten. **Architektur**: Ein einziger Endpoint `POST /api/workspace/{instanceId}/tree/children` mit Body `{parents: [null, ...expandedKeys]}` liefert `nodesByParent` als flachen Map mit allen drei `effective*`-Werten (`neutralize`, `scope`, `ragIndexEnabled` als `boolean|'mixed'` bzw. `string|'mixed'`) pre-computed auf der `mode='aggregate'`-Ebene. Neuer Orchestrator `serviceKnowledge/_buildTree.py` mit stabilem Key-Format (`conn|<id>`, `svc|<connId>|<service>`, `ds|<connId>|<sourceType>|<path>`, `mgrp|<mid>`, `feat|<mid>|<code>|<fiId>`, `fdstbl|<fiId>|<table>`) — preloadet DS+FDS einmal pro Request und dispatched pro Parent-Kind an Connector/Catalog/RBAC. Sourcetype-Mapping (`sharepoint -> sharepointFolder` etc.) ist nun Backend-autoritativ. **FE-Refactor**: `SourcesTab.tsx` von ~2500 auf ~530 Zeilen reduziert. State nur noch `childrenByParent: Map`, `expandedKeys: Set`, `pendingToggles: Set`. Toggle-Flow strikt PATCH -> Refetch -> Render mit Spinner ueber dem Flag-Button bis API-Response zurueck ist. Generischer `_TreeNodeView` rekursiv fuer ALLE Kinds, generischer `_FlagButton` mit einheitlichem Mixed-Symbol (`U+25E9`, "square with diagonal lines") fuer alle drei Flags. **RAG fuer FDS**: `_INHERITABLE_FDS_FLAGS` enthaelt nun `ragIndexEnabled`; `FeatureDataSource.ragIndexEnabled: Optional[bool]` Field (Auto-Migration via `ALTER TABLE ADD COLUMN`); `PATCH /api/datasources/{id}/rag-index` akzeptiert via `_findSourceRecord` sowohl DS als auch FDS (Bootstrap-Job + Chunk-Purge bleiben DS-only); `GET /feature-datasources` liefert `effectiveRagIndexEnabled`; `resolveEffectiveForFds` um den dritten Wert ergaenzt. **Geloescht** (keine Konsumenten mehr): `POST /datasources/resolve-flags` + 3 Models, `GET /connections`, `GET /connections/{id}/services`, `GET /connections/{id}/browse`, `GET /feature-connections`, `GET /feature-connections/{fiId}/tables`, `GET /feature-connections/{fiId}/parent-objects/{tableName}`, totes `SourcesTab.module.css`. **Bewusste Reduzierung** (User-Entscheidung): FDS-Records sind nicht mehr expandierbar (`hasChildren: false` fuer `fdsTable`); Tabellen-Ebene reicht. `FeatureDataSource.recordFilter` bleibt fuer API-Kompat erhalten. **Tests**: neu `test_buildTree.py` (10 gruen — Key-Coding, Effective-Triplets, Record-Lookup, Orchestrator-Smoke), +5 neue in `test_inheritFlags.py::TestResolveEffectiveForFds` (RAG inherits, RAG aggregate-mixed, `_INHERITABLE_FDS_FLAGS` enthaelt RAG) +1 in `TestCascadeResetFdsRag`. Resultat: 82/82 gruen; Frontend `npx tsc --noEmit` clean.
|
||
- 2026-05-18 | feat | gateway+frontend-nyla | **UDB Toggle-Semantik v2: 'mixed'-Aggregation + bottom-up cascade + Backend-autoritative effective values** — Grundlegendes Redesign der Toggle-Semantik (neutralize, scope, ragIndexEnabled) für DataSource und FeatureDataSource. (1) Backend: `getEffectiveFlag` und `getEffectiveFlagFds` mit `mode='walk'|'aggregate'` — walk gibt immer konkret, aggregate gibt 'mixed' wenn Subtree divergiert. (2) `cascadeResetDescendants`/`Fds` jetzt bottom-up (deepest-first) für Crash-Sicherheit, Rückgabe `List[str]` statt `int`. (3) GET /datasources und /feature-datasources liefern computed `effectiveNeutralize`, `effectiveScope`, `effectiveRagIndexEnabled` pro Item. (4) PATCH-Response enthält `resetDescendantIds` + `updatedAncestors` für optimistic UI. (5) Bug-Fixes B1-B6: routeDataConnections consent-re-enable RAG, routeRagInventory reindex+inventory, routeDataSources settings-RBAC, _dataSourceTools download neutralize, _featureSubAgentTools FDS neutralize cascade — alle auf `getEffectiveFlag(mode='walk')` umgestellt. (6) Frontend: Workarounds entfernt (`_effectiveFlag`, `_findAncestorDs`, `_AUTHORITY_SOURCE_TYPES`, prop-drilling `inheritedScope/Neutralize`), zentrale `_readDsFlags`/`_readFdsFlags` aus Backend-Werten, Toggle-Handler mit optimistic cascade via `resetDescendantIds`. (7) 'mixed'-Icon-Darstellung im UI.
|
||
- 2026-05-18 | chore | gateway | RAG-Walker und `requestIngestion`: per-item Lognois reduziert — `subWalkerHelpers` (`walker.item.start`, `walker.download.start`, `walker.extract.start`) und `ingestion.skipped.duplicate` von INFO auf DEBUG, damit Daily-Resync / wiederholtes Durchlaufen nicht das App-Log flutet; Stuck-Triage via DEBUG auf `modules.serviceCenter.services.serviceKnowledge.subWalkerHelpers` bzw. `mainServiceKnowledge`.
|
||
- 2026-05-18 | fix | gateway+frontend-nyla | **UDB Cascade-Inherit Bugfix: Connection-Root Toggle hatte keinen UI-Effekt** — User-Report: "no change in UI, whatever icon I press". Log-Analyse zeigte: jeder Toggle macht POST `/datasources` (Backend gibt via Upsert die bereits existierende ID zurück) gefolgt von PATCH (Backend updated korrekt), aber UI bleibt unverändert. **Root-Cause 1**: Die ConnectionRoot-DataSource (`sourceType='msft'`/`'google'`/`'clickup'`/`'infomaniak'`/`'local'`, `path='/'`) wurde im Frontend von `_findDs` ignoriert (`if (node.type === 'connection') return undefined`) — Workaround aus dem Vortag, der eine andere Race-Condition verhindern sollte. Folge: `ds === undefined` für Connection-Nodes → `_addAsDataSource`-POST → Backend Upsert findet bestehenden DS via `connectionId+path`-Match und returnt dieselbe ID → PATCH erfolgreich → UI rendert aber weiter mit `ds=undefined` → opacity bleibt 0.35. **Fix 1**: `_findDs` matcht jetzt deterministisch via `sourceType`: für Connection-Nodes `node.authority` ('msft'/'google'/…), für Service-Nodes `_SERVICE_TO_SOURCE_TYPE[node.service]` ('sharepointFolder'/…). Zwei DS mit `connectionId+path='/'` aber unterschiedlichem `sourceType` (Connection-Root vs Service-Root) sind dadurch eindeutig unterscheidbar. **Root-Cause 2**: Cross-Authority-Vererbung fehlte komplett. User-Erwartung: Toggle auf Connection-Root muss alle Service-Children (SharePoint, OneDrive, Outlook unter derselben msft-Connection) visuell mitziehen. Backend `getEffectiveFlag` und `cascadeResetDescendants` filterten aber strikt auf `sourceType==parentSourceType`, also keine Vererbung über die Authority-Grenze hinweg. **Fix 2**: Neue Konstante `_AUTHORITY_SOURCE_TYPES = {'local','google','msft','clickup','infomaniak'}` in `_inheritFlags.py` und Mirror im Frontend. `_findAncestorChain` ergänzt um den ConnectionRoot als "äusseren" Ancestor (after all same-sourceType ancestors). `cascadeResetDescendants` cascadiert bei `parentIsConnectionRoot=True` über die GANZE Connection (cross-sourceType). Frontend `_findAncestorDs` analog. **Tests**: 23/23 grün (4 neue für Cross-Authority: `test_connection_root_inherits_cross_sourcetype`, `test_same_sourcetype_ancestor_wins_over_connection_root`, `test_connection_root_does_not_self_inherit`, `test_connection_root_cascades_cross_sourcetype`). Frontend `npm run build` + `tsc --noEmit` grün.
|
||
- 2026-05-18 | feat | gateway+frontend-nyla | **UDB Cascade-Inherit für DataSource-Flags (`neutralize`, `ragIndexEnabled`, `scope`)** — Plan: `c-work/1-plan/2026-05-udb-cascade-inherit.md`. Schliesst die Konsistenz-Lücke, dass Toggles an einem Parent nicht nach unten propagieren konnten, sobald ein Descendant einen eigenen DataSource-Record hatte. Beispiel-Bug: SharePoint=true → Folder1=false (explizit) → SharePoint=true (zweites Toggle) → Folder1 blieb auf false statt mit dem Parent zu folgen. **Architektur**: 3-wertige Felder mit `NULL = inherit`, expliziter `True/False` (oder `'personal'/'mandate'/'platform'/'global'` für scope). **Backend**: (1) Datenmodell `DataSource.{neutralize,ragIndexEnabled,scope}` und `FeatureDataSource.{neutralize,scope}` auf `Optional[...]` umgestellt; Migration `script_db_migrate_datasource_inherit.py` macht Spalten nullable (idempotent, additiv — bestehende Werte bleiben explizit, NEW records starten mit NULL). (2) Neuer zentraler Helper `serviceKnowledge/_inheritFlags.py` mit `getEffectiveFlag(rec, flag, allDs)` (path-traversal aufwärts, longest-prefix wins, defensiv `connectionId` UND `sourceType` als Filter), `cascadeResetDescendants(rootIf, parentRec, flag)` (setzt nur das EINE Flag der explizit-belegten Descendants auf NULL, andere Flags unangetastet) und `_isAncestorPath` (`/` ist Ancestor von allem; `/foo` NICHT von `/foobar` — `/`-Separator-Pflicht). (3) PATCH-Endpoints `routeDataSources.{_updateDataSourceScope,_updateDataSourceNeutralize,_updateDataSourceRagIndex}` akzeptieren `Optional[bool|str]` als Body-Wert: `null` → reset auf inherit (kein Cascade); `true/false` → explizit + Cascade-Reset aller Descendants. RAG-Endpoint zusätzlich: nur bei `True` Mini-Bootstrap-Job + `_ensureConnectionKnowledgeFlag`; nur bei `False` synchrone Chunk-Purge — `null` no-op. Audit-Log `rag_index_toggled` trägt `cascadedDescendants` Count. (4) Walker-Integration: `_loadRagEnabledDataSources` filtert auf **effective** ragIndexEnabled (via `getEffectiveFlag`) und schreibt resolved Werte für `neutralize/scope` direkt in das returned dict — Walker (Sharepoint/Outlook/Gdrive/Gmail/Clickup/Kdrive) bleiben unverändert und lesen weiter `ds.get("neutralize", False)`. Alter `subPolicyResolver.py` zu Backward-Compat-Shim auf `getEffectiveFlag` deprecated. **Frontend**: `UdbDataSource` Interface mit `boolean|null` und `string|null`; neue Helper `_findAncestorDs` + `_effectiveFlag` (path-traversal analog zu Backend); Toggle-Handler senden `!currentEffective` (= aktuell sichtbarer Wert wird invertiert), Backend macht den Cascade. Local State: optimistisch + `_fetchDataSources()` nach PATCH damit cascade-resettete Descendants aus DB neu geladen werden. Alte unbenutzte `_togglePersonalNeutralize/_togglePersonalRagIndex/_cyclePersonalScope` entfernt. **Tests**: neuer `test_inheritFlags.py` mit 19 grün — explicit-wins, ancestor-traversal, default-fallback, sourceType-Isolation, connectionId-Isolation, `/foo` ≠ Ancestor von `/foobar`, root-is-ancestor-of-everything, scope-string-default, cascade-touches-only-target-flag, cascade-skips-other-sourcetypes. Bestehende `test_knowledge_ingest_consumer.py` 8/8 grün. Frontend `npm run build` grün, TypeScript clean. **Pre-existing Test-Failures** (nicht durch diesen PR): `test_p1d_consent_prefs.py` (5) — Python-3.13 asyncio-Deprecation + Schema-Drift `ConnectionIngestionPrefs.neutralizeBeforeEmbed`; `test_bootstrap_sharepoint.py` + `test_bootstrap_gmail.py` (5) — rufen `bootstrapSharepoint/Gmail` ohne `dataSources=` auf, was seit dem 2026-04 Unified-Indexing-PR den Early-Return triggert.
|
||
|
||
## 2026-05-17
|
||
|
||
- 2026-05-17 | fix | frontend-nyla | **UDB Settings-Modal: RAG-Limits nur auf DataSource-Root** — Settings-Icon (⚙️) bleibt auf allen Nodes sichtbar, aber RAG-Limits- und Kostenschätzungs-Sektionen werden nur noch auf DataSource-Root-Nodes (Level 2 = `service`) angezeigt. Subelemente (Folder/File) können weiterhin die Connection-Settings sehen, erben aber die Walker-Limits vom Root. Neue Modal-Prop `showRagSection`. Neutralisierung/RAG-Toggle: Vererbungslogik ist korrekt (Parent aktiviert → Kinder werden mitgezogen, volle Opacity). Kein visueller Unterschied nötig — das ist gewolltes Verhalten.
|
||
- 2026-05-17 | feat | gateway+frontend-nyla | **i18n für BackgroundJob-Progress-Messages (Backend-translated)** — User-Report: RAG-Page zeigte "145 Dateien verarbeitet, 106 indexiert" auch bei UI-Sprache=`en`, weil walker das Plaintext-Deutsch direkt in `BackgroundJob.progressMessage` schrieben und das Frontend es 1:1 rendert. Root-Cause: BackgroundWorker hat keinen Request-Sprach-Kontext (`_CURRENT_LANGUAGE` ist ContextVar pro Request), und `progressMessage` wird persistiert — wäre selbst dann gefroren, wenn der User später die Sprache wechselt. **Architektur (regelkonform zu `wiki/b-reference/gateway/architecture.md#i18n`):** Backend speichert strukturiert + übersetzt server-side beim Route-Read; Frontend rendert 1:1 — kein `t()` auf Backend-Werten. (1) Neue JSONB-Spalte `BackgroundJob.progressMessageData = {key, params}` (Migration `script_db_migrate_backgroundjob_progress_data.py`, additiv + idempotent). (2) `JobProgressCallback.__call__` akzeptiert `messageKey="LITERAL"` + `messageParams={…}` und schreibt beides als JSON; zusätzlich rendert es einen DE-Fallback in `progressMessage` für Logs/Audit/Legacy-Clients. (3) Alle Walker (6 RAG + `subConnectorIngestConsumer` + Trustee push/sync/import + `accountingDataSync._progress`) umgestellt — `messageKey=` ist immer ein String-Literal. (4) Key-Registrierung über string-literale `t("…")` Calls: neues `serviceKnowledge/_progressMessages.py` (Side-Effect-Import in `app.py` lifespan, 5 RAG-Keys), Trustee 14 Keys in `mainTrustee.py` — KEINE Variable-Aufrufe von `t()` (Wiki-Regel #1: `t(variable)` ist verboten). (5) Neuer Helper `i18nRegistry.resolveJobMessage(messageData)` analog zu `resolveText(value)` — der einzige zulässige `t(variable)`-Pfad, weil er in der i18n-Infrastruktur lebt; nutzt `_CURRENT_LANGUAGE` aus dem Request-Kontext und substituiert Params via `.format(**params)`. (6) `routeJobs._serialiseJob` und `routeRagInventory` rufen `resolveJobMessage` beim Read und schreiben das Ergebnis in `progressMessage` — Frontend bekommt einen fertigen, übersetzten String. (7) Frontend zurückgebaut: `utils/jobProgressUtils.ts` Helper **gelöscht**, DTOs (`useBackgroundJob`, `connectionApi`, `trusteeApi`) ohne `progressMessageData`-Feld, Render-Stellen (`RagInventoryPage`, `RagRunningBadge`, `TrusteeAccountingSettingsView`) lesen direkt `job.progressMessage`. Tests: 22/26 grün; die 4 Failures in `test_knowledge_ingest_consumer.py` sind pre-existing (verifiziert via `git stash` Diff). Frontend `npm run build` grün. Smoke: `resolveJobMessage({'key': '{n} Dateien verarbeitet, {indexed} indexiert', 'params': {'n': 145, 'indexed': 106}})` → `'145 Dateien verarbeitet, 106 indexiert'`. Wiki: neuer Abschnitt "BackgroundJob-Progress-Messages" in `b-reference/gateway/architecture.md` mit den 4 Schritten (Walker → Registrierung → Route-Resolve → Frontend-Render).
|
||
- 2026-05-17 | feat | gateway+frontend-nyla | **UDB DataSource Settings (⚙️) + konfigurierbare RAG-Limits** (Plan & Build: `c-work/2-build/2026-05-udb-datasource-settings.md`). Schliesst zwei Lücken: (1) RAG-Walker-Limits (`maxBytes=200 MB` etc.) waren hartkodiert — User mit 500-MB-Folder konnte nur Code-Änderung machen; (2) FeatureDataSource hatte gar keinen Settings-Ort. **Backend**: JSONB-Spalte `settings` auf `DataSource` + `FeatureDataSource` (Migration `script_db_migrate_datasource_settings.py`, additiv + idempotent). Neues Modul `serviceKnowledge/_ragLimits.py` mit `FILES_LIMITS_DEFAULT` / `CLICKUP_LIMITS_DEFAULT` als zentrale Source-of-Truth — die alten `MAX_*_DEFAULT`-Konstanten in den 4 Walkern (`subConnectorSyncSharepoint/Kdrive/Gdrive/Clickup.py`) sind nur noch Aliase. Kritische Semantik: `getStoredOverrides(ds, kind)` liefert NUR explizit gesetzte Overrides → Walker mergen sie auf den **caller-supplied** `limits=`-Parameter, damit Test-/Caller-Overrides weiter gewinnen (`test_bootstrap_maxTasks_caps_ingestion=3` bleibt grün); `getRagLimits(ds, kind)` mergt auf Defaults → API/Cost-Estimate-Pfad. **Keine Override-Schicht, keine Resolver-Logik** — was im Modal steht, ist exakt was der Walker liest. Zwei neue Endpunkte in `routeDataSources.py`: `PATCH /api/datasources/{id}/settings` (akzeptiert nur Top-Level-Key `ragLimits`, unknown → 400, positive Ints only, Owner-only/Mandate-Admin, Audit-Log `datasource_settings_changed`) und `GET /api/datasources/{id}/cost-estimate` (indikative USD-Schätzung via `_costEstimate.py`-Heuristik: `text-embedding-3-small @ $0.02/1M Token`, `BYTES_PER_TOKEN=4`, `EXTRACTABLE_FRACTION=0.4`; Antwort trägt vollständiges `basis`-Objekt mit Annahmen/Formel/Notes). **Frontend**: Neues ⚙️-Icon pro Node im `UnifiedDataBar/SourcesTab.tsx` (vor dem 🧠) öffnet den neuen `DataSourceSettingsModal.tsx` mit drei klar abgegrenzten Sektionen: (1) **Connection** — `knowledgeIngestionEnabled`-Toggle via `patchKnowledgeConsent` (mit Confirm-Dialog beim Deaktivieren); (2) **RAG-Limits** — Felder editierbar, Bytes in MB im UI; (3) **Kostenschätzung** — refresh nach Save. Dasselbe Modal wird auf der `RagInventoryPage.tsx` vom amber Partial-Banner (`stoppedAtLimit`) via neuen "Limit anpassen"-Button geöffnet → User hat direkten Pfad vom Symptom zur Behebung. Workspace-Route `GET /api/workspace/{instanceId}/connections` liefert jetzt `knowledgeIngestionEnabled` mit, damit der Modal-Initial-Toggle korrekt vorbelegt. **Tests**: 12 neue Unit-Tests in `tests/unit/services/test_ragLimits.py` + 6 in `test_costEstimate.py` (Defaults-Isolation, partial-override, non-int dropped, doubling-formula, basis-shape) — alle grün; bestehende Bootstrap-Tests für Sharepoint/Kdrive/Gdrive/ClickUp weiter grün (caller-limits-Override respektiert). Frontend `npm run build` grün, keine neuen Lint-Errors. Doku: `b-reference/gateway/ai-agent.md` (Abschnitt "Konfigurierbare RAG-Limits"), `TOPICS.md` (neuer Eintrag). Verbleibende Hard-Limits in `subConnectorSyncOutlook/Gmail.py` haben aktuell kein UI-Override, bleiben aber als next-step (gleicher Helper anwendbar).
|
||
- 2026-05-17 | feat | frontend-nyla+gateway | **Knowledge-Consent Toggle auf ConnectionsPage + Forward-Sync DataSource→Connection.** Zwei Lücken in der RAG-Consent-UX geschlossen, die zu der Beobachtung "valueon hat Index aktiviert, aber Checkbox fehlt" geführt haben: (1) Die ConnectionsPage zeigte `knowledgeIngestionEnabled` nur als generische "Ja/Nein"-Spalte der FormGeneratorTable — kein Toggle-Element. Neu: zwei CustomActions (`FaToggleOn`/`FaToggleOff`, je nach State sichtbar via `visible`-Filter), Klick ruft `patchKnowledgeConsent` → `/api/connections/{id}/knowledge-consent` und refetcht die Liste. Damit ist die UI 1:1 konsistent mit dem Master-Switch auf der RagInventoryPage (gleiches Backend-Endpoint, gleiches Icon, gleicher Confirm-Dialog beim Deaktivieren). (2) Backend: `routeDataSources._updateDataSourceRagIndex` propagierte bisher nicht auf die Parent-Connection. Neuer Helper `_ensureConnectionKnowledgeFlag(rootIf, connectionId)` setzt **forward-only** `UserConnection.knowledgeIngestionEnabled=True`, sobald min. eine DataSource auf `ragIndexEnabled=true` toggelt — kein Auto-Disable, weil der Master-Switch dem User gehört (verhindert versehentliches Zurücksetzen eines explizit gegebenen Consents, z.B. einer Connection ohne aktive DataSource, aber mit `knowledgePreferences`). Plan-Doc für die UDB-Settings-Erweiterung (Issue 2): `c-work/1-plan/2026-05-udb-datasource-settings.md`. Der Fix für Limit-Transparenz wirkte UI-seitig nicht, weil `_bootstrapJobHandler` in `subConnectorIngestConsumer.py` die Sub-Service-Results in ein wrappendes Dict packt (`{"authority", "connectionId", "sharepoint": {...}, "outlook": {...}}` für msft; analog für `drive`/`gmail`/`clickup`/`kdrive`). `routeRagInventory._buildConnectionInventory` griff aber auf Top-Level `result.stoppedAtLimit`/`indexed`/etc. zu — alle `None`. Folge: amber Banner blieb aus UND die Statistik-Zeile zeigte gar keine Zahlen ("Sync erfolgreich" ohne "— 25 unverändert"). Neuer `_flattenJobResult()`-Helper aggregiert über alle bekannten Sub-Keys (sum für counters, max für durationMs, erstes Limit-Hit für `stoppedAtLimit`/`limits`). Verifiziert anhand Job `2374aecd-3e17-460a-a13e-530f9f1115e6`: `bytesProcessed=209894527` ≥ `maxBytes=209715200`, jetzt korrekt als `stoppedAtLimit="maxBytes"` an die UI durchgereicht. Diagnose-Skript `gateway/scripts/debug_rag_job_result.py` zeigt vor/nach-Flatten und bleibt für künftige Bootstrap-Result-Debugging im Repo.
|
||
- 2026-05-17 | feat | gateway+frontend-nyla | **RAG-Inventar: echte Chunks + Limit-Transparenz.** Drei Probleme behoben: (1) `routeRagInventory._buildConnectionInventory` zählte bisher `len(FileContentIndex)` (= indizierte Dateien) und labelte das im UI als "Chunks" — bei einer 99-Seiten-PDF erscheint dort statt der echten ~99 Chunks die Zahl 1. Neue `interfaceDbKnowledge.countChunksByFileIds()` macht eine einzige Aggregat-SQL `SELECT "fileId", COUNT(*) FROM "ContentChunk" WHERE "fileId" = ANY(%s) GROUP BY "fileId"` (kein Vector-Body geladen), die Response trägt jetzt `fileCount` UND `chunkCount` pro DataSource + `totalFiles/totalChunks` pro Connection. (2) `RagInventoryPage.tsx` / `connectionApi.ts` zeigen beide Werte getrennt ("25 Dateien · 1240 Chunks") mit Tooltip-Definition für Chunks (~400 Tokens). (3) **Limit-Transparenz**: SharePoint/kDrive/gDrive-Bootstrap stoppen bei den ersten Limits (`MAX_BYTES_DEFAULT=200 MB`, `MAX_ITEMS_DEFAULT=500`, `MAX_DEPTH_DEFAULT=4`, `MAX_FILE_SIZE_DEFAULT=25 MB`); ClickUp analog (`MAX_TASKS_DEFAULT=500`, `MAX_WORKSPACES_DEFAULT=3`, `MAX_LISTS_PER_WORKSPACE_DEFAULT=20`). Bisher: `return` ohne Log + ohne Marker im Bootstrap-Result → User sah "Sync erfolgreich" obwohl 706 Dateien fehlten. Fix: neuer `_recordLimitStop()`-Helper in allen 4 Connectoren setzt `BootstrapResult.stoppedAtLimit` (1. exhausted Budget), schreibt 1 WARNING in den Log und liefert das Feld + die effektiven `limits` im `_finalizeResult` Dict an `BackgroundJob.result`. `routeRagInventory` reicht `lastSuccess.stoppedAtLimit/limits/bytesProcessed` ans Frontend durch. Neuer amber `partialBanner` auf der RagInventoryPage warnt mit "Limit maxBytes=200 MB (200 MB verarbeitet) erreicht — Weitere Dateien wurden NICHT indexiert" und bietet "Erneut indexieren". Verifiziert anhand `local/logs/log_app_20260517.log`: SharePoint-Sync hat genau bei `bytesProcessed=209_894_527 ≥ MAX_BYTES_DEFAULT (209_715_200)` gestoppt (Kumulative Summe der 25 indizierten Dateigrößen = 200.17 MB). ClickUp hat bei `skippedDup=500 >= maxTasks=500` gestoppt. Outlook/Gmail brauchen das gleiche Pattern noch (haben aktuell keine harten Limits im Code, daher kein Bug, aber wenn welche kommen → gleicher Helper).
|
||
- 2026-05-17 | fix | gateway | **Secrets Decryption TTL-Cache** (`gateway/modules/shared/configuration.py`): `decryptValue()` cached jetzt erfolgreich entschlüsselte Plaintexts process-wide für 60 s (Key = Ciphertext, thread-safe, `clearDecryptionCache()` für Rotation/Tests). Root-Cause aus S7-Smoke-Test (`local/logs/log_app_20260517.log:609`): RAG-Inventory-Polling + paralleler Walker-Burst triggerte für `system`/`DB_PASSWORD_SECRET` >10 Decrypts/s, das Brute-Force-Schutz-Rate-Limit warf `ValueError: Decryption rate limit exceeded` → `routeRagInventory._getInventoryPlatform` HTTP 500. Hot-Path war `mainBackgroundJobService._getDb()`, das pro Call `APP_CONFIG.get("DB_PASSWORD_SECRET")` evaluiert (eager arg eval), bevor `getCachedConnector` überhaupt seinen Wrapper-Cache prüfen kann. Cache-Hit umgeht das Rate-Limit (kein neuer Krypto-Op, nur Re-Read eines bereits autorisierten Plaintexts); Cache-Miss konsumiert weiter Rate-Budget — die Schutzfunktion gegen wiederholt falsche Decrypts bleibt damit erhalten. Wirkt global für alle `_SECRET`-Reader (`auditLogger`, `routeI18n`, alle Feature-Interfaces), nicht nur für den BackgroundJobService.
|
||
- 2026-05-17 | refactor | gateway | PostgreSQL Connection Pool — Steps S3–S6 abgeschlossen (`c-work/2-build/2026-05-postgres-connection-pool.md`). **S3**: `getCachedConnector` Docstring präzisiert (Cache = Wrapper-Recycling + DB-Init-Spam-Schutz, Pool = echte Connection-Verwaltung). **S4**: Shutdown-Hook `closeAllPools()` in `gateway/app.py` lifespan als letzter Schritt nach Feature-`onStop`-Hooks. **S5**: Neuer Test-File `gateway/tests/unit/connectors/test_connectorDbPostgre_pool.py` mit 6 Concurrency-Tests gegen live-Postgres (auto-skip wenn keine DB erreichbar): 50 Threads × 20 Reads (0 Errors), 20 Threads × 50 Reads (p99 < 5 s), interleaved load/save, `statement_timeout=500ms` triggert `QueryCanceled` und gibt Connection sauber zurück, Pool-Identity pro (host, db, port), `closeAllPools` leert Registry. Beim ersten Lauf entdeckt: psycopg2-Pool wirft `PoolError` sofort bei Exhaustion statt zu blockieren → `borrowConn()` um bounded Wait-Retry erweitert (`_BORROW_WAIT_TIMEOUT_S=30s`, `_BORROW_WAIT_BACKOFF_S=50ms`). Alter `test_connectorDbPostgre_failLoud.py` auf das neue `borrowConn`-Mocking umgestellt (alle 6 weiter grün). **S6**: Regression-Run: 639/656 unit grün (vorher 638) — der eine durch den Refactor verursachte Fail (`test_folder_crud._FakeDb` brauchte `borrowCursor`-Stub) gefixt, die übrigen 17 Failures sind pre-existing RAG/Adapter/Workflow-Drift ohne Pool-Bezug. 76/79 integration grün (3 pre-existing Trustee-Workflow-Fails). Backward-Compat-Stub `borrowCursor` auch in `test_folderRbac._FakeDb` ergänzt. Offen: **S7** (manueller 1 h Smoke-Test, Anleitung in der Plan-Doc) und **S8** (`b-reference/platform/database-architecture.md`).
|
||
- 2026-05-17 | refactor | gateway | **CORE**: PostgreSQL Connection Pooling implementiert (S1+S2 von `c-work/2-build/2026-05-postgres-connection-pool.md`). Root-Cause: `DatabaseConnector` hielt **eine** psycopg2-Connection pro Instanz und teilte sie via `getCachedConnector(...)` über den gesamten FastAPI-Thread-Pool **und** über asyncio-Tasks. psycopg2-Connections sind NICHT thread-safe — paralleler Zugriff aus z.B. RAG-Polling, `routeI18n`, `mainBackgroundJobService` und Hintergrund-Jobs führte zu `another command in progress` und — viel schlimmer — unendlichem Block in `recv()` (kein `statement_timeout` gesetzt). Das `self._lock` in `DatabaseConnector` war zwar deklariert, aber **nirgends** verwendet. Folge: Backend hat sich komplett aufgehängt, sogar die i18n-API für die Login-Seite lieferte nichts mehr. **Lösung**: Neuer `_PoolRegistry` (`gateway/modules/connectors/connectorDbPostgre.py`) mit `psycopg2.pool.ThreadedConnectionPool` pro `(host, db, port)`, lazy-init, thread-safe (`min=2`, `max=20` per `DB_POOL_MAX_CONN`, `statement_timeout=30s`, `connect_timeout=10s`). Jede DB-Operation borrowed eine Connection via neuem `db.borrowConn()`-Context-Manager (auto-commit/rollback/return); `db.borrowCursor()` als 1:1-Ersatz für das alte `with db.connection.cursor() as cursor:` Pattern. `getCachedConnector` bleibt API-kompatibel, Connector-Wrapper sind nun leichtgewichtig (kein per-instance Socket). Backward-Compat-Shim `db.connection` (no-op `commit()`/`rollback()`/`closed`, RuntimeError auf `cursor()` damit kein Stillschweigend-Bruch). 18 interne Cursor-Stellen + ~30 externe (interfaceRbac, interfaceDbManagement, interfaceDbBilling, interfaceFeatureRealEstate, routeWorkflowDashboard, routeHelpers, gdprDeletion, dbMultiTenantOptimizations, _featureSubAgentTools, scripts/stage0) auf das neue Pattern umgestellt. `_ensure_connection` als No-Op gehalten (Pool re-connectet selbständig). Public Shutdown-Hook `closeAllPools()` wartet auf S4 (FastAPI-Lifespan-Integration). Working-Doc: `c-work/2-build/2026-05-postgres-connection-pool.md` (Step S1+S2).
|
||
|
||
## 2026-05-16
|
||
|
||
- 2026-05-16 | fix | frontend-nyla | `AddConnectionWizard` Admin-Consent-Button war NoOp: `ConnectionsPage` hat das `onMsftAdminConsent`-Prop nie übergeben, der `?.()`-Aufruf im Wizard wurde schweigend übersprungen und der Wizard sprang einfach zum nächsten Schritt. Im Backend kam kein einziger Request an `/api/msft/adminconsent` an — User aus Multi-Tenants, in denen die App-Registration noch nie admin-consented wurde, hingen unauflöslich im "Anforderung gesendet"-Screen fest. Fix: `ConnectionsPage._handleMsftAdminConsent` öffnet jetzt ein Popup auf `/api/msft/adminconsent`, und das Prop wird an den Wizard durchgereicht. Doc-Sync: `d-guides/microsoft-entra-registration-checklist.md` (Redirect-URI-Tabelle um `/api/msft/adminconsent/callback` ergänzt — Fehlen führte zu `AADSTS50011`; Multi-Tenant-Hinweis: Admin Consent gilt pro Tenant).
|
||
|
||
## 2026-05-15
|
||
|
||
- 2026-05-15 | fix | gateway | `subAiCallLooping.py`: fehlender Top-Level-Import `extractJsonString` (und `repairBrokenJson`) im Modul-Header ergänzt. Bei `getContexts()`-Success (jsonParsingSuccess=True, overlapContext='') flog ein `NameError`, wurde vom zu breiten `except Exception` als "completePart not serializable" geschluckt, hat `mergeFailCount` hochgezählt und nach 3 Iterationen leeren String zurückgegeben — Folge: `subStructureFilling` bekam `""` und meldete `tryParseJson failed: Expecting value` / `No elements produced`. Zusätzlich `except`-Hygiene: `(json.JSONDecodeError, KeyError, TypeError)` → WARNING + retry (erwartete Daten-Probleme), generischer `except Exception` → ERROR mit `exc_info=True` und Re-Raise (Code-Bugs werden nicht mehr 3× silently verfressen). Logging enthält jetzt den Exception-Typ als Prefix.
|
||
- 2026-05-15 | feat | gateway | Feature Data Sub-Agent Phase 1.5 + Phase 2 abgeschlossen. **Eval-Harness** (`gateway/tests/eval/runTrusteeBenchmark.py`, standalone Runner) fährt 19 Goldstandard-Fragen × 3 Modi (baseline / phase1 / phase2) mit echten AI-Calls gegen einen `FakeFeatureDataProvider` (in-memory `BenchmarkFixture`, kein DB-Setup) und schreibt Markdown + JSON-Report nach `local/notes/`. **Trustee-Ontologie** (`gateway/modules/features/trustee/trusteeOntology.py`): 6 Entities (Account + BankAccount/CashAccount-Spezialisierungen, AccountBalance, JournalEntry/Line), 3 Relations, 6 Constraints (NEVER_AGGREGATE auf alle 4 Balance/Total-Felder, REQUIRES_FILTER_ON für AccountBalance, PREFERRED_TABLE_FOR_INTENT), 8 CanonicalQueryPatterns. **OntologyToPromptCompiler** (`ontologyToPromptCompiler.py`) rendert die Descriptor deterministisch als kompakten Prompt-Block. `mainTrustee.getAgentOntology()` Hook + `_AGENT_DOMAIN_HINTS_LEGACY` geparkt. `featureDataAgent._buildSchemaContext` nutzt `_loadFeatureOntologyBlock()` bevorzugt (Fallback auf `_loadFeatureDomainHints`); `_buildValidatorForFeature()` verkabelt Validator+Ontologie automatisch (Single Source of Truth). Eval-only Override `POWERON_DISABLE_FEATURE_ONTOLOGY=1`. **Side-Fix**: `aggregateTable` exponiert jetzt `filters` im Tool-Schema (war Code-Bug, blockierte SUM-pro-Konto-Anfragen); Validator validiert filters analog zu queryTable. **Resultate** (`local/notes/trustee-benchmark-20260515-161126.md`): Accuracy Baseline 89.5 % → Phase 1 94.7 % (Validator triggert in q13 2× und steuert Agent eigenständig auf queryTable um) → Phase 2 100 % (Ontologie verhindert q09-Halluzination "creditTotal statt closingBalance" präemptiv). +18 neue Unit-Tests in `test_trusteeOntology.py` (Descriptor, Compiler, Validator-Integration, mainTrustee-Hook, _buildValidatorForFeature); `test_featureDataAgent_schema.py` um Ontology-Pfad + Eval-Override erweitert. Working-Doc verschoben nach `c-work/3-validate/2026-05-feature-data-agent-ontology-and-repair.md`. Doc-Sync: `b-reference/gateway/ai-agent.md` (neuer Abschnitt "FeatureDataAgent: Query-Repair-Loop + Ontologie"), `b-reference/gateway/features/trustee.md` (neuer Abschnitt "Agent-Ontologie"), `d-guides/coding-conventions.md` (Migrations-Muster `getAgentDomainHints` → `getAgentOntology`).
|
||
- 2026-05-15 | feat | gateway | Feature Data Sub-Agent Phase 1 (Query-Repair-Loop) implementiert. Neuer `QueryValidator` (`gateway/modules/serviceCenter/services/serviceAgent/queryValidator.py`) prüft `browseTable`/`queryTable`/`aggregateTable`-Calls **vor** dem Provider gegen das Pydantic-Modell und liefert strukturierte Repair-Hints statt SQL-Exceptions. Vier Constraint-Klassen: `FIELD_NOT_FOUND` (mit Fuzzy-Suggestion via difflib), `OPERATOR_INCOMPATIBLE` (LIKE/ILIKE nur auf String, `>=`/`<=` nur auf Numerisch), `INVALID_AGGREGATE_TARGET` (SUM/AVG auf `*Balance`/`*Total` -- fängt die flagship Trustee-Halluzination `SUM(closingBalance) × 7 Jahre × 13 Perioden ≈ 90× Saldo` deterministisch ab), `ORDER_BY_INVALID`. Neues Datenmodell `datamodelOntology.py` mit `QueryValidationError`, `Constraint`, `OntologyDescriptor` (Phase-2-Ready); Phase-2-Override via Ontologie-Constraints schon eingebaut, aber inaktiv solange keine Ontologie pro Feature definiert ist. `ToolResult.errorDetails: Optional[Dict]` und `ToolCallLog.validationFailureCode: Optional[str]` zu `datamodelAgent.py` ergänzt (LLM bekommt machine-readable Repair-Hint, Audit-Log behält Kurz-String). `agentLoop._computeRepairCounters` aggregiert pro Sub-Agent-Run `validationFailures`, `repairAttempts`, `successAfterRepair` aus den `ToolCallLog`-Einträgen und legt sie auf `AgentTrace` + ins `AGENT_SUMMARY`-Event (Eval-Harness-Ready). Tool-Descriptions der drei Sub-Agent-Tools erklären das `errorDetails`-Format explizit. 35 neue Unit-Tests (24 für QueryValidator, 3 für Tool-Integration, 8 für Trace-Aggregation), alle 62 bestehenden serviceAgent-Tests bleiben grün. Working-Doc: `c-work/2-build/2026-05-feature-data-agent-ontology-and-repair.md`.
|
||
- 2026-05-15 | chore | wiki | Plan-Finalisierung: (1) RAG C&C Unification+Implementation → status `done`, alle Testplan-Einträge manuell verifiziert, `b-reference/platform/neutralization.md` (DataSource=SSoT, kein neutralizeBeforeEmbed, Tree-Vererbung) und `b-reference/frontend-nyla/architecture.md` (RagInventoryPage, UDB 4. Button, RagRunningBadge, AddConnectionWizard) aktualisiert, beide Pläne nach `4-done/` verschoben. (2) Enterprise Subscription → `4-done/`. (3) FormGenerator Grouping → `4-done/`. (4) STT Benchmark Page implementiert (Backend + Frontend, SysAdmin-only).
|
||
- 2026-05-15 | docs | wiki | Feature Data Sub-Agent Plan (`c-work/1-plan/2026-05-feature-data-agent-ontology-and-repair.md`) gegen Codebase verifiziert und um 5 Klärungen geschärft: (A) `ToolResult.errorDetails: Optional[Dict]` neu in `datamodelAgent.py` statt JSON-in-error-String; (B) Repair-Telemetrie wandert von `aiAuditLogger` in `AgentTrace`/`ToolCallLog` (per-Run-Aggregation passt nicht in per-Call-Audit-Log); (C) Eval-Fixture als Python-Loader + Pydantic/`recordCreate` statt `fixture.sql` (konsistent mit Trustee-Tests); (D) AC#3 als `repairConversionRate ≥ 0.8` über Repair-Triggered-Subset präzisiert, nicht als End-Accuracy; (E) Doc-Sync-Liste um `b-reference/gateway/features/trustee.md` und `d-guides/coding-conventions.md` erweitert. Plan ist damit umsetzungsreif für Phase 1.
|
||
|
||
## 2026-05-16
|
||
|
||
- 2026-05-16 | fix | gateway, frontend-nyla | RAG-Reindex hängt nach manuellem Trigger im Status RUNNING/PENDING, ohne dass ein Walker startet — UI zeigt endlosen Spinner bis Zombie-Killer nach 30 min eingreift. Root Cause: drei Job-Submit-Routen waren sync (`def`, nicht `async def`) und enthielten ein "loop = asyncio.get_event_loop(); ... except RuntimeError: asyncio.run(_enqueue())"-Konstrukt. FastAPI führt sync-Routes im Worker-Threadpool aus → kein laufender Event-Loop → `asyncio.run` öffnet einen temporären Loop, in dem `startJob` `_runJob` via `create_task` registriert → `asyncio.run` schliesst den Loop sofort nach Return → Task wird gecancelled, bevor er ein einziges Statement ausführt. Daily-Resync funktionierte, weil er aus APScheduler im Main-Loop läuft. Fix: alle drei Routen auf `async def` umgestellt und `await startJob(...)` direkt verwendet — keine Loop-Hack-Logik mehr. Betroffene Routes: `routeRagInventory._reindexConnection`, `routeDataSources._updateDataSourceRagIndex` (UDB-Toggle 🧠), `routeDataConnections._updateKnowledgeConsent` (globaler Consent-Toggle). Zusätzlich: Inventar-Response liefert jetzt `lastSuccess` mit `{jobId, finishedAt, indexed, skippedDuplicate, skippedPolicy, failed, durationMs}` plus `lastError.finishedAt` — Frontend zeigt grünes Erfolgs-Banner mit Stats + relativem Zeitstempel ("Sync erfolgreich vor 3 Min — 4 neu indexiert · 183 unverändert (198.3s)") statt nur leerem Spinner; Error wird nur angezeigt wenn er neuer ist als der letzte Erfolg, sonst gewinnt das Success-Banner. `RagInventoryPage` und `RagRunningBadge` pollen jetzt schnell (5s) während Jobs laufen und langsam (60s) im Idle. Badge zeigt einen 4s-"Sync abgeschlossen ✓"-Toast wenn der letzte aktive Job verschwindet. Hängender Job 7ee09ca7 wurde via Onetime-Skript gekillt.
|
||
|
||
## 2026-05-15
|
||
|
||
- 2026-05-15 | fix | gateway | RAG-Sync Log-Spam + DB-Reinit-Storm. Root Cause: `mainBackgroundJobService._getDb()` rief bei jeder Job-CRUD-Operation `DatabaseConnector(...)` direkt auf — pro Reindex-Klick mehrfach (`submitJob`, `_updateJob`, `getJob`, `listJobs`, `cancelJob`). Jeder Konstruktor-Call lief komplett durch `_create_database_if_not_exists` → `_create_tables` → neue psycopg2-Connection → `_initializeSystemTable` und loggte "PostgreSQL database system initialized successfully" auf INFO. Folgen: Log-Lärm bei jedem Reindex (~5-10 INFO-Zeilen) + echter DB-Overhead pro Job-Operation. Fix: (1) `_getDb()` nutzt jetzt `getCachedConnector()` (Cache-Key = host/db/port, FIFO-Eviction nach 32, Thread-safe), pro Worker-Lifetime nur noch 1× Init für die jobs-DB. Smoke-Test bestätigt: 3× `_getDb()` → identische Instanz. (2) Init-Log in `connectorDbPostgre.initDbSystem` von INFO auf DEBUG gesenkt + um `db/host/port`-Felder ergänzt — wenn doch mal ein Connector neu erzeugt wird, ist das im Steady-State nicht mehr wert auf INFO-Level zu schreien. Andere Hot-Path-Komponenten (`interfaceDbApp`, `interfaceDbKnowledge`, `aiAuditLogger`) nutzten den Cache bereits korrekt; `auditLogger` ist Singleton, also unkritisch.
|
||
|
||
## 2026-05-14
|
||
|
||
- 2026-05-14 | fix | gateway | RAG-Sync: Zombie-Job-Handling + Walker-Timeouts. (1) Neuer 5-Minuten-Cron `background_jobs.zombie_killer` in `mainBackgroundJobService.killZombieJobs()` markiert RUNNING-Jobs ohne Progress-Update >30 min als ERROR und beendet so auf Dauer hängende Bootstraps. (2) Neuer Helper `subWalkerHelpers.py` (`downloadWithTimeout` 60s, `extractWithTimeout` 90s via `asyncio.to_thread`+`wait_for`, `ingestWithTimeout` 60s, `logItemStart`) — alle Walker (sharepoint, kdrive, gdrive, gmail, outlook, clickup) loggen jetzt vor jedem Item `walker.item.start service=… path=…`, sodass das letzte solche Log bei einem Hang das verursachende Item exakt benennt. Sync-Extraktion läuft auf Worker-Thread, blockiert das Event-Loop nicht mehr. (3) Aktive Zombies (msft 81min, infomaniak 81min, clickup 81min) wurden via Onetime-Skript gekillt.
|
||
- 2026-05-14 | docs | wiki | WW Stephan-Lieferablage: `c-work/2-build/walderwyss-stephan-output/` (Stephan legt nichts in pamocreate ab). Auftrags-PDFs Homepage + Infomaniak für Stephan.
|
||
- 2026-05-14 | docs | wiki | Lawyer-Feature geplant (Mandatsvorbereitung + Dashboards für Anwaltskanzleien), ausgelöst durch WW-Pitch-Bedarf (David Vasella). Working-Doc in `c-work/1-plan/2026-05-lawyer-feature.md`.
|
||
|
||
## 2026-05-12
|
||
|
||
- 2026-05-12 | fix | service-teams-browser-bot | Auth bot PiP loop fix: in full Teams web app, chat toggle navigates to Chat section -> PiP -> periodic scan reopens -> PiP again (endless loop). Fix: added isAuthMode flag to ChatProcedure; in auth mode: skip chat panel toggle entirely, skip periodic reopen, skip panel-open preflight for sendChatMessage. Chat send uses direct input lookup in the meeting view. Replaced _returnToMeetingIfPip() approach (reactive) with prevention (don't toggle)
|
||
- 2026-05-12 | fix | service-teams-browser-bot | Auth bot meeting minimized (PiP): chat button click hit Teams sidebar "Chats" navigation instead of in-meeting toggle -> meeting minimized, all PeerConnections closed, video/audio broke. Fix: isDangerousNavButton filter excludes sidebar nav, tab-items, submenu triggers; aria-pressed fallback for panel detection in full Teams web app; _openMoreMenu scoped to calling toolbar
|
||
- 2026-05-12 | feat | gateway, frontend-nyla, teams-bot | Avatar-Bild/Video für TeamsBot: Neues Feld `avatarFileId` in `TeamsbotConfig`/`TeamsbotUserSettings` und `defaultAvatarFileId` in `TeamsbotMeetingModule`. Benutzer können in den Bot-Einstellungen und pro Modul ein Bild oder Video aus den Systemdateien auswählen, das anstelle der statischen Farbfläche als Bot-Video im Meeting gerendert wird. Modul-Einstellung überschreibt Instanz-Default. Gateway löst die Datei beim Session-Start auf, konvertiert zu Base64, und sendet sie im Join-Payload an den Browser-Bot. Bot-seitig: `mediaGetUserMediaPatch.ts` rendert Bilder per `drawImage()` auf den Canvas, Videos per `<video>`-Element mit Loop. Für Videos wird FPS auf 15 erhöht und `contentHint='motion'` gesetzt. Fallback bleibt die statische Farbfläche mit Bot-Name.
|
||
- 2026-05-12 | fix | gateway, frontend-nyla | TeamsBot Module-Status `[null]`: `createModule`-Route schrieb keinen `status` in die DB, weil `CreateMeetingModuleRequest` kein `status`-Feld hat und `recordCreate` bei Dict-Input keine Pydantic-Defaults anwendet. Frontend `t(null)` ergab `[null]`. Fix: (1) Route setzt `data.setdefault("status", "active")`, (2) `getModules` setzt fehlenden Status defensiv auf `"active"` für existierende Records, (3) Frontend-Fallback `mod.status || 'Aktiv'` als letzte Absicherung.
|
||
- 2026-05-12 | fix | frontend-nyla | TeamsBot Director-Panel Sichtbarkeit: gleiches Whitelist-Problem wie zuvor beim Stop-Button. `TeamsbotSessionView.tsx` Z.903 prüfte `['active','joining','pending'].includes(session.status)` — wenn der Status direkt nach Mount kurz leer / unbekannt war (SSE-Race vor `_loadSession`-Resolve, oder Backend schickt einen Übergangsstatus den die Liste nicht kennt), verschwand das ganze "Regieanweisungen"-Panel und kam erst nach Page-Reload wieder. Auf Blacklist umgestellt: `!['ended','error','leaving'].includes(session.status)`. Andere Whitelist-Stellen in derselben Datei (Session-Auswahl Z.136, SSE-Reconnect Z.186/373/439, Listen-Label Z.792) sind defensive Filter mit `status &&`-Guard und bleiben korrekt; Dashboard-Stop-Button war bereits auf Blacklist (Vorgänger-Fix).
|
||
- 2026-05-12 | fix | teams-bot, gateway | STT-Sprache: hardcodierten `alternativeLanguages=["en-US"]`-Fallback in `service._processAudioChunk` entfernt. Symptom: nach längerem Bot-TTS-Playback (z.B. 30s Web-Recherche-Antwort) sprang Google STT bei verrauschter Audio auf en-US (`language_code: "en-us"` im Response, Confidence 0.3–0.5) und lieferte englisches Kauderwelsch ("The transition trade constitute the Range Line."), während saubere Sprache derselben Session korrekt als de-DE mit 0.97 transkribiert wurde. Root Cause: der hardcodierte Englisch-Alternative gab Google die Erlaubnis, bei niedriger DE-Konfidenz nach EN umzuschalten. Fix: nur noch die Sessionsprache (`self.config.language`, Default `de-DE`) wird übergeben — `TeamsbotUserSettings.language` überschreibt `TeamsbotConfig.language` wie gehabt. Settings-Audit bestätigt: alle 12 UI-Felder (`botName`, `aiSystemPrompt`, `responseMode`, `responseChannel`, `transferMode`, `language`, `voiceId`, `triggerIntervalSeconds`, `triggerCooldownSeconds`, `contextWindowSegments`, `debugMode`, `browserBotUrl`) sind im Code aktiv genutzt — keine Karteileichen. (b-ref: teams-bot/architecture.md → "STT auf dem Gateway")
|
||
- 2026-05-12 | refactor | teams-bot | Chat-Panel-Detection: tote Fallback-Schichten entfernt. `_isChatPanelOpen()` reduziert auf den nachweislich funktionierenden Pfad: `[data-tid="calling-right-side-panel"]` Existenz+Visibility + chat-spezifischer Child-`data-tid` darin. Schicht 2 (`aria-pressed`-Toggle für "ältere Auth-Layouts") und Schicht 3 (Compose-Box-Sichtbarkeit als Last-Resort) waren toter Code — anon und auth nutzen beide denselben `calling-right-side-panel`-Container, der `aria-pressed`-Pfad war zwei Iterationen vorher selbst als unzuverlässig verworfen worden. Konform mit "Do not add fallback code, if not necessary". (b-ref: teams-bot/architecture.md → "Chat-Panel-Detection")
|
||
- 2026-05-12 | feat | teams-bot | Statisches Avatar-Video für anonymen Bot ersetzt Teams' grünen "no video"-Spinner. Neuer Toggle `BOT_USE_CANVAS_VIDEO=true` (Default true im `.env`) plus `BOT_AVATAR_BG_COLOR=#a8d4f0` / `BOT_AVATAR_TEXT_COLOR=#1a3552` in `src/config.ts`, durchgereicht via `audioProcedure.ts` an den Init-Script-Payload `mediaGetUserMediaPatch.ts`. `_startBotAvatarStream()` zeichnet jetzt eine ruhige einfarbige Fläche + zentrierter Anzeigename (kein Pulse, kein Gradient, keine "PORTA"-Marke), Tick-Rate von 15 fps auf 2 fps gesenkt (genug um `captureStream()` in headless Chromium aktiv zu halten, ohne dass der Encoder Frame-Diffs sieht), `contentHint='motion'` → `'detail'` damit WebRTC für statisches Bild Bitrate spart und Text scharf bleibt. Auth-Bot ist nur betroffen wenn der Toggle aktiv ist. (b-ref: teams-bot/architecture.md → "Statisches Avatar-Video (ersetzt grünen Lade-Spinner)")
|
||
- 2026-05-12 | fix | frontend-nyla | TeamsBot Stop-Button Sichtbarkeit: Logik von Whitelist (`['active','joining','pending']`) auf Blacklist (`!['ended','error','leaving']`) umgestellt in `TeamsbotSessionView.tsx` Z.841 + `TeamsbotDashboardView.tsx` Z.264. Verhindert Verschwinden des Buttons bei kurzfristig leerem/unbekanntem Status (z.B. SSE-Race kurz nach Mount, neuer Backend-Status). Button verschwindet nur noch nach explizit terminalen States. Hinweis zur i18n: Source-Keys `t('Sitzung beenden')` / `t('Stoppen')` waren bereits korrekt verpackt — die User-sichtbare englische Anzeige "End Session" stammt aus der Übersetzungs-DB und ist die intendierte i18n-Auflösung des deutschen Source-Keys.
|
||
- 2026-05-12 | fix | teams-bot | Chat-Panel-Toggle-Auswahl im Auth-Layout: `chatProcedure._openChatPanel()` neu implementiert. Auth-Full-Teams hat zwei "Chat"-Buttons — einen echten Toggle (UUID-id, `aria="Chat (Ctrl+Shift+2)"`, `aria-pressed="false"`) und einen Schein-Button `#chat-button` ohne `aria-pressed`, der nicht togglt. Vorher: Selector-Liste nahm `#chat-button` als ersten Treffer und klickte 12× denselben falschen Button. Neu: alle visibility-gefilterten Chat-Hint-Kandidaten in Page-Evaluate gesammelt, Toggle-Buttons (mit `aria-pressed`) bevorzugt, geklickte Keys getrackt — derselbe Button wird nie zweimal geklickt, Loop wechselt zum nächsten Kandidaten. Sprachunabhängig (DE/EN-Hints `chat`/`unterhalt`/`besprechung`/`conversation`). (b-ref: teams-bot/architecture.md → "Chat-Panel-Toggle-Auswahl im Auth-Layout")
|
||
- 2026-05-12 | fix | teams-bot | Chat-Panel Detection — `vdi-occlusion`-Trapdoor entschärft + Side-Pane-Container als primäre Quelle. Befund am DOM (User-Inspect): die Klasse `vdi-occlusion` ist im neuen Calling-Layout **Permanent-Marker** auf `calling-right-side-panel` und `message-pane-layout` — auch bei sichtbar offenem Panel. Mein vorheriger Check "vdi-occlusion → zu" war daher immer false-negative → Toggle-Loop. Der `<button id="chat-button">` selbst ist byte-identisch in beiden States (kein `aria-pressed`, kein `data-state`, blaue Linie kommt aus CSS-`:has()` auf dem Side-Panel). Detection neu: Schicht 1 prüft `[data-tid="calling-right-side-panel"]` Existenz + offsetWidth/Height + offsetParent (echtes Visibility-Signal), und Mode-Disambiguation per chat-spezifischen Tids drinnen (`message-pane-layout`, `chat-pane-compose-message-footer`, `#chat-pane-list`, `[data-app-name="chats"]` u.a.) — sprachunabhängig, trennt Chat von People/Info ohne Text-Lookup. Schicht 2 (aria-pressed Toggle) bleibt für legacy-Auth-Layouts. (b-ref: teams-bot/architecture.md → "Chat-Panel-Detection — Schicht-Strategie")
|
||
- 2026-05-12 | fix | teams-bot | Chat-Panel Detection (zwischenzeitlich) — Schicht-Strategie via aria-pressed: `chatProcedure._isChatPanelOpen()` umgestellt auf "echter Toggle-Button" (chat-Hint im aria-label UND `aria-pressed` ∈ {true,false}, sprachunabhängig) und liest dessen `aria-pressed` als Quelle der Wahrheit — fixt den Auth-Toggle-Loop. Im Auth-Layout existieren mehrere "chat"-aria Buttons (Side-Nav-Einträge "Chats", "Meeting chats", Tab-Items `tab-item-com.microsoft.chattabs.*`), aber nur der echte Meeting-Chat-Toggle hat `aria-pressed`. Vorher prüften wir hartcodiert `#chat-button` (= Side-Nav-App in Auth, NICHT der Toggle), bekamen False-Negative "Panel zu" obwohl offen → periodischer Scan klickte den echten Toggle → schloss Panel → klickte weitere Buttons → Endlos-Toggle-Loop mit `UPR`-Page-Errors. Light-meetings-Pfad (`message-pane-layout` mit `vdi-occlusion`-Klasse oder `offsetHeight=0`) bleibt als Schicht 2 für Anon (kein `aria-pressed`-Toggle vorhanden). (b-ref: teams-bot/architecture.md → "Chat-Panel-Detection — Schicht-Strategie")
|
||
- 2026-05-12 | build | teams-bot | Container-Image installiert echtes Chrome: `Dockerfile` ergänzt um `RUN npx playwright install --with-deps chrome` (lädt Google Chrome stable + alle apt-Deps an Playwright-bekannten Pfad) und `ENV BOT_BROWSER_CHANNEL=chrome`. `docker-compose.yml` setzt `BOT_BROWSER_CHANNEL=${BOT_BROWSER_CHANNEL:-chrome}` als Default. Macht den anon-Bot-Fix container-deploy-fähig. (b-ref: teams-bot/architecture.md → "Container-Deployment")
|
||
- 2026-05-12 | fix | teams-bot | Anonymer Bot: Browser-Channel auf echtes Chrome umgestellt (`BOT_BROWSER_CHANNEL=chrome`). Playwrights gebündeltes Chromium wird von Teams' `light-meetings`-Pfad als Automation gefingerprintet → erzwungene Lobby + Preheating-Crash (`rejectMediaDescriptionsUpdateAsync`) → "Sorry, we couldn't connect you". Mit lokal installiertem echten Chrome geht der Bot direkt ohne Lobby ins Meeting, kein Crash. Neu: `botBrowserChannel` in `config.ts`, an `chromium.launch({ channel })` in `orchestrator._launchBrowser()` durchgereicht. Bisect bestätigt: weder Media-Wrapper (`BOT_DISABLE_MEDIA_WRAPPERS`) noch Anon-spezifische Chromium-Args / Stealth-Init (`BOT_ANON_USE_AUTH_BROWSER_SETUP`) waren die Ursache; beide Debug-Schalter bleiben als Bisect-Tools im Code. Auth-Joins funktionieren auch mit Bundled-Chromium (echte MS-Session überspringt den Check). (b-ref: teams-bot/architecture.md → "Browser-Channel: echtes Chrome für anonyme Joins")
|
||
- 2026-05-12 | fix | teams-bot | TeamsBot Chat-Scraper: Container-Fallback für light-meetings DOM-Branche. **`chatProcedure.ts`** periodischer Scan promoviert `target` zu `document` wenn der Chat-Container (`message-pane-layout`) `offsetHeight=0` hat ODER Selectoren 0 Treffer liefern, aber global `[class*="fui-ChatMessage"]` existiert (light-meetings rendert Chat-Bubbles in paralleler DOM-Branche). Zusätzlich Root-Cause-Guard `if (!text && author !== 'Unknown')` in beiden Pfaden (MutationObserver Strategy 1 + periodischer Scan) restauriert — verhindert dass strukturelle Fragmente ohne Author als `Unknown: 22:04` Transcripts durchsickern. (c-work: 4-done/2026-04-teamsbot-greenfield-ia-and-live-update.md)
|
||
- 2026-05-12 | fix | teams-bot | Anonymer Bot: Audio-Capture WebRTC-Wrapper greift nicht mehr in Teams' Pre-Join/Lobby-SDP-Zyklen ein (Ursache des `rejectMediaDescriptionsUpdateAsync`-Crashes und der Lobby-Hänger). `audioCaptureProcedure.ts`: neues `__audioCaptureEnabled`-Flag (default false), `track`-Handler im Wrapper macht nur noch DIAG-Log solange Flag false ist; `__audioCaptureAttachTrack` als window-exponierter Builder; `startCapture()` setzt Flag erst nach `_setState('in_meeting')` und iteriert `getReceivers()` aller `connected` PCs für bereits existierende Audio-Spuren. Label-Filter `mainAudio-*` entfernt (war falsch generalisiert — manche Sessions haben nur eine PC mit UUID-Label). (c-work: 4-done/2026-04-teamsbot-greenfield-ia-and-live-update.md)
|
||
- 2026-05-12 | feat | frontend-nyla, gateway | FormGeneratorTable Grouping Refactor: Default auf Inline-Modus umgestellt; Toggle-Icon (Inline/Sections) in TableViewsBar; Sections-Mode Multi-Level (alle Permutationen als flache Sections); pageSizeOptions um 1000/2000/10000 erweitert; Collapse-All/Expand-All Buttons fuer Inline-Grouping; 4 Pages (Connections, Prompts, Files, BillingData) auf Inline-Default umgestellt.
|
||
- 2026-05-12 | feat | frontend-nyla | RAG Consent & Control Phase D Ergänzungen: UDB `SourcesTab` 4. Toggle-Button (🧠 ragIndexEnabled) mit Vererbung; `RagRunningBadge` Floating-Komponente (Polling, Job-Dropdown); `WorkspaceRagInsightsPage` physisch gelöscht; `ConnectionsPage` AdminConsent+Infomaniak Standalone-Buttons entfernt (nur noch via Wizard).
|
||
- 2026-05-12 | docs | wiki | `b-reference/gateway/ai-agent.md` Abschnitt "RAG Consent & Control" ergänzt (Prinzipien, Datenmodell, Walker-Architektur, API, Frontend-Komponenten, Vererbung); `TOPICS.md` RAG-C&C-Eintrag.
|
||
- 2026-05-12 | feat | gateway, frontend-nyla | RAG Consent & Control: Phase A–D implementiert. Backend: `DataSource.autoSync` → `ragIndexEnabled` (rename + Migration-Script); `cancelJob()` + `cancelJobsByConnection()` in BackgroundJobService; `JobProgressCallback.isCancelled()` (3s-cached); Walker-Refactor (alle 5 Connectoren iterieren nur über ragIndexEnabled DataSources + Cancel-Check alle 50 Items + `provenance.dataSourceId`); neuer `subPolicyResolver.py` (Tree-Vererbung); neue Routes `/knowledge-consent`, `/knowledge-preferences`, `/knowledge-stop`, `/datasources/{id}/rag-index`; neuer `routeRagInventory` (4 Endpoints); `GET /connections/` liefert Knowledge-Felder; `WorkspaceRagInsights` Route+Permission gelöscht. Frontend: `AddConnectionWizard` vereinfacht (connector-aware Steps, MSFT AdminConsent + Infomaniak PAT integriert, keine Kostenschätzung/Prefs); `connectionApi.ts` neue Methoden + bereinigte Types; neue `RagInventoryPage` + CSS; `pageRegistry` + `App.tsx` Route + Navigation-Eintrag; `FeatureView` `rag-insights` Mapping entfernt.
|
||
- 2026-05-12 | docs | wiki | Implementierungsplan: `1-plan/2026-05-rag-consent-and-control-implementation.md` — code-grounded Phasenplan (A→F) mit Audit-Befunden (`autoSync` ungenutzt → safe rename; `cancelJob`-API fehlt; `routeDataConnections` GET liefert Knowledge-Felder nicht; PATCH-Pattern aus `routeDataSources` als Vorlage), Datei-genaue Änderungen, Acceptance-Gates pro Phase, Risiko-/Decision-Liste, ~17 Tage T-Shirt-Schätzung.
|
||
- 2026-05-12 | docs | wiki | Plan: `1-plan/2026-05-rag-consent-and-control-unification.md` — datenzentrierte RAG-Architektur: Per-Element-Index-Toggle in UDB analog Scope/Neutralize (kaskadierende Tree-Vererbung; per-Feld bei Tabellen via `neutralizeFields[]`); Walker iteriert nur über `ragIndexEnabled=true` DataSources; Stop-Mechanismus an drei Sichtbarkeits-Orten (Header-Badge, ConnectionsPage-Row, RagInventoryPage); Wizard ist einziger Eintrittspunkt für alle Connector-Typen (integrierter MSFT Admin-Consent-Step + Infomaniak-PAT-Step); globale `Start > Nutzung > RAG-Inventar` Seite; Wizard ohne Kostenschätzung/Preferences; Löschung der workspace-scoped `WorkspaceRagInsightsPage`.
|
||
|
||
## 2026-05-11
|
||
|
||
- 2026-05-11 | feat | gateway | ToolDefinition.displayLabel: neues Feld fuer menschenlesbare Aktivitaetsbeschreibungen; Agent-Loop propagiert Label in TOOL_CALL Events; TeamsBot nutzt es fuer kontextuelle Fortschrittsmeldungen statt "Schritt N von M"
|
||
- 2026-05-11 | fix | gateway | TeamsBot Speaker-Attribution: retroaktive Zuordnung von "Unknown"-Eintraegen erfolgt jetzt bei jedem neuen Caption-Speaker, nicht nur beim ersten
|
||
- 2026-05-11 | fix | service-teams-browser-bot | Chat-Scraper Root Cause: Timestamp-Separatoren ("22:01") wurden als Chat-Nachrichten erkannt weil der innerText-Fallback auch bei unbekanntem Autor griff; Fallback jetzt nur wenn Autor identifiziert wurde
|
||
- 2026-05-11 | fix | gateway | mainServiceWeb progressLogUpdate: fehlende `if operationId:` Guards bei Zeilen 101/125 verursachten "Operation None not found" Warnung wenn Agent-Tool webSearch ohne operationId aufrief
|
||
- 2026-05-11 | fix | gateway | SPEECH_TEAMS Prompt: spezifische Beispiele entfernt, Eskalationsregeln generisch gehalten
|
||
- 2026-05-11 | fix | service-teams-browser-bot | Anonymous bot stuck after lobby admission: _waitForMeetingAdmission now tracks lobby-to-meeting transition, waits patiently when lobby vanishes (= admitted), and reloads page as recovery; isInMeeting expanded with light-meetings + German selectors
|
||
- 2026-05-11 | docs | wiki | d-guides: `google-registration-checklist.md`, `microsoft-entra-registration-checklist.md` (Vendor-Registrierung + Gateway-Env/Code-Referenzen); TOPICS ergänzt.
|
||
- 2026-05-11 | feat | gateway, frontend-nyla, wiki | TeamsBot: `GET /api/teamsbot/{instanceId}/dashboard/stream` (SSE dashboardState 3s/20s); dashboard consumes EventSource + reconnect; module tiles navigate to `modules?moduleId=` with expand + scroll highlight; canonical `b-reference/teams-bot/architecture.md`, TOPICS, `b-reference/frontend-nyla/architecture.md` (Teams Bot UI row). (c-work: 2-build/2026-04-teamsbot-greenfield-ia-and-live-update.md)
|
||
|
||
## 2026-05-10
|
||
|
||
- 2026-05-10 | feat | gateway | CommCoach Fast Conversational Mode: `AgentConfig.excludeAllTools` flag fuer tool-freie Turns; generischer RAG-Session-Cache in `agentLoop` (TTL 120s / 5 Msgs); CommCoach nutzt beides fuer fluessige Coaching-Gespraeche
|
||
- 2026-05-10 | fix | gateway | RAG-Cache-Bug: doppelter `workflowId`-Parameter in `_getOrRefreshRag` behoben (Keyword-Kollision)
|
||
- 2026-05-10 | fix | gateway | CommCoach TTS: `_TTS_WORD_LIMIT` von 200 auf 80 Woerter reduziert; Sprachausgabe fasst laengere Antworten jetzt zusammen statt alles vorzulesen
|
||
- 2026-05-10 | feat | gateway | `AgentConfig.priority` (speed/quality/cost/balanced) an `agentLoop` durchgereicht; CommCoach conversational turns nutzen `PriorityEnum.SPEED` fuer schnellere Modellauswahl
|
||
- 2026-05-10 | fix | gateway | `interfaceDbManagement.getInterface` Singleton Race-Condition behoben: shared mutable instance ueberschrieb featureInstanceId zwischen async Requests; Agent konnte Files nicht finden
|
||
- 2026-05-10 | feat | frontend-nyla | TeamsBot UI aligned to greenfield IA: dashboard as KPI + module-activity + quick actions (no duplicate start form); MFA on live session SSE; assistant step adds join mode, MS account block, session context; modules header `Modul anlegen` dialog + `Meeting starten`; nav icons for assistant/modules; `FEATURE_REGISTRY` tab label Dashboard. (c-work: 2-build/2026-04-teamsbot-greenfield-ia-and-live-update.md)
|
||
- 2026-05-10 | feat, fix | gateway, frontend-nyla, teams-bot | TeamsBot: `startSession` binds `moduleId` with validation; DB migration M2 `TeamsbotMeetingModule.defaultMeetingLink` / `defaultBotName`; assistant prefill + searchable multi-row module list; modules edit saves defaults; session view polls while pending/joining even with SSE and syncs switcher row; browser bot chat compose marker + safe `AudioContext.close`. (c-work: 2-build/2026-04-teamsbot-greenfield-ia-and-live-update.md)
|
||
- 2026-05-10 | docs | wiki | Kanon: `b-reference/gateway/voice-google.md`; TOPICS + README Ordnerbaum; Querverweise in gateway/architecture, teams-bot/architecture, frontend-nyla/architecture, ai-agent.
|
||
- 2026-05-10 | feat | gateway, frontend-nyla | STT: configurable model/lightweight/audioFormat on batch `speechToText`; streaming supports model/lightweight/singleUtterance; duration from `result_end_time`; WS `open` + `end_of_single_utterance` replumbing. CommCoach uses `latest_short` + lightweight + single-utterance; Teamsbot passes `audioFormat=linear16`. Chirp/v2 evaluation tracked in `wiki/c-work/1-plan/stt-chirp-v2-evaluation.md`.
|
||
- 2026-05-10 | fix | gateway | CommCoach: conversational turns use `operationType=DATA_QUERY` + `priority=SPEED` for faster model selection (gpt-5.4-mini instead of gpt-5.5); model selector speed priority weight scaled from `/10` to `*100` to be meaningful.
|
||
- 2026-05-10 | fix | gateway | CommCoach: persona sessions now distinguish first vs follow-up; opening prompt references prior sessions instead of re-introducing persona every time.
|
||
- 2026-05-10 | feat | gateway | Document generation: unified `documentTitle` style separate from `headings.h1`; BASE/renderer converts independently; HTML/CSS, PDF title block, Markdown/Text heading offsets updated; DEFAULT_STYLE h1 lowered vs title.
|
||
|
||
## 2026-05-09
|
||
|
||
- 2026-05-09 | feat | actan | SanctionsCheck: Login rememberMe + session cookies; public `/signup` + `POST /api/public/signup`; e-mail templates + `templateRenderer`; SMS retries + NOTIFICATION activities; profile tabs; activity API enrichments (`akteurTyp`, `sichtbarkeit`, `includeInternal`) and Activities UI badges/panel.
|
||
- 2026-05-09 | feat | gateway | Enterprise Subscription: sysadmin-managed flat-price subscriptions with custom limits (users, features, storage, AI budget), invoice email, hard-block on overage, auto-renewal cron job. New endpoints: POST enterprise/create, enterprise/renew, PUT enterprise/update. (c-work: 1-plan/2026-05-enterprise-subscription.md)
|
||
- 2026-05-09 | refactor | frontend-nyla, gateway | CommCoach: remove Dossier view (route, FeatureView registry, RBAC UI object, Dashboard link, pageRegistry icon, barrel export). Session details (summary, score, duration, export) moved into Modules expand view.
|
||
|
||
## 2026-05-08
|
||
|
||
- 2026-05-08 | fix | frontend-nyla | CommCoach: add missing `Route path="dossier"` under feature-instance routes (was catch-all not-found).
|
||
- 2026-05-08 | fix | gateway | JWT cookies: resolve SameSite/Secure per request via _cookiePolicy() (not import-time); optional APP_COOKIE_SECURE override; env-gateway int/prod: APP_COOKIE_SECURE=true + CORS nyla*.poweron-center.net.
|
||
- 2026-05-08 | fix | gateway | JWT cookies: SameSite=None+Secure when APP_API_URL is HTTPS (cross-origin SPA+API); SameSite=Lax on HTTP localhost. Fixes credentialed API calls when UI and gateway differ by site. CSRF middleware unchanged.
|
||
- 2026-05-08 | chore | frontend-nyla | config/.env.{dev,int,prod}: keep only VITE_API_BASE_URL and VITE_APP_NAME; removed unused flags and duplicated Entra/secret keys (backend owns secrets). env.d.ts aligned.
|
||
- 2026-05-08 | refactor | frontend-nyla | Remove MSAL from UI: deleted authConfig.ts + AuthProvider.tsx, rewrote ProtectedRoute (sessionStorage-only), removed useMsalRegister, simplified logout, uninstalled @azure/msal-browser + @azure/msal-react. All auth logic lives in gateway.
|
||
- 2026-05-08 | chore | frontend-nyla | Rename env files: `.env.{dev,int,prod}` → `env-poweron-nyla-{dev,int,prod}.env` (naming matches workflow). Updated workflows, .gitignore, README.
|
||
- 2026-05-08 | chore | gateway | Rename env files: `env_{dev,int,prod,prod_forgejo}.env` → `env-gateway-{dev,int,prod,prod-forgejo}.env`. Updated GitHub/Forgejo workflows, deploy-gcp, .gitignore, .dockerignore, .gcloudignore, Dockerfile, scripts.
|
||
- 2026-05-08 | chore | gateway | Domain migration poweron-center.net → poweron.swiss: APP_API_URL, CORS origins, OAuth redirect URIs (MSFT, Google, ClickUp) in env-gateway-{int,prod,dev}. Updated billing email and doc URLs in stripeCheckout.py, datamodelTeamsbot.py.
|
||
|
||
## 2026-05-07
|
||
|
||
- 2026-05-07 | fix | gateway | sandboxExecutor: `open` durch In-Memory-VirtualFS ersetzt (statt geblockt); AI-generierter Code kann jetzt Dateien lesen/schreiben ohne echten Dateisystem-Zugriff
|
||
- 2026-05-07 | feat | gateway | RedmineTicketMirror + RedmineTicketDto: Feld `doneRatio` (% erledigt) ergaenzt; Sync-Mapping und DTO-Konvertierung aktualisiert
|
||
- 2026-05-07 | feat | gateway | Neues Agent-Tool `redmine.listRelations` fuer direkte Abfrage der Beziehungstabelle (Filter: issueId, relationType, pagination)
|
||
- 2026-05-07 | feat | gateway | `redmine.listTickets`: `offset`-Parameter ergaenzt fuer echte Pagination; Response liefert `offset` + `hasMore` statt `truncated`
|
||
|
||
## 2026-05-06
|
||
|
||
- 2026-05-06 | fix | frontend | UDB tab "Chatverläufe" renamed to "Dossiers" (UnifiedDataBar.tsx + i18n seed for xx/de/en/fr)
|
||
- 2026-05-06 | fix | gateway | PDF rendering: (1) _convertUnifiedStyleToInternal now maps spaceBeforePt/spaceAfterPt for headings, lineSpacing for paragraphs, bulletChar for lists — previously dropped silently; (2) DEFAULT_STYLE heading spacing increased (h1: 24pt before, h2: 20pt) for professional visual hierarchy; (3) _renderJsonBulletList uses dedicated BulletItem ParagraphStyle with leftIndent/firstLineIndent from bullet_list config — was identical to paragraph normalStyle
|
||
|
||
## 2026-05-05
|
||
|
||
- 2026-05-05 | fix | frontend-nyla | FormGeneratorTree: `window.confirm()` durch `useConfirm`-Modal ersetzt; Hover-Icons ueberlappen jetzt die Dateigroesse statt daneben zu stehen (spart Breite im File-Tree)
|
||
- 2026-05-05 | fix | gateway | 4 warning fixes: (1) mainServiceAgent skips getWorkflow for synthetic workflowIds with ":" prefix (commcoach billing keys); (2) ActionNodeExecutor + actionToolAdapter inject parentOperationId so ai.process progress nests correctly; (3) ChatService.interfaceDbComponent now receives featureInstanceId — root cause was missing scope causing getFile to miss featureInstance-scoped files during graph execution; (4) IMAGE_GENERATE sections use concise _buildImagePrompt instead of full 700KB userPrompt — eliminates DALL-E truncation
|
||
- 2026-05-05 | fix | gateway | _getOrCreateTempFolder rewritten to use ComponentObjects.getOwnFolderTree/createFolder instead of raw db.getRecordset bypass; added explicit logging for all code paths; _persistLargeDocument now logs updateFields before updateFile call
|
||
- 2026-05-05 | fix | frontend+gateway | AI-generated files not visible: (1) useCommcoach.ts sendMessage documentCreated handler used undefined `sessionId` instead of `session.id` causing ReferenceError silently swallowed by SSE parser catch-all — system note never shown; (2) SSE parser catch blocks narrowed to JSON.parse only so handler errors propagate; (3) _getOrCreateTempFolder re-implemented to find/create user Temp folder; (4) all file-update call sites consolidated into single updateFile call to avoid RBAC scope conflict
|
||
- 2026-05-05 | fix | gateway | CommCoach completeSession: session.get("contextId") → session.get("moduleId") — stale field name caused sessionCount to never update (always 0); getModules now computes live sessionCount from sessions table
|
||
- 2026-05-05 | fix | gateway | actionToolAdapter: _persistLargeDocument now handles bytes documentData (PDF/DOCX/PPTX were silently discarded); _formatActionResult returns sideEvents for fileCreated; scope set to featureInstance when featureInstanceId available; CommCoach+TeamsBot _runAgent forward FILE_CREATED as documentCreated SSE; silent warnings elevated to errors for data-loss scenarios
|
||
|
||
## 2026-05-04
|
||
|
||
- 2026-05-04 | feat | * | **CommCoach Persona-Management: Gespraechspartner konfigurierbar.** Backend: 5 neue Builtin-Personas (Paartherapeutin, Psychologe, Rechtsanwalt, Mediatorin, HR-Managerin), ModulePersonaMapping M:N-Tabelle mit DB-Migration M8, GET/PUT Module-Persona-Zuordnung. Frontend: Settings-Tab 'Gespraechspartner' mit FormGeneratorTable CRUD (Create/Edit/Delete custom Personas, Inline-Toggle isActive), Modul-Edit-Dialog mit Persona-Multi-Select, Session-Persona-Picker filtert nach Modul-Zuordnung. (c-work: `2-build/2026-04-comcoach-greenfield-ia.md`)
|
||
|
||
## 2026-05-03
|
||
|
||
- 2026-05-03 | feat | * | **ComCoach + TeamsBot Greenfield-IA: Implementierung abgeschlossen.** Backend: CoachingContext -> TrainingModule (Rename, moduleType Enum, kpiTargets, category entfernt), neue Module-CRUD-Routes. TeamsBot: TeamsbotMeetingModule Entity (additiv), Module-CRUD, agentRun SSE-Events sichtbar, Stats-Karten, adaptives Dashboard-Polling (3s/30s). Frontend: Beide Features 5-Tab-IA (Dashboard, Assistent, Module, Session, Settings), neue View-Komponenten (AssistantView Wizard, ModulesView CRUD), KeepAlive nur noch fuer Session-Tab, Settings Statistik entfernt, Dashboard navigiert zu Modules statt Dossier. (c-work: `2-build/2026-04-comcoach-greenfield-ia.md`, `2-build/2026-04-teamsbot-greenfield-ia-and-live-update.md`)
|
||
- 2026-05-03 | docs | wiki | **ComCoach + TeamsBot Greenfield-IA: Plaene verifiziert und in `2-build/` verschoben.** Alle Zeilennummern und Code-Referenzen gegen aktuelle Codebase geprueft (alle korrekt). ComCoach-Plan ergaenzt: `goals`-Feld existiert bereits (JSON->Freitext-Migration), `category`-Enum wird durch `moduleType` ersetzt, `description`-Feld bleibt. TeamsBot-Plan ergaenzt: Namenskonvention `startedByUserId` dokumentiert. Beide Plaene: `<!-- status: build -->`, `<!-- verified: 2026-05-03 -->`. (c-work: `2-build/2026-04-comcoach-greenfield-ia.md`, `2-build/2026-04-teamsbot-greenfield-ia-and-live-update.md`)
|
||
- 2026-05-03 | fix | gateway | **AI Step Output: `context` Feld zeigte Prompt statt Input-Context.** `actionNodeExecutor.py` baute `out["context"]` falsch aus `promptText + extractedContext` zusammen. Wenn AI ein Binary-Dokument erzeugte (z.B. Excel), war `extractedContext` leer und `context` wurde identisch mit `prompt`. Jetzt wird der tatsaechliche aufgeloeste `context`-Input-Parameter gespeichert.
|
||
- 2026-05-03 | fix | frontend-nyla | **FormGeneratorTree: Auto-Scroll bei Expand am unteren Bildschirmrand.** Wenn ein Gruppenobjekt in der unteren Haelfte des sichtbaren Bereichs expanded wird, scrollt der Container den Parent-Node zur Mitte, damit Kinder ohne manuelles Scrollen sichtbar sind.
|
||
- 2026-05-03 | fix | frontend-nyla | **Automation > Workspace Tab: Polling fuer laufende Runs.** `_WorkspaceTab` pollt `fetchWorkspaceRunDetail` alle 3s solange Run-Status nicht terminal. Stoppt automatisch bei completed/failed/cancelled.
|
||
- 2026-05-03 | fix | gateway | **executeCode Sandbox: `type` entblockt, `io` restricted, Modul-Liste dynamisch.** `type()` aus `_PYTHON_BLOCKED_BUILTINS` entfernt. `import io` liefert eingeschraenktes Modul (nur StringIO/BytesIO, kein io.open). Tool-Beschreibung dynamisch aus `SANDBOX_ALLOWED_MODULES` generiert. `type()` war faelschlich in `_PYTHON_BLOCKED_BUILTINS` (harmlos ohne exec/eval). `StringIO`/`BytesIO` als sichere Builtins (io.open wird nicht exponiert). Tool-Beschreibung aktualisiert.
|
||
- 2026-05-03 | fix | gateway | **AI Agent: docItem-Resolution Root Cause + executeCode readFile.** (1) `coerceDocumentReferenceList`: Dict-Pfad strippt jetzt `docItem:`/`docList:` Prefix korrekt via `from_string_list` (war: Prefix blieb in `documentId`, erzeugte Doppel-Prefix bei `to_string()`). (2) `process.py`: `DocumentItemReference` wird nur im Automation2-Kontext (kein Chat-Workflow) an `_resolve_file_refs_to_content_parts` geroutet; im Agent-Kontext fliessen sie korrekt durch `getChatDocumentsFromDocumentList` (war: alle Refs wurden abgefangen und fehlerhaft als File-Store-IDs behandelt). Gebrochenen `_resolveChatDocIdToFileId`-Fallback entfernt. (3) executeCode Sandbox: `readFile(fileId)` Built-in fuer Workspace-Dateizugriff (kein open(), nur managed Files via interfaceDbComponent).
|
||
- 2026-05-03 | fix | gateway | **AI Agent + Rendering: 9 Issues geloest.** (1) Sandbox `time`-Modul erlaubt. (2) ActionToolAdapter: grosse Docs als Workspace-Files persistiert. (3) downloadFromDataSource: Debug-Logging fuer Filename-Swap. (4) clickup_listTasks: Datums-/Custom-Field-Filter. (5) Renderer style-Bug: `style` Keyword auf allen 8 Renderern akzeptiert (CSV, Text, JSON, Markdown, Image, CodeXml, CodeJson, CodeCsv). (6) _ServicesAdapter: workflow-Setter fuer Agent-Kontext (getChatDocumentsFromDocumentList braucht workflow). (7) _ServicesAdapter: interfaceDbComponent Property (ai_process file-ref Resolution). (8) Auto-index nach Neutralize: mandateId/featureInstanceId an _autoIndexFile durchgereicht. (9) Kombination: Agent sollte AI-Workspace-Aufgaben effizient loesen.
|
||
- 2026-05-03 | chore | frontend-nyla | **Stage 4: FolderTree Dead-Code geloescht + Tree-Assessment.** Gesamter `components/FolderTree/`-Ordner entfernt (FolderTree.tsx 1170 LOC, SharepointBrowseTree.tsx 319 LOC, actions/, CSS -- alles Dead Code). ESLint-Deprecation-Regel entfernt. Assessment aller verbleibenden Tree-Kandidaten: DataPicker, InstanceHierarchyView, AccessRulesEditor, TreeNavigation, redmineTreeLogic -- alle SKIP (kein Entity-Tree-Paradigma). (c-work: `4-done/2026-05-formgenerator-tree-and-folder-recovery.md`)
|
||
- 2026-05-03 | docs | wiki | **Stage 5: FormGeneratorTree Wiki-Dokumentation.** `formgenerator.md`: neuer Abschnitt FormGeneratorTree (Provider-Interface, Features, Props, Verwendung, Tree-vs-Table-Vergleich). `architecture.md`: FolderTree-Referenzen durch FormGeneratorTree ersetzt. `TOPICS.md`: FormGenerator-Eintrag ergaenzt. Plan nach `4-done/` verschoben. (c-work: `4-done/2026-05-formgenerator-tree-and-folder-recovery.md`)
|
||
- 2026-05-03 | docs | wiki | **FormGeneratorTree Plan: Stage 3 deferred, Stage 0-2 abgeschlossen.** Stage 3.A/3.B (SourcesTab/ChatsTab-Refactor auf FormGeneratorTree) deferred -- domaen-spezifische Tree-Logik passt nicht sinnvoll auf generische TreeNodeProvider-Abstraktion. Plan-Status auf `done` gesetzt. Stage 2.C Checkliste aktualisiert mit allen 2.C-Fixes (405-Fix, typeMap, Refresh-Icon, confirm-Dialoge, FilesPage-Sync). (c-work: `4-done/2026-05-formgenerator-tree-and-folder-recovery.md`)
|
||
|
||
## 2026-05-02
|
||
|
||
- 2026-05-02 | fix | frontend-nyla | **Tree batch-delete: separate Ordner/Dateien-Aktionen.** `TreeBatchAction.typeFilter` in `types.ts`; `FormGeneratorTree.tsx` filtert `selectedIds` nach Typ und zeigt Counts pro Button. `FolderFileProvider.tsx` liefert zwei getrennte Batch-Aktionen (Ordner-Cascade-Delete vs. File-Delete/Batch-Delete). **FilesPage tree-table Sync wiederhergestellt:** `selectedFolderId` filtert Tabelle nach Ordner; File-Klick im Tree scrollt+highlighted die Tabellenzeile (2.5s auto-clear). (c-work: `1-plan/2026-05-formgenerator-tree-and-folder-recovery.md`)
|
||
|
||
## 2026-05-01
|
||
|
||
- 2026-05-01 | feat | gateway | Stage 1.B FormGenerator Folder RBAC: FileFolder in TABLE_NAMESPACE, 11 folder methods in interfaceDbManagement (CRUD, move, cascade-delete, scope, neutralize), 6 routes in routeDataFiles replacing 501 stubs
|
||
- 2026-05-01 | feat | frontend-nyla | **Stage 2.A + 2.B: FilesTab + FilesPage tree integration.** `FilesTab.tsx` rewritten from `FormGeneratorTable` to two `FormGeneratorTree` sections (Eigene/Geteilt mit mir) with drag-drop upload, refresh-by-key, and workflow-import on node click. `FilesPage.tsx` updated with split-view layout: 300px tree panel (left, own+shared trees) and `FormGeneratorTable` (right) with view-mode toggle (Tree-Sicht / Liste mit Gruppen); groupingConfig applied only in grouped mode; upload and refresh sync both tree and table. (c-work: `1-plan/2026-05-formgenerator-tree-and-folder-recovery.md`)
|
||
- 2026-05-01 | feat | gateway | **FormGeneratorTree Plan Stage 0 + 1.A:** Schema-Check-Skript `scripts/stage0_filefolder_schema_check.py`; `FileFolder` Pydantic + `FileItem.folderId` in `datamodelFiles.py`; Stub `getOwnFolderTree`/`getSharedFolderTree`; Routen `GET /api/files/folders/tree` (leere Liste) + Folder-Mutationen 501 bis Stage 1.B; `migrate_folders_to_groups.py` nach `modules/migrations/_archive/` mit README. (c-work: `1-plan/2026-05-formgenerator-tree-and-folder-recovery.md`)
|
||
- 2026-05-01 | docs | wiki | **Plan FormGeneratorTree: Stages packetisiert nach LLM.** Stages 1-3 in Sub-Packets aufgeteilt (1.A BE-Boilerplate / 1.B BE RBAC-Kern / 1.C FE Greenfield / 2.A FE-Boilerplate / 2.B FE-Komposition / 2.C manuelle Verifikation / 3.A Provider-Refactors / 3.B Tab-Umbau). Pro Packet: Modell-Hinweis (Opus 4.6 fuer Architektur/RBAC/Greenfield, Composer 2 Fast fuer Boilerplate/Recovery/Doku), Eingang/Lieferumfang/Abnahme. Eskalations-Regel ergaenzt. (c-work: `1-plan/2026-05-formgenerator-tree-and-folder-recovery.md`)
|
||
- 2026-05-01 | docs | wiki | **Plan FormGeneratorTree + Folder-Recovery konsolidiert.** Neuer FormGenerator-Familienteil `FormGeneratorTree` (Provider-Pattern, Cascade-Multiselect, DnD `application/x-poweron-tree-items`, Backend-Attribut-Resolution) zur Konsolidierung der ~8 parallelen Tree-Implementierungen. Recovery der Folder/File-Funktionen ueber **Modell A** (`FileFolder` + `FileItem.folderId` reaktivieren; DB-Schema unveraendert). RBAC-/Sichtbarkeitsmodell verbindlich: Default-Scope `personal`; Sharing nur ueber Owner-Scope-Patch; geteilte Objekte read-only fuer Nicht-Owner (analog `updateFile`/`deleteFile`); UI rendert in `FilesTab`/`FilesPage` **zwei getrennte Trees** (Eigene/CRUD + Geteilt mit mir/read-only); Files ohne sichtbaren Folder-Kontext fallen in den Root mit `contextOrphan`-Hint; Folder-Scope-Cascade auf Files = opt-in; Folder-Neutralize-Vererbung beim Drop = nein; Drag aus Geteilt in Eigenes = gesperrt. 22 konsolidierte Entscheidungen (D1-D22), keine offenen Backlog-Punkte mehr. UDB hat fix drei Tabs (Files, Sources, Chats) auf `FormGeneratorTree`. `FormGeneratorTable.groupingConfig` bleibt unveraendert. Kein `FormGeneratorChart` -- Berichte = **`FormGeneratorReport`** (Komponenten-Zeile in `b-reference/frontend-nyla/formgenerator.md`). 6 Stages (0 Schema-Sanity-Check optional, 1 Backend+Skeleton, 2 FilesTab/FilesPage Recovery, 3 SourcesTab/ChatsTab Konsolidierung, 4 optional weitere Trees, 5 Doku). (c-work: `1-plan/2026-05-formgenerator-tree-and-folder-recovery.md`)
|
||
|
||
## 2026-05-01
|
||
|
||
- 2026-05-01 | docs | wiki | **Plan D (AI Reports Pipeline) abgeschlossen -> `4-done/`.** Alle Checklisten-Items auf `[x]`, Testplan-Status auf `done`, Header `status: done`, `completed: 2026-05-01`. Wiki-Referenz-Updates (`ai-agent.md`, `workflow.md`, `neutralization.md`) als TODO fuer naechste Review-Runde markiert. (c-work: `4-done/2026-04-ai-reports-theming-and-pipeline.md`)
|
||
|
||
## 2026-04-30
|
||
|
||
- 2026-04-30 | refactor | gateway | **GraphEditor: Hidden DataRefs sichtbar gemacht fuer alle `ai.*` Nodes.** `frontendType: "hidden"` -> `"dataRef"` fuer `documentList` in `ai.prompt`, `ai.summarizeDocument`, `ai.translateDocument`, `ai.convertDocument` ([gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py](../../gateway/modules/features/graphicalEditor/nodeDefinitions/ai.py)). Zwei neue sichtbare Parameter auf `ai.prompt`: `context` (`dataRef`, beliebiger Upstream-Output, wird vom Action zu JSON serialisiert) + `documentTheme` (`select`, finance/legal/...). Action-Definition `ai.process` ([gateway/modules/workflows/methods/methodAi/methodAi.py](../../gateway/modules/workflows/methods/methodAi/methodAi.py)) deklariert `context` und `documentTheme` jetzt explizit, statt sie als undeklarierte Pass-Through-Keys mitlaufen zu lassen. Effekt: Trustee-Templates (Budget-Vergleich, KPI, Cashflow, Forecast, Year-end) zeigen ihre bisher unsichtbaren DataRef-Bindings (`trigger.payload.documentList`, `refresh.data.accountingData`) jetzt im Properties-Panel als gruene Bindungs-Boxen, der User kann sie via DataPicker veraendern. Kein Frontend-Code-Change noetig: bestehender `DataRefRenderer` + `DataPicker` rendern die JSON-DataRef-Werte direkt. Runtime unveraendert -- `resolveParameterReferences` verarbeitet `{"type":"ref",...}` wie bisher.
|
||
|
||
## 2026-04-29
|
||
|
||
- 2026-04-29 | test | gateway | Phase 7 AI-Reports: 19 unit tests for MD-to-JSON parser (inlineRuns), styleDefaults resolver, AiCallOptions allowedModels whitelist, inline-image paragraphs
|
||
- 2026-04-29 | feat | gateway, frontend-nyla | **D: AI Reports Pipeline komplett umgebaut.** Phase 1: MD->JSON konsolidiert (Inline-Run-Modell, `_parseInlineRuns`). Phase 2: Generisches Style-System (`styleDefaults.py`, `resolveStyle`, `renderDocument` style-Param). Phase 3: Alle 5 Renderer auf Style-Lookups + Inline-Runs umgestellt. Phase 4: Inline-Bilder in Paragraph/Tabelle/Liste. Phase 5: `allowedModels` in `AiCallOptions` + `_calculateEffectiveModels` im AI-Gate. Phase 5a: `WorkspaceUserSettings` Persistenz (GET/PUT Endpoint). Phase 5b: `modelMultiSelect` im FlowEditor + Workspace-Settings UI. Phase 6: Trustee-Templates mit `requireNeutralization` + Finance-Style-Hint. Phase 7: 19 Unit-Tests. (c-work: `1-plan/2026-04-ai-reports-theming-and-pipeline.md`)
|
||
- 2026-04-29 | feat | gateway, frontend-nyla | **B: Trustee Budget-Vergleich auf Excel umgestellt.** `mainTrustee.py` Template: `resultType: "xlsx"` + `documentTheme: "finance"` hart gesetzt. Prompt komplett refaktoriert: 1 Tabelle alle Konten, 1 Uebersichts-Chart (kein pro-Konto-Chart), Management-Summary. Frontend: Hinweistext "Excel-Bericht" im Budget-Tab ergaenzt. XLSX-Renderer (PNG-unter-Tabelle) verifiziert. (c-work: `3-validate/2026-04-trustee-budget-comparison-refactor.md`)
|
||
|
||
- 2026-04-29 | feat | gateway, frontend-nyla | **A2 Workflow-Run-Workspace + targetFeatureInstanceId implementiert.** Phase 1: `AutoWorkflow.targetFeatureInstanceId` (Pydantic + DB), createWorkflow-Fallback, Save-Validation (400 fuer non-template ohne targetId), Execute-RBAC-Check, `executeGraph` Placeholder-Substitution (`{{featureInstanceId}}`), Scheduler-Durchreichung, `_copyTemplateWorkflows` explizites Setzen, idempotente Boot-Backfill-Migration. Phase 2: FlowEditor CanvasHeader "Ziel-Instanz" Dropdown mit FeatureStore-Integration, Save/Load mit `targetFeatureInstanceId`. Phase 3: Neuer Backend-Endpoint `GET /api/automations/runs` + `GET /api/automations/runs/{runId}/detail` (RBAC via FeatureAccess), neuer "Workspace" Tab in AutomationsDashboardPage mit Run-Liste + Detail-View (Steps, Files, Download). Phase 4: TrusteeAnalyseView inline-Results durch "Im Workspace ansehen"-Link ersetzt, TrusteeAbschlussView Workspace-Link nach Completion ergaenzt. (c-work: `1-plan/2026-04-trustee-workflow-audit-and-run-workspace.md`)
|
||
|
||
- 2026-04-29 | docs | wiki | **Plan A2 finalisiert: Trustee Workflow-Audit + Generischer Workflow-Run-Workspace.** Cross-Check gegen Codebase (12 Punkte verifiziert, 4 Korrekturen eingearbeitet): `executeGraph` hat keine Placeholder-Substitution (muss neu gebaut werden), `_copyTemplateWorkflows` setzt `featureInstanceId` nicht im Payload (implizit via GE-Interface), `TrusteeAbschlussView` hat kein `resultText`/`resultDocuments` (nur status/summary), 7 Trustee-Templates statt 5 im Audit. Risiko-Sektion ergaenzt. (c-work: `1-plan/2026-04-trustee-workflow-audit-and-run-workspace.md`)
|
||
|
||
- 2026-04-29 | chore | gateway | **`gateway/scripts/` aufgeraeumt: 5 obsolete one-shot-Scripts archiviert + 1 Ad-hoc-Snippet geloescht.** Im Anschluss an den Bootstrap-Cleanup. Neuer Unter-Ordner `gateway/scripts/_archive/` mit eigenem README beschreibt Inhalt + Begruendung pro Datei. Verschoben (mit User-Bestaetigung pro File): `check_orphan_featureinstance.py` (hardcoded Vor-Ort-UUIDs), `script_db_cleanup_duplicate_roles.py` (`IS NULL`-Bug-Cleanup, Bug laengst gefixt), `migrate_async_to_sync.py` (one-shot `async def` -> `def` Codemod, Refactor durch), `i18n_rekey_plaintext_keys.py` (Frontend Klartext-Keys, Migration durch siehe `4-done/2026-04-ui-i18n-dynamic-language-sets.md`), `script_db_migrate_accessrules_objectkeys.py` (Navigation-API-Migration MIGRATION_MAP nur fuer trustee+realestate hardcoded, durch). Geloescht: `_listMandates.py` (26-Zeilen Ad-hoc-Debug-Snippet, jederzeit aus Git rekonstruierbar). Status danach: 21 aktive Scripts in `gateway/scripts/` (inkl. neues `script_db_audit_legacy_state.py`) + 5 archivierte Scripts. Dev-Boot 20:24:09 bestaetigt das aufgeraeumte interfaceBootstrap.py + Telemetrie-Hook laufen sauber durch (kein WARN, kein Restbestand, neue Code-Pfad-Line-Refs). (c-work: `4-done/2026-04-bootstrap-migrations-cleanup.md`)
|
||
|
||
- 2026-04-29 | refactor | gateway | **Bootstrap-Cleanup ausgefuehrt: 4 idempotente Migrations-Routinen + 1 Aggregations-Fallback aus dem Boot-Pfad entfernt.** Vor Removal Audit-Skript `gateway/scripts/script_db_audit_legacy_state.py` (NEU, lese-only, exit-code-gated) gegen Dev-DB gelaufen -> 4/5 GREEN sofort, Check 5 (RAG-Orphans) RED mit 20 verwaisten `FileContentIndex`-Rows ohne `mandateId`/`featureInstanceId` -> via `--purge-rag-orphans` bereinigt -> Re-Audit 5/5 GREEN. Dann entfernt aus `gateway/modules/interfaces/interfaceBootstrap.py`: `_migrateMandateDescriptionToLabel` (Funktion + Aufruf), `_migrateMandateNameLabelSlugRules` (Funktion + Aufruf, ~64 Zeilen), `initRootMandate`-Legacy-Block (`name="Root"`-Migration, 7 Zeilen; Funktion selbst bleibt), `_migrateAndDropSysAdminRole` (Funktion + Aufruf, ~95 Zeilen). In `interfaceDbKnowledge.py`: `aggregateMandateRagTotalBytes`-Fallback-Block (`try`/`except` mit FileItem-ID-Korrelation aus Management-DB, ~27 Zeilen) entfernt -- die Funktion bleibt aktiv, da sie 4 externe Caller hat. Ersatz: neuer Helper `gateway/modules/interfaces/_legacyMigrationTelemetry.py` mit 4 lese-only WARN-Checks (gleiche Logik wie Audit-Skript, prozessweit gecached) wird am Ende von `initBootstrap` einmalig aufgerufen -- falls je doch Restbestand auftauchen sollte (alter DB-Restore o.ae.), gibt's klare WARN-Logs mit Routine-Name + IDs. Tests `tests/unit/bootstrap/test_mandateNameMigration.py` (8 Tests) und `tests/unit/rbac/test_sysadmin_migration.py` (5 Tests) geloescht (referenzierten entfernte Funktionen, wuerden ImportError werfen). Smoke-Test: 17/17 verbliebene rbac+bootstrap-Tests GREEN, Imports aller drei Module GREEN. User-Statement zur Risk-Lage: "die codebase lief bereits auf int und main/prod" -- d.h. die idempotenten Migrations sind dort schon mehrfach durchgelaufen, das Removal-Risiko = 0; das Audit-Skript bleibt fuer pre-deploy-Gating. Plan urspruenglich in `1-plan/`, jetzt direkt in `4-done/2026-04-bootstrap-migrations-cleanup.md`. (c-work: `4-done/2026-04-bootstrap-migrations-cleanup.md`)
|
||
|
||
- 2026-04-29 | feat | frontend-nyla, gateway | **Generischer `frontendType: templateTextarea`** fuer Freitext mit `{{nodeId.path}}`-Variablen (DataPicker-Insert); `email.draftEmail.context` und `ai.prompt.aiPrompt` nutzen ihn statt reiner Textarea -- Aufloesung ausschliesslich via bestehendes `resolveParameterReferences` (kein Loop-Spezialcode im Executor). Loop-Preview-Enrichment + IfElse/AI-`responseData`-Picker bleiben. Unit-Test `test_legacy_string_template_loop_current_item_nested` in `test_automation2_graphUtils.py`.
|
||
- 2026-04-29 | docs | wiki | **6 neue UX-/Architektur-Plaene angelegt** in `wiki/c-work/1-plan/` aus Topics-TODO A-F: (A1+A2) Trustee-Workflow-Audit (alle 5 Reporting-Workflows GREEN auf Pick-not-Push) + generischer `WorkflowRunWorkspace`-Tab unter `/automations` als Single-Source-of-Truth fuer Workflow-Resultate, plus Pflicht-Binding `Workflow.featureInstanceId` (`2026-04-trustee-workflow-audit-and-run-workspace.md`); (B) Budget-Vergleich auf Excel-only mit eindeutigem 1-Tabelle-1-Chart-Prompt, Word-Pfad raus (`2026-04-trustee-budget-comparison-refactor.md`); (C) Inventar idempotenter Boot-Routinen, Removal-Plan fuer 5 b-Kandidaten via Audit-Skript + 30-Tage-Telemetrie (`2026-04-bootstrap-migrations-cleanup.md` -- noch am gleichen Tag umgesetzt, siehe Eintrag oben, jetzt unter `4-done/`); (D) Theme-System fuer AI-Reports pro Workflow (4 Themes standard/finance/marketing/presentation + Mandate-CI-Overlay), MD->JSON-Konsolidierung, Renderer-Refactor, Bilder-in-Tabellenzellen (`2026-04-ai-reports-theming-and-pipeline.md`); (E) ComCoach Greenfield-IA mit `TrainingModule`-Datenmodell (Rename `CoachingContext`) + 5-Tab-Struktur Dashboard/Assistent/Module/Session/Einstellungen, dossier=coaching-Doppelung weg, `?context=`-Bug fix (`2026-04-comcoach-greenfield-ia.md`); (F) TeamsBot Greenfield-IA analog mit neuer `MeetingModule`-Entity + 5-Tab-Struktur und 4 Live-Update-Fixes (SSE-Reconnect-Hook, agentRun-Status-Bubble, stats-Karten, adaptives Dashboard-Polling) (`2026-04-teamsbot-greenfield-ia-and-live-update.md`). Empfohlene Reihenfolge der Bauphase: C -> A2-Phase-1 (FeatureInstance-Pflicht) -> A2-Phase-2/3 (Workspace) -> B -> D -> E/F parallel. (c-work: 6 neue Dateien in `1-plan/`)
|
||
|
||
- 2026-04-29 | fix | gateway | **`checkForDuplicateFile` macht jetzt einen RBAC-Cross-Check und liefert keine "Geister-Duplicate" mehr aus.** Ursache des `File with ID ... not found`-Fehlers in `downloadFromDataSource` direkt nach `Duplicate detected for user ...`: `interfaceDbComponent` wird ueber `serviceHub` ohne `featureInstanceId` initialisiert, `checkForDuplicateFile` faellt deshalb auf den `mandateId`-Filter zurueck und benutzte `db.getRecordset` (kein RBAC) -- damit konnte er ein File aus einer FREMDEN featureInstance returnen. Der nachfolgende `updateFile`-Aufruf prallte dann am RBAC-gefilterten `getFile` ab und crashte den ganzen Tool-Call. Sauberer Fix an der Wurzel: nach dem Recordset-Treffer zwingend `self.getFile(fileId)` als RBAC-Cross-Check; wenn `None`, gilt als kein Duplicate fuer den aktuellen Scope und der Caller (`saveUploadedFile`/`createFile`) erstellt eine frische per-Scope-Kopie. Damit entfaellt jeglicher Workaround in `updateFile` (die in der Vorgaenger-Session gebaute Try/Except-Schleife wurde gestern bereits ausgebaut, weil sie in einer Sackgasse stand). Folge: identische Files koennen pro Mandate mehrfach existieren -- eines pro featureInstance -- was gewollt ist, da sie pro Scope eigene Folder-/Tag-/Neutralize-Metadaten brauchen. Symptom-Doku in `wiki/b-reference/gateway/agent-file-bridge.md` (Section "Ghost-Duplicate-Fix"). (c-work: Begleitfix zum Agent-File-Bridge-Build vom selben Tag)
|
||
|
||
- 2026-04-29 | fix | gateway | **Agent-Tools binden jetzt jede produzierte Datei als ChatDocument an den aktiven Workflow -- damit funktioniert der `documentList`-Resolver fuer Agent-Outputs.** Bisher erzeugten `downloadFromDataSource`, `writeFile mode=create`, `renderDocument`, `generateImage` und `createChart` zwar eine `FileItem` (via `saveUploadedFile`/`saveGeneratedFile`), liessen den Workflow-Document-Graph aber unberuehrt -- statt eines `ChatDocument` floss nur ein `sideEvent fileCreated` an die UI. Folge: `getChatDocumentsFromDocumentList` (und damit `ai_summarizeDocument` / `ai_process` / `context_extractContent` / `context_neutralizeData`) konnte die FileItem-IDs nicht aufloesen, weil der Resolver ausschliesslich `workflow.messages[*].documents[*].id` matcht. Symptom war "Building structure prompt with 0 valid ContentParts" und entsprechend leere Summaries direkt nach einem Agent-Download. Loesung: zentraler Helper `_attachFileAsChatDocument(services, fileItem, label, userMessage)` in `coreTools/_helpers.py`, der intern eine ChatMessage (Rolle `assistant`, Status `step`, generierter `documentsLabel`) inklusive einem ChatDocument (mit `roundNumber`/`taskNumber`/`actionNumber` aus dem aktiven Workflow) via `chatService.storeMessageWithDocuments` persistiert -- exakt das Pattern, das `workflowProcessor.persistTaskResult` und `methodTrustee.extractFromFiles` schon laenger benutzen. Helper wird jetzt aus allen fuenf File-erzeugenden Agent-Tools aufgerufen; der ToolResult-Text traegt einheitlich beide IDs (`documentList ref: docItem:<chatDocId>` fuer AI-Tools, `file id: <fileId>` fuer `readFile`/Embeds). Tool-Descriptions + `conversationManager.buildSystemPrompt` ergaenzt um die explizite Anweisung "use docItem:<id> in documentList, NOT the file id, NOT a `{"documents":[...]}` wrapper". Zusatzlich: `mainServiceAgent.runAgent` propagiert das Workflow-Object jetzt in alle Service-Contexts (`chat._context.workflow` etc.) -- bisher tat das nur `workflowManager._propagateWorkflowToContext`, weshalb der Agent ueber die Workspace-Route ohne aktiven Workflow-Context lief und `chatService._workflow` `None` war. Folge: der Helper konnte ohne diesen Propagations-Fix nie greifen. Die in der vorhergehenden Session eingebaute RBAC-tolerante `updateFile`-Try/Except-Schleife in `_downloadFromDataSource` ist jetzt obsolet und wieder ausgebaut -- mit korrektem ChatDocument-Bind kommt der `featureInstanceId` ueber den Workflow-Pfad und die Duplicate-File-RBAC-Probleme verschwinden an der Wurzel. Pattern-Doc neu unter `wiki/b-reference/gateway/agent-file-bridge.md`. (c-work: kein dedizierter Eintrag, kritischer Fix on top der documentList-Coercer-Aenderung)
|
||
|
||
- 2026-04-29 | fix | gateway | **`ai_process` / `context_extractContent` / `context_neutralizeData` akzeptieren jetzt LLM-typische Dict-Wrapper-Formate fuer `documentList`.** Der Agent serialisiert `documentList` regelmaessig als `{"documents":[{"id":"<uuid>","name":"<file>"}]}` (Folge der `type=DocumentList`-Schema-Definition, das LLMs als generic Object lesen). Bisher fielen alle drei Actions in den `else: Invalid documentList type: <class 'dict'>`-Branch und liefen mit leerer Document-Liste weiter -- der Folder-Summarize-Workflow produzierte dann eine Zusammenfassung "ueber 0 Dokumente". Loesung: zentraler Helper `coerceDocumentReferenceList(value)` in `datamodelDocref.py` der ALLE praktisch vorkommenden Shapes parst -- `None`, `str`, `DocumentReferenceList`, `list[str]`, `list[dict mit id/documentId/label]`, `dict mit "documents"/"references"/"items"/"files"-Wrapper`, und `dict mit id/documentId` (single item). Alle vier Aufrufstellen (process.py + extractContent.py + neutralizeData.py x2) auf den Helper umgezogen; die Inline-`ActionDocument`-Sonderbehandlung in `process.py` bleibt davor. Helper wirft NIE -- gibt im worst case eine leere Liste mit WARN-Log zurueck, der Caller entscheidet ob das fatal ist. (c-work: kein dedizierter Eintrag, Begleitfix zum Infomaniak-Test)
|
||
|
||
- 2026-04-29 | fix | gateway | **`listFiles`-Tool: dict-vs-attribute-Mismatch in `mainServiceChat.listFiles` behoben.** `interfaceDbComponent.getAllFiles()` returnt seit dem Pydantic-Refactor `List[dict]` (jeder Eintrag ist ein `FileItem.model_dump()` mit Label-Spalten), aber `mainServiceChat.listFiles()` griff weiter mit `fileItem.fileName` / `fileItem.id` zu (Pydantic-Style) -- daher `'dict' object has no attribute 'fileName'` und `'dict' object has no attribute 'id'` aus dem `listFiles`-Agent-Tool. Komplette Methode auf `.get(...)` umgestellt; Type-Annotation in `getAllFiles` (`Union[List[FileItem], PaginatedResult]`) ist immer noch irrefuehrend -- das ist ein orthogonaler Tech-Debt-Punkt, kein Blocker. (c-work: kein dedizierter Eintrag)
|
||
|
||
- 2026-04-29 | fix | gateway | **kDrive: Single-File-DataSources funktionieren jetzt sauber (Browse + Download).** Wenn der User eine einzelne Datei als DataSource anhaengt (z.B. `path=/2980592/12`, wo `12` die kDrive-File-ID einer `.html`-Datei ist), brachten browseDataSource und downloadFromDataSource bisher Folgefehler: (1) Browse rief blind `/2/drive/{driveId}/files/{fileId}/files` auf -> kDrive antwortet `400 destination_not_a_directory` -> Adapter loggte das als Empty-Folder -> Agent dachte "leerer Ordner" und konstruierte einen Pseudo-Pfad `/2980592/12/platform-overview.html`. (2) `download(/2980592/12/platform-overview.html)` nahm dann `segments[-1] = "platform-overview.html"` als File-ID -> `/2/drive/2980592/files/platform-overview.html` -> `404 method_not_found`. Saubere Loesung: (a) Neuer Helper `_lastNumericSegment(segments)` zieht aus einem Pfad immer die letzte rein-numerische ID -- kDrive-IDs sind grundsaetzlich Integer; haengt der Agent einen Filename dran, wird dieser ignoriert. (b) `KdriveAdapter.browse` holt vor dem Children-Listing die Item-Metadata (`/files/{id}`); bei `type=file` wird ein Single-Entry mit Name/Size/MimeType/Modified zurueckgegeben statt children aufzurufen. (c) `KdriveAdapter.download` benutzt denselben Helper + denselben Metadata-Fetch (jetzt extrahiert in `_fetchItemMeta`). Folge: Single-File-Quellen sind jetzt browse-/downloadbar; Folder-Quellen verhalten sich unveraendert. (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
- 2026-04-29 | fix | gateway | **downloadFromDataSource: Metadata-Updates auf Duplicate-Files werfen den Tool-Call nicht mehr aus dem Tritt.** `saveUploadedFile` returnt bei Hash+Name-Match das EXISTIERENDE FileItem -- das kann aber in einem anderen `featureInstanceId`/Folder-Scope leben als die aktuelle Anfrage. Die nachfolgenden `updateFile`-Aufrufe (`featureInstanceId`/`neutralize`/`folderId`) prallten dann am RBAC-gefilterten `getFile` ab und warfen `File with ID ... not found` -- obwohl der Download korrekt war (File ist in der DB, addressierbar via `fileItem.id`). Fix: die drei Metadata-Updates laufen jetzt in einer Schleife mit individuellem Try/Except und WARN-Log; der Tool-Call meldet weiter Success mit der File-ID. (c-work: kein dedizierter Eintrag, Folge des kDrive-Fixes oben)
|
||
|
||
- 2026-04-29 | fix | gateway | **Agent-Tools: `kdriveFolder`/`calendarFolder`/`contactFolder` werden jetzt korrekt auf die Connector-Services `kdrive`/`calendar`/`contact` gemappt.** Der `SourcesTab.tsx` schreibt diese FE-seitigen Source-Type-Literals beim Anhaengen einer Datenquelle ans `DataSource`-Record; `_dataSourceTools._resolveDataSource` (und parallel `routeFeatureWorkspace._SOURCE_TYPE_TO_SERVICE`) hatten aber nur Eintraege fuer SharePoint/OneDrive/Drive/Outlook/Gmail/FTP/ClickUp -- daher kamen `Service 'kdriveFolder' not available. Options: ['kdrive', 'calendar', 'contact']` aus `browseDataSource`/`searchDataSource`/`downloadFromDataSource` sobald der Agent eine Infomaniak/Calendar/Contact-Quelle anfasste. Beide Maps um die drei Eintraege erweitert; `DataSource.sourceType`-Field-Description ergaenzt; Inline-Kommentar im `_dataSourceTools.py` warnt vor Drift gegenueber FE und `_SERVICE_MAP`. Bestehende `DataSource`-Records funktionieren ohne Migration (das `sourceType`-Literal bleibt gleich). (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
- 2026-04-29 | fix | gateway | **kDrive-Download folgt jetzt dem 302-Redirect.** Der Endpoint `/2/drive/{driveId}/files/{fileId}/download` antwortet bandwidth-bedingt mit `302 Found -> presigned CDN URL` (Standard fuer File-Bytes); unser `_infomaniakDownload`-Helper hatte aber `allow_redirects=False` (kopiert vom `_infomaniakGet`-Helper, wo das wichtig ist um nicht versehentlich auf OAuth-Login-Pages zu landen). Folge: jeder kDrive-Download lieferte `None` -> `Tool result: downloadFromDataSource FAILED -> Download returned empty` im Agent-Log. Fix: nur fuer Downloads `allow_redirects=True`, mit Doc-String der erklaert warum (gleiches Pattern bei Calendar/Contacts-Export-Endpoints, gleicher Host = Authorization-Header bleibt erhalten). Listing/Metadata-Calls bleiben weiter `allow_redirects=False`, damit nicht-PAT-faehige Routes als `302` sichtbar bleiben statt eine HTML-Login-Page zu liefern. (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
- 2026-04-29 | fix | gateway | **Anthropic-Plugin: `temperature` wird fuer Extended-Thinking-Modelle (Claude 4.7 Opus, spaeter 4.7 Sonnet/Haiku, alle 5.x) nicht mehr gesendet.** Anthropic antwortet seit dem 4.7-Release mit `400 invalid_request_error: 'temperature' is deprecated for this model.` -- nur der modellinterne Default ist akzeptiert. Analog zum gestrigen `_supportsCustomTemperature`-Helper im OpenAI-Plugin (gpt-5/o-Serie) jetzt auch hier: Praefix-Match auf `claude-opus-4-7`/`-sonnet-4-7`/`-haiku-4-7` und `claude-*-5*` -> `temperature` weglassen. Wirkt in allen drei Anthropic-Pfaden (`callAiBasic`, `callAiBasicStream`, `callAiImage`). Aeltere Modelle (Claude 4.5/4.6) bekommen `temperature` weiter wie gehabt. (c-work: kein dedizierter c-work-Eintrag -- analog OpenAI gpt-5-Fix vom 2026-04-28)
|
||
|
||
- 2026-04-29 | fix | gateway, frontend-nyla, wiki | **Infomaniak-Connector: kDrive findet jetzt auch Drives, in denen der User nur `role: user` ist (statt `account_admin`).** Live-Beweis vom User mit Files in `https://ksuite.infomaniak.com/1696919/kdrive/app/drive/2980592/files/11`: das Drive haengt korrekt an account_id 1696919, aber `/2/drive?account_id=1696919` antwortet trotzdem `200 [] -- empty`, weil dieser Endpoint zur Drive-Manager-Admin-Sicht gehoert (filtered auf `account_admin: true`) und nicht zur Endbenutzer-Sicht. Direkt-Aufrufe wie `/2/drive/2980592/files` funktionieren fuer denselben User mit `role: user` einwandfrei (PDF "Start_with_kDrive.pdf", Ordner "Nyla-Analysen" und "Onboarding" alle sichtbar). Root-Endpoint gefunden: `GET /2/drive/init?with=drives` -- enumeriert ALLE Drives die der User sehen kann, unabhaengig von der Admin-Rolle, braucht NUR den `drive`-Scope (verifiziert mit PAT der `accounts`-Scope explizit nicht hat). Implementierung: (a) Neuer Helper `listAccessibleDrives(token) -> List[dict]` im `connectorInfomaniak.py` -- ein einzelner `/2/drive/init?with=drives`-Call, raised `InfomaniakIdentityError` mit Scope-Message wenn `drive`-Scope fehlt. (b) `KdriveAdapter` haelt jetzt `_drives: Optional[List[Dict]]` (statt `_accountId`/`_accountIds`); `_listDrives()` mappt direkt aus dem gecachten Init-Response. (c) `submit_infomaniak_token` validiert in zwei Schritten: `listAccessibleDrives` (`drive`-Scope) und `resolveOwnerIdentity` (`workspace:calendar`/`workspace:contact`-Scope). (d) Der zwischenzeitliche `resolveAccessibleAccountIds()` + `accounts`-Scope-Workaround wieder ENTFERNT (war eine Sackgasse: `/1/accounts` listet Manager-Organizations, nicht Drive-Accounts). (e) `_probeDriveScope()`-httpx-Helper im Submit-Route entfernt; `httpx`-Import + `INFOMANIAK_API_BASE`-Konstante raus. Frontend: PAT-Setup-Modal wieder auf 4 Pflicht-Scopes zurueck (`accounts` raus). Doku: Status-Tabelle, Validation-Section und "How the kDrive adapter discovers your drives" komplett auf den `init`-Endpoint umgeschrieben. **Bestehende Connections sollten ohne User-Aktion sofort funktionieren -- es ist kein neuer Scope und keine Token-Rotation noetig, der Adapter wechselt nur den Discovery-Endpoint.** (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
- 2026-04-29 | fix | gateway | **Infomaniak-Connector: Calendar-Events und Contacts-Download auf die echten PAT-faehigen Pfade gezogen.** Live-Tests gegen die Vendor-API zeigten zwei Pfad-Mismatches im gestrigen Build: (1) Calendar-Events: der nested Route `/api/pim/calendar/{id}/event` 302t zur OAuth-Login-Seite (also nicht PAT-faehig); korrekter Endpoint ist `/api/pim/event?calendar_id={id}&from=YYYY-MM-DD HH:MM:SS&to=...` mit Pflicht-Range max 3 Monate (Vendor-Constraint `range_must_be_lower_than_3_months`) -- Adapter waehlt jetzt fix 90-Tage-Window (heute -30 / +60), URL-Encoding via `urllib.parse.quote`. Event-Detail und `.ics`-Export laufen ueber `/api/pim/event/{eventId}` und `.../export` (also ohne calendar-Praefix). (2) Contacts-Download: `/addressbook/{book}/contact/{id}` antwortet mit `500 unexpected_error` und `.../export` 302t zu OAuth -- beide Detail-Endpoints sind also nicht PAT-faehig. Listing dagegen funktioniert, liefert aber per Default nur Stammdaten -- ohne `with=emails,phones,addresses,details` kommen Email/Phone/Adresse leer. Loesung: ContactAdapter holt das Listing mit dem `with`-Param und rendert die `.vcf` selbst via `_renderInfomaniakVcard()` (vCard 3.0, escaped, mit N/FN/ORG/EMAIL/TEL/ADR/URL/NOTE) -- konsistent mit MSFT/Google-Adapter, die ihre `.vcf`s ebenfalls selbst synthetisieren. Plus: Helper `_safeFileName` aus dem Calendar-Adapter zu modullokal hochgezogen, von beiden Adaptern genutzt; ungenutzte `import re`/`import json`-Inline-Imports raus. **kDrive-Adapter ist im Live-Test korrekt:** `/2/drive?account_id=1696919` antwortet 200 mit leerem Array fuer den Test-Account (kein kDrive-Produkt aktiviert). (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
## 2026-04-28
|
||
|
||
- 2026-04-28 | refactor | gateway | **Infomaniak-Connector: `account_id` ist Adapter-State, nicht Connection-State.** Symptom im Log: `Infomaniak GET https://api.infomaniak.com/2/drive?account_id=pat-XXXXXXXX -> 422 validation_rule_integer "The account id must be an integer."`. Root cause: der `KdriveAdapter` las `connection.externalId` als `account_id`-Quelle, und bei kaputten Submits konnte dort der Token-Fingerprint ("pat-59ee48d9") statt der `account_id` stehen. Saubere Loesung statt Fingerprint-Migration: (a) Neuer modullokaler Helper `resolveOwnerIdentity(token) -> InfomaniakOwnerIdentity` im `connectorInfomaniak.py` -- versucht PIM Calendar (`workspace:calendar`-Scope), faellt auf PIM Contacts (`workspace:contact`-Scope) zurueck, raised `InfomaniakIdentityError` wenn keine Owner-Records gefunden. (b) `KdriveAdapter` hat keinen `accountId`-Konstruktor-Parameter mehr, sondern resolvt zur Laufzeit ueber `_ensureAccountId()` (gecached auf der Adapter-Instanz). Damit ist der Adapter self-contained und liest **nichts** mehr aus der Connection -- `externalId` ist reiner UI-State. (c) `submit_infomaniak_token` ruft denselben `resolveOwnerIdentity()` als Pre-Flight-Check, dann `/2/drive?account_id={resolved}` als sauberer 200-Probe. Der frueher noetige `_probeScope`-422-Tolerance-Hack ist entfallen. (d) `getServiceAdapter` hat keine kDrive-Sonderbehandlung mehr; alle drei Adapter werden uniform mit `accessToken` konstruiert. (e) `_PIM_PREFIX` ist auf Modul-Ebene definiert; CalendarAdapter und ContactAdapter haben keine Klassen-Konstanten mehr. **Konsequenz: jede existierende Infomaniak-Connection arbeitet ohne User-Aktion sofort wieder, auch wenn `externalId` historisch einen Fingerprint enthaelt -- der Adapter zieht die `account_id` deterministisch aus der API.** Setup-Guide um Architektur-Abschnitt erweitert. (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
- 2026-04-28 | feat | gateway, frontend-nyla | **MSFT- und Google-Connector: CalendarAdapter + ContactsAdapter neu, plus Reconnect-Button.** Nachdem Infomaniak heute Calendar/Contacts kann, ziehen MSFT und Google nach. Backend: (a) `oauthProviderConfig.googleDataScopes` um `calendar.readonly` + `contacts.readonly` erweitert, `msftDataScopes` um `Calendars.Read` + `Contacts.Read`. (b) `connectorMsft.CalendarAdapter` (Graph: `me/calendars`, `me/calendars/{id}/events?$top&$orderby=start/dateTime desc`, Pagination via `@odata.nextLink`, `.ics`-Download als selbstgebautes RFC-5545 VCALENDAR/VEVENT da Graph keinen `$value`-Endpoint fuer Events kennt; `$search` fuer query). (c) `connectorMsft.ContactsAdapter` (Graph: `me/contactFolders` + virtueller `default`-Ordner fuer `me/contacts`, `me/contactFolders/{id}/contacts?$orderby=displayName`, `.vcf` als vCard-3.0 selbstgebaut mit N/FN/ORG/TITLE/EMAIL/TEL/ADR/NOTE). Helper `_eventToIcs`, `_contactToVcard`, `_safeFileName`, `_personLabel` plus `_icsEscape`/`_icsDateTime`. (d) `connectorGoogle.CalendarAdapter` (Calendar v3: `users/me/calendarList`, `calendars/{id}/events?singleEvents=true&orderBy=startTime`, `.ics` aus Event-Detail). (e) `connectorGoogle.ContactsAdapter` (People API: `contactGroups` + virtueller `all`-Folder ueber `people/me/connections`, fuer Gruppen `people:batchGet?resourceNames=...`, Search via `people:searchContacts`, `.vcf` aus `personFields=names,emailAddresses,phoneNumbers,organizations,addresses,biographies`). (f) `_SERVICE_MAP` von beiden Connectoren um `"calendar"`/`"contact"` ergaenzt; `routeFeatureWorkspace` und `routeFeatureGraphicalEditor` Service-Label-/Icon-Maps um `kdrive`, `calendar`, `contact` ergaenzt, damit die UDB sinnvolle Anzeigen macht. (g) **Reconnect-Flow**: `POST /api/connections/{id}/connect` akzeptiert optionalen Body `{"reauth": true}` und haengt `&reauth=1` an die Auth-URL. `routeSecurityMsft.auth_connect` setzt bei `reauth=1` `prompt=consent` (sonst select_account/login), `routeSecurityGoogle.auth_connect` droppt bei `reauth=1` `include_granted_scopes=true` damit Google strikt fuer die aktuelle Scope-Liste neu signiert (sonst werden neue Scopes still uebersprungen). Frontend: `connectionApi.connectService(id, reauth?)` -> POST mit Body, `useConnections.connectWithPopup(id, reauth?)` reicht durch, `ConnectionsPage` zeigt fuer aktive MSFT/Google/ClickUp-Connections einen `FaSyncAlt`-Button "Erneut verbinden (neue Scopes erteilen)" mit eigenem Loading-Set. Bestehende Connections muessen einmal reconnected werden, damit Calendar/Contacts in der UDB auftauchen. (c-work: `c-work/2-build/2026-04-msft-google-calendar-contacts.md`)
|
||
|
||
- 2026-04-28 | fix | gateway | **OpenAI-Connector: `temperature` fuer GPT-5.x / o-Serie aus dem Payload nehmen.** Symptom im Log: jede AI-Anfrage failt mit HTTP 400 `Unsupported value: 'temperature' does not support 0.2 with this model. Only the default (1) value is supported.`, der Failover spricht 14 Modelle durch und schreibt `Recorded failure for gpt-5.5, cooldown 60.0s`. Root cause: die GPT-5-Familie (gpt-5, gpt-5.4*, gpt-5.5*) und die o-Serie (o1/o3/o4) sind Reasoning-Modelle; OpenAI akzeptiert dort -- analog zur `max_tokens` -> `max_completion_tokens`-Restriction -- nur den Default (`1`). Wir senden aber unverhandelt `temperature=0.2` aus jedem `AiModel`-Eintrag. Fix: Helper `_supportsCustomTemperature(modelName)` und in `callAiBasic`/`callAiBasicStream`/`callAiImage` den Key nur conditional ins Payload aufnehmen (Modellnamen mit Praefix `gpt-5`, `o1`, `o3`, `o4` lassen ihn weg). Der vom User im UI gesetzte Override ueber `AiCallOptions.temperature` wird auf den nicht unterstuetzten Modellen still verworfen statt einen 400 zu erzwingen. Tests: `tests/unit/aicore/test_aicorePluginOpenai_temperature.py` (18 Tests, parametrisiert ueber Legacy-Modelle vs. Reasoning-Familie). Suite gesamt: 530 passed.
|
||
|
||
- 2026-04-28 | docs | wiki | **Infomaniak-Connector: Mail-Adapter formal als "blocked by vendor" markiert.** Erschoepfende Pfad-Tests am 2026-04-28 zeigen: alle 7 plausiblen Mail-Endpoints sind heute nicht PAT-faehig. `api.infomaniak.com/{1,2}/mail` -> 404 nginx (existiert nicht); `mail.infomaniak.com/api/mail[?account_id=...]`, `/api/pim/mail`, `/api/pim/mailbox`, `/api/pim/folder` -> 302 zu `login.infomaniak.com/authorize` (nur OAuth-Web-Session, Bearer-PAT wird abgelehnt); `mail.infomaniak.com/api/mail/?account_id=...` -> 301 zu `http://mail.infomaniak.com:5000` (interner Cyrus-IMAP-Port, von aussen nicht erreichbar). Der `workspace:mail`-Scope bleibt im PAT-Standard-Setup, damit der MailAdapter spaeter ohne Token-Rotation freigeschaltet werden kann; Setup-Guide und c-work-Doku zementieren den Befund. Kein Code-Change. (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
- 2026-04-28 | feat | gateway, frontend-nyla | **Infomaniak-Connector: ContactAdapter neu.** Nachfolge-Tests gegen die Contacts-PIM-API zeigten, dass `https://contacts.infomaniak.com/api/pim/addressbook` (Singular!) mit dem PAT-Scope `workspace:contact` und Bearer-Auth `200` + JSON liefert -- gleiche Antwort-Struktur wie Calendar (`addressbooks[].id/name/account_id/...`). Die Plural- und `/contact*`-Pfade (`/api/pim/contacts`, `/api/pim/contact/addressbook`) sind weiterhin OAuth-only bzw. 404. Neuer `ContactAdapter` 1:1 analog `CalendarAdapter`: `browse("/")` -> Adressbuecher, `browse("/{bookId}")` -> Kontakte (Display-Name, Email, Phone, Organization in Metadata), `download("/{bookId}/{contactId}")` -> `.vcf` via `/contact/{id}/export` mit JSON-Fallback, `search()` als kostenguenstiger Client-Filter. Geteilte Organisations-Adressbuecher (`name=""`, `is_dynamic_organisation_member_directory=true`) bekommen "Organisation" als Anzeigename, sonst waere der Tree-Knoten leer. Neue Konstante `_CONTACTS_BASE`, `ContactAdapter` in `_SERVICE_MAP` registriert. Frontend: `SourcesTab` kennt `contact`-Icon (👤), -Color und Mapping; PAT-Modal nennt Contacts als heute aktiv (Mail bleibt "in Vorbereitung"). Setup-Guide: Status-Tabelle, UDB-Verifikations-Liste und Validation-Beschreibung aktualisiert. (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
- 2026-04-28 | feat | gateway, frontend-nyla | **Infomaniak-Connector: kDrive PAT-Fix + Calendar-Adapter neu.** Nach den ersten echten PAT-Test-Calls aufgeraeumt: (a) `/2/drive` braucht ein `account_id`-Query-Arg, sonst `422 account_id required`. Fix: `account_id` einmalig beim Token-Submit aus dem Calendar-PIM-Endpoint (`https://calendar.infomaniak.com/api/pim/calendar` -- liefert `account_id`, `user_id`, Anzeigename) ziehen, in `UserConnection.externalId` persistieren und ueber `InfomaniakConnector.getServiceAdapter` als Konstruktor-Parameter in den `KdriveAdapter` injizieren. `/1/profile` (haette `user_info`-Scope verlangt) und `/1/mail` (existiert nicht: 404 nginx) raus aus den Probes. (b) `_probeScope` toleriert jetzt 4xx ausser 401/403 (z.B. 422 `validation_failed`) als "Scope ist da, Endpoint braucht nur weitere Args". (c) Neuer `CalendarAdapter` (`browse` -> Calendars/Events ueber `calendar.infomaniak.com/api/pim/calendar`, `download` -> `.ics` via `/event/{id}/export`, JSON-Fallback). `_infomaniakGet` und `_infomaniakDownload` akzeptieren ein optionales `baseUrl`, sodass Calendar gegen `calendar.infomaniak.com` und kDrive gegen `api.infomaniak.com` laufen koennen. (d) `MailAdapter` aus `_SERVICE_MAP` entfernt: `mail.infomaniak.com/api/mail` redirected mit 302 zu `login.infomaniak.com/authorize`, akzeptiert also keine PATs; gleiches gilt fuer `contacts.infomaniak.com/api/pim/contact`. Beide Scopes werden weiterhin in `grantedScopes` gespeichert, damit kuenftige Adapter ohne Token-Rotation aufgeschaltet werden koennen. (e) Frontend: `SourcesTab` kennt `calendar`-Icon, -Color und `_SERVICE_TO_SOURCE_TYPE`-Mapping; PAT-Modal in `ConnectionsPage` zeigt Calendar als zweiten aktiven Service, Mail/Contact als "in Vorbereitung, Scope schon mitnehmen". (f) Setup-Guide aktualisiert (Status-Tabelle + Validation-Beschreibung). (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
- 2026-04-28 | refactor | gateway, frontend-nyla | **Infomaniak-Connector: OAuth -> Personal Access Token.** Infomaniaks `login.infomaniak.com/authorize` akzeptiert nur Identity-Scopes (`openid`, `profile`, `email`, `phone`); Versuche mit `kdrive`/`mail`-Scopes quittieren mit `error=invalid_scope`. Datenzugriff geht ausschliesslich ueber manuell im Manager erstellte PATs. Umbau: (a) Backend `routeSecurityInfomaniak` komplett neu -- ein Endpoint `POST /api/infomaniak/connections/{id}/token`, validiert PAT via `GET https://api.infomaniak.com/1/profile`, persistiert Bearer mit 10-Jahres-Horizont (analog ClickUp), entfernt OAuth-Connect/Callback-Pfade. (b) `tokenManager.refreshInfomaniakToken` + `tokenRefreshService._refresh_infomaniak_token` entfernt, AuthAuthority.INFOMANIAK aus den Background-Refresh-Filtern raus -- PATs sind langlebig. (c) `oauthProviderConfig.infomaniakDataScopes` + `infomaniakDataScopesForRefresh` entfernt. (d) `routeDataConnections.connect_service` antwortet bei Infomaniak jetzt mit 400 + Hinweis auf den PAT-Endpoint. (e) Env-Cleanup: `Service_INFOMANIAK_DATA_CLIENT_ID/SECRET` und `Service_INFOMANIAK_OAUTH_REDIRECT_URI` aus `.env` + `env_dev/int/prod[_forgejo].env` raus. (f) Frontend: `useConnections.createInfomaniakConnectionAndAuth` (OAuth-Popup) ersetzt durch `createInfomaniakConnection` + `submitInfomaniakToken`; `ConnectionsPage` zeigt PAT-Modal mit Schritt-Anleitung + Deeplink zu `manager.infomaniak.com/v3/ng/accounts/token/list`; Cancel rollt PENDING-Connection per DELETE zurueck. (g) Doku: `wiki/d-guides/infomaniak-oauth-setup.md` geloescht, `wiki/d-guides/infomaniak-token-setup.md` neu. (c-work: `c-work/2-build/2026-04-infomaniak-connector.md`)
|
||
|
||
- 2026-04-28 | refactor | gateway | **Cleanup der zwei tieferliegenden Defensive-Programming-Schichten, die den Trustee-Bug (vorheriger Eintrag) ueberhaupt erst durchgelassen haben.**
|
||
- **(1) DB-Connector: fail-loud statt swallow.** `connectorDbPostgre.getRecord/getRecordset/getRecordsetPaginated/getDistinctColumnValues/_loadTable/semanticSearch` haben bisher jede Exception per `except Exception → log → return []` (bzw. `None`/leeres Pagination-Resultat) verschluckt. Folge: jeder echte DB-Fehler (Postgres-Adapt, UndefinedTable, UndefinedColumn, OperationalError, etc.) wurde fuer den Caller ununterscheidbar von "0 Rows" -- darauf basierten misleading downstream Errors wie "No active accounting configuration found". Neu: typisierte Exception `DatabaseQueryError(table, message, original)` plus zentrales `_rollbackQuietly(connection)` (Postgres setzt die Connection in Error-State nach jedem fehlgeschlagenen Statement). Empty Result Sets liefern weiterhin `[]`/`None`/`{items: [], totalItems: 0, totalPages: 0}` (= Normalpfad ueber `cursor.fetchall()/fetchone()`), aber jede Exception innerhalb des Query-Pfads wird hochgereicht. Tests: `tests/unit/connectors/test_connectorDbPostgre_failLoud.py` (9 Tests).
|
||
- **(2) Action-Parameter: zentrale Validierung statt impliziter Kontrakt.** Workflow-Actions haben `parameters: Dict[str, Any]` ohne Schema-Enforcement bekommen; die Aktionsimplementationen mussten ad-hoc `isinstance`-Branches haben oder mit Postgres-Errors abstuerzen (siehe Trustee-Bug). Neues Modul `gateway/modules/workflows/processing/shared/parameterValidation.py` mit `InvalidActionParameterError(ValueError)` + `validateAndCoerceParameters(actionDef, parameters)`. Zentral aufgerufen in `ActionExecutor.executeAction` -- gilt fuer alle Aufrufpfade (Agent, Workflow-Graph, REST). Logik:
|
||
1. Required-Parameter erzwungen (typisierter Fehler statt opaque downstream).
|
||
2. Ref-Schemas (`FeatureInstanceRef`/`ConnectionRef`/...) -- Dict mit `id` wird auf String-UUID kollabiert; Pass-Through fuer bereits-Strings; Dict ohne `id` raisst kontrolliert.
|
||
3. Primitive-Coercion (`bool`/`int`/`float`) aus haeufigen String-Formen ("true"/"12"/"3.14"). Unbekannte Extra-Keys (`parentOperationId`, `expectedDocumentFormats`, ...) bleiben unangetastet. Die in der vorherigen Iteration in `actionToolAdapter` eingebaute Ref-Normalisierung wurde komplett entfernt (Single Source of Truth in `parameterValidation`). Tests: `tests/unit/workflows/test_parameterValidation.py` (19 Tests).
|
||
- Gesamttest-Suite: 512 passed (vorher 503, plus 9 neue DB-Tests; +19 neue Validation-Tests; -7 obsolete Adapter-Tests, da Logik umgezogen).
|
||
|
||
- 2026-04-28 | fix | gateway | Agent-Tool-Calls auf Workflow-Actions mit `*Ref`-Parametern (z.B. `trustee_refreshAccountingData(featureInstanceId=...)`) brachen mit irrefuehrendem "No active accounting configuration found" ab. Root cause: das Tool-Schema (Phase-3 Typed Action Architecture) exponiert `FeatureInstanceRef`/`ConnectionRef` absichtlich als typisiertes Objekt mit `id`+Diskriminator (`featureCode`/`authority`), damit der LLM bei mehreren Instanzen die richtige picken kann -- aber die Action-Implementierungen verwenden den Wert direkt als String-UUID in `recordFilter={"featureInstanceId": <value>, ...}`. Der LLM uebergibt korrekt das Dict `{id, featureCode, label, mandateId}`, Postgres-Adapter scheitert mit `can't adapt type 'dict'`, der DB-Connector swallowed den Fehler (soft-fail mit `[]`), und die Action interpretiert das leere Resultset als "Konfiguration fehlt". Initial-Fix in `actionToolAdapter` (Ref-Dict -> id-String). **Diese Adapter-Normalisierung wurde im Folgeschritt zur zentralen `parameterValidation` migriert (siehe naechster Eintrag).**
|
||
|
||
## 2026-04-27
|
||
|
||
- 2026-04-27 | fix | gateway | Trustee-Subagent gab fuer "Banksaldo per 31.12.2025" CHF 11'861'162.50 zurueck statt der echten 48'507.41 (Konto 1020) und identifizierte 5400 (Materialaufwand) + 3434 (Erloeskorrekturen) als "Bankkonten". Root cause war doppelt: (1) `closingBalance` ist bereits ein Saldo pro Periode -- der Agent rief `aggregateTable(SUM, closingBalance, GROUP BY accountNumber)` ohne periodYear/periodMonth-Filter und summierte 7 Jahre x 13 Perioden auf (~90x echter Saldo); (2) er hatte kein Wissen darueber, dass Schweizer KMU-Bankkonten dem Praefix `102x` folgen und `periodMonth=0` das Jahres-Total bedeutet. Fix in zwei Teilen: (a) generische Regel in `featureDataAgent._buildSchemaContext` System-Prompt -- "NEVER apply SUM/AVG to columns that already represent a balance, closing/opening total or aggregate" mit konkreten Beispielen `closingBalance/openingBalance/debitTotal/creditTotal`; (b) Pro-Feature-Hook `getAgentDomainHints() -> str` in `mainXxx.py`: wenn die Funktion existiert, wird ihr Rueckgabetext ans Ende des Subagent-Prompts angehaengt. Trustee liefert jetzt einen kompakten Domain-Guide mit KMU-Kontoplan-Praefixen (1xxx/2xxx/3xxx/4xxx, 100x/102x), Periodenkonvention (`periodMonth=0` = Jahr, 1-12 = Monat), drei kanonischen Query-Patterns (Banksaldo, Konto-Saldo, Buchungen-im-Monat) und einer Anti-Pattern-Liste (kein SUM auf closingBalance, debitTotal/creditTotal sind keine Salden). Loader in `_loadFeatureDomainHints` nutzt `loadFeatureMainModules()` und ist tolerant gegen fehlende Hooks/Module. Unit-Tests in `tests/unit/services/test_featureDataAgent_schema.py` (4 neue: Generische Regel, Trustee-Hints angehaengt, kein Hints-Block fuer Features ohne Hook, Anti-Pattern-Erwaehnungen)
|
||
|
||
## 2026-04-26
|
||
|
||
- 2026-04-26 | fix | gateway+frontend | Automation Workflow-Tab: `Automation2WorkflowView` erstellt damit sysCreatedAt (timestamp) und lastStartedAt korrekt als PeriodPicker-Spalten erkannt werden; lastStartedAt nutzt jetzt AutoRun.startedAt statt sysCreatedAt; computed-field Filter/Sort via applyFiltersAndSort in-memory; Runs-Tab auf startedAt/completedAt umgestellt statt System-Audit-Felder
|
||
- 2026-04-26 | perf | gateway | routeWorkflowDashboard get_system_workflows: N+1 AutoRun-Abfragen ersetzt durch LEFT JOIN + Subquery-Aggregation (eine Daten- + eine Count-Query); FK-Sort-Pfad nutzt eine gebündelte Run-Stats-Query; lastStartedAt/runCount/isRunning-Filter im Join-Pfad in SQL
|
||
- 2026-04-26 | fix | gateway | Feature-Data-Subagent (`queryFeatureInstance`) Schema-Prompt war zu duenn: Agent erhielt nur Tabellennamen + flache Spalten-Liste, ohne Typen / Beschreibungen / FK-Beziehungen. Folge: bei Trustee-Saldo-Queries summierte er `TrusteeDataJournalLine.debitAmount/creditAmount` ohne Datumsfilter (JournalLine hat gar kein `bookingDate`!) statt die Periode-bezogenen `TrusteeDataAccountBalance.closingBalance` zu nutzen; ISO-Date-Strings wurden gegen Float-Unix-Timestamps gefiltert (`bookingDate <= '2025-12-31'`). Fix in `featureDataAgent._buildSchemaContext`: pro Tabelle wird jetzt der zugehoerige Pydantic-Klasse via `MODEL_REGISTRY` resolved und pro selektiertem Feld eine angereicherte Zeile gerendert -- Python-Typ aus `field.annotation`, deutsches Label aus `json_schema_extra.label`, Description aus `Field(description=...)`, FK-Target aus `fk_target`. Dazu drei neue Regeln im System-Prompt: (a) Float-Felder mit "unix timestamp" in der Description sind Sekunden-seit-Epoch (Beispiel `'2025-12-31' -> 1735603200.0`), (b) Tools koennen nicht JOINen -- FK-Tabellen separat abfragen, (c) Periode-aggregierte Tabellen (Opening/Closing-Balances) bevorzugt vor SUM ueber Rohdaten. Fallback auf flache Feldliste wenn die Tabelle nicht im Pydantic-Registry ist. Unit-Tests in `tests/unit/services/test_featureDataAgent_schema.py`
|
||
- 2026-04-26 | feat | gateway+frontend-nyla | Infomaniak-Connector (kDrive + Mail) als neuer ProviderConnector analog Google/MSFT/ClickUp. Backend: `AuthAuthority.INFOMANIAK`, `providerInfomaniak/connectorInfomaniak.py` mit `KdriveAdapter`+`MailAdapter` (httpx, OAuth-Bearer, Path-Konvention `/{driveId}/{fileId}` bzw. `/{mailboxId}/{folderId}/{uid}`), `routeSecurityInfomaniak.py` mit `_FLOW_CONNECT`-only (kein Login -- pure DATA_CONNECTION), Token-Refresh via `tokenManager.refreshInfomaniakToken` + `tokenRefreshService._refresh_infomaniak_token`, `connectorResolver`-Registry-Eintrag, Authority-Map/Labels/Dispatch in `routeDataConnections`, Router-Mount in `app.py`. Refresh-Token-Persistierung holt bei fehlendem `refresh_token`-Response aus dem letzten gespeicherten Token (analog Google). Frontend: `connectionApi.ts` Authority-Typ erweitert, `useConnections.createInfomaniakConnectionAndAuth` + `infomaniak_connection_success/error`-Event-Listener, `ConnectionsPage` mit Infomaniak-Button (FaCloud), `SourcesTab` Icons/Colors/Service-Mapping fuer `infomaniak`/`kdrive`/`mail` -- inkl. Fix der bisher fehlenden ClickUp-Eintraege in `_SERVICE_ICONS` + `_SERVICE_TO_SOURCE_TYPE`. Setup-Guide unter `wiki/d-guides/infomaniak-oauth-setup.md` (c-work: c-work/2-build/2026-04-infomaniak-connector.md)
|
||
- 2026-04-26 | fix | gateway | Feature-Data-Subagent (`queryFeatureInstance`) hat seine Loop hardcoded auf 8 Runden begrenzt, unabhaengig vom Workspace `maxAgentRounds`. Im int-System brachen Trustee-Saldo-Queries deshalb mit `Maximum rounds reached. Progress after 8 rounds` ab, obwohl der Parent-Agent z.B. mit 25 Runden konfiguriert war. Fix: `agentLoop._executeToolCalls` propagiert jetzt `parentMaxRounds` + `parentMaxCostCHF` ueber den Tool-Context; `_featureSubAgentTools._queryFeatureInstance` liest sie aus und reicht sie an `runFeatureDataAgent(maxRounds=, maxCostCHF=)` weiter. Default fuer Direktaufrufer/Tests bleibt 8. Cost-Cap skaliert linear (`_MAX_COST_CHF_PER_ROUND = 0.02 * maxRounds`), damit nicht der 0.15-CHF-Guard die Loop vor Erreichen der konfigurierten Runden abschiesst (25 Runden -> 0.50 CHF). Subagent-Start loggt jetzt effektive `maxRounds`/`maxCostCHF` zur Diagnose
|
||
- 2026-04-26 | feat | gateway+frontend-nyla | Database-Health Orphan-Cleanup: neue Checkbox `Ohne FK-Referenzen zu UserInDB.id` (default ON). Deleted-User-Reste in Audit/Billing/Membership-Tabellen sammeln sich natuerlich an wenn ein User geloescht wird und gehoeren in den separaten User-Purge-Workflow, nicht in die generische FK-Bereinigung. Backend: `_isUserIdFk(targetTable, targetColumn)`-Helper (case-insensitive auf Tabellenname); `_cleanAllOrphans(force, excludeUserFks)` ueberspringt entsprechende Relationen; `/orphans?excludeUserFks=true` filtert Scan-Resultate; `OrphanCleanAllRequest.excludeUserFks` filtert clean-all. Frontend: Checkbox neben `Nur Probleme`, default checked, mit Tooltip; URL-Param + clean-all Body-Field synchron; `Alle bereinigen`-Counter zeigt jetzt nur Non-User-FK-Orphans
|
||
- 2026-04-26 | fix | gateway | aicorePluginOpenai: `max_tokens` durch `max_completion_tokens` ersetzt in `callAiBasic` und `callAiBasicStream`. Hintergrund: OpenAI lehnt `max_tokens` fuer gpt-5.x / o-series Modelle mit HTTP 400 `unsupported_parameter` ab (`Use 'max_completion_tokens' instead`). Im Log `log_app_20260426.log` (L741-764) sichtbar: `gpt-5.4-nano` failover scheiterte sofort, ModelSelector wechselte auf `claude-opus-4-6`. Per OpenAI API-Reference akzeptieren ALLE aktuellen Chat-Completions-Modelle (legacy gpt-4o/gpt-4.1, gpt-5.x, o1/o3/o4) `max_completion_tokens`, daher universeller Wechsel statt Modell-spezifischer Verzweigung
|
||
- 2026-04-26 | feat | gateway | PDF-Renderer Emoji-Support: Noto Emoji (monochrome, OFL) als Fallback-Font registriert. Bisher rendern WinAnsi-Core-Fonts (Helvetica/Courier) Emoji-Codepoints (U+2600+, U+1F300+) als fehlende Glyphen-Quadrate. Neu unter `gateway/assets/fonts/NotoEmoji-Regular.ttf` (~419 KB, 887 Codepoints) + `_pdfFontFallback.py` Helper: registriert die TTF einmalig bei reportlab, scannt deren cmap, und `wrapEmojiSpansInXml` umschliesst zusammenhaengende Emoji-Runs (codepoint >= U+2000 ∧ in cmap) mit `<font name="NotoEmoji">…</font>` — nestet sauber in `<b>`/`<i>`/`<font name="Courier">`. `rendererPdf._markdownInlineToReportlabXml` wendet das am Ende an, also greift es ueberall wo Paragraph-Markup gebaut wird (Headings, Paragraphs, Bullet-Lists, Table-Cells, extracted_text). `Preformatted` (Code-Blocks) ist Single-Font-only und bleibt unveraendert — Emojis in Code-Bloecken sind selten, Box-Drawing wird wie bisher zu ASCII normalisiert. Smoke-Test in `test_renderer_pdf_smoke.py`
|
||
- 2026-04-26 | fix | gateway | FK Orphan-Scanner loeschte korrekte Trustee-Workflows: `AutoWorkflow.templateSourceId` enthaelt teils Sentinel-IDs (z.B. `"trustee-receipt-import"` aus `featureModule.getTemplateWorkflows()`), die absichtlich keine DB-Zeile haben — wurden faelschlich als Orphans markiert und mit `force=true` (oder unter 50%-Schwelle) geloescht. Neuer `softFk: True` Flag in `fk_target`: `fkRegistry.FkRelationship` traegt das Flag, `databaseHealth._scanOrphans`/`_cleanOrphans`/`_listOrphans` ueberspringen soft FKs komplett (kein Display, kein Cleanup). Label-Resolution unveraendert. `templateSourceId` als `softFk: True` markiert. Wiki `b-reference/platform/database-architecture.md` aktualisiert
|
||
- 2026-04-26 | refactor | gateway+frontend-nyla | Letzte 4 hardcoded Cell-Label-Stellen entfernt: (1) `RoleView.scopeType` (select mit `frontend_options` System-Template/Template/Mandant) + `RoleView.userCount` -> `AdminMandateRolesPage` zieht Attribute jetzt von `RoleView`, kein lokaler `scopeType`-Formatter mehr; (2) `Invitation.expiredFlag` als Pydantic `@computed_field` (live aus `expiresAt`+`time.time()`) mit `frontend_format_labels=["Ja","-","Nein"]`; (3) `Invitation.emailSent` -> `emailSentFlag` umbenannt + neues `emailSentAt`-Feld (Persistenz im DB-Record), `routeInvitations.create_invitation` setzt beide nach erfolgreichem Mailversand; (4) `TrusteePositionView` mit `syncStatus` (select Ausstehend/Synchronisiert/Fehler/Abgebrochen) + `syncErrorMessage` -> `routeFeatureTrustee.get_positions` enriched Rows aus `TrusteeAccountingSync`, `useTrustee` lookt Attribute via neuem `attributesEntityName`-Override, `TrusteePositionsView` hat eigenen Sync-State + Custom-Renderer geloescht. `attributeUtils.getModelAttributeDefinitions` und `i18nRegistry.@i18nModel` verarbeiten jetzt auch `model_computed_fields` (Labels + `frontend_format_labels` werden registriert)
|
||
- 2026-04-26 | refactor | gateway+frontend-nyla | Hardcoded Cell-Labels aus FormGeneratorTable-Pages entfernt: Boolean-Formatter ("Ja"/"Nein", "OK"/"Fehler") und Enum-Maps (`_STATUS_LABELS`, `scopeLabels`) aus `GraphicalEditorWorkflowsPage`, `GraphicalEditorTemplatesPage`, `AutomationsDashboardPage`, `ComplianceAuditPage` ersatzlos geloescht. Stattdessen Pydantic-Modelle (`AutoWorkflow.active|sharedReadOnly|isTemplate|notifyOnFailure|templateScope`, `AutoRun.status`, `AutoStep.status`, `AutoTask.status`, `AutoVersion.status`, `Automation2WorkflowView.isRunning`, `AuditLogEntry.success`) mit `frontend_format_labels`/`frontend_options` ausgestattet. `resolveColumnTypes` merged jetzt auch `label` und `options` aus dem Backend; `FormGeneratorTable` rendert Cells UND Filter-Dropdowns ueber `column.options` automatisch — Pages duerfen Labels nicht mehr im Frontend hardcoden
|
||
- 2026-04-26 | feat | frontend-nyla | FormGeneratorTable + columnTypeResolver: `ColumnConfig.options` (aus `frontend_options` der Pydantic-Felder) ist jetzt erste Klasse; Cell-Renderer und Filter-Liste resolven Value -> Label automatisch; `column.label` ist optional und wird vom Backend-Attribut gefuellt
|
||
- 2026-04-26 | fix | gateway+frontend-nyla | GraphicalEditor Workflows-Tabelle: `createdAt`-Alias aus `routeFeatureGraphicalEditor.get_workflows` entfernt — Frontend nutzt nun das kanonische `sysCreatedAt`. `GraphicalEditorWorkflowsPage` + `GraphicalEditorTemplatesPage` holen Attribute jetzt von `Automation2WorkflowView` (mit `frontend_type=timestamp` fuer `sysCreatedAt`/`lastStartedAt` und `frontend_type=number` fuer `runCount`); Spalten haben explizit `sortable`/`filterable` gesetzt — fehlende Sort-Icons und Zahl-statt-PeriodPicker behoben. `Automation2Workflow`-TS-Interface auf `sysCreatedAt` umgestellt
|
||
- 2026-04-26 | refactor | frontend-nyla | RealEstate Parcels+Projects + GraphicalEditor Workflows+Templates: `apiEndpoint` auf den jeweiligen Listenroute gesetzt — Backend-Routen unterstuetzen `mode=filterValues&column=X` und `mode=ids` ueber `handleFilterValuesInMemory`/`handleIdsInMemory`; FormGeneratorTable holt Filter-Werte jetzt sauber vom Backend (kein Local-Mode mehr noetig)
|
||
- 2026-04-26 | feat | gateway | routeFeatureGraphicalEditor: `/workflows` und `/templates` Endpunkte unterstuetzen jetzt `mode=filterValues&column=X` und `mode=ids` (FormGeneratorTable Backend-Pattern) ueber `handleFilterValuesInMemory`/`handleIdsInMemory` aus routeHelpers
|
||
- 2026-04-26 | fix | frontend-nyla | AdminLanguagesPage: `hookData.fetchFilterValues` implementiert (offizielles Pattern fuer In-Memory-Tabellen ohne Backend-Endpunkt) — distinct Filter-Werte aus `displayRows` mit Cross-Filter-Support; ersetzt das zuvor versuchte FormGeneratorTable-Local-Mode
|
||
- 2026-04-26 | revert | frontend-nyla | FormGeneratorTable: Local-Mode-Fallback in `getUniqueValuesForColumn` und das Entfernen der console.warn rueckgaengig gemacht — silent Fallbacks verstossen gegen das Prinzip "klare Datenstrukturen + Modelle im Backend"; Tabellen muessen stattdessen `apiEndpoint` (Backend) oder `hookData.fetchFilterValues` (explizit) setzen
|
||
- 2026-04-26 | fix | frontend-nyla | AutomationsDashboardPage Workflows-Tab: Spalten `isRunning` und `runCount` als `sortable` + `filterable` markiert (Backend unterstuetzt JOIN-basierte Sortierung/Filterung dieser computed fields)
|
||
- 2026-04-26 | fix | gateway | Automation2 ExecutionEngine: `AutoRun.startedAt` wird jetzt in `createRun` gesetzt; `AutoRun.completedAt` wird in `updateRun` automatisch gesetzt sobald Status terminal wird (completed/failed/stopped/cancelled); routeWorkflowDashboard.stopRun setzt `completedAt` ebenfalls. Bisher wurden diese Felder nie befuellt — daher waren `started`/`completed` Spalten in der Runs-Tabelle leer
|
||
- 2026-04-26 | fix | frontend-nyla | PeriodPicker in FormGeneratorTable: Preset-Kind (`thisMonth`, `thisQuarter` etc.) wird im Filter-Wert mitgespeichert, damit es beim Round-Trip erhalten bleibt und `isValueAllowed` nicht faelschlicherweise auf `ytd` zurueckfaellt
|
||
- 2026-04-26 | fix | gateway | routeAudit: 500-Fehler bei Datumsfilter behoben — `PaginationParams(pageSize=999999)` verletzte `le=1000`-Constraint; nutzt jetzt `model_construct` + `SortField`-Konvertierung
|
||
- 2026-04-26 | refactor | gateway | 5 Pattern-Inkonsistenzen aus FormGeneratorTable-Audit behoben: routeDataUsers stiller Fallback entfernt; routeFeatureRealEstate Projekte+Parzellen nutzen jetzt `applyFiltersAndSort` statt nur Sorting; routeAdminRbacRules custom filter/sort durch shared Helper ersetzt + `enrichRowsWithFkLabels` ergaenzt
|
||
- 2026-04-26 | fix | frontend-nyla | ComplianceAuditPage: Fallback-Formatter fuer `instanceLabel` und `username` zeigen jetzt `NA(uuid)` statt abgeschnittener UUID ohne Kontext
|
||
- 2026-04-26 | fix | gateway | aicoreModelRegistry: Race-Condition in `refreshModels` behoben — Lock verhindert konkurrierende Refreshes; harmlose Duplikate (gleicher Name+Connector) werden toleriert statt als Fehler geworfen
|
||
- 2026-04-26 | fix | gateway | routeDataFiles: `mode=filterValues` nutzt jetzt `enrichRowsWithFkLabels` + `handleFilterValuesInMemory` statt direktem `getDistinctColumnValues` — FK-Spalten (mandateId, featureInstanceId) zeigen wieder Labels statt UUIDs
|
||
- 2026-04-26 | fix | gateway | routeFeatureTrustee: 3x `mode=filterValues` (Documents, Positions, generisch) von `getDistinctColumnValuesWithRBAC` auf `enrichRowsWithFkLabels` + `handleFilterValuesInMemory` umgestellt — FK-Spalten (organisationId, roleId, userId, contractId etc.) zeigen Labels statt UUIDs; generischer Endpunkt nutzt zusaetzlich `_buildFeatureInternalResolvers` fuer Feature-interne FKs
|
||
- 2026-04-26 | fix | gateway | routeAudit: `_enrichUserAndInstanceLabels` setzt jetzt `NA(uuid)` als Fallback statt `None` fuer nicht aufloesbare FeatureInstance/User-IDs — Filter-Dropdown fuer Feature-Instanz war leer weil alle Labels `None` waren
|
||
- 2026-04-26 | fix | gateway | Zwei Filter-Bugs: (1) `applyFiltersAndSort` in routeHelpers: `value is None` filtert jetzt auf leere Felder statt den Filter zu ueberspringen ("Leer"-Option funktioniert); (2) `routeAudit._applySortFilterSearch` durch Delegation an shared `applyFiltersAndSort` ersetzt — Datumsbereich-Filter (`between`-Operator) und Null-Filter funktionieren jetzt konsistent
|
||
- 2026-04-26 | fix | gateway | Stille `except Exception`-Fallbacks in `mode=filterValues` entfernt: `routeFeatureTrustee` (_handleDocumentMode, _handlePositionMode, _paginatedReadEndpoint), `routeDataFiles`, `routeDataMandates` — Fehler bubblen jetzt hoch statt stillschweigend auf teuren In-Memory-Pfad auszuweichen
|
||
- 2026-04-26 | fix | gateway | Filter-Dropdown-UUID-Bug: `enrichRowsWithFkLabels` fehlte im `mode=filterValues`-Pfad bei 8 Routen (routeDataConnections, routeInvitations, routeAdminFeatures, routeSubscription, routeFeatureRealEstate x2); Wiki `fk-label-resolution.md` mit Filter-Enrichment-Regel fuer AI-Agent ergaenzt
|
||
- 2026-04-26 | refactor | gateway | FK-Metadaten konsolidiert: alle Datamodels nutzen `fk_target` mit Pflicht-Keys `db`/`table`/`labelField`; `fk_model`/`fk_label_field` entfernt; `_BUILTIN_FK_RESOLVERS["UserInDB"]`; `_buildLabelResolversFromModel` skip ohne `labelField`; `attributeUtils` setzt `displayField` nur bei gesetztem `labelField`; `validateFkTargets()` Startup-Validierung in `fkRegistry.py` + `app.py lifespan`; Wiki `fk-label-resolution.md` + `database-architecture.md` aktualisiert
|
||
- 2026-04-26 | fix | gateway | `connectorDbPostgre._ensureTableExists`: TEXT->DOUBLE PRECISION Spalten-Migration schlug fehl fuer ISO-Datetime-Strings — Regex `\\d{{4}}` korrigiert zu `\\d{4}` (doppelte Klammern waren kein f-string-Escaping sondern literal), `::timestamp` auf `::timestamptz` (Timezone-Offset korrekt parsen), SAVEPOINT pro ALTER (eine fehlgeschlagene Migration killt nicht mehr die gesamte Transaktion) — betraf MandateSubscription (6 Spalten) und BackgroundJob (3 Spalten)
|
||
- 2026-04-26 | refactor | frontend-nyla | FlowEditor Form-Field-Type-Zentralisierung: `FORM_FIELD_TYPES` + `FORM_FIELD_TYPE_LABELS` in `attributeTypeMapper.ts`; `FormStartNodeConfig`, `FormNodeConfig`, `FieldBuilderEditor` beziehen Feldtypen aus zentraler Library statt hardcoded Listen; ClickUp-spezifische Typen (`clickup_status`, `clickup_tasks`) und zugehoerige UI (Connection-Picker, Status-Hinweis) entfernt; shared `FormField`-Typ auf `AttributeType` + generisches `options` umgestellt; `TriggerFormFieldRow` eliminiert; `clickupFormSync.ts` geloescht (dead code, nirgends importiert)
|
||
- 2026-04-26 | refactor | gateway+frontend-nyla | Column-Type-Refactoring Schritte 1-10 abgeschlossen: 6 Pydantic View-Modelle (`UserMandateView`, `FeatureAccessView`, `BillingTransactionView`, `MandateSubscriptionView`, `UiLanguageSetView`, `DataNeutralizerAttributesView`) in `datamodelViews.py`; `createdAt`/`createdBy` Aliase in Invitation- und Billing-DTOs auf `sysCreatedAt`/`sysCreatedBy` standardisiert; `_COL_MAP`-Remapping in `interfaceDbBilling` entfernt; 7 Admin/Billing/Compliance-Seiten beziehen Spaltentypen via `resolveColumnTypes` + `fetchAttributes('<ViewModelName>')` statt hardcoded `type:` — tsc + Grep-Completeness-Check bestanden
|
||
- 2026-04-26 | refactor | frontend-nyla | Schritt 8: Vollstaendigkeits-Grep — verbleibende hardcoded `type:` in ComplianceAuditPage entfernt (username/instanceLabel/ipAddress im Modell); alle anderen type:-Werte berechtigt dokumentiert (enriched View-Spalten, synthetische Zaehler, Alias-Keys)
|
||
- 2026-04-26 | refactor | frontend-nyla | Schritt 7: weitere FormGenerator-Tabellen (AdminUsers, Connections, Files/Prompts, Mandate-Hook, RealEstate*, Trustee*) bauen Spaltentypen nur noch via `resolveColumnTypes` statt `type: attr.type` im Column-Map
|
||
- 2026-04-26 | feat | gateway | `attributeUtils.getModelClasses`: Feature-`datamodel*.py` unter `modules/features/**` rekursiv importieren (Trustee, Teamsbot, GraphicalEditor, …) fuer `/api/attributes/{entityType}`
|
||
- 2026-04-26 | refactor | frontend-nyla | Workflow-Seiten (GraphicalEditorWorkflowsPage, AutomationsDashboardPage) beziehen Spaltentypen via `resolveColumnTypes` + `fetchAttributes` vom Backend statt hardcoded `type:` im Frontend; neuer Shared-Utility `columnTypeResolver.ts`
|
||
- 2026-04-26 | feat | frontend-nyla | `attributesApi.AttributeDefinition.type` nutzt `AttributeType` aus `attributeTypeMapper`; Mapper um Backend-Typ `object` (JSON/Dict) ergaenzt
|
||
- 2026-04-26 | feat | gateway | Pydantic CHECK-Cleanup: fehlendes `frontend_type: "timestamp"` bei float-Zeitfeldern (UAM resetTokenExpires, DataSource, Security Token, Chat ChatLog/publishedAt/ActionItem/TaskItem/TaskHandover, Knowledge extractedAt); Redmine `*OnTs` von `number` auf `timestamp`; Redmine DTOs (`RedmineSyncResultDto`, `RedmineSyncStatusDto`, `RedmineConfigDto`); `UsageStatistics.periodStart` mit `frontend_type: "date"`; alle `frontend_type: "datetime"` auf `"timestamp"` (Audit, AuthEvent, GraphicalEditor Auto*, Messaging sentAt) — konsistent mit `attributeTypeMapper.isDateTimeType`
|
||
- 2026-04-26 | refactor | gateway | Boot-Optimierung: Chatbot-Duplikat-Prewarm entfernt (`routeFeatureChatbot`), Stripe-Bootstrap parallelisiert via ThreadPoolExecutor (`stripeBootstrap`) — erwartete Bootzeit-Reduktion ~8s
|
||
- 2026-04-26 | fix | gateway | `interfaceRbac`: Pagination-Dict-Filter (`getRecordsetPaginatedWithRBAC` / `getDistinctColumnValuesWithRBAC`) nutzen `_rbacAppendPaginationDictFilter` — numerische `gt`/`gte`/`lt`/`lte`/`between` mit `::double precision`, ISO-Datum + numerische Spalte als Unix-Bounds wie Connector
|
||
- 2026-04-26 | feat | frontend-nyla | `FormGeneratorTable`: Datum-Filter nutzt PeriodPicker (Presets + Kalender) statt primitiver `<input type="date">`; PeriodPicker rendert ausserhalb `filterDropdownOptions` (Popover nicht durch `overflow-y: auto` geclippt)
|
||
- 2026-04-26 | fix | gateway | `TrusteeDataJournalEntry.bookingDate`: `Optional[str]` -> `Optional[float]` (unix timestamp); Konvertierung in `_persistJournal` via `_isoDateToTimestamp` (ValueError bei ungueltigem Datum, kein Fallback); `_aggregateLocalMovements` liest float; FK-Label-Resolver formatiert float als ISO; Demo-Daten konvertiert; DB-Migration TEXT->DOUBLE PRECISION in `_ensureTableExists`
|
||
- 2026-04-26 | fix | gateway | `datamodelFeatureTrustee`: `lastSyncAt`/`chartCachedAt`/`syncedAt` bekommt `frontend_type: "timestamp"`, `lastSyncDateFrom`/`lastSyncDateTo` `frontend_type: "date"` — damit Frontend Date-Filter statt Text anzeigt
|
||
- 2026-04-26 | fix | frontend-nyla | `FormGeneratorTable`: Filter-Dropdown per `useLayoutEffect` als `position: fixed` in den Viewport geklemmt; Audit-Timestamp-Spalten (`sysCreatedAt` etc.) bei numerischem `type` als Datums-UI + kein distinct-Fetch
|
||
- 2026-04-26 | feat | frontend-nyla | `FormGeneratorTable`: typbezogene Spaltenfilter — Zahlen (`integer`/`int`/`number`/`float`) mit Operator (=, >, >=, <, <=, Zwischen) und `Anwenden`; Datum-Filter mit CSS-Panel; kein `filterValues`-Fetch mehr fuer bool/date/number-Spalten
|
||
- 2026-04-26 | fix | gateway | `routeHelpers._matchesBetween`: numerische `from`/`to` nach fehlgeschlagenem Datums-Parse (korrekte BETWEEN-Logik fuer Zahlenspalten); `connectorDbPostgre`: `gt`/`gte`/`lt`/`lte` und `between` auf INTEGER/DOUBLE PRECISION mit `::double precision` statt lexikographischem TEXT-Vergleich
|
||
|
||
## 2026-04-25
|
||
|
||
- 2026-04-25 | feat | * | Phase 4 FK: `frontend_fk_*` und FormGenerator-`fkSource`/Client-Cache entfernt; `fk_label_field` + `displayField` only; `_resolveRoleLabels`; `getRecordsetPaginated` + `getRecordsetPaginatedWithRBAC` + FK-Sort-Pfad mit `_enrichRowsWithFkLabels`; `attributeUtils` + betroffene Datamodels + Pages auf reines Backend-Enrichment
|
||
- 2026-04-25 | fix | gateway | Trustee Account Balances: echte Schlusssalden aus Buchhaltungssystem importieren (RMA via `/gl/saldo`; Bexio via Journal-Aggregation; Abacus via OData-Aggregation); korrigierte kumulative Fallback-Berechnung in `_persistBalances`; neues `AccountingPeriodBalance`-Modell + `getAccountBalances`-Methode in `BaseAccountingConnector`; Bug "Banksaldo per Stichtag falsch" (BuHa SoHa Konto 1020) geloest (c-work: c-work/4-done/2026-04-trustee-account-balances-import.md)
|
||
- 2026-04-25 | test | gateway | Unit-Tests fuer Trustee-Balance-Import: RMA-Connector (BuHa-SoHa-Szenario + ER-Reset), Bexio-Connector (kumulative Aggregation + Carry-Over), Abacus-Connector (OData-Aggregation), AccountingDataSync (Connector-Path + Local-Fallback)
|
||
- 2026-04-25 | feat | gateway | FK-Resolution Phase 2 (A1+A2): Neue zentrale `_enrichRowsWithFkLabels()` in `routeHelpers.py` — bulk-resolved FK-Labels als `{field}Label`-Spalten pro Row; `_resolveMandateLabels`/`_resolveInstanceLabels`/`_resolveUserLabels` liefern `None` statt ID bei fehlender Aufloesung; `routeWorkflowDashboard`, `routeAudit`, `routeBilling` (Transactions + Billing-Aggregation), `routeSubscription` auf zentrale Funktion migriert (`or mid[:8]` / `or uid[:8]` / `or iid`-Fallbacks entfernt)
|
||
- 2026-04-25 | feat | gateway | FK-Resolution Phase 2 (B2): `_enrichedFilterValues` in `routeWorkflowDashboard` liefert `{value, label}` Objekte fuer FK-Spalten (mandateId, featureInstanceId) — Frontend zeigt Labels im Filter-Dropdown ohne separate `fkSource`-Aufloesung; Leerwerte (`null`) fuer "(Leer)"-Filter inkludiert
|
||
- 2026-04-25 | fix | gateway+frontend | FK-Resolution Korrektur: `routeWorkflowDashboard` runs/workflows-Enrichment benennt `mandateIdLabel` → `mandateLabel` um (Frontend-Interface-Kompatibilitaet); `AutomationsDashboardPage` Spalten mandateId/featureInstanceId nutzen `displayField: 'mandateLabel'/'instanceLabel'`
|
||
- 2026-04-25 | feat | gateway | FK-Resolution Phase 2 (B1): `getDistinctColumnValues` + `getDistinctColumnValuesWithRBAC` + `_extractDistinctValues` + `_distinctColumnValues` liefern `null` als letzten Eintrag wenn NULL/Leer-Zeilen existieren — Frontend kann "(Leer)"-Filter anbieten
|
||
- 2026-04-25 | feat | frontend-nyla | FK-Resolution Phase 3 (C1+C2): `FormGeneratorTable.ColumnConfig.displayField` — neues Pattern: Cell rendert `row[displayField]` statt `row[key]`, CSV nutzt `displayField`; `fkSource`/`fkDisplayField` als `@deprecated` markiert (Legacy-Pfad funktioniert weiterhin)
|
||
- 2026-04-25 | feat | frontend-nyla | FK-Resolution Phase 3 (B3): `FilterValuesList` akzeptiert `string | null | {value, label}` Eintraege; `FilterValue`-Typ eingefuehrt; `_normalizeFilterValue` normalisiert alle 3 Formate; Backend-`null`-Eintraege werden als "(Leer)"-Option gerendert
|
||
- 2026-04-25 | fix | gateway | Fallback-Cleanup Phase 1 (D1+D2): Pagination-Parsing in `routeWorkflowDashboard` (runs/workflows) und `routeDataMandates` wirft 400 bei kaputtem JSON statt silent default; `runsByStatus`/Run-Enrichment in `/metrics` + `/workflows` propagieren DB-Fehler statt `logger.warning`+200; `delete_system_workflow` Callback-Trigger meldet Listener-Bugs (500 statt `except: pass`); `routeBilling._isAdminOfMandate`/`_isMemberOfMandate` und `routeSubscription._assertMandateAdmin` fail-loud (kein "DB-Down → 403"-Mask mehr); Stripe `Subscription.retrieve` im Checkout-Webhook re-raised statt silent skip
|
||
- 2026-04-25 | fix | gateway | Fallback-Cleanup Phase 1 (D2): `routeInvitations` Rollen-Zuweisung — `addRoleToFeatureAccess`/`addRoleToUserMandate` sind bereits idempotent, daher `try/except: pass # Role might already be assigned` entfernt → echte FK-/DB-Fehler beim Einladungs-Akzept werden jetzt sichtbar
|
||
- 2026-04-25 | fix | frontend-nyla | Fallback-Cleanup Phase 1 (D3+D4): `AutomationsDashboardPage._handleExecute` zeigt "Workflow gestartet" nur noch, wenn die 1s-Beobachtungs-Phase weder Erfolg noch Fehler beobachtet hat (kein Doppel-Toast "gestartet" + "fehlgeschlagen" mehr); `_loadMetrics` toast-t Backend-Fehler statt nur `console.error`; `Automation2FlowEditor.handleWorkflowRename` zeigt Fehler-Toast statt unsichtbarem `console.error`
|
||
- 2026-04-25 | feat | frontend-nyla | `FormGeneratorTable`: Leerwert-Filter `(Leer)` in allen Filter-Dropdowns — filtert auf `IS NULL OR = ''` (Backend unterstützt bereits `null` in Pagination-Filtern); Filter-Icon/Clear-Button erkennen `null`-Filter korrekt via `key in filters`
|
||
- 2026-04-25 | fix | frontend-nyla | NodeConfigPanel/RequiredAttributePicker/FeatureInstancePicker: Texte (Type-Badges, Bound-Refs, Vorschlag-Labels, Beschreibungen) verlassen den 280px-Panel-Frame nicht mehr — Header-Layout `label flex:1 1 100 %` lässt Badge umbrechen; `box-sizing: border-box`, `overflow-x: hidden`, `overflow-wrap: anywhere` als Safety-Net auf `.nodeConfigPanel`; Bound-Chip/Vorschlag-Button mit `whitespace: normal` + `word-break`
|
||
- 2026-04-25 | fix | frontend-nyla | KeepAlive-Wrapper (`GraphicalEditor`, `Workspace`, `Commcoach`): Persistenz strikt pro `(mandateId, instanceId)` — `key={mandate:instance}` an die gehaltene Page; Wechsel der Mandanten-/Instanz-Tupel unmountet den alten Editor (kein Cross-Tenant-Save mehr, "not found"-Bug behoben); Unit-Test `GraphicalEditorKeepAlive.test.tsx`
|
||
- 2026-04-25 | fix | frontend-nyla | `DataPicker`: per `createPortal` nach `document.body` (entkoppelt von `.nodeConfigPanel button`-Primary-Override); neues List-Row-Layout/Theme (`dataPickerNodeHeader` neutral), Header-Badge/Filter/Close-Styles, höheres z-index
|
||
- 2026-04-25 | fix | frontend-nyla | Flow-Editor `CanvasHeader`: Zwei-Spalten-Layout (Kontext: fester Workflow-Dropdown + Titel mit Ellipsis | Aktionspanel); Run-Button `min-width`; Version-Zeile getrennt; `retryButton`-Margin im Toolbar-Panel neutralisiert
|
||
- 2026-04-25 | fix | gateway | Trustee-Template `trustee-receipt-import`: `documentList` als DataRef `extract→process→sync` (Pick-not-Push), nicht leere Listen; Unit-Test `test_trustee_template_workflows.py`
|
||
- 2026-04-25 | feat | gateway | Trustee + Redmine Nodes auf typisierten `FeatureInstanceRef[<code>]`-Param + `frontendType: featureInstance` migriert (c-work: c-work/4-done/2026-04-feature-instance-ref-adapter-migration.md)
|
||
- 2026-04-25 | feat | gateway | Neuer Endpoint `GET /api/workflows/{instanceId}/options/feature.instance?featureCode=…` fuer Mandanten-gefilterte FeatureInstance-Auswahl (c-work: c-work/4-done/2026-04-feature-instance-ref-adapter-migration.md)
|
||
- 2026-04-25 | feat | frontend-nyla | `FeatureInstancePicker` (0/1/N) als Renderer fuer `frontendType: featureInstance`; Sysadmin-Toggle "Schema-Details" im CanvasHeader (c-work: c-work/4-done/2026-04-feature-instance-ref-adapter-migration.md)
|
||
- 2026-04-25 | fix | frontend-nyla | NodeConfigPanel-Banner zeigt `param.name` statt der ausschweifenden Description (Tooltip enthaelt vollen Text); hidden-Pflicht-Params werden zentral in `findRequiredErrors` gefiltert (kein Phantom-Pflichtfeld mehr) (c-work: c-work/4-done/2026-04-feature-instance-ref-adapter-migration.md)
|
||
- 2026-04-25 | fix | frontend-nyla | DataPicker-Modal auf CSS-Variablen umgestellt; Hover-Safety-Net `dataPickerLeaf:hover *` haelt Type-Hints auf blauem Hintergrund lesbar (c-work: c-work/4-done/2026-04-feature-instance-ref-adapter-migration.md)
|
||
- 2026-04-25 | docs | wiki | Audit `2026-04-node-typization-audit.md` archiviert; Folge-Track-Doc `2026-04-feature-instance-ref-adapter-migration.md` direkt in `4-done/` als erledigt
|
||
- 2026-04-25 | docs | wiki | Changelog-Konvention im `_CHANGELOG.md` eingefuehrt; in `README.md` + `doc-sync.mdc` referenziert
|
||
|