From bd29d6e9b49900cf0b4dbb7cd826814d371cc4e8 Mon Sep 17 00:00:00 2001 From: bsiggel Date: Thu, 26 Mar 2026 23:18:12 +0100 Subject: [PATCH] Update documentation and configuration for architecture changes; remove CAIKnowledge and related entities; update microtime values in config and state files --- custom/DOCUMENTATION_INDEX.md | 15 +- custom/docs/ESPOCRM_BEST_PRACTICES.md | 220 +++++++++++++++----------- data/config.php | 2 +- data/state.php | 4 +- 4 files changed, 144 insertions(+), 97 deletions(-) diff --git a/custom/DOCUMENTATION_INDEX.md b/custom/DOCUMENTATION_INDEX.md index 6c7e6be2..0a2e51bb 100644 --- a/custom/DOCUMENTATION_INDEX.md +++ b/custom/DOCUMENTATION_INDEX.md @@ -334,6 +334,19 @@ cat custom/docs/ESPOCRM_BEST_PRACTICES.md | grep -A 200 "Troubleshooting" --- +## 🔄 Architektur-Update (26. März 2026) + +**Änderungen:** +- ✅ `CAIKnowledge` entfernt (Hooks, Controller, i18n, Metadata) +- ✅ `CAICollections` / `CAICollectionCDokumente` entfernt +- ✅ `CAdvowareAkten` entfernt → ersetzt durch `CAkten` +- ✅ AI-Sync-Architektur: CDokumente → CAkten (direkte n:1, kein Junction Table) +- ✅ Neues Feld `aiProvider` auf CAkten (ragflow/xai, Default: ragflow) +- ✅ Hook-Chain: UpdateJunctionSyncStatus → UpdateLastSyncFromDocuments +- ✅ ESPOCRM_BEST_PRACTICES.md auf v2.5 aktualisiert + +--- + ## 🔄 Reorganisation (9. März 2026) **Änderungen:** @@ -356,6 +369,6 @@ cat custom/docs/ESPOCRM_BEST_PRACTICES.md | grep -A 200 "Troubleshooting" --- -**Letzte Aktualisierung:** 9. März 2026 +**Letzte Aktualisierung:** 26. März 2026 **Für Fragen:** Siehe `custom/docs/ESPOCRM_BEST_PRACTICES.md` diff --git a/custom/docs/ESPOCRM_BEST_PRACTICES.md b/custom/docs/ESPOCRM_BEST_PRACTICES.md index f07b806b..087be171 100644 --- a/custom/docs/ESPOCRM_BEST_PRACTICES.md +++ b/custom/docs/ESPOCRM_BEST_PRACTICES.md @@ -1,11 +1,35 @@ # EspoCRM Best Practices & Entwicklungsrichtlinien -**Version:** 2.4 -**Datum:** 12. März 2026 +**Version:** 2.5 +**Datum:** 26. März 2026 **Zielgruppe:** AI Code Agents & Entwickler --- +## 🔄 Letzte Änderungen (v2.5 - 26. März 2026) + +**Architektur-Refactoring:** +- ✅ **CAIKnowledge entfernt**: Entity vollständig entfernt (inkl. Hooks, Controller, i18n, Metadata) +- ✅ **CAICollections/CAICollectionCDokumente entfernt**: Junction-Entity-Architektur aufgegeben +- ✅ **CAdvowareAkten entfernt**: Durch `CAkten` ersetzt (direkter Link zu CDokumente via `cAktenId`) +- ✅ **CAkten** ist nun zentrales AI+Advoware-Sync-Entity mit eigenen Status-Feldern +- ✅ **`aiProvider` Feld**: Neues Enum-Feld in CAkten (`ragflow` / `xai`, Standard: `ragflow`) +- ✅ **AI-Felder direkt auf CDokumente**: `aiSyncStatus`, `aiLastSync`, `aiFileId`, `aiCollectionId`, `aiSyncHash` + +**Hook-Architektur neu:** +- ✅ **CDokumente/UpdateJunctionSyncStatus** (AfterSave): Markiert CDokumente + CAkten als `unclean` bei Änderungen +- ✅ **CAkten/UpdateLastSyncFromDocuments** (BeforeSave): Aggregiert Status aller CDokumente per PDO-Query +- ✅ **CAkten/PropagateDocumentsUp** (AfterSave): Propagiert Dokument-Verlinkungen zu Räumungsklage/Mietinkasso +- ⚠️ **CAIKnowledge-Hooks entfernt**: CheckGlobalSyncStatus, DokumenteSyncStatus, PropagateDocumentsUp + +**Dokumentierte Patterns:** +- Direkte n:1 CDokumente → CAkten Beziehung (kein Junction Table) +- Worst-Case-Status-Aggregation via Raw PDO (BeforeSave-Hook) +- Globaler Sync-Status (`globalSyncStatus`, `globalLastSync`) auf CAkten +- AI-Provider-Auswahl als Enum-Feld (ragflow/xai) + +--- + ## 🔄 Letzte Änderungen (v2.4 - 12. März 2026) **Neue Features:** @@ -124,28 +148,30 @@ client/custom/ # Frontend-Code ### Custom Entities Übersicht -**19 Custom Entities implementiert (Stand: März 2026):** +**17 Custom Entities implementiert (Stand: 26. März 2026):** | Entity | Beschreibung | Hooks | Typ | |--------|--------------|-------|-----| | `CAdressen` | Adressen-Verwaltung | - | Base | -| `CAICollections` | AI-Dokumenten-Sammlungen | - | Base | -| `CAICollectionCDokumente` | Junction: Collections ↔ Dokumente | - | Junction | +| `CAkten` | Akten (Advoware + AI Sync) | ✅ UpdateLastSync, PropagateDocumentsUp | Base | | `CBankverbindungen` | Bankdaten (IBAN/BIC) | ✅ Validierung | Base | | `CBeteiligte` | Beteiligte Personen | - | Base | | `CCallQueues` | Call-Warteschlangen | - | Base | -| `CDokumente` | Dokumenten-Management | ✅ Hash-Berechnung | Base | -| `CKuendigung` | Kündigungen | - | Base | -| `CMietinkasso` | Mietinkasso-Fälle | - | Base | +| `CDokumente` | Dokumenten-Management | ✅ Hash-Berechnung, UpdateJunctionSyncStatus | Base | +| `CKuendigung` | Kündigungen | ✅ CreateAdvowareAkte, SyncAdvowareAkte | Base | +| `CMietinkasso` | Mietinkasso-Fälle | ✅ PropagateDocuments | Base | | `CMietobjekt` | Mietobjekte | - | Base | | `CPuls` | Posteingangs-System | ✅ Statistik | Base | | `CPulsTeamZuordnung` | Puls-Team-Zuordnungen | - | Base | | `CVMHBeteiligte` | VMH-spezifische Beteiligte | - | Base | | `CVmhErstgespraech` | Erstgespräche | - | Base | | `CVmhMietverhltnis` | Mietverhältnisse | - | Base | -| `CVmhRumungsklage` | Räumungsklagen | - | Base | +| `CVmhRumungsklage` | Räumungsklagen | ✅ PropagateDocuments | Base | | `CVmhVermieter` | Vermieter | - | Base | +> ⚠️ **Entfernt (März 2026):** `CAIKnowledge`, `CAICollections`, `CAICollectionCDokumente`, `CAdvowareAkten` +> — Die AI-Sync-Logik läuft jetzt direkt über `CAkten` ↔ `CDokumente` (n:1). + **Standard-Entities erweitert:** - `Contact` - Erweiterterte Kontakt-Felder - `Call` - Custom Call-Felder @@ -157,10 +183,17 @@ client/custom/ # Frontend-Code - `Team` - Team-Anpassungen - `BpmnUserTask` - Workflow-Task-Erweiterungen -**Implementierte Hooks:** -1. **CBankverbindungen/BankdatenValidation** - IBAN/BIC-Validierung mit Modulo-97 -2. **CDokumente/CDokumente** - MD5/SHA256-Hash-Berechnung für Uploads -3. **CPuls/UpdateTeamStats** - Automatische Statistik-Berechnung +**Implementierte Hooks (Stand: 26. März 2026):** +1. **CBankverbindungen/BankdatenValidation** (BeforeSave) - IBAN/BIC-Validierung mit Modulo-97 +2. **CDokumente/CDokumente** (BeforeSave) - Blake3/MD5-Hash-Berechnung für Uploads +3. **CDokumente/UpdateJunctionSyncStatus** (AfterSave) - Setzt `syncStatus` + `aiSyncStatus` = `unclean` bei Dokumentänderungen; triggert CAkten-Aggregation +4. **CAkten/UpdateLastSyncFromDocuments** (BeforeSave) - Aggregiert Advoware- und AI-Sync-Status aller CDokumente per PDO (worst-case) +5. **CAkten/PropagateDocumentsUp** (AfterSave) - Propagiert `cAktenId`-Änderungen zu Räumungsklage/Mietinkasso +6. **CKuendigung/CreateAdvowareAkte** (AfterSave) - Erstellt CAkten-Eintrag bei neuer Kündigung +7. **CKuendigung/SyncAdvowareAkte** (AfterSave) - Synchronisiert Aktennummer mit Kündigung +8. **CMietinkasso/PropagateDocuments** (AfterRelate/AfterUnrelate) - Propagiert Dokumente zu Räumungsklage +9. **CVmhRumungsklage/PropagateDocuments** (AfterRelate/AfterUnrelate) - Propagiert Dokumente zu Mietinkasso +10. **CPuls/UpdateTeamStats** (AfterSave) - Automatische Statistik-Berechnung --- @@ -236,7 +269,7 @@ client/custom/ # Frontend-Code - `CMietobjekt` - Mietobjekte - `CVmhMietverhltnis` - Mietverhältnisse (VMH = Vermieter Helden) - `CKuendigung` - Kündigungen -- `CAICollections` - AI Collections +- `CAkten` - Akten (Advoware + AI Sync) ### Entity Definition Template @@ -1538,13 +1571,12 @@ class PropagateDocuments implements AfterRelate, AfterUnrelate **Down-Propagierung (Räumungsklage → unten):** - Hook in Räumungsklage/Mietinkasso -- Bei Dokumenten-Link → propagiere zu AdvowareAkten + AIKnowledge -- Deren Hooks versuchen zurück zu propagieren → blockiert durch Loop-Schutz +- Bei Dokumenten-Link → propagiere zu CAkten +- CAkten-Hook (`UpdateLastSyncFromDocuments`) aggregiert Status -**Up-Propagierung (AdvowareAkten → oben):** -- Hook in AdvowareAkten/AIKnowledge -- Bei Dokumenten-Link → propagiere zu Räumungsklage/Mietinkasso -- Deren Hooks propagieren zu anderen Kind-Entities +**Up-Propagierung (CAkten → oben):** +- Hook in CAkten (`PropagateDocumentsUp`) +- Bei `cAktenId`-Änderung → propagiere zu Räumungsklage/Mietinkasso - Loop-Schutz verhindert Rück-Propagierung **Loop-Schutz Mechanismus:** @@ -1832,6 +1864,56 @@ class UpdateTeamStats implements BeforeSave --- +#### Beispiel 4: Sync-Status-Aggregation (CAkten ↔ CDokumente) + +**Dateien:** +- `custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php` +- `custom/Espo/Custom/Hooks/CAkten/UpdateLastSyncFromDocuments.php` + +**Use Case:** Wenn ein Dokument geändert wird → CDokumente markiert sich als `unclean` → CAkten aggregiert den schlechtesten Status aller Dokumente via Raw PDO. + +**Hook-Chain:** +``` +CDokumente (AfterSave) + UpdateJunctionSyncStatus + → setzt dokument.syncStatus = 'unclean' + → setzt dokument.aiSyncStatus = 'unclean' + → speichert Dokument (skipHooks: true) + → löst CAkten.save() aus (silent: true) + → CAkten (BeforeSave) + UpdateLastSyncFromDocuments + → PDO-Query: MAX(lastSyncTimestamp), MAX(aiLastSync), worst-case Status + → setzt akte.syncStatus, akte.aiSyncStatus, akte.lastSync, akte.aiLastSync +``` + +**Trigger-Felder (UpdateJunctionSyncStatus):** +```php +private function hasRelevantChanges(Entity $entity): bool +{ + $relevantFields = ['name', 'description', 'dokument', 'dokumentId', + 'preview', 'previewId', 'fileStatus']; + foreach ($relevantFields as $field) { + if ($entity->isAttributeChanged($field)) return true; + } + return false; +} +``` + +**Status-Aggregation (worst-case Logic in CAkten/UpdateLastSyncFromDocuments):** +``` +failed > unclean/new/null > synced +``` +Wenn ein einziges Dokument `failed` ist → Akte zeigt `failed`. + +**Wichtige Punkte:** +- Skip bei `isNew()` (neue Entities haben noch keine Dokumente) +- Skip bei `skipHooks` - verhindert Endlos-Rekursion +- PDO-Query statt EntityManager für Aggregation (Performance) +- AI-Felder auf CDokumente: `aiSyncStatus`, `aiLastSync`, `aiFileId`, `aiCollectionId`, `aiSyncHash` +- AI-Provider-Auswahl auf CAkten: `aiProvider` (ragflow/xai, Standard: ragflow) + +--- + ### Best Practices für Hooks #### ✅ DO @@ -2535,34 +2617,24 @@ docker exec espocrm bash -c 'curl -s -X GET "http://localhost/api/v1/{EntityName 3. ✅ Prüfe Logs nach Rebuild auf InjectableFactory-Fehler 4. ✅ Teste Entity-Zugriff nach Erstellung -**Real-World-Beispiel (März 2026):** +**Real-World-Beispiel (März 2026 → historisch):** -**Problem:** -- Entities `CAICollection` und `CAdvowareAkten` nicht aufrufbar -- Logs zeigten: `Class 'Espo\Custom\Services\CAICollection' does not exist` +> ⚠️ **VERALTET** — `CAICollection` und `CAdvowareAkten` wurden entfernt. +> Die AI-Sync-Logik läuft seit 26. März 2026 über `CAkten` direkt. +> +> Das Pattern (Service-Klasse erstellen) bleibt gültig für alle neuen Entities: -**Lösung:** -```bash -# Service-Klassen erstellt -cat > custom/Espo/Custom/Services/CAICollection.php << 'EOF' +```php +// Für jede neue Custom Entity eine leere Service-Klasse anlegen: +cat > custom/Espo/Custom/Services/CMeineEntity.php << 'EOF' custom/Espo/Custom/Services/CAdvowareAkten.php << 'EOF' - ✅ Die früheren Warnungen zu `CAICollections` und `CAdvowareAkten` sind entfallen, da diese Entities entfernt wurden. -``` -⚠ CDokumente (en_US): Link 'cAICollections' fehlt in i18n -⚠ CAICollections (de_DE): Link 'meetings' fehlt in i18n -⚠ CAICollections (de_DE): Link 'cDokumente' fehlt in i18n -⚠ CAICollections (en_US): Link 'cDokumente' fehlt in i18n -``` - -**Behebung (optional):** - -**Datei:** `custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json` -```json -{ - "links": { - "cAICollections": "AI Collections" - } -} -``` - -**Datei:** `custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json` -```json -{ - "links": { - "cAICollections": "AI Collections" - } -} -``` - -**Datei:** `custom/Espo/Custom/Resources/i18n/de_DE/CAICollections.json` -```json -{ - "links": { - "cDokumente": "Dokumente", - "meetings": "Meetings" - } -} -``` - -**Datei:** `custom/Espo/Custom/Resources/i18n/en_US/CAICollections.json` -```json -{ - "links": { - "cDokumente": "Documents", - "meetings": "Meetings" - } -} -``` +Aktuelle Validierung läuft sauber über `validate_and_rebuild.py`. +Bei neuen Entities auf vollständige i18n (de_DE + en_US) in `fields` und `links` achten. --- @@ -2637,8 +2665,8 @@ Die folgenden i18n-Link-Labels fehlen aktuell (funktional keine Auswirkung): 5. **CMietinkasso** - Mietinkasso-Verfahren 6. **CVmhRumungsklage** - Räumungsklagen 7. **CDokumente** - Dokumente -8. **CPuls** - Puls-System (Entwicklungen) -9. **CAICollections** - AI Collections +8. **CAkten** - Akten (Advoware + AI Sync) +9. **CPuls** - Puls-System (Entwicklungen) ### Entity-Graph @@ -2647,14 +2675,20 @@ CMietobjekt ├── CVmhMietverhltnis (hasMany) │ ├── CKuendigung (hasMany) │ │ └── CVmhRumungsklage (hasOne) + │ │ └── CAkten (belongsTo) │ ├── CMietinkasso (hasMany) + │ │ └── CAkten (belongsTo) │ └── CBeteiligte (hasMany) └── Contact (hasMany) CDokumente - ├── parent → [CVmhRumungsklage, CMietinkasso, CKuendigung] - └── CAICollections (hasMany via Junction) - └── CPuls (hasMany) + ├── cAkten (belongsTo CAkten) ← direkte n:1 Beziehung + └── parent → [CVmhRumungsklage, CMietinkasso, CKuendigung, ...] + +CAkten + ├── dokumentes (hasMany CDokumente) ← Aggregations-Quelle + ├── vmhRumungsklage (belongsTo) + └── mietinkasso (belongsTo) ``` --- diff --git a/data/config.php b/data/config.php index 9e625531..64ab90e2 100644 --- a/data/config.php +++ b/data/config.php @@ -359,7 +359,7 @@ return [ 0 => 'youtube.com', 1 => 'google.com' ], - 'microtime' => 1774561277.765123, + 'microtime' => 1774562639.614825, 'siteUrl' => 'https://crm.bitbylaw.com', 'fullTextSearchMinLength' => 4, 'webSocketUrl' => 'ws://api.bitbylaw.com:5000/espocrm/ws', diff --git a/data/state.php b/data/state.php index 11697445..7bb66d9a 100644 --- a/data/state.php +++ b/data/state.php @@ -1,7 +1,7 @@ 1774561277, - 'microtimeState' => 1774561277.939448, + 'cacheTimestamp' => 1774562639, + 'microtimeState' => 1774562639.79198, 'currencyRates' => [ 'EUR' => 1.0 ],