# hesprs/obsidian-webdav-sync architecture

> Architecture diagram of the GitHub repository hesprs/obsidian-webdav-sync, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-21). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/hesprs/obsidian-webdav-sync
- Repository: https://github.com/hesprs/obsidian-webdav-sync

## Overview

1. **What this repository is**
   - An Obsidian plugin that performs bidirectional sync between a user’s local vault and a remote WebDAV server.
   - The architecture is centered on keeping three views of state in sync: current local files, current remote files, and the last recorded sync state.

2. **Plugin boundary and host environment**
   - The code runs inside Obsidian, not as a standalone server or web app.
   - The main entrypoint in `src/index.ts` wires the plugin into Obsidian’s lifecycle, settings system, commands, UI surfaces, and sync triggers.

3. **Primary data flow**
   - Local vault content is scanned through a filesystem abstraction.
   - Remote content is traversed through a WebDAV adapter.
   - A sync record store tracks prior state, enabling incremental and conflict-aware decisions instead of blind mirroring.

4. **Sync orchestration layer**
   - `src/events` defines the sync trigger surface, including manual sync, scheduled sync, and termination.
   - `src/services/sync-scheduler.service.ts` and `src/utils/launch-manual-sync.ts` feed those triggers into the central sync execution path.
   - `src/services/sync-executor.service.ts` is the orchestration hub that coordinates traversal, decision-making, task creation, and execution.

5. **Decision engine**
   - The decision subsystem in `src/sync/decision` performs the core three-way comparison.
   - It reconciles local state, remote state, and the recorded last-sync state to determine whether each path should be pushed, pulled, merged, created, or removed.
   - Conflict policies such as smart merge, latest-survive, use remote, use local, and skip are applied here.

6. **Task-based execution model**
   - The sync engine produces explicit tasks in `src/sync/tasks` rather than directly mutating files.
   - Tasks cover file creation, directory creation, deletion, recursive cleanup, push/pull transfers, merge handling, and sync-record maintenance.
   - Utility code in `src/sync/utils` optimizes, orders, merges, and chunks tasks to control concurrency and prevent pathological large-batch behavior.

7. **Local and remote filesystem adapters**
   - `src/fs/vault` adapts Obsidian’s local vault filesystem into traversal and utility operations.
   - `src/fs/webdav` adapts the remote WebDAV server, including API access, traversal, and remote-path utilities.
   - `src/fs/post-traversal.ts` suggests a normalization step after walking either side before the sync engine consumes the results.

8. **Persistence and incremental state**
   - `src/storage` holds durable local state for sync records and large-file chunk metadata.
   - The record store is what makes “current vs. previous sync” comparisons possible across sessions.
   - The chunk store supports resumable or staged transfer of large files, which is important for stability and memory control.

9. **Encryption boundary**
   - Client-side encryption is built into the sync pipeline, not treated as a separate service.
   - `src/composable/encryption.ts`, `src/utils/encryption.ts`, and `src/platform/crypto.ts` indicate a layered design: reusable encryption logic plus platform-specific crypto support.
   - The remote side sees encrypted payloads and metadata sufficient to detect unintended remote modification or movement.

10. **Rate limiting, batching, and resilience**
   - `src/composable/api-limiter.ts` and the WebDAV service layer manage request pacing and concurrency to avoid provider rate limits.
   - Large-file and high-file-count cases are handled with chunking, task optimization, and retryable-error checks.
   - This is a performance-sensitive architecture: network I/O, task concurrency, and memory usage are all controlled explicitly.

11. **User interface and observability**
   - UI is composed of modals in `src/components` for confirmation, filters, remote directory selection, sync progress, and encryption reminders.
   - The explorer and file-tree components provide a structured, selective sync view of pending changes.
   - `src/services/observability.service.ts` and helpers in `src/utils/logger.ts` support status, notices, and log output for troubleshooting.

12. **Configuration and extensibility**
   - Settings are organized under `src/settings` into account, common, filter, development, and plugin-instance concerns.
   - The repository also includes i18n under `src/i18n`, so the user-facing surface is locale-aware rather than hardcoded in one language.
   - `src/webdav-patch.ts` and `src/platform/*` show that some behavior is abstracted for environment-specific compatibility.

