- docker-compose.coolify(.prebuilt).yml: Service craftvia-worker (Target worker, Chromium, shm_size 1gb, gleiche Härtung), Craftvia-Variablen für app und worker. - Dockerfile: worker-Stage mit HOME=/home/app (Chromium-Profil für non-root); lokaler docker build der Targets runner und worker erfolgreich, PDF-Erzeugung im Image geprüft. - .env.example/.env.prod.example/.env.coolify.example: alle Craftvia-Variablen inkl. RLS, KI-Provider, PDF_CHROMIUM_PATH, OFFLINE_MAX_DAYS, API_RATE_LIMIT_*, AI_GENERATION_RETENTION_DAYS, AI_MONTHLY_TOKEN_LIMIT. - CI (.github, .gitea): Job gate mit Postgres (pgvector) und Redis als Service: migrate deploy, seed, Passwort für craftvia_app, tsc, lint, build, npm run test. - docs/craftvia/DEPLOY.md (aus den Certvia-Deploy-Docs abgeleitet): Architektur, Domains, Secrets, Worker, Migrationen, RLS-Aktivierung, Backup/Restore, KI, Rate Limits, Aufbewahrung, Smoke, Update/Rollback. build-and-push-images.sh baut craftvia-worker. - Certvia-/ISMS-Dokumente aus docs/ nach docs/_certvia-archiv/ (mit README); Verweise in README.md und Skript-Kommentaren angepasst. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.1 KiB
5.1 KiB
Konzept — Konfigurierbarer Backup-Zielspeicher (Backend + Lokal) (certvia)
Status: Konzept/Entscheidungsvorlage (kein Code). Produkt: certvia. Folge-Feature der Backup-Lane. Ziel: den Zielspeicher für Backup-/DSGVO-Artefakte im Betreiber-Portal konfigurierbar machen und lokale (persistente) Speicherung als vollwertige Option anbieten — nicht nur über Env.
1. Ist-Zustand (src/server/storage/backup-store.ts)
- Es gibt bereits eine
BackupStore-Abstraktion (put/get/list/remove) mit zwei echten Implementierungen:S3BackupStore(MinIO/S3) undLocalBackupStore(echte Byte-Persistenz). - Aber: Die Wahl trifft
createBackupStore()einmalig beim Prozessstart, rein Env-basiert: alleS3_*gesetzt → S3, sonst lokaler Ordner (BACKUP_LOCAL_DIRbzw.<cwd>/.backups). Exportiert als statisches SingletonbackupStore. - Nur 3 Nutzer:
src/server/backup/export.ts,restore.ts,ops.ts. - Schwächen: (a) nicht im Backend wählbar; (b) der lokale Ordner liegt im Container → beim Redeploy flüchtig; (c) S3-Config nur als Env, nicht pro Betreiber pflegbar.
2. Zielbild
- Betreiber wählt im Portal das Ziel: Lokal oder S3/MinIO, inkl. Config, mit „Verbindung testen".
- Lokal ist persistent (gemountetes Volume), nicht flüchtig.
- Env bleibt als Fallback funktionsfähig (Rückwärtskompatibilität).
3. Datenmodell (PlatformSetting, Singleton erweitern)
Aktuell nur mfaRequired. Ergänzen:
backupTarget String @default("local")—local|s3backupLocalDir String?— Pfad des lokalen Ziels (muss auf ein gemountetes Volume zeigen)backupS3Endpoint / backupS3Bucket / backupS3Region / backupS3AccessKey String?backupS3SecretKeyEnc String?— S3-Secret verschlüsselt at-rest übersrc/server/secret-crypto.ts(encryptSecret/decryptSecret, SchlüsselMFA_ENC_KEY/AUTH_SECRET) — nie Klartext in der DB.
Migration additiv (nullable, Default local). Kein Backfill nötig.
4. Store-Factory umbauen
backupStore-Singleton →getBackupStore(): Promise<BackupStore>: liestPlatformSetting, baut den passenden Store, entschlüsselt den S3-Key.- Präzedenz: DB-Config (wenn
backupTargetgesetzt/vollständig) → sonst Env (S3_*/BACKUP_LOCAL_DIR) → sonst lokaler Default.backups. So bleibt bestehendes Env-Deployment lauffähig. - Caching + Invalidierung: Store memoisieren, bei Änderung der Backup-Settings invalidieren (Version/Timestamp aus
PlatformSetting.updatedAt). - Die 3 Call-Sites (
export.ts,restore.ts,ops.ts) vonbackupStoreaufawait getBackupStore()umstellen. - Fail-secure: unvollständige S3-Config → klarer Fehler (nicht still auf lokal fallen, wenn
backupTarget=s3gewählt wurde).
5. Betreiber-UI
- Neue Seite im Plattform-Portal, z. B.
/admin/backup(oder Abschnitt in den Plattform-Einstellungen). - Gated:
requirePlatformFullAdmin+ MFA-Step-up (assertPlatformStepUp) — Betreiber-Config mit Credentials. - Felder: Ziel-Radio (Lokal/S3), je nach Wahl die Config; „Verbindung testen" (Probe-
put+get+removeeines winzigen Test-Keys) mit klarer Rückmeldung; Speichern über eine Action analogsetPlatformMfaRequired(platformSetting.upsert, S3-Secret vor dem Schreiben verschlüsseln).
6. Persistenz für „Lokal" (Compose)
- In
docker-compose.coolify.ymlein persistentes Volume ergänzen (analogpgdata/miniodata):backups:und in app + worker unter dem Pfad ausbackupLocalDirmounten (z. B./app/.backups). Ohne Mount bleibt Lokal flüchtig. - Doku-Hinweis:
backupLocalDirmuss innerhalb des gemounteten Pfads liegen.
7. Sicherheit
- S3-Secret nur verschlüsselt in der DB (
secret-crypto). - Config-Bearbeitung nur Full-Admin + Step-up, auditiert.
BACKUP_ENC_KEY(Artefakt-Verschlüsselung,src/server/backup/crypto.ts) bleibt getrennt vom Zielspeicher — Verschlüsselung des Inhalts ≠ Wahl des Speicherorts.- Umgebungs-Secret-Kohärenz (Restore) unverändert:
BACKUP_ENC_KEY/PASSWORD_PEPPER/MFA_ENC_KEYsind Env, nicht Artefakt (sieheKONZEPT-backup-restore.md§9).
8. Tests
scripts/test-backup-*erweitern: Store-Auflösung aus DB-Config (local & s3), Präzedenz DB→Env→Default, „Verbindung testen"-Pfad, Fail-secure bei unvollständiger S3-Config.- Export→Restore end-to-end gegen beide Backends.
9. Sofort testbar (ohne Umbau)
Schon heute: ohne S3_* fällt der Store auf lokal zurück → Export/Restore/DSGVO laufen (Artefakte im Container-.backups, flüchtig). Für einen schnellen Funktionstest genügt: backup-worker + Redis (vorhanden) + BACKUP_ENC_KEY (Fallback AUTH_SECRET). Der Umbau macht das Ziel wählbar und persistent.
10. Offene Entscheidungen
- Eigene Seite
/admin/backupvs. Abschnitt in bestehenden Plattform-Einstellungen. - Mehrere Ziele/Profile (Primär + Offsite) — jetzt 1 Ziel, Mehrfachziele als Phase 2.
- Ob der lokale Pfad frei wählbar ist oder auf den gemounteten Volume-Pfad festgelegt wird (empfohlen: fest, um Fehlkonfiguration zu vermeiden).