- C# 100%
| .clinerules | ||
| .plans | ||
| assets | ||
| publish | ||
| .clineignore | ||
| .gitignore | ||
| App.xaml | ||
| App.xaml.cs | ||
| AssemblyInfo.cs | ||
| CHANGELOG.md | ||
| CloudEntryComparer.cs | ||
| CloudFolderWindow.xaml | ||
| CloudFolderWindow.xaml.cs | ||
| CompareWindow.xaml | ||
| CompareWindow.xaml.cs | ||
| ErrorLogger.cs | ||
| FileSizeConverter.cs | ||
| HistoryWindow.xaml | ||
| HistoryWindow.xaml.cs | ||
| JobModels.cs | ||
| MainWindow.xaml | ||
| MainWindow.xaml.cs | ||
| MinValueDateConverter.cs | ||
| NextcloudFolderSync.csproj | ||
| NextcloudUrl.cs | ||
| README.md | ||
| SettingsWindow.xaml | ||
| SettingsWindow.xaml.cs | ||
| StartupManager.cs | ||
| SyncEntry.cs | ||
| SyncWarningWindow.xaml | ||
| SyncWarningWindow.xaml.cs | ||
| WebDavClient.cs | ||
Nextcloud Folder Sync
Windows-Desktop-App (WPF / .NET 8) zur Synchronisation eines oder mehrerer lokaler Ordner mit Nextcloud über WebDAV. Die App ist „self-contained“, d. h. es muss kein .NET-Runtime installiert sein – einfach die EXE starten.
Inhaltsverzeichnis
- Funktionsumfang
- Systemanforderungen
- Installation
- Erstmalige Einrichtung
- Tägliche Nutzung
- Vergleichsansicht
- Synchronisations-Warnung
- Ausschlüsse
- Lösch-Strategien
- Konflikt-Verhalten
- Auto-Login und Windows-Autostart
- Retry-Verhalten bei Netzwerkfehlern
- Datenverzeichnis & Logs
- Sicherheit
- Bekannte Eigenheiten
Funktionsumfang
- Mehrere Sync-Jobs mit jeweils eigenem lokalem Ordner, Cloud-Ordner und Ausschlüssen.
- Globale Anmeldung – Benutzername, Passwort und Server-URL werden einmal hinterlegt und für alle Jobs verwendet. Das Passwort wird mit Windows-DPAPI verschlüsselt.
- Optionaler Auto-Login – gespeichertes Passwort wird beim Start automatisch geladen.
- SHA-256 + WebDAV-ETag zur zuverlässigen Änderungserkennung.
- Konfliktbehandlung – bei beidseitigen Änderungen wird eine
.conflict-YYYYMMDD-HHMMSS-Sicherung der lokalen Datei angelegt, bevor die Cloud-Version geladen wird. - Lösch-Strategien – konfigurierbar pro Job: deaktiviert, „Server gewinnt“, „Lokal gewinnt“ oder „Mirror“ (beidseitiges Löschen).
- Konflikt-Verhalten – pro Job wählbar: manuell (heutiges Verhalten), „Lokal gewinnt", „Cloud gewinnt" oder „Neuere Datei gewinnt" (automatischer Zeitstempel-Vergleich, mit Clock-Skew-Schutz).
- Ausschluss-Filter mit Wildcards (
*,?) – z. B.*.tmp, .git/*, Thumbs.db. - Synchronisations-Vergleich mit farbcodierten Zeilen und Legende.
- Sync-Warnung mit Vorschau, ab einer einstellbaren Warnschwelle an Änderungen.
- Live-Log im Hauptfenster – farbig nach Aktion (Upload / Download / Konflikt / Löschen / Ordnerstruktur / Fehler).
- History-Fenster pro Job – Liste aller vergangenen Aktionen mit Zeitstempel.
- Autostart mit Windows und Synchronisation vor Abmelden/Herunterfahren (optional).
- Dark Theme durchgängig.
- Self-contained – EXE bringt ihre eigene .NET-Runtime mit.
- Konfigurierbarer Retry-Counter – transiente WebDAV-Fehler (HTTP 408, 429, 5xx) und Netzwerkfehler werden automatisch mit exponentiellem Backoff wiederholt (0–10 Versuche, Default 3). Jeder Retry wird im Live-Log als gelbe Warnung protokolliert.
- Cloud-Browser für die Cloud-Ordner-Auswahl – eigener Dialog mit Navigations-Toolbar („🏠 Hauptverzeichnis“, „⬆ Übergeordneter Ordner“), Pfadanzeige mit Kürzung und sortierbaren Spalten; die Einträge
.und..stehen immer am Listenanfang.
Systemanforderungen
- Windows 10 oder 11 (64 Bit, x64)
- .NET 8 Desktop Runtime muss auf dem Zielrechner installiert sein (für die Release-EXEs unter
publish\vX.Y.Z\). Download: https://dotnet.microsoft.com/download/dotnet/8.0. Die EXE ist framework-dependent und bringt die Runtime nicht mit. - Nextcloud-Server (oder beliebiger WebDAV-Server) mit gültigen Zugangsdaten
Für Entwickler und Tester: Die
bin\Release\publish\win-x64\-EXE (Smoke-Build) ist weiterhin self-contained und braucht keine installierte .NET-Runtime.
Installation
- Lade die neueste EXE aus dem
bin\Release\publish\win-x64\-Ordner (bzw. dem Release-Asset) herunter. - Lege die Datei
NextcloudFolderSync.exean einen Ort deiner Wahl, z. B.C:\Programme\NextcloudFolderSync\. - Starte die EXE per Doppelklick.
Hinweis: Beim ersten Start werden
%LocalAppData%\NextcloudFolderSync\und das Datenverzeichnis automatisch angelegt.
Erstmalige Einrichtung
1. App-Passwort in Nextcloud erzeugen
Öffne in deinem Nextcloud-Konto Einstellungen → Sicherheit → App-Passwörter und erzeuge ein neues Passwort für „Nextcloud Folder Sync“. Notiere Benutzernamen und das generierte Passwort.
2. App starten und globale Anmeldung eintragen
Beim ersten Start ist die Job-Liste leer und es wird ein Demo-Job „Testjob“ angelegt.
Im unteren Bereich des Hauptfensters unter „Anmeldung“:
| Feld | Beispiel |
|---|---|
| Benutzer | dein Nextcloud-Benutzername |
| Passwort | das soeben erzeugte App-Passwort |
| Server-URL | https://cloud.example.com/apps/dashboard/ |
Die App leitet daraus automatisch die persönliche WebDAV-URL ab und zeigt sie unter „WebDAV-URL“ zur Kontrolle an.
3. Neuen Job anlegen
Klicke oben rechts auf „+ Neu“, es erscheint ein neuer Eintrag in der Job-ComboBox. Wähle ihn aus und fülle die Job-Felder:
| Feld | Bedeutung |
|---|---|
| Name | Anzeigename in der Job-Liste |
| Lokaler Ordner | Pfad auf deinem Rechner – über 📁 Lokal… auswählbar |
| Cloud-Ordner | Pfad in Nextcloud – über ☁ Cloud… durchsuchbar |
| Ausschlüsse | Wildcard-Muster, die ignoriert werden sollen (s. u.) |
| Lösch-Strategie | Verhalten bei einseitig gelöschten Dateien (s. u.) |
| Warnschwelle | Ab dieser Anzahl Änderungen vor dem Sync nachfragen (0 = nie) |
| Zeitplan | Manuell, bei Windows-Anmeldung oder im Intervall |
| Intervall (Min.) | Minuten für den Intervall-Zeitplan |
| Job aktiv | deaktivierte Jobs werden komplett übersprungen |
Cloud-Browser (☁ Cloud…)
Der Dialog „Cloud-Ordner auswählen“ hat oben eine Navigations-Toolbar:
| Bedienelement | Funktion |
|---|---|
| 🏠 Hauptverzeichnis | springt zur Wurzel deines Cloud-Speichers |
| ⬆ Übergeordneter Ordner | eine Ebene nach oben (automatisch deaktiviert, wenn du bereits im Hauptverzeichnis bist) |
| Pfadanzeige | zeigt den aktuellen Pfad; zu lange Pfade werden gekürzt – der Tooltip zeigt den vollständigen Pfad |
In der Liste stehen . (Hauptverzeichnis) und .. (Übergeordneter Ordner) immer als
erste zwei Zeilen, unabhängig davon, nach welcher Spalte sortiert wird. Ein Klick auf einen
Spaltenkopf sortiert Ordner vor Dateien; ein Doppelklick öffnet den markierten Ordner,
„Diesen Ordner verwenden“ übernimmt den aktuellen Pfad in den Job.
4. Verbindung testen
Klicke „Test“ – die App versucht PROPFIND gegen die WebDAV-URL. Bei Erfolg leuchtet die Statuspille grün und im Live-Log erscheint Verbindung erfolgreich: ….
5. Erste Synchronisation
Klicke „Sync starten“ – die App vergleicht lokal ↔ Cloud und überträgt die Unterschiede. Über „Vergleichen“ kannst du vorher trocken prüfen, was passieren würde.
Tägliche Nutzung
-
Manueller Sync: Button „Sync starten“ im Hauptfenster.
-
Automatisch: Zeitplan „Bei Anmeldung“ oder „Intervall (Min.)“ einstellen.
-
Abbrechen: Es gibt keinen separaten Stop-Button mehr – ein neuer Sync-Start ersetzt den aktuellen Lauf.
-
History: Button „History“ öffnet eine Liste aller Aktionen dieses Jobs (Upload / Download / Konflikt / Löschen / Unverändert).
-
History: Button „History“ öffnet eine Liste aller Aktionen dieses Jobs (Upload / Download / Konflikt / Löschen / Unverändert).
Vergleichsansicht
Der Button „Vergleichen“ öffnet ein zweites Fenster mit allen erkannten Pfaden, sortiert nach Ordner → Endung → Pfad. Jede Zeile ist farbig hinterlegt – die Legende oben erklärt die Farben:
| Farbe | Bedeutung |
|---|---|
| Blau | Upload (nur lokal vorhanden oder lokale Änderung) |
| Grün | Download (nur in Cloud vorhanden oder Cloud-Änderung) |
| Rot | Konflikt / prüfen (beidseitig geändert) |
| Orange | Löschen |
| Lila | Ordnerstruktur – abhängig vom Status (gleich = lila, blau/grün = unsicher) |
| Grau | Ausgeschlossen |
| Dunkelgrau | Nichts zu tun |
Spalten: Datei / Ordner (mit Icon), Dateityp, Status, Lokal, Cloud, Geplante Aktion.
Synchronisations-Warnung
Wenn die Anzahl der Änderungen die Warnschwelle des Jobs übersteigt, öffnet sich vor dem eigentlichen Sync die Sync-Warnung. Sie zeigt dieselben Farben und Spalten wie die Vergleichsansicht, plus drei Buttons am unteren Rand:
- Abbrechen – der Sync wird nicht ausgeführt.
- Lokal gewinnt – alle mehrdeutigen Konflikte werden in Richtung lokal aufgelöst.
- Cloud gewinnt – alle mehrdeutigen Konflikte werden in Richtung Cloud aufgelöst.
Die Auswahl gilt nur für diesen einen Sync-Lauf, nicht dauerhaft.
Ausschlüsse
Im Feld „Ausschlüsse“ kannst du semikolon-getrennte Muster eintragen. Wildcards * und ? sind erlaubt. Beispiele:
*.tmp– alle Dateien mit Endung.tmp.git/*– das versteckte.git-Verzeichnis inkl. InhaltThumbs.db– Windows-Vorschaudateien_MEI*– temporäre Office-Dateien
Ausgeschlossene Pfade werden nicht übertragen, im Vergleich grau markiert und in der History nicht erfasst.
Mehrere Muster trennst du mit Semikolon oder Zeilenumbruch:
*.tmp; .git/*; Thumbs.db
*.bak
node_modules
*.bak node_modules
## Lösch-Strategien
Pro Job kannst du eine der vier Strategien wählen:
| Modus | Verhalten bei nur-lokal / nur-cloud |
|--------------------------|-----------------------------------------------------------------------------|
| **Deaktiviert** | Es werden keine Dateien gelöscht; Konflikte werden per `.conflict-…` gelöst |
| **Server gewinnt** | In der Cloud gelöschte Dateien werden auch lokal gelöscht |
| **Lokal gewinnt** | Lokal gelöschte Dateien werden auch in der Cloud gelöscht |
| **Mirror** | Beidseitiges Löschen: fehlt eine Datei lokal → wird in der Cloud gelöscht; fehlt sie in der Cloud → wird lokal gelöscht |
Die Strategie wird **nur** angewendet, wenn die Datei auf einer Seite fehlt und auf der anderen Seite definitiv vorhanden war (per Hash/ETag aus dem vorherigen Sync bekannt). So werden nie versehentlich Dateien gelöscht, die nur temporär fehlen.
### „Mirror" im Detail
Der **Mirror-Modus** sorgt für eine echte **Spiegel-Synchronisation** — die lokale und die Cloud-Seite sollen **immer identisch** sein:
- Datei ist **neu lokal** (im letzten Sync noch nicht bekannt) → **Upload**
- Datei ist **neu in der Cloud** (im letzten Sync noch nicht bekannt) → **Download**
- Datei ist **lokal verschwunden**, existiert aber noch in der Cloud (war vorher bekannt) → **In der Cloud löschen**
- Datei ist **in der Cloud verschwunden**, existiert aber noch lokal (war vorher bekannt) → **Lokal löschen**
Dadurch bleiben lokaler Ordner und Cloud dauerhaft inhaltsgleich: Ein Löschen auf einer Seite wird automatisch auf die andere Seite übertragen.
⚠️ **Vorsicht**: Im Mirror-Modus führt ein versehentliches Löschen einer Datei dazu, dass sie auch auf der Gegenseite gelöscht wird. Nutze diesen Modus nur, wenn du eine echte Zwei-Wege-Spiegelung möchtest, und prüfe vorher über **Vergleichen**, welche Aktionen geplant sind.
> **Hinweis:** Automatisch gelöscht werden nur **Dateien**. Ordner werden nicht rekursiv entfernt — nach dem Löschen von Dateien können also leere Ordner zurückbleiben.
## Konflikt-Verhalten

Wenn eine Datei **sowohl lokal als auch in der Cloud geändert** wurde (`lc && rc` – beidseitige Änderung seit dem letzten Sync), entscheidet das **Konflikt-Verhalten** des Jobs, was passiert. Pro Job wählbar:
| Modus | Verhalten |
|---|---|
| **Manuell** (Standard) | Konflikt-Sicherung `datei.conflict-yyyyMMdd-HHmmss` + Cloud-Version herunterladen. Die Sync-Warnung öffnet sich, wenn die Warnschwelle überschritten ist. |
| **Lokal gewinnt** | Lokale Version wird hochgeladen, Cloud-Version wird überschrieben. Keine Konflikt-Sicherung. |
| **Cloud gewinnt** | Cloud-Version wird heruntergeladen, lokale Version wird überschrieben. Keine Konflikt-Sicherung. |
| **Neuere Datei gewinnt** | Automatischer Zeitstempel-Vergleich: die Datei mit dem jüngeren `Modified`-Datum gewinnt (lokal vs. Cloud). Der Sync-Warnung-Dialog wird übersprungen, die Entscheidung wird automatisch getroffen. |
### „Neuere Datei gewinnt" im Detail
- **Lokal `File.GetLastWriteTimeUtc` vs. Cloud `RemoteFile.Modified`** (UTC, Sekundenauflösung).
- **Schwellwert**: 2 s Clock-Skew-Schutz. Wenn die Differenz **< 2 s** ist, fällt das Programm auf das **manuelle Konflikt-Verhalten** zurück (`.conflict-…`-Sicherung + Cloud-Version), um ungewolltes Überschreiben bei PC-Uhr-Problemen zu vermeiden.
- **Logbuch-Eintrag**: jeder automatische Konflikt-Auflöser bekommt einen `HistoryStore`-Eintrag mit dem Vermerk `NewestWins (lokal +Xs)` bzw. `NewestWins (cloud +Xs)`.
- **Live-Log**: gelbe Zeile `UPLOAD (NewestWins, lokal +Xs): …` oder `DOWNLOAD (NewestWins, cloud +Xs): …`.
- **Sync-Warnung-Dialog**: wird bei diesem Modus **übersprungen** – die automatische Entscheidung genügt.
### Wann nicht verwenden?
Wenn zwei Personen gleichzeitig am selben Dokument arbeiten, ist „Neuere Datei gewinnt" riskant: die letzte Schreiboperation gewinnt, unabhängig davon, welche Person es war. In solchen Fällen besser `Manuell` belassen und die Konflikt-Sicherung prüfen.
## Auto-Login und Windows-Autostart

Unter **„Settings“** findest du folgende Optionen:
- **Mit Windows starten** – legt einen Eintrag in `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` an, damit die App nach der Anmeldung automatisch startet.
- **Beim Start minimiert starten** - startet die App beim Windows-Autostart minimiert; bei aktivierter Tray-Option bleibt das Hauptfenster unsichtbar.
- **Auto-Login** – beim Start wird das gespeicherte (per DPAPI verschlüsselte) Passwort automatisch in das Feld geladen. Die Statusleiste zeigt dann `Auto-Login aktiv: <Benutzer>` und die Pille leuchtet grün.
- **Vor Abmelden oder Herunterfahren synchronisieren** – registriert einen `SessionEnding`-Handler, der alle aktiven Jobs einmal vollständig synchronisiert, bevor Windows herunterfährt.
- **Fehlerprotokolle aufbewahren (Tage)** – Retention für `%LocalAppData%\NextcloudFolderSync\logs\errors.log` (1–3650 Tage, Standard 30).
- **Fehlerprotokolle aufbewahren (Tage)** – Retention für `%LocalAppData%\NextcloudFolderSync\logs\errors.log` (1–3650 Tage, Standard 30).
## Retry-Verhalten bei Netzwerkfehlern

Unter **„Einstellungen → Anzahl Wiederholungsversuche (0–10)"** kannst du festlegen, wie oft die App fehlgeschlagene WebDAV-Operationen automatisch wiederholt, bevor ein endgültiger Fehler gemeldet wird. Standard ist **3**, Wertebereich **0–10** (0 = keine Wiederholung).
### Was wird retried?
- HTTP-Status **408 Request Timeout**
- HTTP-Status **429 Too Many Requests**
- HTTP-Status **500, 502, 503, 504** (5xx Serverfehler)
- Transiente `HttpRequestException` (z. B. Verbindungsabbruch, DNS-Fehler)
### Was wird **nicht** retried?
- HTTP **401 Unauthorized** → Anmeldedaten prüfen, kein Retry
- HTTP **403 Forbidden** → Berechtigungen prüfen, kein Retry
- HTTP **404 Not Found** → Pfad prüfen, kein Retry
- Andere 4xx-Antworten → sofortige Fehlermeldung
- XML-/JSON-Parse-Fehler in der Antwort (nicht transient)
### Backoff-Zeiten
Zwischen den Versuchen wartet die App exponentiell:
| Versuch | Wartezeit vor diesem Versuch |
|---------|------------------------------|
| 1 | sofort |
| 2 | 200 ms |
| 3 | 400 ms |
| 4 | 800 ms |
| 5 | 1 600 ms |
| 6 | 3 200 ms |
| 7 | 6 400 ms |
Maximal ~51 s bei `MaxRetries = 10`. Der Backoff wird durch `CancellationToken` sauber abgebrochen, wenn du den Sync abbrichst oder Windows herunterfährt.
### Visuelles Feedback
Jeder Retry-Versuch erscheint als **gelbe Warnung** im Live-Log, z. B.:
[2026-09-01 21:30:12] Retry 1/3: PUT unterordner/datei.txt (HTTP 503) [2026-09-01 21:30:13] Retry 2/3: PUT unterordner/datei.txt (HTTP 503) [2026-09-01 21:30:14] [Testjob] Synchronisation abgeschlossen.
Der Wert greift ab dem nächsten Sync-Lauf – laufende Synchronisationen verwenden den Wert, der beim Start gelesen wurde.
## Datenverzeichnis & Logs
Die App legt automatisch folgendes Verzeichnis an:
%LocalAppData%\NextcloudFolderSync
├── settings.json – globale Einstellungen (Anmeldung, Auto-Login, Autostart, Retention)
├── jobs.json – Liste der Sync-Jobs
├── jobs<job-id>
│ ├── state.json – Hash/ETag/Größe aller bekannten Dateien
│ └── history.jsonl – append-only History pro Job
└── logs
└── errors.log – alle unbehandelten Fehler
`%LocalAppData%` ist in der Regel `C:\Users\<du>\AppData\Local`.
## Sicherheit
- Das Passwort wird **nur** im Windows-DPAPI-geschützten Format in `settings.json` gespeichert (`ProtectedPassword`). Klartext-Passwörter liegen nirgends auf der Festplatte.
- Konflikte werden nie still überschrieben: die lokale Datei erhält immer eine `.conflict-…`-Sicherung.
- Beim ersten Vergleich (ohne bekannten Hash) werden unterschiedliche Größen als „Manuell prüfen“ markiert – du siehst das in der Vergleichsansicht.
- `SessionEnding` wird abgefangen und der laufende Sync sauber zu Ende geführt, bevor Windows herunterfährt.
## Bekannte Eigenheiten
- **Build-Tooling:** Die `publish`-EXE benötigt **Microsoft Visual C++ Redistributable** nicht zwingend, da `UseWPF` und `UseWindowsForms` aktiv sind und `SelfContained=true`. Funktioniert auf einem nackten Windows 10 21H2+.
- **Terminal hängt bei Builds:** In manchen Entwicklungsumgebungen blockiert der Build-Befehl im Terminal – dann „Proceed While Running“ klicken, nicht abbrechen.
- **Zeilenenden:** Das Repository nutzt `.gitattributes` mit `* text=auto eol=lf`. Windows-Editoren zeigen dadurch ggf. `LF will be replaced by CRLF` – das ist nur kosmetisch.
- **Erste Synchronisation dauert:** Beim allerersten Sync existiert noch kein `state.json`. Die App scannt deshalb den gesamten Ordner und lädt/hochlädt alle Dateien, deren Größe sich auf der jeweils anderen Seite nicht findet.
---
Viel Spaß mit **Nextcloud Folder Sync**. Bei Fragen oder Problemen bitte ein Issue auf `git.minecrawler.de/dominik/NextcloudFolderSync.git` öffnen.
- **Self-contained** – EXE bringt ihre eigene .NET-Runtime mit.




