Update documentation and configuration for architecture changes; remove CAIKnowledge and related entities; update microtime values in config and state files

This commit is contained in:
2026-03-26 23:18:12 +01:00
parent a0d9d1133a
commit bd29d6e9b4
4 changed files with 144 additions and 97 deletions

View File

@@ -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`

View File

@@ -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'
<?php
namespace Espo\Custom\Services;
use Espo\Services\Record;
class CAICollection extends Record {}
class CMeineEntity extends Record {}
EOF
cat > custom/Espo/Custom/Services/CAdvowareAkten.php << 'EOF'
<?php
namespace Espo\Custom\Services;
use Espo\Services\Record;
class CAdvowareAkten extends Record {}
EOF
# Rebuild
python3 custom/scripts/validate_and_rebuild.py
```
**Ergebnis:** ✅ Beide Entities sofort funktionsfähig, keine Fehler mehr in Logs
**Regelfall:** Rebuild schlägt mit `Class 'Espo\Custom\Services\...' does not exist` fehl → Service-Datei fehlt.
### Formula triggert nicht
@@ -2573,56 +2645,12 @@ python3 custom/scripts/validate_and_rebuild.py
### Bekannte i18n-Warnungen (nicht kritisch)
**Stand: März 2026**
**Stand: 26. März 2026**
Die folgenden i18n-Link-Labels fehlen aktuell (funktional keine Auswirkung):
> ✅ 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)
```
---

View File

@@ -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',

View File

@@ -1,7 +1,7 @@
<?php
return [
'cacheTimestamp' => 1774561277,
'microtimeState' => 1774561277.939448,
'cacheTimestamp' => 1774562639,
'microtimeState' => 1774562639.79198,
'currencyRates' => [
'EUR' => 1.0
],