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) ## 🔄 Reorganisation (9. März 2026)
**Änderungen:** **Ä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` **Für Fragen:** Siehe `custom/docs/ESPOCRM_BEST_PRACTICES.md`

View File

@@ -1,11 +1,35 @@
# EspoCRM Best Practices & Entwicklungsrichtlinien # EspoCRM Best Practices & Entwicklungsrichtlinien
**Version:** 2.4 **Version:** 2.5
**Datum:** 12. März 2026 **Datum:** 26. März 2026
**Zielgruppe:** AI Code Agents & Entwickler **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) ## 🔄 Letzte Änderungen (v2.4 - 12. März 2026)
**Neue Features:** **Neue Features:**
@@ -124,28 +148,30 @@ client/custom/ # Frontend-Code
### Custom Entities Übersicht ### Custom Entities Übersicht
**19 Custom Entities implementiert (Stand: März 2026):** **17 Custom Entities implementiert (Stand: 26. März 2026):**
| Entity | Beschreibung | Hooks | Typ | | Entity | Beschreibung | Hooks | Typ |
|--------|--------------|-------|-----| |--------|--------------|-------|-----|
| `CAdressen` | Adressen-Verwaltung | - | Base | | `CAdressen` | Adressen-Verwaltung | - | Base |
| `CAICollections` | AI-Dokumenten-Sammlungen | - | Base | | `CAkten` | Akten (Advoware + AI Sync) | ✅ UpdateLastSync, PropagateDocumentsUp | Base |
| `CAICollectionCDokumente` | Junction: Collections ↔ Dokumente | - | Junction |
| `CBankverbindungen` | Bankdaten (IBAN/BIC) | ✅ Validierung | Base | | `CBankverbindungen` | Bankdaten (IBAN/BIC) | ✅ Validierung | Base |
| `CBeteiligte` | Beteiligte Personen | - | Base | | `CBeteiligte` | Beteiligte Personen | - | Base |
| `CCallQueues` | Call-Warteschlangen | - | Base | | `CCallQueues` | Call-Warteschlangen | - | Base |
| `CDokumente` | Dokumenten-Management | ✅ Hash-Berechnung | Base | | `CDokumente` | Dokumenten-Management | ✅ Hash-Berechnung, UpdateJunctionSyncStatus | Base |
| `CKuendigung` | Kündigungen | - | Base | | `CKuendigung` | Kündigungen | ✅ CreateAdvowareAkte, SyncAdvowareAkte | Base |
| `CMietinkasso` | Mietinkasso-Fälle | - | Base | | `CMietinkasso` | Mietinkasso-Fälle | ✅ PropagateDocuments | Base |
| `CMietobjekt` | Mietobjekte | - | Base | | `CMietobjekt` | Mietobjekte | - | Base |
| `CPuls` | Posteingangs-System | ✅ Statistik | Base | | `CPuls` | Posteingangs-System | ✅ Statistik | Base |
| `CPulsTeamZuordnung` | Puls-Team-Zuordnungen | - | Base | | `CPulsTeamZuordnung` | Puls-Team-Zuordnungen | - | Base |
| `CVMHBeteiligte` | VMH-spezifische Beteiligte | - | Base | | `CVMHBeteiligte` | VMH-spezifische Beteiligte | - | Base |
| `CVmhErstgespraech` | Erstgespräche | - | Base | | `CVmhErstgespraech` | Erstgespräche | - | Base |
| `CVmhMietverhltnis` | Mietverhältnisse | - | Base | | `CVmhMietverhltnis` | Mietverhältnisse | - | Base |
| `CVmhRumungsklage` | Räumungsklagen | - | Base | | `CVmhRumungsklage` | Räumungsklagen | ✅ PropagateDocuments | Base |
| `CVmhVermieter` | Vermieter | - | 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:** **Standard-Entities erweitert:**
- `Contact` - Erweiterterte Kontakt-Felder - `Contact` - Erweiterterte Kontakt-Felder
- `Call` - Custom Call-Felder - `Call` - Custom Call-Felder
@@ -157,10 +183,17 @@ client/custom/ # Frontend-Code
- `Team` - Team-Anpassungen - `Team` - Team-Anpassungen
- `BpmnUserTask` - Workflow-Task-Erweiterungen - `BpmnUserTask` - Workflow-Task-Erweiterungen
**Implementierte Hooks:** **Implementierte Hooks (Stand: 26. März 2026):**
1. **CBankverbindungen/BankdatenValidation** - IBAN/BIC-Validierung mit Modulo-97 1. **CBankverbindungen/BankdatenValidation** (BeforeSave) - IBAN/BIC-Validierung mit Modulo-97
2. **CDokumente/CDokumente** - MD5/SHA256-Hash-Berechnung für Uploads 2. **CDokumente/CDokumente** (BeforeSave) - Blake3/MD5-Hash-Berechnung für Uploads
3. **CPuls/UpdateTeamStats** - Automatische Statistik-Berechnung 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 - `CMietobjekt` - Mietobjekte
- `CVmhMietverhltnis` - Mietverhältnisse (VMH = Vermieter Helden) - `CVmhMietverhltnis` - Mietverhältnisse (VMH = Vermieter Helden)
- `CKuendigung` - Kündigungen - `CKuendigung` - Kündigungen
- `CAICollections` - AI Collections - `CAkten` - Akten (Advoware + AI Sync)
### Entity Definition Template ### Entity Definition Template
@@ -1538,13 +1571,12 @@ class PropagateDocuments implements AfterRelate, AfterUnrelate
**Down-Propagierung (Räumungsklage → unten):** **Down-Propagierung (Räumungsklage → unten):**
- Hook in Räumungsklage/Mietinkasso - Hook in Räumungsklage/Mietinkasso
- Bei Dokumenten-Link → propagiere zu AdvowareAkten + AIKnowledge - Bei Dokumenten-Link → propagiere zu CAkten
- Deren Hooks versuchen zurück zu propagieren → blockiert durch Loop-Schutz - CAkten-Hook (`UpdateLastSyncFromDocuments`) aggregiert Status
**Up-Propagierung (AdvowareAkten → oben):** **Up-Propagierung (CAkten → oben):**
- Hook in AdvowareAkten/AIKnowledge - Hook in CAkten (`PropagateDocumentsUp`)
- Bei Dokumenten-Link → propagiere zu Räumungsklage/Mietinkasso - Bei `cAktenId`-Änderung → propagiere zu Räumungsklage/Mietinkasso
- Deren Hooks propagieren zu anderen Kind-Entities
- Loop-Schutz verhindert Rück-Propagierung - Loop-Schutz verhindert Rück-Propagierung
**Loop-Schutz Mechanismus:** **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 ### Best Practices für Hooks
#### ✅ DO #### ✅ 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 3. ✅ Prüfe Logs nach Rebuild auf InjectableFactory-Fehler
4. ✅ Teste Entity-Zugriff nach Erstellung 4. ✅ Teste Entity-Zugriff nach Erstellung
**Real-World-Beispiel (März 2026):** **Real-World-Beispiel (März 2026 → historisch):**
**Problem:** > ⚠️ **VERALTET** — `CAICollection` und `CAdvowareAkten` wurden entfernt.
- Entities `CAICollection` und `CAdvowareAkten` nicht aufrufbar > Die AI-Sync-Logik läuft seit 26. März 2026 über `CAkten` direkt.
- Logs zeigten: `Class 'Espo\Custom\Services\CAICollection' does not exist` >
> Das Pattern (Service-Klasse erstellen) bleibt gültig für alle neuen Entities:
**Lösung:** ```php
```bash // Für jede neue Custom Entity eine leere Service-Klasse anlegen:
# Service-Klassen erstellt cat > custom/Espo/Custom/Services/CMeineEntity.php << 'EOF'
cat > custom/Espo/Custom/Services/CAICollection.php << 'EOF'
<?php <?php
namespace Espo\Custom\Services; namespace Espo\Custom\Services;
use Espo\Services\Record; use Espo\Services\Record;
class CAICollection extends Record {} class CMeineEntity extends Record {}
EOF 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 ### Formula triggert nicht
@@ -2573,56 +2645,12 @@ python3 custom/scripts/validate_and_rebuild.py
### Bekannte i18n-Warnungen (nicht kritisch) ### 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.
``` Aktuelle Validierung läuft sauber über `validate_and_rebuild.py`.
⚠ CDokumente (en_US): Link 'cAICollections' fehlt in i18n Bei neuen Entities auf vollständige i18n (de_DE + en_US) in `fields` und `links` achten.
⚠ 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"
}
}
```
--- ---
@@ -2637,8 +2665,8 @@ Die folgenden i18n-Link-Labels fehlen aktuell (funktional keine Auswirkung):
5. **CMietinkasso** - Mietinkasso-Verfahren 5. **CMietinkasso** - Mietinkasso-Verfahren
6. **CVmhRumungsklage** - Räumungsklagen 6. **CVmhRumungsklage** - Räumungsklagen
7. **CDokumente** - Dokumente 7. **CDokumente** - Dokumente
8. **CPuls** - Puls-System (Entwicklungen) 8. **CAkten** - Akten (Advoware + AI Sync)
9. **CAICollections** - AI Collections 9. **CPuls** - Puls-System (Entwicklungen)
### Entity-Graph ### Entity-Graph
@@ -2647,14 +2675,20 @@ CMietobjekt
├── CVmhMietverhltnis (hasMany) ├── CVmhMietverhltnis (hasMany)
│ ├── CKuendigung (hasMany) │ ├── CKuendigung (hasMany)
│ │ └── CVmhRumungsklage (hasOne) │ │ └── CVmhRumungsklage (hasOne)
│ │ └── CAkten (belongsTo)
│ ├── CMietinkasso (hasMany) │ ├── CMietinkasso (hasMany)
│ │ └── CAkten (belongsTo)
│ └── CBeteiligte (hasMany) │ └── CBeteiligte (hasMany)
└── Contact (hasMany) └── Contact (hasMany)
CDokumente CDokumente
├── parent → [CVmhRumungsklage, CMietinkasso, CKuendigung] ├── cAkten (belongsTo CAkten) ← direkte n:1 Beziehung
└── CAICollections (hasMany via Junction) └── parent → [CVmhRumungsklage, CMietinkasso, CKuendigung, ...]
└── CPuls (hasMany)
CAkten
├── dokumentes (hasMany CDokumente) ← Aggregations-Quelle
├── vmhRumungsklage (belongsTo)
└── mietinkasso (belongsTo)
``` ```
--- ---

View File

@@ -359,7 +359,7 @@ return [
0 => 'youtube.com', 0 => 'youtube.com',
1 => 'google.com' 1 => 'google.com'
], ],
'microtime' => 1774561277.765123, 'microtime' => 1774562639.614825,
'siteUrl' => 'https://crm.bitbylaw.com', 'siteUrl' => 'https://crm.bitbylaw.com',
'fullTextSearchMinLength' => 4, 'fullTextSearchMinLength' => 4,
'webSocketUrl' => 'ws://api.bitbylaw.com:5000/espocrm/ws', 'webSocketUrl' => 'ws://api.bitbylaw.com:5000/espocrm/ws',

View File

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