diff --git a/docs/backup-und-seeding.md b/docs/backup-und-seeding.md new file mode 100644 index 0000000..a036533 --- /dev/null +++ b/docs/backup-und-seeding.md @@ -0,0 +1,247 @@ +# Backup & Seeding — Betriebsnotiz Lageplan + +> Stand: 2026-05-20 +> Autor: Automatisch generiert nach Produktionsvorfall + +## Inhalt + +1. [Wichtige Regeln](#wichtige-regeln) +2. [Backup-Strategie](#backup-strategie) +3. [Seed-Skripte](#seed-skripte) +4. [Post-Deploy Prüfung](#post-deploy-prüfung) +5. [Notfall-Recovery](#notfall-recovery) +6. [Docker-Build Hinweise](#docker-build-hinweise) + +--- + +## Wichtige Regeln + +### Nie löschen + +- **Keine** `deleteMany()`, `DELETE FROM`, `TRUNCATE` oder Cascade-Resets in Production +- **Nie** direkt in `icon_assets`, `icon_categories`, `tenant_symbols`, `features`, `projects` löschen +- Alle Seed-Skripte müssen **idempotent** sein (`upsert` statt `delete` + `create`) +- Vor jedem Seed/Repair in Production: **Databasus-Backup erstellen** + +### Databasus Backup + +- Databasus ist als GUI-Backup eingerichtet +- Backups werden gespeichert unter: `/volume1/docker/backups/databasus` +- **Nie** das Docker-Volume unter `/volume1/@docker` als einzige Backup-Strategie verwenden + +### Container-Informationen + +| Service | Container-Name | +|---------|---------------| +| PostgreSQL DB | `lageplan-db-1` | +| Web App | `lageplan-web-1` | +| DB-Name | `lageplan` | +| DB-User | `lageplan` | + +--- + +## Backup-Strategie + +### Automatisch (Databasus) + +1. Databasus GUI öffnen +2. Datenbank `lageplan` auswählen +3. "Backup Now" klicken +4. Backup wird unter `/volume1/docker/backups/databasus` abgelegt + +### Manuell (pg_dump) + +```bash +# In der NAS-Shell (oder im DB-Container) +docker exec lageplan-db-1 pg_dump -U lageplan -d lageplan \ + --no-owner --no-privileges \ + > /volume1/docker/backups/databasus/lageplan-manual-$(date +%Y%m%d-%H%M%S).sql +``` + +### Wiederherstellen + +```bash +# 1. Backup-Datei prüfen +ls -la /volume1/docker/backups/databasus/ + +# 2. App stoppen +docker stop lageplan-web-1 + +# 3. DB zurückspielen (ACHTUNG: überschreibt aktuelle Daten!) +docker exec -i lageplan-db-1 psql -U lageplan -d lageplan \ + < /volume1/docker/backups/databasus/lageplan-backup-YYYYmmdd-HHMMSS.sql + +# 4. App starten +docker start lageplan-web-1 +``` + +--- + +## Seed-Skripte + +### Übersicht + +| Skript | Zweck | Sicherheit | Aufruf | +|--------|-------|-----------|--------| +| `prisma/seed.js` | Vollständiger Seed (Tenant, Users, Icons, HoseTypes, Demo-Projekt) | ✅ Idempotent, nur `upsert` | `npm run db:seed` oder `node prisma/seed.js` | +| `prisma/seed-icons-only.js` | Nur Icons aus `public/signaturen/*.svg` | ✅ Idempotent, nur `upsert` | `npm run db:seed:icons` oder `node prisma/seed-icons-only.js` | +| `prisma/seed.ts` | Legacy-TypeScript-Seed (korrigiert, aber nicht der Primary) | ✅ Korrigiert | Nicht direkt aufrufen | +| `prisma/seed-symbol-templates.ts` | Erstellt `SymbolTemplate`-Einträge | ✅ Nur `findFirst` + `create` (skip if exists) | `npx tsx prisma/seed-symbol-templates.ts` | +| `prisma/migrate-tenant-symbols.ts` | Migriert bestehende `TenantSymbol` zu neuem Schema | ✅ Nur `findFirst`, `create`, `update` | `npx tsx prisma/migrate-tenant-symbols.ts` | +| `prisma/recover-symbols.js` | Recovery: Icons + TenantSymbols wiederherstellen | ✅ Dry-Run/Apply Modus | `npm run recover:symbols:dry-run` / `npm run recover:symbols:apply` | +| `prisma/repair-features.js` | Repariert kaputte `iconId`-Referenzen in Features | ✅ Dry-Run/Apply Modus + Backup | `npm run repair:features:dry-run` / `npm run repair:features:apply` | +| `prisma/migrate.js` | DB-Migrationen (Raw SQL, idempotent) | ✅ Keine Deletes auf User-Daten | Wird automatisch beim Container-Start ausgeführt | + +### Empfohlene Seed-Strategie + +1. **Neue Umgebung** (erstmalig): + ```bash + node prisma/seed.js + ``` + +2. **Nur Icons aktualisieren** (z.B. nach SVG-Update): + ```bash + node prisma/seed-icons-only.js + ``` + +3. **Recovery nach Icon-Verlust**: + ```bash + # 1. Erst Databasus-Backup erstellen! + # 2. Dann: + node prisma/recover-symbols.js --dry-run # Analyse + node prisma/recover-symbols.js --apply # Anwenden + ``` + +--- + +## Post-Deploy Prüfung + +### 1. SVG-Dateien im Container + +```bash +docker exec -it lageplan-web-1 sh -c 'find /app/public/signaturen -type f -name "*.svg" | wc -l' +``` +**Erwartung:** ca. 117 + +### 2. Icons seeden + +```bash +docker exec -it lageplan-web-1 node prisma/seed-icons-only.js +``` +**Erwartung:** +``` +✅ 10 icon categories upserted +✅ FKS Signaturen: X created, Y updated (117 total SVGs) +``` + +### 3. Datenbank-Prüfung + +```bash +docker exec -it lageplan-db-1 psql -U lageplan -d lageplan -c " +SELECT 'icon_categories' AS table_name, COUNT(*) AS count FROM icon_categories +UNION ALL +SELECT 'icon_assets' AS table_name, COUNT(*) AS count FROM icon_assets +UNION ALL +SELECT 'tenant_symbols' AS table_name, COUNT(*) AS count FROM tenant_symbols +UNION ALL +SELECT 'features' AS table_name, COUNT(*) AS count FROM features +UNION ALL +SELECT 'projects' AS table_name, COUNT(*) AS count FROM projects; +" +``` + +### 4. Logs prüfen + +```bash +docker logs --tail=100 lageplan-web-1 +``` +**Keine** der folgenden Fehler sollen auftreten: +- `404` für `/signaturen/*.svg` +- `Prisma error` wegen `tenant_symbols.categoryId` +- `Seed failed` + +--- + +## Notfall-Recovery + +### Szenario: Symbole sind verschwunden (404) + +**Ursache:** `IconAsset`-Einträge wurden gelöscht (z.B. durch altes Seed-Skript mit `deleteMany`) + +**Lösung:** + +```bash +# 1. Backup erstellen (Databasus GUI oder pg_dump) + +# 2. Container-Status prüfen +docker exec -it lageplan-web-1 sh -c 'ls -la /app/public/signaturen/ | head -5' +# → Sollte SVG-Dateien anzeigen + +# 3. Icons neu seeden (idempotent, sicher) +docker exec -it lageplan-web-1 node prisma/seed-icons-only.js + +# 4. Tenant-Symbols wiederherstellen (falls auch gelöscht) +docker exec -it lageplan-web-1 node prisma/recover-symbols.js --dry-run +docker exec -it lageplan-web-1 node prisma/recover-symbols.js --apply + +# 5. Prüfen +docker exec -it lageplan-web-1 node -e " +const {PrismaClient} = require('@prisma/client'); +const p = new PrismaClient(); +p.iconAsset.count({where:{isSystem:true}}).then(c=>console.log('System-Icons:',c)); +p.tenantSymbol.count().then(c=>console.log('TenantSymbols:',c)); +" +``` + +### Szenario: Features haben kaputte iconId-Referenzen + +**Ursache:** Alte `iconId`-UUIDs in `Feature.properties` zeigen auf gelöschte `IconAsset`s + +**Lösung:** + +```bash +# 1. Dry-Run: Analyse +docker exec -it lageplan-web-1 node prisma/repair-features.js --dry-run + +# 2. Apply: Reparatur (erstellt automatisch JSON-Backup) +docker exec -it lageplan-web-1 node prisma/repair-features.js --apply +``` + +--- + +## Docker-Build Hinweise + +### public/signaturen muss im Image sein + +- `public/signaturen/*.svg` muss im Git-Index sein (`.gitignore` erlaubt es explizit) +- `.dockerignore` darf `public/signaturen/` **nicht** ausschliessen +- `Dockerfile` kopiert `public/` in die Runtime-Stage: + ```dockerfile + COPY --from=builder /app/public ./public + ``` + +### Next.js standalone + +- `next.config.js` hat `output: 'standalone'` +- Der Build erzeugt `.next/standalone/` (minimaler Server) +- `public/` wird explizit in die Runtime-Stage kopiert + +### Multi-Stage Build + +1. **deps**: `npm ci` (nur Dependencies) +2. **builder**: `npm run build` (inkl. Prisma Generate) +3. **runner**: Runtime-Image mit `public/`, `.next/standalone/`, Prisma-Client + +--- + +## Änderungshistorie + +| Datum | Änderung | +|-------|----------| +| 2026-05-20 | `.gitignore` korrigiert: `Signaturen/` → `/Signaturen/` (Root-only), `public/signaturen/*.svg` erlaubt | +| 2026-05-20 | 117 SVG-Dateien force-added zum Git-Index | +| 2026-05-20 | `.dockerignore` korrigiert: `Signaturen` → `/Signaturen/` | +| 2026-05-20 | `package.json`: `db:seed` zeigt jetzt auf `prisma/seed.js` statt broken `seed.ts` | +| 2026-05-20 | `seed.ts` korrigiert: Role-Enums + stabile IDs für `iconCategory.upsert` | +| 2026-05-20 | Alle Seed-Skripte auf `deleteMany`-Freiheit geprüft | +| 2026-05-20 | Dokumentation `docs/backup-und-seeding.md` erstellt | diff --git a/package.json b/package.json index 7abe22b..c03f376 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,12 @@ "db:seed": "node prisma/seed.js", "db:studio": "prisma studio", "postinstall": "prisma generate", + "db:seed:icons": "node prisma/seed-icons-only.js", + "db:seed:safe": "node prisma/seed.js", "repair:features:dry-run": "node prisma/repair-features.js --dry-run", "repair:features:apply": "node prisma/repair-features.js --apply", - "recover:symbols": "node prisma/recover-symbols.js" + "recover:symbols:dry-run": "node prisma/recover-symbols.js --dry-run", + "recover:symbols:apply": "node prisma/recover-symbols.js --apply" }, "dependencies": { "@dnd-kit/core": "^6.1.0",