2c7a87ccd3
Erweitert das bestehende Factory-Defaults-Bundle um vier HTML-Standardtexte (Datenschutzerklärung, Impressum, Vollmacht-Vorlage, Website-Datenschutz) und ergänzt den bisherigen CLI-Only-Import um einen Upload-Pfad in der UI. Backend: - collectFactoryDefaults() zieht jetzt auch die Whitelist-AppSettings - exportFactoryDefaults() legt sie als app-settings/app-settings.json ins ZIP - importFactoryDefaults(buffer) liest die ZIP idempotent ein – upserts pro Kategorie, Whitelist-Filter für AppSettings, Anti-Zip-Slip durch basename beim PDF-Lookup - POST /api/factory-defaults/import (multer memoryStorage, max 50 MB, settings:update) - seed-factory-defaults.ts (CLI) gleichermaßen um seedAppSettings() erweitert Frontend: - Import-Card in FactoryDefaults.tsx: Datei-Upload statt CLI-Anleitung - Erfolgs-Box mit Counts pro Kategorie + Warnings (z.B. fehlende PDFs im ZIP) - Preview zeigt jetzt auch die Anzahl HTML-Templates Live verifiziert: Round-Trip Export → DELETE privacyPolicyHtml → Import → Wert (13.6 KB) wieder vollständig hergestellt, Audit-Log zeigt EXPORT + UPDATE-Eintrag mit Detail-Counts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
291 lines
8.3 KiB
Markdown
291 lines
8.3 KiB
Markdown
# Factory Defaults
|
||
|
||
Dieser Ordner enthält **Stammdaten-Kataloge**, die beim Initialisieren einer neuen
|
||
OpenCRM-Installation automatisch eingespielt werden können.
|
||
|
||
Siehe auch den Abschnitt „Factory-Defaults" in der Haupt-[README.md](../../README.md)
|
||
für einen Gesamtüberblick und die Abgrenzung zum Datenbank-Backup.
|
||
|
||
---
|
||
|
||
## Inhalt
|
||
|
||
```
|
||
backend/factory-defaults/
|
||
├── providers/
|
||
│ └── providers.json # Anbieter inkl. Tarife
|
||
├── contract-meta/
|
||
│ ├── cancellation-periods.json # Kündigungsfristen
|
||
│ ├── contract-durations.json # Vertragslaufzeiten
|
||
│ └── contract-categories.json # Vertragskategorien (Strom/Gas/DSL/...)
|
||
├── pdf-templates/
|
||
│ ├── pdf-templates.json # Metadaten + Feldzuordnungen
|
||
│ └── *.pdf # PDF-Vorlagen-Dateien
|
||
└── app-settings/
|
||
└── app-settings.json # HTML-Templates: Datenschutz / Impressum /
|
||
# Vollmacht / Website-Datenschutz
|
||
```
|
||
|
||
**Was NICHT enthalten ist:** Kundendaten, Verträge, Dokumente, E-Mails, SMTP-Einstellungen,
|
||
Secrets oder benutzerspezifische AppSettings. Dafür gibt es den separaten
|
||
**Datenbank-Backup-Export** (Einstellungen → Datenbank & Zurücksetzen).
|
||
|
||
Bei den AppSettings ist nur eine **Whitelist** vorgesehen (HTML-Texte für rechtliche
|
||
Standardpflichten) – andere Keys werden beim Import ignoriert.
|
||
|
||
---
|
||
|
||
## Export (aus einer bestehenden Installation)
|
||
|
||
1. Im CRM als Admin einloggen
|
||
2. **Einstellungen** → **Factory-Defaults**
|
||
3. Auf **„Factory-Defaults exportieren"** klicken
|
||
4. Die heruntergeladene ZIP (`factory-defaults-YYYY-MM-DD.zip`) speichern
|
||
|
||
### Inhalt der ZIP
|
||
|
||
```
|
||
factory-defaults-2026-04-23.zip
|
||
├── manifest.json # Version, Datum, Einträge pro Kategorie
|
||
├── providers/providers.json
|
||
├── contract-meta/cancellation-periods.json
|
||
├── contract-meta/contract-durations.json
|
||
├── contract-meta/contract-categories.json
|
||
├── pdf-templates/pdf-templates.json
|
||
├── pdf-templates/*.pdf
|
||
└── app-settings/app-settings.json
|
||
```
|
||
|
||
Die ZIP kann an andere Installationen weitergegeben werden – z.B. für Test-Systeme,
|
||
neue Installationen oder Partner-Setups.
|
||
|
||
---
|
||
|
||
## Import (in eine andere Installation)
|
||
|
||
### Variante A: Über die UI (empfohlen)
|
||
|
||
1. Im Ziel-CRM als Admin einloggen
|
||
2. **Einstellungen → Factory-Defaults**
|
||
3. Im Bereich **Import** auf **„ZIP hochladen"** klicken
|
||
4. Die exportierte ZIP wählen – der Import läuft direkt
|
||
5. Erfolgsmeldung zeigt Counts pro Kategorie an
|
||
|
||
### Variante B: Über die CLI (für Bare-Metal / Migration / mehrere ZIPs zusammenführen)
|
||
|
||
1. **ZIP herunterladen** (aus einer Export-Installation oder von einer Vorlage)
|
||
2. **Inhalt entpacken** in diesen Ordner (`backend/factory-defaults/`),
|
||
Unterordnerstruktur beibehalten
|
||
3. **Script ausführen:**
|
||
```bash
|
||
cd backend
|
||
npm run seed:defaults
|
||
```
|
||
4. **Ausgabe prüfen** – bei Erfolg:
|
||
```
|
||
📦 Factory-Defaults werden eingespielt...
|
||
|
||
✓ Anbieter: 7, Tarife: 12
|
||
✓ Kündigungsfristen: 5
|
||
✓ Laufzeiten: 4
|
||
✓ Vertragskategorien: 8
|
||
✓ PDF-Vorlagen: 3
|
||
|
||
✅ Factory-Defaults erfolgreich eingespielt.
|
||
```
|
||
|
||
### Idempotenz
|
||
|
||
Das Script nutzt ausschließlich `upsert`:
|
||
- **Neue Einträge** werden angelegt
|
||
- **Bestehende Einträge** (match per unique key: `name` / `code`) werden aktualisiert
|
||
- Nichts wird gelöscht
|
||
|
||
Du kannst `npm run seed:defaults` **beliebig oft ausführen** – kein Datenverlust,
|
||
keine Duplikate.
|
||
|
||
### Was passiert mit den PDF-Dateien?
|
||
|
||
Die PDFs aus `pdf-templates/*.pdf` werden beim Import nach
|
||
`backend/uploads/pdf-templates/` kopiert (mit eindeutigem Zeitstempel-Suffix).
|
||
Die Pfade in der DB werden automatisch auf die neue Kopie gesetzt.
|
||
|
||
Beim Re-Import einer bereits existierenden Vorlage wird die alte Datei in `uploads/`
|
||
entsorgt und durch die neue ersetzt.
|
||
|
||
---
|
||
|
||
## Mehrere Exporte mergen
|
||
|
||
Wenn du mehrere ZIPs hast (z.B. "Verivox-Paket", "Check24-Paket", "eigene"), kannst
|
||
du die JSON-Dateien frei benennen und in einen Ordner legen. Das Script liest
|
||
alle `*.json` im jeweiligen Unterordner und merged den Inhalt zusammen.
|
||
|
||
**Beispiel:**
|
||
```
|
||
backend/factory-defaults/
|
||
providers/
|
||
verivox.json # 40 Anbieter aus dem Verivox-Paket
|
||
check24.json # 30 Anbieter aus dem Check24-Paket
|
||
eigene.json # 5 eigene, firmenspezifische Anbieter
|
||
contract-meta/
|
||
standard.json # Standard-Kündigungsfristen + Laufzeiten + Kategorien
|
||
pdf-templates/
|
||
ewe-paket.json # EWE-Vorlage
|
||
moon-paket.json # Moon-Vorlage
|
||
ewe-auftrag.pdf
|
||
moon-formular.pdf
|
||
```
|
||
|
||
Bei gleichem Unique-Key (z.B. `providers.name: "EWE"` in mehreren Dateien) gewinnt
|
||
der zuletzt gelesene Eintrag.
|
||
|
||
---
|
||
|
||
## Teil-Import (nur Kategorien auswählen)
|
||
|
||
Falls du nur einen Teil importieren willst (z.B. nur PDF-Vorlagen ohne Anbieter),
|
||
lösche oder verschiebe einfach die nicht gewünschten JSON-Dateien, bevor du das
|
||
Script ausführst. Das Script überspringt Kategorien ohne Dateien ohne Fehler.
|
||
|
||
**Beispiel: nur PDF-Vorlagen:**
|
||
```
|
||
backend/factory-defaults/
|
||
pdf-templates/ # nur diesen Ordner behalten
|
||
pdf-templates.json
|
||
*.pdf
|
||
```
|
||
|
||
---
|
||
|
||
## Struktur-Referenz (für manuelle Pflege)
|
||
|
||
### `providers/providers.json`
|
||
|
||
Array von Providern, jeweils inkl. zugehöriger Tarife:
|
||
|
||
```json
|
||
[
|
||
{
|
||
"name": "EWE",
|
||
"portalUrl": "https://www.ewe.de/privatkunden/meine-ewe/login",
|
||
"usernameFieldName": "username",
|
||
"passwordFieldName": "password",
|
||
"isActive": true,
|
||
"tariffs": [
|
||
{ "name": "EWE Zuhause Strom", "isActive": true },
|
||
{ "name": "EWE Zuhause Gas", "isActive": true }
|
||
]
|
||
}
|
||
]
|
||
```
|
||
|
||
**Unique Key:** `name`
|
||
|
||
### `contract-meta/cancellation-periods.json`
|
||
|
||
```json
|
||
[
|
||
{ "code": "14T", "description": "14 Tage", "isActive": true },
|
||
{ "code": "1M", "description": "1 Monat", "isActive": true },
|
||
{ "code": "3M", "description": "3 Monate", "isActive": true }
|
||
]
|
||
```
|
||
|
||
**Unique Key:** `code`
|
||
|
||
### `contract-meta/contract-durations.json`
|
||
|
||
```json
|
||
[
|
||
{ "code": "12M", "description": "12 Monate", "isActive": true },
|
||
{ "code": "24M", "description": "24 Monate", "isActive": true }
|
||
]
|
||
```
|
||
|
||
**Unique Key:** `code`
|
||
|
||
### `contract-meta/contract-categories.json`
|
||
|
||
```json
|
||
[
|
||
{
|
||
"code": "ELECTRICITY",
|
||
"name": "Strom",
|
||
"icon": "Zap",
|
||
"color": "#FFC107",
|
||
"sortOrder": 1,
|
||
"isActive": true
|
||
}
|
||
]
|
||
```
|
||
|
||
**Unique Key:** `code`
|
||
|
||
### `pdf-templates/pdf-templates.json`
|
||
|
||
```json
|
||
[
|
||
{
|
||
"name": "EWE Auftragsformular",
|
||
"description": "Auftrag für Glasfaser-Anschluss",
|
||
"providerName": "EWE",
|
||
"originalName": "EWE-Auftrag-Privat.pdf",
|
||
"fieldMapping": {
|
||
"Vorname": "customer.firstName",
|
||
"Nachname": "customer.lastName",
|
||
"Strasse": "address.streetFull",
|
||
"PLZ": "address.postalCode",
|
||
"Ort": "address.city"
|
||
},
|
||
"phoneFieldPrefix": "Rufnummer",
|
||
"maxPhoneFields": 8,
|
||
"isActive": true,
|
||
"pdfFilename": "EWE_Auftragsformular.pdf"
|
||
}
|
||
]
|
||
```
|
||
|
||
**Unique Key:** `name`
|
||
**Wichtig:** Die `pdfFilename` muss zu einer PDF-Datei im selben Ordner passen.
|
||
|
||
### `app-settings/app-settings.json`
|
||
|
||
HTML-Standardtexte als Werkseinstellung. Es ist eine **Whitelist** aktiv – andere Keys
|
||
werden beim Import ignoriert (Schutz vor versehentlichem Überschreiben von Secrets).
|
||
|
||
```json
|
||
[
|
||
{ "key": "privacyPolicyHtml", "value": "<h1>Datenschutzerklärung</h1>..." },
|
||
{ "key": "imprintHtml", "value": "<h1>Impressum</h1>..." },
|
||
{ "key": "authorizationTemplateHtml","value": "<h1>Vollmacht</h1>..." },
|
||
{ "key": "websitePrivacyPolicyHtml", "value": "<h1>Website-Datenschutz</h1>..." }
|
||
]
|
||
```
|
||
|
||
**Unique Key:** `key`
|
||
**Erlaubte Keys:** `privacyPolicyHtml`, `imprintHtml`, `authorizationTemplateHtml`,
|
||
`websitePrivacyPolicyHtml`.
|
||
|
||
---
|
||
|
||
## Berechtigungen
|
||
|
||
| Aktion | Berechtigung |
|
||
|--------|--------------|
|
||
| Factory-Defaults Vorschau | `settings:read` |
|
||
| Factory-Defaults Export (UI) | `settings:update` |
|
||
| Factory-Defaults Import (UI) | `settings:update` |
|
||
| Factory-Defaults Import (CLI) | Server-Zugang (SSH/Shell) |
|
||
|
||
---
|
||
|
||
## Git & Versionierung
|
||
|
||
Dieser Ordner ist in `.gitignore` eingetragen (außer `.gitkeep` und `README.md`),
|
||
damit firmen-spezifische Exporte nicht versehentlich ins Repo kommen.
|
||
|
||
Wenn du **öffentlich teilbare Katalog-Pakete** versionieren willst, lege sie
|
||
außerhalb dieses Ordners ab (z.B. in einem eigenen Repository) und kopiere sie
|
||
bei Bedarf hierher.
|