# darktable-sync — Projektdokumentation für Claude ## Zweck Bash-Skripte zur bidirektionalen Synchronisation der Darktable-Datenbank und Fotobibliothek zwischen lokalem Rechner und einem Server via Unison/SSH. Entwickelt für Linux mit systemd. ## Architektur ``` darktable_wrapper.sh → Startet Pre-/Post-Sync, dann Darktable darktable_sync.sh → Hauptsync-Engine (Upload + Download) darktable_common.sh → Gemeinsame Hilfsfunktionen (wird per source eingebunden) ``` ### Ablauf darktable_sync.sh 1. Dependencies prüfen (unison, ssh, notify-send, darktable) 2. Config laden und validieren 3. Lock erwerben (atomares `mkdir`) 4. Dry-Run-Modus prüfen (Standard: Trockenlauf; `--execute`/`-e` für echten Sync) 5. Darktable-Prozess prüfen (Sync verboten wenn darktable läuft) 6. Server-Erreichbarkeit prüfen → `sync_pending` bei Fehler 7. Unison-Versionen abgleichen (exakt gleiche Version auf beiden Seiten erforderlich) 8. Active-Marker prüfen (verhindert gleichzeitige Clients) 9. Darktable-Versionen abgleichen (Major.Minor müssen übereinstimmen) 10. Sync-Token prüfen (Konflikterkennung bei mehreren Clients) → `-force local`/`-force remote`/`-prefer newer` 11. DB-Backup erstellen (library.db.bak, data.db.bak) — nur bei `--execute` 12. Backup-Verzeichnisse anlegen (`${LOCAL_PHOTO_DIR}-bak`, `${LOCAL_DARKTABLE_DB_DIR}-bak`) 13. DB-Sync: bidirektional via Unison (lokal gelöscht + im Archiv → Server löschen; nie lokal vorhanden → herunterladen) 14. Foto-Sync: bidirektional via Unison mit `-prefer newer` 15. Sync-Token und Versionsdatei speichern 16. Alte Backups bereinigen (`cleanup_old_backups`, >730 Tage) ## Konfiguration - Datei: `~/.config/darktable-sync/.env` (Permissions: 600) - Wichtige Variablen: `SERVER_IP`, `SERVER_USER`, `SERVER_SSH_PORT`, `SERVER_DB_DIR`, `SERVER_PHOTO_DIR`, `LOCAL_DARKTABLE_DB_DIR`, `LOCAL_PHOTO_DIR`, `DARKTABLE_BIN`, `SYNC_BIN` - Vorlage: `.env.example` ## Unison-Flags | Operation | Flags | |---|---| | DB-Sync | `-batch -times -auto -prefer newer -ignore "Name *.lock" -ignore "Name darktable_version" -backup "Name *" -backupdir "${LOCAL_DARKTABLE_DB_DIR}-bak"` | | Foto-Sync | `-batch -times -auto -prefer newer -ignore "Name *.lock" -backup "Name *" -backupdir "${LOCAL_PHOTO_DIR}-bak"` | | Bei DB-Konflikt (upload) | `-force local` statt `-prefer newer` | | Bei DB-Konflikt (download) | `-force remote` für DB und Fotos | Dry-Run: `UNISON_DRY_FLAG=(-dryrun)` wird zu allen Aufrufen hinzugefügt. ## Unison-Output-Format (Dryrun) - `new file ----> path` — neue Datei (Upload, an Server) - `<---- new file path` — neue Datei (Download, lokal) - `changed ----> path` — aktualisiert (Upload) - `<---- changed path` — aktualisiert (Download) - `deleted ----> path` — gelöscht (Upload) - `<---- deleted path` — gelöscht (Download) ## Sicherheitsmechanismen - `validate_path`: Blockiert `' " ; | & \` $ ( ) \` und `..` in Pfaden (Server- UND lokale Pfade) - `load_config`: Blockiert `; | & \`` in der .env vor dem source - Leeres Quellverzeichnis vor Upload → Abbruch (Schutz vor falschem Mount) - Atomares Locking via `mkdir` - SSH immer mit `BatchMode=yes` und `ConnectTimeout=5` ## Test-Infrastruktur - Framework: **BATS** (`tests/*.bats`) - Stubs in `tests/stubs/`: `unison`, `ssh`, `darktable`, `notify-send`, `pgrep`, `zenity`, `kdialog` - Stub-Aktivierung: `run_with_stubs` setzt `tests/stubs/` vorne in PATH - Steuerung via Env-Variablen: `UNISON_STUB_FAIL`, `UNISON_STUB_DRY_LINES`, `UNISON_STUB_ARGS_FILE`, `SSH_STUB_FAIL`, `SSH_STUB_OUTPUT`, `UNISON_SERVER_VERSION`, `PGREP_STUB_FOUND` - Setup: `create_valid_env` in `tests/helpers/setup.bash`; jeder Test bekommt isoliertes `$HOME` in `$BATS_TMPDIR` - Tests ausführen: `bats tests/` ## Installation `install.sh` — interaktiv, prüft Dependencies, kopiert Skripte nach `~/.local/bin/`, richtet systemd-Service ein. ## Bekannte offene Punkte - **M1 (Security, niedrig):** `validate_path` sieht `$VAR` nicht, da bash beim `source .env` bereits expandiert. Angreifer braucht Schreibzugriff auf `.env` — begrenzter Schaden.