13. **External boundaries**
   - The only major external dependencies in the runtime architecture are Obsidian itself, the user’s local vault filesystem, and the remote WebDAV server.
   - Credentials are integrated with Obsidian’s keychain flow, so authentication is managed through the host app rather than a custom backend.
   - There is no separate application server; the plugin is a client-only sync engine embedded in Obsidian.

Main entry points: [`src/services/sync-executor.service.ts`](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/services/sync-executor.service.ts) (Sync executor), [`src/sync/index.ts`](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/index.ts) (Sync core), [`src/index.ts`](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/index.ts) (Plugin entry), [`src/events/index.ts`](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/events/index.ts) (Sync events)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_entry["Plugin entry"]
  node_src_index["Plugin entry<br/>obsidian plugin bootstrap<br/>[index.ts]"]
  node_events_index["Sync events<br/>trigger surface<br/>[index.ts]"]
  node_sync_scheduler["Scheduler<br/>sync trigger"]
  node_manual_launch["Manual launch<br/>sync trigger"]
end

subgraph group_sync["Sync engine"]
  node_sync_executor["Sync executor<br/>orchestrator"]
  node_sync_core["Sync core<br/>sync pipeline<br/>[index.ts]"]
  node_decider["Decider<br/>three-way compare<br/>[two-way.decider.ts]"]
  node_decider_fn["Decide fn<br/>decision rules"]
  node_task_types["Tasks<br/>task model<br/>[task.interface.ts]"]
  node_task_utils["Task utils<br/>task optimizer<br/>[optimize-tasks.ts]"]
end

subgraph group_fs["Filesystem adapters"]
  node_vault_fs["Vault FS<br/>local adapter<br/>[index.ts]"]
  node_webdav_fs["WebDAV FS<br/>remote adapter<br/>[index.ts]"]
  node_post_traversal["Post traversal<br/>normalizer<br/>[post-traversal.ts]"]
end

subgraph group_state["Persistent state"]
  node_sync_records[("Record store<br/>sync-state store")]
  node_chunk_store[("Chunk store<br/>transfer state")]
end

subgraph group_ui["UI and settings"]
  node_settings_index["Settings<br/>configuration<br/>[index.ts]"]
  node_components["Modals<br/>ui surfaces"]
  node_explorer["Explorer<br/>change browser<br/>[index.tsx]"]
end

subgraph group_infra["Shared infrastructure"]
  node_observability["Observability<br/>status and logging"]
  node_encryption["Encryption<br/>crypto layer<br/>[encryption.ts]"]
  node_api_limiter["API limiter<br/>rate limiter<br/>[api-limiter.ts]"]
  node_platform_crypto["Platform crypto<br/>platform support<br/>[crypto.ts]"]
end

node_src_index -->|"registers"| node_events_index
node_src_index -->|"loads"| node_settings_index
node_src_index -->|"opens"| node_components
node_src_index -->|"mounts"| node_explorer
node_events_index -->|"schedules"| node_sync_scheduler
node_events_index -->|"launches"| node_manual_launch
node_manual_launch -->|"starts"| node_sync_executor
node_sync_scheduler -->|"starts"| node_sync_executor
node_sync_executor -->|"scans"| node_vault_fs
node_sync_executor -->|"scans"| node_webdav_fs
node_vault_fs -->|"normalizes"| node_post_traversal
node_webdav_fs -->|"normalizes"| node_post_traversal
node_sync_executor -->|"reads/writes"| node_sync_records
node_sync_executor -->|"orchestrates"| node_sync_core
node_sync_core -->|"compares"| node_decider
node_decider -->|"implements"| node_decider_fn
node_sync_core -->|"produces"| node_task_types
node_sync_core -->|"optimizes"| node_task_utils
node_task_utils -->|"reorders"| node_task_types
node_task_types -->|"uses"| node_chunk_store
node_sync_core -->|"applies"| node_encryption
node_encryption -->|"delegates"| node_platform_crypto
node_webdav_fs -->|"throttles"| node_api_limiter
node_sync_executor -->|"reports"| node_observability

