From 513acc5606025bbd44354588f0ecb0ebe465ae07 Mon Sep 17 00:00:00 2001 From: Tristan Michael Date: Fri, 3 Apr 2026 10:34:44 -0700 Subject: [PATCH] Document WebDAV sync, workspace theming, and credential hardening Update CLAUDE.md to reflect completed WebDAV sync and expanded config/sync features. The docs now describe AppConfig fields (mode, theme, WebDAV URL), WorkspaceMode enum, WebDAV client details and credential handling (scoped keyring keys `com.onyx.webdav.::` with auto-migration from legacy dot-separated format on load), three-way sync with a 60s timeout and auto-creation of the Onyx/ remote subfolder, a 10MB PROPFIND response cap, plus UI changes (setup flow, per-workspace theme options) and other sync/setup UI improvements. --- CLAUDE.md | 18 +++++++++++------- docs/API.md | 3 +++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 344e0ea..cf557af 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,7 +37,9 @@ Two-crate workspace (`resolver = "2"`, edition 2021) plus a Tauri app: - **Storage trait** (`storage.rs`): Strategy pattern for task persistence. `FileSystemStorage` reads/writes markdown files with YAML frontmatter and JSON metadata files. - **Repository** (`repository.rs`): `TaskRepository` wraps a `Storage` impl and provides the public API for task/list CRUD, ordering, and grouping. Tests live here. -- **Config** (`config.rs`): `AppConfig` manages named workspaces with paths. Stored in platform-specific config dirs via the `directories` crate. +- **Config** (`config.rs`): `AppConfig` manages named workspaces with paths, mode (local/webdav), theme, and WebDAV URL. Stored in platform-specific config dirs via the `directories` crate. +- **Sync** (`sync.rs`): Three-way diff sync with offline queue. Auto-appends `Onyx/` to WebDAV URL. Wrapped in `tokio::time::timeout` (60s) to handle unreachable servers on Windows. +- **WebDAV** (`webdav.rs`): reqwest client with rustls-tls, 30s request timeout, 10s connect timeout. Credentials stored via `keyring` crate (feature-gated). `Zeroizing` for credential fields. Scoped keyring keys (`com.onyx.webdav.::`); auto-migrates legacy dot-separated format on load. 10MB PROPFIND response cap. ### On-disk format @@ -49,8 +51,8 @@ The GUI uses Svelte 5 runes mode (`$state`, `$derived`, `$effect`, `$props()`). - **Sliding drawer**: Left panel (lists) slides with main content as one piece via `translateX`. 80vw wide. List items show checkmark for active list and chevron on hover. - **Three-panel slide**: Main content area is 300% wide with three panels (task list, task detail, subtask detail) that slide via `translateX` using a `taskStack` array. Stack depth 0 = list, 1 = task detail, 2 = subtask detail. -- **Settings popup**: Floating overlay card with backdrop, not a sliding panel. -- **Workspace switcher**: Custom drop-up menu in drawer footer (left), settings gear (right). +- **Settings modal**: Per-workspace settings opened from workspace kebab menu. Shows WebDAV config (for webdav workspaces), sync controls, and theme selector. +- **Workspace switcher**: Custom drop-up menu in drawer footer (left), kebab menu per workspace (right) with Settings option. - **Task animations**: Grid-rows `0fr`/`1fr` trick for smooth collapse/expand. Module-level `animateInIds` Set coordinates expand-in after toggle. - **Inline editing**: Click task to edit, auto-save on blur. `debouncedSave` snapshots task before timer to prevent stale-reference errors on component destroy. - **Kebab menus**: Tasks and lists use kebab menus with custom `ConfirmDialog` component (not native `confirm()`). "Move to..." is inline in the menu (not a submenu) to avoid overflow. @@ -60,7 +62,7 @@ The GUI uses Svelte 5 runes mode (`$state`, `$derived`, `$effect`, `$props()`). ### Current state (2026-04-03) - **Phase 1** (Core + CLI): Complete -- **Phase 2** (WebDAV sync): Backend done, CLI done, GUI wired (settings auto-populates credentials) +- **Phase 2** (WebDAV sync): Complete — CLI + GUI sync working, auto-creates `Onyx/` subfolder on remote - **Phase 3** (GUI MVP): Complete - **Phase 4** (Mobile): Tauri Android cfg-gated, needs `tauri android init` + build @@ -73,7 +75,7 @@ The GUI uses Svelte 5 runes mode (`$state`, `$derived`, `$effect`, `$props()`). - Sliding lists drawer with checkmark selection - Settings popup overlay - Workspace switcher drop-up with add/remove -- Dark mode (GNOME-style neutral grays, cyan-blue accent) +- Per-workspace theme system (System default, Light, Dark, Nord, Dracula, Solarized Dark) via CSS `data-theme` attribute - Completed tasks section with animated show/hide - Due date picker/editor (DateTimePicker in new task + task detail); `has_time: bool` field tracks whether time is set - Move task between lists (inline list in kebab menu, no submenu) @@ -81,11 +83,13 @@ The GUI uses Svelte 5 runes mode (`$state`, `$derived`, `$effect`, `$props()`). - Group-by-due-date toggle per list (main panel kebab) - Delete completed tasks (main panel kebab + subtask kebab, with confirmation dialogs) - Keyboard shortcuts (Escape priority chain: settings → detail → list menu → drawer → menus) -- WebDAV setup flow (settings auto-populates URL/credentials from config + keychain) +- Setup screen with 2-step mode selection (Local Folder vs WebDAV Server), window dragging, "Open Existing Folder" option +- WebDAV setup flow with connection test, credential storage in system keychain +- WebDAV sync: auto-creates `Onyx/` subfolder on remote, 60s hard timeout, sync error display in settings - File watcher (notify crate, 500ms debounce, auto-reloads on external changes) -- Setup screen with window dragging + "Open Existing Folder" option - Sync status indicators (last-sync time + upload/download counts chip) - Push/pull/full sync mode selection (session-only, in settings) +- WorkspaceMode enum (local/webdav) with per-workspace config - Desktop packaging (Linux: AppImage + .deb; Windows: MSI) - Tauri desktop-only deps (notify, keyring) feature-gated for Android compilation - Subtask hierarchy: subtask count shown on parent tasks in list, subtask detail via three-panel slide navigation, inline add at top of subtask list (new subtasks prepend), collapsible completed subtasks section, cascade delete (parent deletion removes all subtasks with confirmation warning) diff --git a/docs/API.md b/docs/API.md index a877d4e..0216504 100644 --- a/docs/API.md +++ b/docs/API.md @@ -318,6 +318,8 @@ let status = get_sync_status(Path::new("/home/user/tasks"))?; Credentials are stored in the platform keychain (Windows Credential Manager, macOS Keychain, Linux Secret Service). +Keyring service keys use the format `com.onyx.webdav.::` — the `::` separator prevents key collisions when usernames contain dots. On first load, credentials stored in the legacy `.`-separated format (`com.onyx.webdav..`) are automatically migrated to the scoped format and the old entries are removed. + ```rust use onyx_core::webdav::{store_credentials, load_credentials, delete_credentials}; @@ -363,6 +365,7 @@ client.delete_file("old-task.md").await?; - **Conflict resolution**: Last-write-wins using file timestamps - **Offline queue**: Pending operations are queued and replayed when connectivity returns - **Sync state**: Stored in `.syncstate.json` within the workspace directory +- **Response size cap**: PROPFIND responses are limited to 10 MB (checked via `Content-Length` header and actual body size) to prevent memory exhaustion from malicious servers ## Error Handling