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>
Wenn der Client vorher aktiv war und dann deaktiviert wurde (oder
hart beendet), wandelt CfUnregisterSyncRoot alle Platzhalter in
normale Dateien um. Beim erneuten Aktivieren versuchte
populate_placeholders einen neuen Platzhalter anzulegen, was aber
mit ERROR_FILE_EXISTS scheiterte - der Fehler wurde zudem nur per
eprintln geloggt und verschluckt.
Ergebnis: die Datei blieb eine ganz normale Datei (kein Platzhalter,
kein Wolken-Icon). Spaeter fragt CfDehydratePlaceholder dann mit
HRESULT 0x80070178 "Die Datei ist keine Clouddatei", und "Speicher
freigeben" funktioniert nicht.
Jetzt prueft populate_placeholders vor jedem Create, ob die Datei
schon existiert und KEIN Platzhalter ist. Wenn ja: loeschen,
dann neu als Platzhalter anlegen. Erfolge und Fehler gehen beide
ins .minicloud-cloudfiles.log, damit man das Ergebnis prueft.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
set_pin_state hatte drei Probleme:
- FILE_READ_ATTRIBUTES: CfSetPinState braucht WRITE_ATTRIBUTES
- Kein OPEN_REPARSE_POINT: das Oeffnen selbst hat evtl. die
Hydration getriggert, bevor wir unpinnen konnten
- Kein CfDehydratePlaceholder: Pin-Wechsel auf UNPINNED aendert
nur das Flag, der Disk-Space wird nicht freigegeben
Jetzt:
- WRITE_ATTRIBUTES + OPEN_REPARSE_POINT beim Handle-Oeffnen
- Bei Unpin zusaetzlich CfDehydratePlaceholder, damit "Speicher
freigeben" auch wirklich Platz freiraeumt
- Ergebnis + Fehler werden nach <parent>\.minicloud-cloudfiles.log
geschrieben, damit wir sehen was passiert
handle_cli_shortcuts loggt nun nach %LOCALAPPDATA%\MiniCloud Sync\
cli.log, weil Explorer die stdout/stderr eines gestarteten Prozesses
verwirft. Ohne das Log kann man die vom Kontextmenue gestarteten
Aktionen nicht debuggen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Alter AppliesTo-Wert hatte:
- verdoppelte Backslashes (Windows AQS will einfache)
- einen verirrten Schluss-Backslash in der Quote, was die Query
aufgebrochen hat
Neu:
- Saubere AQS-Syntax: System.ItemPathDisplay:~< "C:\\..." mit
einfachen Backslashes (winreg schreibt REG_SZ 1:1)
- Registrierung unter AllFilesystemObjects statt *, damit auch
Ordner den Menueeintrag erhalten
- Default-Wert (MUIVerb zusaetzlich) gesetzt, weil manche Windows-
Versionen den Default fuer den Anzeigename nutzen
- uninstall entfernt beide Registry-Stellen (alte und neue)
Hinweis fuer Windows 11: klassische Shell-Verben stehen standard-
maessig nur unter "Weitere Optionen anzeigen" (Shift+F10). Fuer
das Haupt-Menue braeuchte man IExplorerCommand via COM-Extension.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wenn der Windows-Client mit Cloud-Files (OneDrive-Style) laeuft,
macht der klassische Sync-Pfade-Abschnitt samt lokalem .cloud-
Dateibrowser keinen Sinn mehr - Cloud-Files erzeugt Platzhalter
direkt im Explorer und bietet das gleiche On-Demand-Verhalten
mit nativer Shell-Integration.
Server-Dateien bleiben sichtbar (nuetzlich als Remote-Browser
unabhaengig vom Mount).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend:
- /api/sync/tree liefert jetzt {tree, shared} - shared enthaelt alle
Dateien die MIT dem Benutzer geteilt wurden (FilePermission), nur
Top-Level-Shares, mit Owner-Name im Anzeigenamen
- updated_at zusaetzlich als modified_at im Response fuer Client-
Kompatibilitaet
Client:
- fetch_remote_entries merged Shared-Subtree unter virtuellem Ordner
"Geteilt mit mir" (synthetische ID -1) in den Mount-Point
- modified_at faellt auf updated_at zurueck, falls nicht vorhanden
Kontextmenue:
- Neue HKCU-Registry-Eintraege fuer "Immer offline verfuegbar" und
"Speicher freigeben", AppliesTo filtert auf Mount-Pfad, sodass die
Verben nur bei Dateien unterhalb des Sync-Ordners erscheinen
- Aufruf der eigenen .exe mit --pin / --unpin <file>
- handle_cli_shortcuts fuehrt die Aktion aus und beendet sofort,
ohne die UI/Tray/Single-Instance-Logik anzustossen
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Registriert den Sync-Ordner als Shell-Namespace-Extension unter
HKEY_CURRENT_USER (kein Admin noetig), sodass er mit eigenem Icon
in der linken Leiste des Datei-Explorers erscheint - wie bei
OneDrive oder Dropbox.
- Neues Modul cloud_files::shell_integration mit install/uninstall
- Registry-Eintraege unter HKCU\Software\Classes\CLSID\{GUID} und
HKCU\...\Explorer\Desktop\NameSpace\{GUID}
- Nutzt die laufende .exe als Icon-Quelle (fallback: imageres.dll)
- SHChangeNotify(SHCNE_ASSOCCHANGED) damit Explorer sofort aktualisiert
- install/uninstall werden aus register_sync_root/unregister aufgerufen
- winreg-Crate fuer sauberen Registry-Zugriff
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CfUnregisterSyncRoot VOR CfRegisterSyncRoot, damit alte Policies
(z.B. PARTIAL) nicht durch UPDATE-Flag kleben bleiben
- FETCH_PLACEHOLDERS-Stub registriert, der mit leerer Antwort und
DISABLE_ON_DEMAND_POPULATION-Flag antwortet. Safety-Net falls
Windows trotz FULL-Policy doch danach fragt
- log_msg an kritischen Stellen (register, connect, populate), damit
wir beim naechsten Timeout sehen wo es haengt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mit PARTIAL erwartet Windows einen FETCH_PLACEHOLDERS-Callback
fuer die Ordnerenumeration. Den haben wir nicht registriert, also
lief der Explorer beim Oeffnen des Mount-Ordners in Timeout.
FULL bedeutet: wir fuellen alle Platzhalter selbst vor (machen wir
schon in populate_placeholders) und Windows fragt nicht nach.
Hydration bleibt PARTIAL - Datei-Inhalt wird weiter bei Zugriff
per FETCH_DATA geladen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ursache des "voll gesynct"-Problems: der notify-Watcher feuerte auf die
cfapi-Platzhalter, die wir selbst beim Aktivieren angelegt haben. Der
sync_loop hat die dann als lokale Aenderung hochgeladen, was implizit
die Hydration ausgeloest hat. Ergebnis: keine On-Demand-Platzhalter,
sondern voller Sync.
- is_cfapi_placeholder() prueft FILE_ATTRIBUTE_OFFLINE /
RECALL_ON_DATA_ACCESS / RECALL_ON_OPEN - solche Dateien werden beim
Upload uebersprungen
- Log-Datei liegt jetzt NEBEN dem Mount (nicht drin), damit sie nicht
selbst als Cloud-Datei behandelt wird
- FETCH_DATA loggt jetzt auch Success, damit man sieht dass der
Callback ueberhaupt feuert
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- cloud_files_mount in AppConfig -> bleibt ueber Neustarts erhalten
- Beim Auto-Login wird Cloud-Files automatisch wieder aktiviert
- Neue Commands cloud_files_get_mount und cloud_files_force_cleanup
- UI zeigt "Aufraeumen"-Button wenn Mount gesetzt aber nicht aktiv,
damit User einen Ordner der nach hartem Beenden des Clients als
toter Sync-Root haengt wieder freigeben/loeschen kann
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- HTTP-Client bekommt 60s-Timeout (statt unendlich)
- Bei Send-/Netzwerkfehler wird CfExecute immer mit Failure-Status
abgeschlossen, damit Explorer nicht ins OS-Timeout laeuft
- Wenn Server kein Range unterstuetzt (200 statt 206), wird aus dem
Full-Body der angeforderte Bereich herausgeschnitten und die
tatsaechliche Laenge an CfExecute uebergeben
- Fehler werden in <mount>\.minicloud-cloudfiles.log geschrieben,
damit man das Problem bei Timeout ueberhaupt sehen kann
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Jetzt tatsaechlich funktionsfaehig, nicht mehr nur Dummy:
- Register-Fallback: erst CF_REGISTER_FLAG_NONE, bei "bereits registriert"
automatisch mit UPDATE erneut versuchen. Klappt damit bei Erstaktivierung
und bei Client-Neustart.
- Hintergrund-Loop (cloud_files::sync_loop) pollt alle 30s
/api/sync/changes, legt neue Placeholder an und ersetzt geaenderte.
- Eigener Callback-Watcher (cloud_files::watcher::CallbackWatcher) hoert
auf den Mount-Ordner und sendet lokale Aenderungen (Create/Modify) an
den Loop, der sie via POST /api/files/upload hochlaedt.
- Helper create_placeholder_at() vom Windows-Modul exportiert, damit der
Loop neue Server-Dateien als Placeholder anlegen kann.
- AppState erhaelt cloud_files_loop + cloud_files_watcher Felder; beim
Disable wird der Loop sauber gestoppt und der Watcher gedroppt.
Frontend (App.vue):
- Neue Sektion "Cloud-Files (OneDrive-Style)" nur sichtbar wenn die
Plattform es unterstuetzt (cloud_files_supported).
- Ordner-Picker + Aktivieren/Deaktivieren-Button.
- Fehlermeldungen + Sync-Log-Eintraege.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
In windows-rs 0.58 hat CfConnectSyncRoot nur 4 Argumente und liefert
den CF_CONNECTION_KEY direkt zurueck, keinen out-Parameter mehr.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Neuer Modus neben dem bestehenden Full-Sync: Dateien erscheinen im
Explorer als Platzhalter mit Wolken-Icon und werden erst bei Zugriff
vom Mini-Cloud-Server gestreamt.
Windows (MVP):
- CfRegisterSyncRoot + CfConnectSyncRoot
- CfCreatePlaceholders fuer jede Datei aus /api/sync/tree
- FETCH_DATA-Callback mit Range-basiertem HTTPS-Download + CfExecute
- CfSetPinState fuer manuelles "Immer offline halten"
Linux (Skelett):
- FUSE-Provider hinter Feature-Flag linux_fuse (libfuse3-dev)
- Stub-Funktionen - Implementierung folgt
macOS:
- Platzhalter, erfordert Apple-Signatur - spaeter
Tauri-Commands: cloud_files_supported/enable/disable/pin/unpin.
Cargo.toml: target-spezifische windows-rs Dependency.
Doku: clients/desktop/CLOUD_FILES.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Damit ist auf den ersten Blick erkennbar, dass auch der Ordner-Button
einen Upload ausloest (und nicht bloss eine Ordner-Aktion).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wenn der eigene und ein freigegebener Kalender/Adressbuch/Aufgabenliste
denselben Namen tragen, sind sie in den Anlegen-Dialogen jetzt
unterscheidbar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stift-Icon neben dem Namen oeffnet Inline-Editor (Eingabefeld + Check/X).
Enter speichert, ESC bricht ab. Nur fuer Eigentuemer sichtbar.
Backend-PUT-Endpunkte sind bereits vorhanden.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ContactsView: Adressbuch-Auswahl im Kontakt-Dialog (versteckt bei nur
einem beschreibbaren Buch). Neuer-Kontakt-Button disabled wenn keiner.
- TasksView: gleiches fuer Aufgabenlisten.
- CalendarView: writableCalendars (eigene + Schreibfreigaben) ersetzt
ownCalendars in Event-Dialog und Import-Auswahl. Auswahlfeld nur ab 2.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend:
- User.first_name / User.last_name (nullable, Auto-Migrate fuegt sie an)
full_name/display_name als Properties + in to_dict
- TaskList.owner-Relationship ergaenzt (fehlte, daher wurden geteilte
Listen beim Empfaenger nicht korrekt aufgeloest)
- /auth/me GET + PUT (Profil bearbeiten: Vorname, Nachname, E-Mail)
- /users/search findet jetzt auch nach Vor-/Nachname und liefert
full_name/display_name mit
- list_tasklists/list_calendars/list_addressbooks liefern
owner_full_name und owner_display_name
Frontend:
- Sidebars bei Kontakten/Kalender/Aufgaben: "(geteilt von <Voller Name>)"
mit Fallback auf Username
- User-Search-Popup zeigt vollen Namen neben Username
- SettingsView: Vorname/Nachname/E-Mail bearbeiten
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stift-Icon neben Freigabe oeffnet Inline-Editor mit Select "Lesen" /
"Lesen+Schreiben" (analog zu Kontakten/Kalender).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Vermeidet unnoetigen Platzbedarf beim Build (31 Pakete / 192 MB werden
sonst mitgezogen).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Analog zu Kontakten/Kalender: ab 2 Zeichen werden Vorschlaege per
/users/search eingeblendet.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- /api/settings gibt zusaetzlich timezone, timezone_abbr, server_time,
ntp_server zurueck (alle read-only, aus Config/ENV).
- AdminView zeigt neuen Abschnitt "System-Zeit" mit Zeitzone, aktueller
Server-Zeit und NTP-Server samt Hinweis "wird in der .env festgelegt".
- .env.example: Liste gaengiger TZ-Werte mit Link zur IANA-Vollliste.
- README.md: neuer Abschnitt "Zeitzone & NTP" mit Werte-Tabelle.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- .env / .env.example: TZ=Europe/Berlin und NTP_SERVER=ptbtime1.ptb.de
(offizielle deutsche Zeitreferenz, hohe Verfuegbarkeit)
- app/__init__.py setzt prozessweite Zeitzone frueh via os.environ+tzset
- Leichtgewichtiger SNTP-Client (pure socket, keine deps) prueft den
Uhr-Offset beim Start im Hintergrund-Thread und warnt bei Abweichung >5s
- Dockerfile installiert tzdata und ENV TZ=Europe/Berlin als Fallback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Kontakte:
- Mehrfachauswahl in der Liste (Checkbox-Spalte) mit Bulk-Loeschen
- Export als Sammel-vCard (.vcf), als ZIP mit Einzel-vCards oder als CSV
- Import aus vCard (mehrere im File moeglich) oder CSV; Match per UID,
bestehende Kontakte werden aktualisiert
Kalender:
- Export als iCalendar (.ics) oder CSV
- Import aus .ics oder CSV; bestehende Termine via UID aktualisiert
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Browser/Kalender-App fragen sonst nach Benutzername+Passwort - der
Benutzername muss leer bleiben.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Checkbox-Spalte plus Header-Checkbox "Alle". Bulk-Aktion mit
Bestaetigung loescht ausgewaehlte Termine; Read-Only-Eintraege
werden uebersprungen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Titel reagiert reaktiv auf Login/Logout. Favicon ist die Wolke aus
der Sidebar (pi-cloud-Style).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Anrede: Herr/Frau/Divers (fest), Titel: Dr./Prof./Dipl.-Ing./... (editierbar).
Beim Speichern werden beide zu vCard-PREFIX zusammengesetzt, beim Laden
wieder aufgesplittet.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Anrede/Suffix/PLZ etc. hatten max-width-Container, das InputText darin
behielt aber die Default-Breite und ueberlief. Globale CSS-Regel sorgt
nun dafuer, dass jedes Input/Select seinen Field-Container ausfuellt.
field-row wrappt auf schmalen Dialogen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- caldav.py sendet SSE-Notifications bei Event-PUT/DELETE und Kalender-Loeschung,
damit das Web-UI auch auf Aenderungen aus DAVx5 sofort reagiert.
- FullCalendar navLinks: Klick auf Tagesnummer im Monatsraster wechselt in
die Tagesansicht.
- Neue Listen-Ansicht mit Volltext-Suche, Datumsbereich, Kalender-Filter,
Sortierung nach Datum/Titel und Loeschen-Button pro Zeile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Master-Event eines Serientermins liegt oft vor dem sichtbaren Bereich -
das FullCalendar-RRULE-Plugin braucht ihn trotzdem zur Expansion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Die CardDAV-Route /<username>/<ab_part>/ fing REPORT auf Kalender-URLs
(z.B. /dav/Adam/cal-1/) mit 404 ab, weil 'cal-1' nicht mit 'ab-' startet.
DAVx5 bekam bei der calendar-query einen 404 und markierte den EVENTS-
Sync als Hard Error. Fix analog zu PROPFIND/OPTIONS: wenn ab_part nicht
ab-* ist, an den CalDAV-REPORT-Handler delegieren.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DAVx5 registriert Dienste basierend auf dem DAV-Response-Header. Ohne
'addressbook' im Header wurde CardDAV bei der Auto-Discovery ignoriert,
obwohl addressbook-home-set korrekt gemeldet wurde. Das erklaert warum
nur der caldav-Service fuer Adam angelegt wurde.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Die zuletzt eingefuehrten Sub-Container (calendars/, addressbooks/) bei
PROPFIND Depth 1 auf /dav/<user>/ wurden von DAVx5 als leere Kalender
gezaehlt (DEFAULT_TASK_CALENDAR_NAME-Phantom-Eintraege). Da die CardDAV-
Route jetzt korrekt an den Home-Set-Handler delegiert, reicht es wenn der
Principal nur sich selbst liefert - Clients folgen den Home-Sets.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Die CardDAV-Route /<username>/<ab_part>/ ist in Flask spezifischer als
die generische /<path:subpath> des CalDAV-Handlers und hat daher auch
/dav/<user>/calendars/ abgefangen - mit 404, weil 'calendars' nicht mit
'ab-' anfaengt. Ergebnis: DAVx5 bekam auf das Home-Set eine 404 und
zeigte keine Eintraege mehr an.
Fix: wenn ab_part nicht mit 'ab-' anfaengt, an den CalDAV-PROPFIND/OPTIONS
delegieren statt 404 zurueckzugeben.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Checkbox pro Eintrag, "Alle auswaehlen" oben und roter Loesch-Button mit
Anzahl. Sicherheitsabfrage vor dem Loeschen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DAVx5 brauchte Kind-Container unter /dav/<user>/ - sonst blieben die
Listen nach Aktualisieren leer. Die Home-Sets bleiben getrennt
(calendar-home-set vs addressbook-home-set), aber der Principal zeigt
beide Sub-Container jetzt explizit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Kalender und Adressbuecher teilten sich den gleichen Home-Set
(/dav/<user>/). DAVx5 hat bei Depth-1-PROPFIND beide Collection-
Typen angezeigt und mangels bekanntem Resourcetype als
"DEFAULT_TASK_CALENDAR_NAME"-Kacheln gelistet.
Loesung:
* calendar-home-set zeigt auf /dav/<user>/calendars/
* addressbook-home-set zeigt auf /dav/<user>/addressbooks/
* Beide Pfade sind eigene Container-Collections - PROPFIND Depth 1
liefert nur den jeweils passenden Typ
* /dav/<user>/ selbst gibt bei Depth 1 keine Kinder mehr zurueck,
Clients folgen den Home-Sets
* Die konkreten URLs cal-<id> / ab-<id> liegen weiterhin unter
/dav/<user>/ (keine Breaking Change fuer existierende Clients;
nur die Discovery-URL aendert sich)
Frontend:
CalendarView + ContactsView zeigen als Auto-Discovery-URL nur
noch den Hostname - PROPFIND auf / funktioniert ja jetzt. Die
Direkt-URL bleibt vollstaendig mit /dav/<user>/cal-<id> bzw.
ab-<id> fuer Clients die das brauchen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Komplette Kontakte-Ueberarbeitung analog zum Kalender-Ausbau.
Backend-Model:
* AddressBook: color (pro Buch), ausserdem Per-User-Color via
AddressBookShare.color wie bei CalendarShare.
* Contact: volle Outlook-artige Struktur - prefix/first/middle/
last/suffix, display_name, nickname, organization, department,
job_title, birthday, anniversary, notes, photo sowie JSON-
Spalten fuer mehrfach vorhandene Felder (emails, phones,
addresses mit allen Adressteilen, websites, impp, categories).
Backend-API:
* REST CRUD uebernimmt die neuen Felder und generiert vCard 3.0
als Source of Truth fuer CardDAV. Voller vCard-Parser +
-Builder mit Escape/Unescape, TYPE-Parametern, Line-Folding.
* Neuer Endpoint PUT /addressbooks/<id>/my-color - persoenliche
Farbe pro Buch ohne den Besitzer zu beeinflussen.
* SSE-Events vom Typ 'addressbook' an Besitzer + alle Share-
Empfaenger bei jeder Aenderung.
CardDAV-Server (backend/app/dav/carddav.py):
* Volle Discovery via principal - addressbook-home-set wird
neben calendar-home-set annonciert.
* PROPFIND/REPORT/GET/PUT/DELETE/MKCOL fuer
/dav/<user>/ab-<id>/ und /<...>/{uid}.vcf
* addressbook-query + addressbook-multiget REPORTs
* ETag-basierte Konfliktpruefung via If-Match/If-None-Match
Frontend (ContactsView.vue):
* Komplett neuer Editor mit vier Tabs: Allgemein (Name, Org),
Kommunikation (Emails/Phones/Websites/IMPP dynamisch),
Adressen (mehrere mit allen Teilen), Details (Geburtstag,
Jahrestag, Kategorien, Notizen).
* Avatar mit Fotoauswahl oder Initialen-Farbkreis.
* Kalender-Sharing-Flow 1:1 uebernommen: Autocomplete fuer
Benutzersuche, Share-Liste mit Stift zum Bearbeiten, Muelleimer
zum Entfernen, Per-User-Farbe, CardDAV-URL-Info-Block pro
Adressbuch, Live-Refresh via SSE.
* Suche durchsucht Displayname, E-Mail und Firma.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bisher wurde immer die komplette calendar-data mitgeschickt, auch
wenn der Client nur getetag wollte. DAVx5 macht einen zweistufigen
Sync: erst calendar-query nach ETags, dann multiget fuer die
neuen/geaenderten Events. Server-seitig zu viel zu liefern bricht
diesen Ablauf - Client denkt er hat alles und ueberspringt die
zweite Stufe, aber die Events landen nicht in der Android-Kalender-
DB.
Jetzt: calendar-query schaut nach ob <c:calendar-data/> in den
angefragten Props steht und liefert entsprechend.
calendar-multiget liefert weiterhin immer die vollen Daten.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DAVx5 sendet bei calendar-query oft nur <time-range start=.../>
ohne end. Mein Code hat dann blind CalendarEvent.dtstart < None
gefiltert, was SQLAlchemy mit TypeError abbrechen liess - Ergebnis
HTTP 500, Sync scheitert komplett.
Zwei Korrekturen:
* end-Filter wird nur gesetzt wenn end wirklich vorhanden ist
* time-range-Parser strippt tzinfo, damit Vergleiche mit den
tz-naiven DB-Spalten keine Exception werfen
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>