wiki/c-work/_CHANGELOG.md
2026-04-28 11:58:53 +02:00

35 KiB

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: gateway frontend-nyla private-llm teams-bot wiki infra *

Skip: reine Refactors, Formatting, Lint, Dep-Bumps, Test-only, Wiki-Tippfehler.

2026-04-28

  • 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 | 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 mandateIdLabelmandateLabel 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
  • 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