factory-import: --save-as-builtin Flag + README-Überarbeitung
Schließt die Lücke „nach Import landet die ZIP nicht im Image-Default":
./factory-import.sh --save-as-builtin
→ entpackt die ZIP nach erfolgreichem DB-Import zusätzlich in
backend/factory-defaults/ (alter Inhalt vorher aufgeräumt, README.md
und .gitkeep bleiben). Beim nächsten Image-Build sind die Defaults
drin und seeden frische VMs automatisch.
README-Abschnitt „Factory-Defaults" komplett überarbeitet:
- Drei Transport-Pfade explizit erklärt (laufende DB / Drop-Box / Image)
- HTML-Standardtexte + AppSetting-Whitelist dokumentiert
- Auto-Seed-Verhalten + Berechtigungen aktualisiert
- Typische Workflows als End-zu-End-Sequenz inkl. scp-Sync
Live verifiziert: STALE_FILE.txt im backend/factory-defaults/ wurde beim
--save-as-builtin sauber entfernt, README.md blieb erhalten, Subfolder neu
befüllt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1066,8 +1066,9 @@ Folgende Felder werden in Audit-Logs gefiltert:
|
||||
## Factory-Defaults: Stammdaten-Kataloge teilen
|
||||
|
||||
Das **Factory-Defaults**-System erlaubt den Export und Import von
|
||||
Stammdaten-Katalogen (Anbieter, Tarife, PDF-Vorlagen usw.) zwischen verschiedenen
|
||||
OpenCRM-Installationen. Es ist bewusst **streng abgegrenzt** zu Datenbank-Backups:
|
||||
Stammdaten-Katalogen (Anbieter, Tarife, PDF-Auftragsvorlagen, HTML-Standardtexte)
|
||||
zwischen verschiedenen OpenCRM-Installationen. Es ist bewusst **streng abgegrenzt**
|
||||
zu Datenbank-Backups:
|
||||
|
||||
### Abgrenzung
|
||||
|
||||
@@ -1075,64 +1076,117 @@ OpenCRM-Installationen. Es ist bewusst **streng abgegrenzt** zu Datenbank-Backup
|
||||
|---|---|---|
|
||||
| Anbieter, Tarife, Kündigungsfristen, Laufzeiten, Kategorien | ✅ | ✅ |
|
||||
| PDF-Auftragsvorlagen (inkl. Dateien + Feldzuordnungen) | ✅ | ✅ |
|
||||
| HTML-Standardtexte: Datenschutzerklärung, Impressum, Vollmacht-Vorlage, Website-Datenschutz | ✅ | ✅ |
|
||||
| **Kundendaten, Verträge, Dokumente** | ❌ | ✅ |
|
||||
| **Emails, SMTP-/IMAP-Zugangsdaten** | ❌ | ✅ |
|
||||
| **System-Einstellungen, Datenschutzerklärungen, Impressum** | ❌ | ✅ |
|
||||
| **Secrets, JWT, Encryption-Keys, User-Accounts** | ❌ | ✅ |
|
||||
| Zwischen verschiedenen Installationen teilbar | ✅ | ❌ (zu firmen-spezifisch) |
|
||||
|
||||
> **Kurz:** Factory-Defaults = reine Kataloge, Backup = alles.
|
||||
> **Kurz:** Factory-Defaults = generische Stammdaten + rechtliche Standardtexte,
|
||||
> Backup = die komplette Instanz.
|
||||
|
||||
### Export (Installation A → ZIP)
|
||||
### Drei Wege, eine ZIP zu transportieren
|
||||
|
||||
Es gibt drei Pfade, je nachdem wo die ZIP gerade liegen soll:
|
||||
|
||||
| Wo | Pfad | Wann |
|
||||
|---|---|---|
|
||||
| **Laufende DB einer Instanz** | UI-Upload oder `./factory-import.sh` | Bestehende Live-Instanz updaten |
|
||||
| **Drop-Box im Repo** (`factory-exports/`) | `./factory-export.sh` legt ab, `./factory-import.sh` liest | Transfer zwischen dev und prod via `scp` |
|
||||
| **Werkseinstellung im Image** (`backend/factory-defaults/`) | `./factory-import.sh --save-as-builtin` oder manuell entpacken | Neue VMs sollen die Defaults beim allerersten Start mitbringen |
|
||||
|
||||
Alle drei sind unabhängig, **alle drei zusammen** decken den typischen Workflow ab.
|
||||
|
||||
### Export
|
||||
|
||||
**Variante A – UI:**
|
||||
1. **Einstellungen** → **Factory-Defaults** öffnen
|
||||
2. Übersicht prüfen (Anzahl pro Kategorie)
|
||||
3. Button **„Factory-Defaults exportieren"** klicken
|
||||
4. ZIP wird als `factory-defaults-YYYY-MM-DD.zip` heruntergeladen
|
||||
2. Button **„Factory-Defaults exportieren"** klicken
|
||||
3. ZIP wird als `factory-defaults-YYYY-MM-DD.zip` heruntergeladen
|
||||
|
||||
**Variante B – CLI (für scp-Transfers):**
|
||||
```bash
|
||||
./factory-export.sh # → factory-exports/factory-defaults-…zip
|
||||
OPENCRM_URL=https://crm.prod.example.de \
|
||||
OPENCRM_EMAIL=admin@example.de ./factory-export.sh # gegen Prod-Instanz
|
||||
```
|
||||
Ohne `OPENCRM_PASSWORD` wird das Passwort interaktiv abgefragt. Der Zielordner
|
||||
`factory-exports/` ist gitignored – die ZIPs landen also nicht ins Repo.
|
||||
|
||||
**ZIP-Struktur:**
|
||||
```
|
||||
factory-defaults-2026-04-23.zip
|
||||
factory-defaults-2026-05-07-1949.zip
|
||||
├── manifest.json # Version + Datum + Counts
|
||||
├── providers/
|
||||
│ └── providers.json # Anbieter inkl. zugehöriger Tarife
|
||||
├── providers/providers.json
|
||||
├── contract-meta/
|
||||
│ ├── cancellation-periods.json # Kündigungsfristen (Code + Beschreibung)
|
||||
│ ├── contract-durations.json # Laufzeiten (Code + Beschreibung)
|
||||
│ └── contract-categories.json # Kategorien (Strom, Gas, DSL, ...)
|
||||
└── pdf-templates/
|
||||
├── pdf-templates.json # Vorlagen-Metadaten + Feldzuordnungen
|
||||
└── *.pdf # Die eigentlichen PDF-Dateien
|
||||
│ ├── cancellation-periods.json
|
||||
│ ├── contract-durations.json
|
||||
│ └── contract-categories.json
|
||||
├── pdf-templates/
|
||||
│ ├── pdf-templates.json
|
||||
│ └── *.pdf # Die eigentlichen PDF-Dateien
|
||||
└── app-settings/
|
||||
└── app-settings.json # HTML-Templates (Whitelist-only)
|
||||
```
|
||||
|
||||
Die ZIP kann an andere Installationen weitergegeben werden
|
||||
(Partner, Test-System, neue Installation).
|
||||
### Import
|
||||
|
||||
### Import (ZIP → Installation B)
|
||||
**Variante A – UI:**
|
||||
1. **Einstellungen** → **Factory-Defaults**
|
||||
2. Bereich **Import** → **„ZIP hochladen"** → Datei wählen
|
||||
3. Erfolgs-Box zeigt Counts pro Kategorie
|
||||
|
||||
1. ZIP herunterladen bzw. erhalten
|
||||
2. Inhalt nach `backend/factory-defaults/` entpacken (Unterordnerstruktur beibehalten)
|
||||
3. Im Backend-Verzeichnis ausführen:
|
||||
```bash
|
||||
npm run seed:defaults
|
||||
```
|
||||
**Variante B – CLI:**
|
||||
```bash
|
||||
./factory-import.sh # nimmt jüngste ZIP aus factory-exports/
|
||||
./factory-import.sh ./factory-exports/foo.zip # explizite ZIP
|
||||
./factory-import.sh --save-as-builtin # zusätzlich ins Image-Default
|
||||
./factory-import.sh --save-as-builtin ./foo.zip # entpacken (siehe unten)
|
||||
```
|
||||
|
||||
Konfigurierbar per ENV: `OPENCRM_URL`, `OPENCRM_EMAIL`, `OPENCRM_PASSWORD`.
|
||||
|
||||
**Variante C – Container-Bare-Metal (für Migration / mehrere ZIPs zusammenführen):**
|
||||
```bash
|
||||
# Inhalt der ZIP nach backend/factory-defaults/ entpacken (Unterordner beibehalten)
|
||||
cd backend && npm run seed:defaults
|
||||
```
|
||||
|
||||
**Beispiel-Output:**
|
||||
```
|
||||
📦 Factory-Defaults werden eingespielt...
|
||||
|
||||
✓ Anbieter: 7, Tarife: 12
|
||||
✓ Kündigungsfristen: 5
|
||||
✓ Laufzeiten: 4
|
||||
✓ Vertragskategorien: 8
|
||||
✓ PDF-Vorlagen: 3
|
||||
|
||||
✅ Factory-Defaults erfolgreich eingespielt.
|
||||
✓ Anbieter: 10
|
||||
✓ Tarife: 4
|
||||
✓ Kündigungsfristen: 18
|
||||
✓ Laufzeiten: 18
|
||||
✓ Vertragskategorien: 8
|
||||
✓ PDF-Vorlagen: 2
|
||||
✓ HTML-Templates: 2
|
||||
```
|
||||
|
||||
### Mehrere ZIPs kombinieren
|
||||
### `--save-as-builtin`: ZIP zur Werkseinstellung machen
|
||||
|
||||
Du kannst mehrere Exporte in `backend/factory-defaults/` übereinanderlegen –
|
||||
JSON-Dateien werden automatisch gemerged:
|
||||
Mit `--save-as-builtin` entpackt `factory-import.sh` die ZIP nach **erfolgreichem
|
||||
DB-Import** zusätzlich in `backend/factory-defaults/`. Beim nächsten
|
||||
`docker-compose up --build` landen die Defaults im Image. Frisch hochgezogene
|
||||
VMs bringen sie dann beim ersten Start automatisch mit (Auto-Seed-Pfad im
|
||||
Container-Entrypoint).
|
||||
|
||||
```bash
|
||||
# typischer Sync prod → dev → Image-Default
|
||||
ssh prod './factory-export.sh'
|
||||
scp prod:opencrm/factory-exports/factory-defaults-*.zip factory-exports/
|
||||
./factory-import.sh --save-as-builtin
|
||||
docker-compose up -d --build # neuer Build, neue VMs starten direkt mit Defaults
|
||||
```
|
||||
|
||||
Der Inhalt von `backend/factory-defaults/` wird beim `--save-as-builtin` vorher
|
||||
geleert (außer `README.md` und `.gitkeep`), damit nichts Veraltetes liegen
|
||||
bleibt.
|
||||
|
||||
### Mehrere ZIPs kombinieren (CLI-only, Variante C)
|
||||
|
||||
`backend/factory-defaults/` darf mehrere `*.json` pro Unterordner haben –
|
||||
`npm run seed:defaults` merged sie automatisch:
|
||||
|
||||
```
|
||||
backend/factory-defaults/
|
||||
@@ -1142,40 +1196,73 @@ backend/factory-defaults/
|
||||
eigene.json # 5 eigene Anbieter
|
||||
```
|
||||
|
||||
Das Import-Script liest **alle** `*.json` im jeweiligen Unterordner und merged per
|
||||
unique Key (letzter Eintrag gewinnt). Duplikate sind also unproblematisch.
|
||||
Bei gleichem Unique-Key gewinnt der zuletzt gelesene Eintrag. Der UI-/HTTP-Import
|
||||
nimmt nur eine ZIP entgegen – für Merges nutze `npm run seed:defaults`.
|
||||
|
||||
### Idempotenz
|
||||
|
||||
Das Script nutzt ausschließlich Prisma `upsert`:
|
||||
Alle Pfade nutzen Prisma `upsert`:
|
||||
- **Neue Einträge** werden angelegt
|
||||
- **Bestehende Einträge** (per unique Key: `name`, `code`) werden aktualisiert
|
||||
- **Bestehende Einträge** (per unique Key: `name` / `code` / `key`) werden aktualisiert
|
||||
- Nichts wird gelöscht
|
||||
|
||||
Du kannst `npm run seed:defaults` also beliebig oft ausführen, ohne Datenverlust
|
||||
Du kannst Imports also beliebig oft hintereinander ausführen, ohne Datenverlust
|
||||
oder Duplikate.
|
||||
|
||||
### PDF-Dateien beim Import
|
||||
### PDF-Dateien
|
||||
|
||||
Beim Import werden PDF-Vorlagen aus `factory-defaults/pdf-templates/*.pdf` nach
|
||||
`uploads/pdf-templates/` kopiert und die Pfade in der DB entsprechend gesetzt.
|
||||
Beim Re-Import wird die alte Datei in `uploads/` entsorgt und durch die neue
|
||||
ersetzt.
|
||||
Beim Import werden PDF-Vorlagen aus dem ZIP nach `uploads/pdf-templates/`
|
||||
kopiert (mit eindeutigem Suffix) und die `templatePath`-Spalte entsprechend
|
||||
gesetzt. Beim Re-Import wird die alte Datei in `uploads/` entsorgt und durch
|
||||
die neue ersetzt.
|
||||
|
||||
### AppSettings-Whitelist
|
||||
|
||||
Beim Import werden nur die Keys mit AppSetting-Schreibzugriff gewährt, die auch
|
||||
exportiert werden – aktuell:
|
||||
|
||||
- `privacyPolicyHtml`
|
||||
- `imprintHtml`
|
||||
- `authorizationTemplateHtml`
|
||||
- `websitePrivacyPolicyHtml`
|
||||
|
||||
Andere Keys (SMTP, JWT, etc.) werden mit einer Warnung ignoriert. Whitelist ist
|
||||
in [`backend/src/services/factoryDefaults.service.ts`](backend/src/services/factoryDefaults.service.ts)
|
||||
zentral gepflegt.
|
||||
|
||||
### Auto-Seed beim Erst-Deploy
|
||||
|
||||
Bei einer **frischen** Installation (leere DB) spielt der Container-Entrypoint
|
||||
nach dem Prisma-Seed automatisch das Built-in-Verzeichnis ein:
|
||||
|
||||
```
|
||||
[entrypoint] DB ist leer (User-Count=0) – Auto-Seed wird ausgeführt
|
||||
[entrypoint] Spiele eingebaute Factory-Defaults ein…
|
||||
✓ Anbieter: 10, Tarife: 4
|
||||
…
|
||||
```
|
||||
|
||||
Bei bestehenden Installs passiert das **nicht** – nur frische DBs.
|
||||
|
||||
### Berechtigungen
|
||||
|
||||
| Aktion | Berechtigung |
|
||||
|--------|--------------|
|
||||
| Factory-Defaults Vorschau | `settings:read` |
|
||||
| Factory-Defaults Export | `settings:update` |
|
||||
| Factory-Defaults Import (CLI) | Server-Zugang (SSH/Shell) |
|
||||
| Factory-Defaults Export (UI/CLI) | `settings:update` |
|
||||
| Factory-Defaults Import (UI/CLI) | `settings:update` |
|
||||
| Werkseinstellungen ändern (`--save-as-builtin` / `npm run seed:defaults`) | Server-Zugang (SSH/Shell) |
|
||||
|
||||
### Typischer Einsatzzweck
|
||||
### Typische Einsatzzwecke
|
||||
|
||||
- **Neue Installation aufsetzen**: Eine Kollegen-ZIP importieren und sofort mit
|
||||
gepflegtem Anbieter- und Vorlagenkatalog loslegen
|
||||
- **Neue VM aufsetzen**: ZIP einmalig nach `backend/factory-defaults/` entpacken
|
||||
(oder per `--save-as-builtin`), dann `docker-compose up --build` – die
|
||||
Werkseinstellungen sind beim ersten Start automatisch drin.
|
||||
- **Prod-Stand zurück nach dev synchronisieren**: `./factory-export.sh` auf prod,
|
||||
`scp` ins dev, `./factory-import.sh --save-as-builtin` lokal – damit ist
|
||||
sowohl die dev-DB aktuell als auch der nächste Image-Build.
|
||||
- **Vorlagen-Paket teilen**: Eine ZIP mit nur PDF-Vorlagen weitergeben
|
||||
(die anderen Ordner einfach aus der ZIP entfernen vor dem Entpacken)
|
||||
(andere Ordner aus der ZIP entfernen vor dem Entpacken).
|
||||
- **Anbieter-Paket teilen**: ZIP mit nur `providers/` weitergeben
|
||||
- **Versionskontrolle**: Die entpackten JSON-Dateien unter Versionskontrolle
|
||||
stellen (außerhalb von `backend/factory-defaults/`, da der Ordner gitignored ist)
|
||||
|
||||
Reference in New Issue
Block a user