click node_src_index "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/index.ts"
click node_events_index "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/events/index.ts"
click node_sync_scheduler "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/services/sync-scheduler.service.ts"
click node_manual_launch "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/utils/launch-manual-sync.ts"
click node_sync_executor "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/services/sync-executor.service.ts"
click node_sync_core "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/index.ts"
click node_decider "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/decision/two-way.decider.ts"
click node_decider_fn "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/decision/two-way.decider.function.ts"
click node_task_types "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/tasks/task.interface.ts"
click node_task_utils "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/utils/optimize-tasks.ts"
click node_vault_fs "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/fs/vault/index.ts"
click node_webdav_fs "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/fs/webdav/index.ts"
click node_post_traversal "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/fs/post-traversal.ts"
click node_sync_records "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/storage/sync-record.store.ts"
click node_chunk_store "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/storage/file-chunk.store.ts"
click node_settings_index "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/settings/index.ts"
click node_components "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/components/SyncProgressModal.ts"
click node_explorer "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/components/explorer/index.tsx"
click node_observability "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/services/observability.service.ts"
click node_encryption "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/composable/encryption.ts"
click node_api_limiter "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/composable/api-limiter.ts"
click node_platform_crypto "https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/platform/crypto.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_src_index,node_events_index,node_sync_scheduler,node_manual_launch toneBlue
class node_sync_executor,node_sync_core,node_decider,node_decider_fn,node_task_types,node_task_utils toneAmber
class node_vault_fs,node_webdav_fs,node_post_traversal toneMint
class node_sync_records,node_chunk_store toneRose
class node_settings_index,node_components,node_explorer toneIndigo
class node_observability,node_encryption,node_api_limiter,node_platform_crypto toneTeal
```

## Components

### Plugin entry

Obsidian plugin lifecycle, commands, and sync triggers.

- [Plugin entry](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/index.ts): obsidian plugin bootstrap · Wires settings, commands, UI surfaces, and sync lifecycle into Obsidian. · `src/index.ts`
- [Sync events](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/events/index.ts): trigger surface · Defines manual sync, scheduled sync, and termination events. · `src/events/index.ts`
- [Scheduler](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/services/sync-scheduler.service.ts): sync trigger · Runs periodic sync initiation and timing control. · `src/services/sync-scheduler.service.ts`
- [Manual launch](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/utils/launch-manual-sync.ts): sync trigger · Starts a user-requested sync from commands or UI. · `src/utils/launch-manual-sync.ts`

### Sync engine

Three-way comparison, task generation, and execution.

- [Sync executor](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/services/sync-executor.service.ts): orchestrator · Coordinates traversal, decisions, task creation, and task execution. · `src/services/sync-executor.service.ts`
- [Sync core](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/index.ts): sync pipeline · Shared sync flow and error handling around decision and task phases. · `src/sync/index.ts`
- [Decider](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/decision/two-way.decider.ts): three-way compare · Compares local, remote, and last-sync state to decide actions. · `src/sync/decision/two-way.decider.ts`
- [Decide fn](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/decision/two-way.decider.function.ts): decision rules · Implements the decision logic used by the sync engine. · `src/sync/decision/two-way.decider.function.ts`
- [Tasks](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/tasks/task.interface.ts): task model · Encodes file create, delete, push, pull, merge, and record updates. · `src/sync/tasks/task.interface.ts`
- [Task utils](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/sync/utils/optimize-tasks.ts): task optimizer · Orders, merges, chunks, and limits task batches for safe execution. · `src/sync/utils/optimize-tasks.ts`

### Filesystem adapters

Local vault and remote WebDAV traversal abstractions.

- [Vault FS](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/fs/vault/index.ts): local adapter · Adapts Obsidian vault traversal and local file operations. · `src/fs/vault/index.ts`
- [WebDAV FS](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/fs/webdav/index.ts): remote adapter · Adapts remote WebDAV traversal, API access, and remote path handling. · `src/fs/webdav/index.ts`
- [Post traversal](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/fs/post-traversal.ts): normalizer · Normalizes walked file state before the sync engine consumes it. · `src/fs/post-traversal.ts`

### Persistent state

Durable sync records and transfer metadata.

- [Record store](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/storage/sync-record.store.ts): sync-state store · Persists prior sync state for incremental and conflict-aware comparison. · `src/storage/sync-record.store.ts`
- [Chunk store](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/storage/file-chunk.store.ts): transfer state · Persists large-file chunk metadata for staged or resumable transfers. · `src/storage/file-chunk.store.ts`

### UI and settings

User-facing modals, explorer views, and configuration.

- [Settings](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/settings/index.ts): configuration · Bundles account, filter, common, development, and plugin-instance settings. · `src/settings/index.ts`
- [Modals](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/components/SyncProgressModal.ts): ui surfaces · Confirmation, selection, progress, and reminder dialogs for sync workflows. · `src/components/SyncProgressModal.ts`
- [Explorer](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/components/explorer/index.tsx): change browser · Structured view of pending local and remote changes for selective sync. · `src/components/explorer/index.tsx`

### Shared infrastructure

Encryption, rate limiting, platform, and logging support.

- [Observability](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/services/observability.service.ts): status and logging · Provides notices, status updates, and troubleshooting logs. · `src/services/observability.service.ts`
- [Encryption](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/composable/encryption.ts): crypto layer · Shared encryption logic plus platform crypto support for client-side encrypted sync. · `src/composable/encryption.ts`
- [API limiter](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/composable/api-limiter.ts): rate limiter · Paces remote requests and controls concurrency to avoid WebDAV limits. · `src/composable/api-limiter.ts`
- [Platform crypto](https://github.com/hesprs/obsidian-webdav-sync/blob/main/src/platform/crypto.ts): platform support · Host-specific cryptographic primitives and compatibility helpers. · `src/platform/crypto.ts`

## Connections

- Plugin entry → Sync events: registers · Plugin startup wires sync triggers into Obsidian lifecycle.
- Plugin entry → Settings: loads · Plugin entry initializes user settings and configuration.
- Plugin entry → Modals: opens · Entry point connects commands and actions to modal UI.
- Plugin entry → Explorer: mounts · Entry point exposes the file-tree explorer surface.
- Sync events → Scheduler: schedules · Event surface feeds scheduled sync execution.
- Sync events → Manual launch: launches · Event surface includes manual sync initiation.
- Manual launch → Sync executor: starts · Manual sync hands control to the execution hub.
- Scheduler → Sync executor: starts · Scheduled sync hands control to the execution hub.
- Sync executor → Vault FS: scans · Executor traverses the local vault state.
- Sync executor → WebDAV FS: scans · Executor traverses the remote WebDAV state.
- Vault FS → Post traversal: normalizes · Local traversal results are normalized before comparison.
- WebDAV FS → Post traversal: normalizes · Remote traversal results are normalized before comparison.
- Sync executor → Record store: reads/writes · Executor consults and updates recorded sync state.
- Sync executor → Sync core: orchestrates · Executor delegates core sync flow to the sync pipeline.
- Sync core → Decider: compares · Core sync uses the decider for three-way reconciliation.
- Decider → Decide fn: implements · Decision object wraps the rules function.
- Sync core → Tasks: produces · Sync flow emits explicit execution tasks.
- Sync core → Task utils: optimizes · Task utilities batch and reorder tasks before execution.
- Task utils → Tasks: reorders · Optimization operates on the task model.
- Tasks → Chunk store: uses · Transfer tasks coordinate with chunk persistence for large files.
- Sync core → Encryption: applies · Encryption is embedded in the sync pipeline.
- Encryption → Platform crypto: delegates · Reusable encryption logic relies on platform crypto support.
- WebDAV FS → API limiter: throttles · Remote adapter controls request pacing and concurrency.
- Sync executor → Observability: reports · Execution path emits notices, status, and logs.
