CfSetPinState aendert nur das Pin-Flag - ohne expliziten Call passiert am Disk-Inhalt nichts und das Explorer-Icon bleibt unveraendert. Darum klickte "Immer offline verfuegbar" scheinbar ins Leere. - Bei Pin: CfHydratePlaceholder triggert FETCH_DATA und laedt die Datei komplett herunter - Bei Unpin: CfDehydratePlaceholder (war schon da) - Nach jeder Zustandsaenderung SHChangeNotify(SHCNE_UPDATEITEM) damit das Overlay-Icon sofort neu gezeichnet wird, ohne dass der User F5 druecken muss - Log bekommt zusaetzlich hydrate_err fuer Debugging Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| backend | ||
| clients/desktop | ||
| frontend | ||
| .env.example | ||
| .gitignore | ||
| CHANGELOG.md | ||
| Dockerfile | ||
| README.md | ||
| build.sh | ||
| docker-compose.yml | ||
| nginx.example.conf | ||
README.md
Mini-Cloud
Selbstgehostete Web-Cloud-Plattform mit Dateiverwaltung, Kalender, Kontakte, E-Mail-Webclient, Office-Editor und Passwort-Manager.
Features
- Dateiverwaltung - Upload/Download (Drag & Drop + Ordner-Upload), Berechtigungen, Share-Links (Lesen/Schreiben/Nur-Upload, Passwort, Ablaufdatum), Papierkorb, Ordner als ZIP downloaden
- Kalender - CalDAV-kompatibel (iOS, DAVx5, Thunderbird, Outlook), iCal-Export, Teilen mit Benutzern
- Kontakte - CardDAV-kompatibel, vCard-Export, Adressbuecher teilen
- E-Mail-Webclient - IMAP/SMTP-Proxy (kein eigener Mailserver), Multi-Account, Absender-Logik
- Office-Editor - DOCX, XLSX, PPTX bearbeiten mit OnlyOffice; PDF, Bilder, Text als Vorschau
- Passwort-Manager - AES-256-GCM clientseitig verschluesselt, TOTP, Passkeys, KeePass/Firefox/CSV-Import, Ordner teilen
- Benutzerverwaltung - Rollen (Admin/User), Speicher-Quotas, Einladungslinks, oeffentliche Registrierung an/aus
- Backup - Lokales ZIP-Backup, SFTP-Backup mit Scheduler + Versionierung, Einzeldatei-Restore
- Benachrichtigungen - System-Email bei Freigaben, Downloads, neuen Benutzern
- Sync-API - Delta-Sync fuer Desktop/Mobile-Clients
Tech-Stack
| Bereich | Technologie |
|---|---|
| Backend | Python / Flask |
| Frontend | Vue 3 / Vite / PrimeVue |
| Datenbank | SQLite (WAL-Modus) |
| Auth | JWT (Web-UI) + HTTP Basic Auth (CalDAV/CardDAV) |
| Office-Editor | OnlyOffice Document Server (optional) |
Installation
Voraussetzungen
- Python 3.11+
- Node.js 18+
- npm
- Docker (fuer Produktion)
Entwicklungsumgebung
# Repository klonen
git clone <repo-url>
cd mini-cloud-datei-email-kalender-kontakte
# .env anlegen
cp .env.example .env
# SECRET_KEY und JWT_SECRET_KEY generieren:
python3 -c "import secrets; print(secrets.token_urlsafe(64))"
# Generierte Werte in .env eintragen
# Backend einrichten
cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Backend starten
python wsgi.py
# -> laeuft auf http://localhost:5000 (nur API, nicht im Browser oeffnen)
# Frontend einrichten (neues Terminal)
cd frontend
npm install
# Frontend starten
npm run dev
# -> laeuft auf http://localhost:3100
Wichtig - Ports in der Entwicklung:
| Port | Dienst | Im Browser oeffnen? |
|---|---|---|
5000 |
Backend (Flask API) | Nein - nur API, kein Frontend |
3100 |
Frontend (Vite Dev Server) | Ja - hier arbeiten! |
Im Entwicklungsmodus immer http://localhost:3100 im Browser oeffnen. Der Vite Dev Server leitet API-Aufrufe automatisch an Port 5000 weiter (Proxy in vite.config.js).
In der Docker-Produktion laeuft alles auf einem einzigen Port (5000) - Backend liefert das gebaute Frontend direkt mit aus.
Beim ersten Registrieren wird der Benutzer automatisch zum Admin.
Docker (Produktion)
# .env anlegen und Secrets eintragen
cp .env.example .env
# SECRET_KEY und JWT_SECRET_KEY generieren und eintragen:
python3 -c "import secrets; print(secrets.token_urlsafe(64))"
# Starten
docker-compose up --build -d
Die Datenbank und hochgeladene Dateien liegen unter ./data/ (Bind Mount, keine Docker Volumes).
Docker aufraeumen (Speicher freigeben)
Nach vielen Builds sammeln sich alte Images und Cache-Layer an:
# Alles Ungenutzte loeschen (Images, Container, Cache, Netzwerke):
docker system prune -a -f
# Nur alte/ungenutzte Images loeschen:
docker image prune -a -f
# Nur Build-Cache loeschen:
docker builder prune -a -f
# Speicherverbrauch anzeigen:
docker system df
Bei Problemen nach Updates (alte Frontend-Version etc.):
docker-compose down
docker-compose build --no-cache
docker-compose up -d
Nginx Reverse-Proxy (Beispiel)
Die Datei nginx.example.conf enthaelt eine vollstaendige Beispielkonfiguration:
# cloud.example.com -> Mini-Cloud (Port 5000)
server {
listen 443 ssl http2;
server_name cloud.example.com;
ssl_certificate /etc/letsencrypt/live/cloud.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cloud.example.com/privkey.pem;
client_max_body_size 0;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Let's Encrypt Zertifikat erstellen:
certbot --nginx -d cloud.example.com
OnlyOffice Document Server
Fuer die Bearbeitung von Word, Excel und PowerPoint Dateien direkt im Browser. OnlyOffice benoetigt eine eigene Subdomain mit HTTPS.
1. .env - OnlyOffice URL setzen:
ONLYOFFICE_URL=https://office.example.com
Das JWT-Secret wird automatisch vom JWT_SECRET_KEY verwendet - kein extra Secret noetig.
2. docker-compose.yml - OnlyOffice-Service aktivieren:
Der OnlyOffice-Service ist in der docker-compose.yml bereits vorbereitet. Er nutzt den gleichen JWT_SECRET_KEY aus der .env.
3. Nginx - Eigene Subdomain fuer OnlyOffice:
server {
listen 443 ssl http2;
server_name office.example.com;
ssl_certificate /etc/letsencrypt/live/office.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/office.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
4. Starten:
certbot --nginx -d office.example.com
docker-compose up --build -d
Ohne OnlyOffice (ONLYOFFICE_URL leer) werden Office-Dateien in einer einfachen Vorschau angezeigt. Mit OnlyOffice erhaelt man einen vollwertigen Editor (wie Google Docs).
Zeitzone & NTP
In der .env stehen zwei Variablen die die Systemzeit betreffen:
TZ=Europe/Berlin
NTP_SERVER=ptbtime1.ptb.de
TZ setzt die prozessweite Zeitzone (wirkt auf Log-Zeitstempel, Kalender/Task-Zeiten, datetime.now()). IANA-Format Region/Stadt.
Haeufige Werte:
| Region | Beispielwerte |
|---|---|
| Deutschland | Europe/Berlin |
| DACH/EU | Europe/Vienna, Europe/Zurich, Europe/Amsterdam, Europe/Paris, Europe/London, Europe/Madrid, Europe/Rome, Europe/Warsaw |
| Nord-EU | Europe/Copenhagen, Europe/Stockholm, Europe/Helsinki, Europe/Oslo |
| Sonstige | UTC, America/New_York, America/Los_Angeles, Asia/Tokyo, Australia/Sydney |
Vollstaendige Liste: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
NTP_SERVER wird beim Start abgefragt, um die Abweichung der Systemuhr zu pruefen. Bei Drift > 5 s erscheint eine Warnung im Log. Hinweis: Im Container wird die Uhr dadurch nicht gesetzt (benoetigt CAP_SYS_TIME) - auf dem Host sollte ein NTP-Daemon laufen. Der Check dient nur zur Sichtbarkeit.
Default: ptbtime1.ptb.de (offizielle deutsche Zeitreferenz der Physikalisch-Technischen Bundesanstalt, Stratum 1, sehr hohe Verfuegbarkeit).
Alternativen: ptbtime2.ptb.de, ptbtime3.ptb.de, de.pool.ntp.org, time.cloudflare.com. Leerlassen um den Check zu deaktivieren.
Aktuelle Werte sind im Admin-Bereich unter Einstellungen > System einsehbar.
Verwendung
Dateien
- Dateien per Drag-and-Drop oder Upload-Button hochladen
- Ganze Ordner mit Unterordnern hochladen (Drag & Drop oder Ordner-Button)
- Ordner erstellen, Dateien verschieben/umbenennen
- Ordner als ZIP herunterladen
- Geloeschte Dateien landen im Papierkorb (wiederherstellen oder endgueltig loeschen)
- Share-Links erstellen mit drei Berechtigungsstufen:
- Nur Lesen - Download, Ordnerinhalt sehen
- Lesen + Schreiben - Download, Upload, Loeschen
- Nur Upload - Hochladen ohne Einblick (Briefkasten-Modus)
- Optional: Passwort und Ablaufdatum fuer Share-Links
- Dateien/Ordner mit anderen Benutzern teilen (Lesen/Schreiben/Admin)
- Gruenes Icon zeigt an welche Dateien bereits Freigaben haben
Kalender
- Monats-/Wochen-/Tagesansicht (FullCalendar)
- Drag & Drop zwischen Tagen, Termindauer per Rand-Ziehen
- Wiederkehrende Termine: taeglich/woechentlich/monatlich/jaehrlich, "jeden 2. Mittwoch", eigene Intervalle, Enddatum oder Anzahl
- Serientermine: "Nur diesen" oder "Ganze Serie" bearbeiten
- Kalender-Sichtbarkeit pro Kalender per Checkbox
- Kalender mit anderen Benutzern teilen (Lesen oder Lesen+Schreiben)
- iCal-Abo-Link mit optionalem Passwort (HTTP Basic Auth)
- Voller CalDAV-Server (RFC 4791 Subset) - siehe unten
CalDAV-Zugriff
Native Sync mit Handy/Laptop-Kalendern. Server-URL ist immer
https://<deine-domain>/dav/ - Benutzername + Passwort wie im Web.
| Client | Einrichtung |
|---|---|
| iOS/macOS | Einstellungen > Kalender > Accounts > Anderer > CalDAV-Account, Server cloud.example.com/dav/ |
| Android (DAVx5) | Konto hinzufuegen > Anmeldung mit URL und Benutzername, URL https://cloud.example.com/dav/ |
| Thunderbird | Neuer Kalender > Im Netzwerk > CalDAV, URL https://cloud.example.com/dav/ (Thunderbird findet die Kalender selbst) |
| Outlook | Plugin CalDAV-Synchronizer, Server-URL https://cloud.example.com/dav/ |
Unterstuetzte Operationen: PROPFIND (Auto-Discovery via /.well-known/caldav),
REPORT (calendar-query / calendar-multiget inkl. Zeitraumfilter), GET/PUT/DELETE
fuer einzelne Termine, MKCALENDAR, EXDATE fuer Serienausnahmen. ETags werden
benutzt damit Clients erkennen, was sich geaendert hat.
Kontakte
- Adressbuecher anlegen, Kontakte erstellen/bearbeiten
- Adressbuecher mit anderen Benutzern teilen
- vCard-Export fuer Backup
- CardDAV-Zugriff analog zum Kalender
- E-Mail-Konten unter Einstellungen hinzufuegen (IMAP/SMTP-Zugangsdaten)
- Admin kann E-Mail-Konten fuer andere Benutzer anlegen
- Kein eigener Mailserver noetig - verbindet sich mit externen Mailservern
- Bei keinem konfigurierten Konto wird der E-Mail-Bereich ausgeblendet
- Mehrere Konten: Ordner nach Konten gruppiert, Standard-Absender = aktives Konto
Office-Dateien
- Doppelklick oder Auge-Icon oeffnet die Vorschau
- Mit OnlyOffice: Vollwertiger Editor fuer DOCX, XLSX, PPTX (wie Google Docs)
- Ohne OnlyOffice: Einfache Vorschau (HTML/Tabelle/Folien), Text-Dateien bearbeitbar
- PDF wird inline angezeigt, Bilder mit Vorschau
Passwort-Manager
- Alle Daten clientseitig mit AES-256-GCM verschluesselt (Zero Knowledge)
- TOTP-Codes direkt generieren
- Passwort-Generator integriert
- Import aus: KeePass (.kdbx), Firefox (CSV), Chrome/Bitwarden/1Password (CSV)
- Ordner/Gruppen wie in KeePass
- Einzelne Passwoerter oder ganze Ordner mit anderen Benutzern teilen
Backup & Restore
- Lokales Backup: ZIP-Download mit Datenbank + allen Dateien
- SFTP-Backup: Automatisch auf SFTP-Server sichern
- Mehrere Backup-Ziele moeglich
- Konfigurierbares Intervall (15 Min. bis woechentlich)
- Versionierung mit automatischem Aufraumen
- Versionen durchsuchen und Einzeldateien wiederherstellen
- Restore: ZIP hochladen (Chunked Upload fuer grosse Backups) oder direkt von SFTP
Administration
- Benutzer anlegen, bearbeiten, deaktivieren, loeschen
- Benutzersuche
- E-Mail-Konten pro Benutzer verwalten
- Oeffentliche Registrierung an/aus
- Einladungslinks (funktionieren auch bei deaktivierter Registrierung)
- System-Email (SMTP) fuer Benachrichtigungen und Einladungen
Projektstruktur
backend/
app/
api/ # REST-Endpunkte
models/ # SQLAlchemy-Models
services/ # Business-Logik (Crypto, SFTP, Email, Scheduler)
dav/ # CalDAV/CardDAV (Radicale-Vorbereitung)
wsgi.py # Einstiegspunkt
frontend/
src/
views/ # Vue-Seiten
components/ # Wiederverwendbare Komponenten
stores/ # Pinia State Management
api/ # Axios API-Client
router/ # Vue Router
data/ # Laufzeitdaten (gitignored)
minicloud.db # SQLite-Datenbank
files/ # Hochgeladene Dateien
Desktop Sync Client
Der Desktop-Client (clients/desktop/) synchronisiert Dateien zwischen der Cloud und einem lokalen Ordner. Gebaut mit Tauri 2 (Rust + Vue).
Features
- Multi-Sync-Pfade: Beliebig viele Server-Ordner auf lokale Ordner mappen (z.B.
/Projekte->~/Projekte,/Shared/Team->~/Team) - Virtual Files:
.cloud-Platzhalter (0 Bytes), Download erst bei Doppelklick. Kein Speicherverbrauch fuer nicht benoetigte Dateien - Full Sync: Alternativ alle Dateien komplett lokal spiegeln (pro Pfad waehlbar)
- Offline-Markierung: Einzelne Dateien als offline verfuegbar markieren (Rechtsklick im Datei-Browser)
- Sofort-Sync: Filesystem-Watcher erkennt lokale Aenderungen sofort (3s Debounce), kein Polling
- Intelligenter Sync: Checksum-Tracking erkennt wer sich geaendert hat (Server oder Lokal)
- Konflikt-Erkennung: Bei gleichzeitiger Aenderung wird eine Konflikt-Kopie erstellt
- File Locking: Lock beim Oeffnen, Heartbeat alle 60s, manuelles Entsperren per Rechtsklick, auto-unlock nach 15 Min ohne Heartbeat
- System-Tray: Minimiert in den Tray statt zu beenden, Doppelklick oeffnet Fenster
- Minimiert starten: Optional direkt im Tray starten (Checkbox in Einstellungen)
- Auto-Login: Zugangsdaten und Sync-Pfade bleiben nach Neustart/Update erhalten
- Terminalserver: Pro User eine eigene Instanz, keine Konflikte zwischen Benutzern
- .cloud Datei-Handler: Doppelklick im Explorer oeffnet ueber den Client
Terminalserver-Verhalten
| Szenario | Verhalten |
|---|---|
| User A startet Client | Laeuft, eigenes Lock-File in %APPDATA%\MiniCloud Sync\ |
| User B startet Client | Laeuft separat, eigenes Lock-File in seinem %APPDATA% |
User A doppelklickt .cloud |
Laufende Instanz von User A oeffnet die Datei |
| User A startet nochmal | "Already running" -> beendet sich sofort |
| Client crashed | Naechster Start prueft ob PID noch lebt -> stale Lock -> ueberschreibt |
Virtual Files vs. Full Sync
| Virtual Files | Full Sync | |
|---|---|---|
| Speicher | Nur .cloud Platzhalter (0 Bytes) | Alle Dateien komplett lokal |
| Zugriff | Doppelklick = Download + Oeffnen | Sofort verfuegbar |
| Offline | Nur markierte Dateien | Alles offline |
| Upload | Neue lokale Dateien werden hochgeladen | Bidirektionaler Sync |
| Empfehlung | Grosse Datenmengen, Laptops | Kleine Ordner, immer offline noetig |
Sync-Logik (Checksum-Tracking)
Der Client merkt sich den Checksum jeder Datei beim letzten Sync. Beim naechsten Sync wird verglichen wer sich geaendert hat:
| Lokal geaendert | Server geaendert | Aktion |
|---|---|---|
| Nein | Ja | Server -> Lokal (Download) |
| Ja | Nein | Lokal -> Server (Upload) |
| Ja | Ja | Konflikt: Lokale Datei wird zu Datei (Konflikt).txt, Server-Version wird heruntergeladen |
| Nein | Nein | Nichts (identisch) |
Beim ersten Sync (kein gespeicherter Checksum) gewinnt immer der Server.
File Locking
Dateien werden beim Oeffnen ueber den Client automatisch auf dem Server gesperrt. Andere Benutzer sehen "Datei gesperrt von X" und koennen sie nicht bearbeiten.
| Szenario | Was passiert |
|---|---|
| .cloud Datei oeffnen | Download + Lock + Heartbeat alle 60s |
| Fertig -> Rechtsklick "Entsperren" | Lock sofort aufgehoben |
| Rechtsklick "Nicht mehr offline" | Lock aufgehoben + zurueck zu .cloud |
| Client beenden ohne Entsperren | Kein Heartbeat -> Lock laeuft nach 15 Min ab |
| Laptop zugeklappt / Netzwerk weg | Kein Heartbeat -> Lock laeuft nach 15 Min ab |
| Admin im Web-UI | Kann jeden Lock jederzeit manuell loesen |
Was das Lock wirklich kann (und was nicht)
Das Auschecken ist ein Hinweis-Schloss, kein physikalisches Dateischloss. Kurz gesagt: es hindert alle Mini-Cloud-Wege am Bearbeiten, aber nicht den Windows-Explorer oder andere Programme auf der Festplatte.
| Wo greift das Lock? | Beispiel |
|---|---|
| ✅ Web-Oberflaeche | Anna kann im Browser die Datei nicht oeffnen/bearbeiten - "wird von Adam bearbeitet" |
| ✅ Desktop-Client | Doppelklick in der Client-Ansicht -> Fehlermeldung, Datei oeffnet nicht |
| ✅ Automatischer Upload | Hat Anna die Datei trotzdem editiert, hebt der Client sie nicht hoch, solange Adam das Lock haelt |
| ❌ Windows-/Mac-Explorer | Anna kann die lokale Datei im Dateimanager oeffnen (ist ja eine ganz normale Datei auf der Platte) |
| ❌ Externe Programme | Word, Excel, Notepad usw. sehen das Lock nicht - jedes Programm kann die Datei oeffnen |
Beispiel im Alltag:
- Adam checkt
Bericht.xlsxaus (oeffnet sie im Client) - Anna hat den Ordner auch gesynct und die Datei liegt bei ihr lokal
- Anna versucht, sie im Browser zu oeffnen -> blockiert
- Anna versucht, sie im Client zu oeffnen -> blockiert
- Anna oeffnet sie im Explorer direkt -> geht auf (weil die Datei technisch ja nur eine normale Datei ist)
- Anna bearbeitet und speichert lokal -> Client bemerkt die Aenderung, sieht das Fremd-Lock und haelt den Upload zurueck
- Adam checkt ein: jetzt vergleicht der Client - hat Adam auch geaendert? Wenn ja, wird Annas Version zu
Bericht (Konflikt Anna 2026-04-12 143022).xlsxund Adams Version gewinnt. Niemand verliert Daten, aber ein Mensch muss die Versionen zusammenfuehren.
Das ist derselbe Ansatz wie bei Nextcloud oder Dropbox: Konflikt-Kopie als Sicherheitsnetz, keine kernel-tiefe Dateisperre. Der Schutz kommt ueber die Upload-Sperre - damit landet ein versehentliches Bearbeiten nie beim eigentlichen Owner.
Bauen
# Voraussetzung: Docker
# Linux:
./build.sh linux
# Windows (Cross-Compile):
./build.sh windows
# macOS (nur auf Mac):
./build.sh mac
# Alle Desktop-Plattformen:
./build.sh all-desktop
Auto-Upload auf den Server
Nach dem Build wird der Client automatisch auf den Cloud-Server hochgeladen und steht dort zum Download bereit.
Auf der Entwicklungsmaschine (nicht auf dem Server!) in die .env eintragen:
# URL der Cloud-Instanz
CLOUD_URL=https://cloud.example.com
# SECRET_KEY des Zielservers (identisch mit SECRET_KEY in der Server-.env)
BUILD_UPLOAD_TOKEN=der-secret-key-vom-server
Danach laedt ./build.sh linux (etc.) den Build automatisch hoch. Auf der Login-Seite erscheint dann "Desktop & Mobile Clients herunterladen".
Wichtig: CLOUD_URL und BUILD_UPLOAD_TOKEN gehoeren NUR in die .env der Entwicklungsmaschine, NICHT auf den Produktionsserver!
Einstellungen
Einstellungen werden gespeichert in:
- Windows:
%APPDATA%\MiniCloud Sync\config.json - Linux:
~/.config/MiniCloud Sync/config.json - macOS:
~/Library/Application Support/MiniCloud Sync/config.json
Gespeichert werden: Server-URL, Benutzername, Passwort (base64), Sync-Pfade. Bleiben bei Updates erhalten.
Roadmap
- Mobile Sync-Client (iOS, Android) mit On-Demand-Download + File Provider
- Native Passwort-Manager Clients mit Autofill und Biometrie
- Radicale-Integration fuer vollstaendiges CalDAV/CardDAV-Protokoll
Lizenz
Privates Projekt.