From 00d206162794c469eb1f7e574c9d6b09c8b7df5b Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sat, 22 Nov 2025 12:13:22 +0000 Subject: [PATCH] Update docs --- .github/workflows/deploy-docs.yml | 5 + docs/.prettierignore | 4 + docs/.prettierrc | 19 ++ docs/.vitepress/config.mts | 115 +++++----- docs/README.md | 17 +- docs/architecture/data-flow.md | 79 ++++--- docs/architecture/index.md | 12 ++ docs/architecture/sync-algorithm.md | 141 ++++++++---- docs/config/advanced.md | 207 +++++++++--------- docs/config/authentication.md | 264 +++++++++++++---------- docs/config/server.md | 167 +++++++------- docs/guide/alternatives.md | 324 ++++++++++++++++++++++++++++ docs/guide/cli-client.md | 86 +++++--- docs/guide/getting-started.md | 36 ++-- docs/guide/obsidian-plugin.md | 38 ++-- docs/guide/server-setup.md | 68 +++--- docs/guide/what-is-vaultlink.md | 10 + docs/index.md | 62 +++--- docs/package.json | 5 +- docs/public/logo.svg | 59 +++-- 20 files changed, 1149 insertions(+), 569 deletions(-) create mode 100644 docs/.prettierignore create mode 100644 docs/.prettierrc create mode 100644 docs/guide/alternatives.md diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 5deecf7d..49829998 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -42,6 +42,11 @@ jobs: cd docs npm ci + - name: Check formatting + run: | + cd docs + npm run format:check + - name: Build documentation run: | cd docs diff --git a/docs/.prettierignore b/docs/.prettierignore new file mode 100644 index 00000000..da61f8d6 --- /dev/null +++ b/docs/.prettierignore @@ -0,0 +1,4 @@ +node_modules/ +.vitepress/dist/ +.vitepress/cache/ +package-lock.json diff --git a/docs/.prettierrc b/docs/.prettierrc new file mode 100644 index 00000000..ea125e10 --- /dev/null +++ b/docs/.prettierrc @@ -0,0 +1,19 @@ +{ + "printWidth": 120, + "tabWidth": 4, + "useTabs": true, + "semi": false, + "singleQuote": false, + "trailingComma": "none", + "endOfLine": "lf", + "proseWrap": "preserve", + "overrides": [ + { + "files": "*.md", + "options": { + "proseWrap": "preserve", + "printWidth": 120 + } + } + ] +} diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 90eea790..d901bfde 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -1,62 +1,59 @@ -import { defineConfig } from 'vitepress' +import { defineConfig } from "vitepress" export default defineConfig({ - title: 'VaultLink', - description: 'Self-hosted real-time synchronization for Obsidian', - base: '/vault-link/', - themeConfig: { - logo: '/logo.svg', - nav: [ - { text: 'Home', link: '/' }, - { text: 'Guide', link: '/guide/getting-started' }, - { text: 'Architecture', link: '/architecture/' }, - { text: 'GitHub', link: 'https://github.com/schmelczer/vault-link' } - ], - sidebar: [ - { - text: 'Introduction', - items: [ - { text: 'What is VaultLink?', link: '/guide/what-is-vaultlink' }, - { text: 'Getting Started', link: '/guide/getting-started' } - ] - }, - { - text: 'Setup', - items: [ - { text: 'Server Setup', link: '/guide/server-setup' }, - { text: 'Obsidian Plugin', link: '/guide/obsidian-plugin' }, - { text: 'CLI Client', link: '/guide/cli-client' } - ] - }, - { - text: 'Configuration', - items: [ - { text: 'Server Configuration', link: '/config/server' }, - { text: 'Authentication', link: '/config/authentication' }, - { text: 'Advanced Options', link: '/config/advanced' } - ] - }, - { - text: 'Architecture', - items: [ - { text: 'Overview', link: '/architecture/' }, - { text: 'Sync Algorithm', link: '/architecture/sync-algorithm' }, - { text: 'Data Flow', link: '/architecture/data-flow' } - ] - } - ], - socialLinks: [ - { icon: 'github', link: 'https://github.com/schmelczer/vault-link' } - ], - footer: { - message: 'Released under the MIT License.', - copyright: 'Copyright © 2024-present Andras Schmelczer' - }, - search: { - provider: 'local' - } - }, - head: [ - ['link', { rel: 'icon', type: 'image/svg+xml', href: '/vault-link/logo.svg' }] - ] + title: "VaultLink", + description: "Self-hosted real-time synchronization for Obsidian", + base: "/vault-link/", + themeConfig: { + logo: "/logo.svg", + nav: [ + { text: "Home", link: "/" }, + { text: "Guide", link: "/guide/getting-started" }, + { text: "Architecture", link: "/architecture/" }, + { text: "GitHub", link: "https://github.com/schmelczer/vault-link" } + ], + sidebar: [ + { + text: "Introduction", + items: [ + { text: "What is VaultLink?", link: "/guide/what-is-vaultlink" }, + { text: "Getting Started", link: "/guide/getting-started" }, + { text: "Comparison with Alternatives", link: "/guide/alternatives" } + ] + }, + { + text: "Setup", + items: [ + { text: "Server Setup", link: "/guide/server-setup" }, + { text: "Obsidian Plugin", link: "/guide/obsidian-plugin" }, + { text: "CLI Client", link: "/guide/cli-client" } + ] + }, + { + text: "Configuration", + items: [ + { text: "Server Configuration", link: "/config/server" }, + { text: "Authentication", link: "/config/authentication" }, + { text: "Advanced Options", link: "/config/advanced" } + ] + }, + { + text: "Architecture", + items: [ + { text: "Overview", link: "/architecture/" }, + { text: "Sync Algorithm", link: "/architecture/sync-algorithm" }, + { text: "Data Flow", link: "/architecture/data-flow" } + ] + } + ], + socialLinks: [{ icon: "github", link: "https://github.com/schmelczer/vault-link" }], + footer: { + message: "Released under the MIT License.", + copyright: "Copyright © 2024-present Andras Schmelczer" + }, + search: { + provider: "local" + } + }, + head: [["link", { rel: "icon", type: "image/svg+xml", href: "/vault-link/logo.svg" }]] }) diff --git a/docs/README.md b/docs/README.md index a1032bbb..7a9f4522 100644 --- a/docs/README.md +++ b/docs/README.md @@ -44,6 +44,20 @@ Preview the built site: npm run preview ``` +### Format + +Format all markdown and TypeScript files: + +```bash +npm run format +``` + +Check formatting without making changes: + +```bash +npm run format:check +``` + ## Deployment The documentation is automatically deployed to GitHub Pages when changes are pushed to the `main` branch. @@ -81,6 +95,7 @@ docs/ ### Markdown Features VitePress supports: + - GitHub Flavored Markdown - Custom containers (tip, warning, danger) - Code syntax highlighting @@ -112,7 +127,7 @@ npm install ```yaml server: - port: 3000 + port: 3000 ``` ```` diff --git a/docs/architecture/data-flow.md b/docs/architecture/data-flow.md index 1b8ae1aa..228b11a9 100644 --- a/docs/architecture/data-flow.md +++ b/docs/architecture/data-flow.md @@ -22,6 +22,7 @@ sequenceDiagram ``` **Steps**: + 1. Client initiates WebSocket connection to server 2. Server accepts connection 3. Client sends authentication message with token and vault name @@ -72,6 +73,7 @@ sequenceDiagram ``` **Process**: + 1. Client scans local filesystem 2. Client requests file list from server 3. Server queries database and returns metadata @@ -106,6 +108,7 @@ sequenceDiagram ``` **Flow**: + 1. Filesystem watcher detects local change 2. Client reads file content 3. Client uploads file via WebSocket @@ -325,6 +328,7 @@ CREATE TABLE cursors ( ### Queries **Get files since version**: + ```sql SELECT * FROM documents WHERE version > ? AND deleted = FALSE @@ -332,6 +336,7 @@ ORDER BY version ASC; ``` **Store new version**: + ```sql INSERT INTO versions (document_id, version, content, created_at) VALUES (?, ?, ?, ?); @@ -342,6 +347,7 @@ WHERE id = ?; ``` **Update cursor**: + ```sql INSERT OR REPLACE INTO cursors (client_id, last_version, last_updated) VALUES (?, ?, ?); @@ -352,87 +358,96 @@ VALUES (?, ?, ?); ### Client → Server Messages **Upload File**: + ```json { - "type": "upload_file", - "path": "notes/example.md", - "content": "File content here...", - "base_version": 10, - "timestamp": "2024-01-01T12:00:00Z" + "type": "upload_file", + "path": "notes/example.md", + "content": "File content here...", + "base_version": 10, + "timestamp": "2024-01-01T12:00:00Z" } ``` **Download File**: + ```json { - "type": "download_file", - "path": "notes/example.md" + "type": "download_file", + "path": "notes/example.md" } ``` **Delete File**: + ```json { - "type": "delete_file", - "path": "notes/old.md" + "type": "delete_file", + "path": "notes/old.md" } ``` **List Files**: + ```json { - "type": "list_files", - "since_version": 0 + "type": "list_files", + "since_version": 0 } ``` ### Server → Client Messages **File Updated**: + ```json { - "type": "file_updated", - "path": "notes/example.md", - "version": 11, - "size": 1024, - "hash": "abc123..." + "type": "file_updated", + "path": "notes/example.md", + "version": 11, + "size": 1024, + "hash": "abc123..." } ``` **File Content**: + ```json { - "type": "file_content", - "path": "notes/example.md", - "content": "Updated content...", - "version": 11 + "type": "file_content", + "path": "notes/example.md", + "content": "Updated content...", + "version": 11 } ``` **File Deleted**: + ```json { - "type": "file_deleted", - "path": "notes/old.md", - "version": 12 + "type": "file_deleted", + "path": "notes/old.md", + "version": 12 } ``` **Sync Complete**: + ```json { - "type": "sync_complete", - "total_files": 150, - "current_version": 200 + "type": "sync_complete", + "total_files": 150, + "current_version": 200 } ``` **Error**: + ```json { - "type": "error", - "message": "File too large", - "code": "FILE_TOO_LARGE" + "type": "error", + "message": "File too large", + "code": "FILE_TOO_LARGE" } ``` @@ -441,18 +456,21 @@ VALUES (?, ?, ?); ### Client-Side Errors **Network failure**: + 1. Detect WebSocket disconnect 2. Queue pending operations 3. Retry connection with exponential backoff 4. Replay queued operations on reconnect **File read error**: + 1. Log error 2. Skip file 3. Continue with other files 4. Report to user **Write conflict**: + 1. Receive updated version from server 2. Apply OT merge locally 3. Overwrite local file @@ -461,16 +479,19 @@ VALUES (?, ?, ?); ### Server-Side Errors **Database error**: + 1. Log error 2. Return error to client 3. Client retries operation **Invalid operation**: + 1. Validate message format 2. Return specific error code 3. Client handles error appropriately **Authentication failure**: + 1. Reject connection 2. Send auth error 3. Client prompts for new credentials diff --git a/docs/architecture/index.md b/docs/architecture/index.md index e88c2b9d..888830d3 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -43,6 +43,7 @@ VaultLink is built as a distributed system with a central sync server and multip The central authority for synchronization, written in Rust using Axum framework. **Responsibilities**: + - Accept WebSocket connections from clients - Authenticate users via token-based auth - Store document versions in SQLite @@ -51,6 +52,7 @@ The central authority for synchronization, written in Rust using Axum framework. - Manage vault access control **Technology**: + - **Language**: Rust 1.89+ - **Framework**: Axum (async web framework) - **Database**: SQLite with SQLx @@ -62,6 +64,7 @@ The central authority for synchronization, written in Rust using Axum framework. TypeScript library providing core synchronization logic, used by both the Obsidian plugin and CLI client. **Responsibilities**: + - Manage WebSocket connection to server - Watch local filesystem for changes - Upload and download files @@ -70,6 +73,7 @@ TypeScript library providing core synchronization logic, used by both the Obsidi - Maintain sync metadata **Technology**: + - **Language**: TypeScript - **Build**: Webpack - **Protocol**: WebSocket client @@ -80,12 +84,14 @@ TypeScript library providing core synchronization logic, used by both the Obsidi Integration layer between sync client and Obsidian. **Responsibilities**: + - Provide UI for configuration - Bridge sync client with Obsidian's file system API - Handle Obsidian lifecycle events - Display sync status to users **Technology**: + - **Platform**: Obsidian Plugin API - **Core**: sync-client library - **UI**: Obsidian settings UI @@ -95,12 +101,14 @@ Integration layer between sync client and Obsidian. Standalone executable for syncing vaults without Obsidian. **Responsibilities**: + - Command-line interface - File system access via Node.js - Daemon mode for continuous sync - Health check endpoint for monitoring **Technology**: + - **Language**: TypeScript - **Runtime**: Node.js - **CLI**: Commander.js @@ -190,6 +198,7 @@ databases/ ``` **Database Schema** (simplified): + - **documents**: File metadata (path, size, modified time) - **versions**: Document content with version history - **cursors**: Client sync state @@ -213,6 +222,7 @@ The `.vaultlink` directory tracks which files have been synced and their version Client-server communication uses JSON messages over WebSocket. **Message Types**: + - `upload_file`: Client → Server (file upload) - `download_file`: Client → Server (request file) - `file_updated`: Server → Client (file changed notification) @@ -253,11 +263,13 @@ Token-based authentication on connection: ### Scaling Approaches **Vertical Scaling**: + - Increase server resources (CPU, RAM, storage) - Optimize database queries and indexing - Tune connection limits **Horizontal Scaling** (future): + - Separate vault servers (vault sharding) - Load balancer with sticky sessions - Shared storage layer for SQLite databases diff --git a/docs/architecture/sync-algorithm.md b/docs/architecture/sync-algorithm.md index 1f567efe..021c8ad7 100644 --- a/docs/architecture/sync-algorithm.md +++ b/docs/architecture/sync-algorithm.md @@ -9,11 +9,13 @@ Operational transformation is a technique for managing concurrent edits to the s ### Why OT? Traditional conflict resolution approaches: + - **Last write wins**: Loses data, frustrating for users - **Manual merging**: Interrupts workflow, requires user intervention - **Version branching**: Complex, not suitable for real-time sync Operational transformation: + - **Automatic**: No user intervention required - **Preserves all edits**: No data loss - **Real-time**: Changes appear immediately @@ -23,6 +25,39 @@ Operational transformation: VaultLink uses the [`reconcile-text`](https://crates.io/crates/reconcile-text) Rust library for operational transformation on text documents. +### Why reconcile-text over CRDTs? + +VaultLink faces a **differential synchronization** challenge: users edit Obsidian vaults with various editors (Obsidian desktop, Obsidian mobile, Vim, VS Code, or any text editor), often while offline. This means we only observe the **final state** of each document after editing, not the individual keystrokes or operations that produced it. + +**The fundamental problem**: + +- **CRDTs and traditional OT** require capturing every individual operation (each character insertion, deletion, cursor movement) +- **VaultLink's reality**: Users edit files with arbitrary tools, sync happens after the fact +- **What we know**: Parent version and two modified versions +- **What we don't know**: The sequence of operations that created those modifications + +**Why reconcile-text wins for this use case**: + +1. **Works with end states only**: reconcile-text performs conflict-free 3-way merging given just parent, left, and right versions—no operation history needed + +2. **Editor-agnostic**: Users can edit with any tool without requiring VaultLink-specific plugins or operation tracking + +3. **Offline-first**: Edits made while disconnected are merged cleanly when sync resumes, because we're diffing final states rather than replaying operations + +4. **No conflict markers**: Unlike Git merge, produces clean merged output without `<<<<<<<` markers that interrupt note-taking flow + +5. **Human text forgiveness**: For knowledge bases and documentation, a slightly imperfect merge (e.g., minor word order issues) is vastly preferable to manual conflict resolution + +6. **Simpler infrastructure**: No need for complex operation capture, transformation logs, or tombstone management that CRDTs require + +**The tradeoff**: + +CRDTs excel when you control the entire editing infrastructure and can capture every operation. reconcile-text excels when you're synchronizing independently-edited files—exactly VaultLink's scenario. The merge quality depends on Myers' diff algorithm rather than operation history, which is the correct tradeoff for differential sync. + +For note-taking workflows where users value editor freedom and offline editing, this approach provides superior user experience compared to either CRDTs (which would require operation tracking) or Git-style merging (which requires manual conflict resolution). + +[Learn more about reconcile-text →](https://schmelczer.dev/reconcile) + ### How It Works Given a base document and two sets of changes, OT produces a merged result that includes both changes. @@ -41,6 +76,7 @@ OT result: "Hello beautiful world!" (both changes applied) ### Operation Types The algorithm handles these operations: + - **Insert**: Add text at position - **Delete**: Remove text from position - **Retain**: Keep existing text unchanged @@ -62,10 +98,12 @@ VaultLink maintains sync state to track which changes have been applied. ### Version Vectors Each document has a version tracked by: + - **Server version**: Incremented on each change - **Client cursors**: Track which version each client has seen This enables: + - Efficient syncing (only send changes since last sync) - Conflict detection (concurrent edits to same version) - Ordering of operations @@ -84,6 +122,7 @@ struct Cursor { ``` On sync: + 1. Client sends cursor (last seen version) 2. Server returns all changes since that version 3. Client applies changes and updates cursor @@ -95,42 +134,47 @@ On sync: Two users edit the same paragraph simultaneously. **Initial state**: + ``` Version 10: "The quick brown fox jumps over the lazy dog." ``` **User A's edit** (version 11): + ``` "The quick brown fox jumps over the very lazy dog." ``` -*Inserts "very " at position 40* + +_Inserts "very " at position 40_ **User B's edit** (also from version 10): + ``` "The quick red fox jumps over the lazy dog." ``` -*Replaces "brown" with "red" at position 10* + +_Replaces "brown" with "red" at position 10_ ### Server Processing 1. **Receive User A's operation**: - - Base: version 10 - - Operation: Insert("very ", position=40) - - Apply to database → version 11 + - Base: version 10 + - Operation: Insert("very ", position=40) + - Apply to database → version 11 2. **Receive User B's operation**: - - Base: version 10 - - Operation: Replace("brown"→"red", position=10) - - **Conflict detected**: Base is version 10, but current is version 11 + - Base: version 10 + - Operation: Replace("brown"→"red", position=10) + - **Conflict detected**: Base is version 10, but current is version 11 3. **Transform User B's operation**: - - Transform against User A's operation - - Adjust positions/content as needed - - Apply transformed operation → version 12 + - Transform against User A's operation + - Adjust positions/content as needed + - Apply transformed operation → version 12 4. **Broadcast updates**: - - Send User A's operation to User B - - Send transformed User B's operation to User A + - Send User A's operation to User B + - Send transformed User B's operation to User A ### Final Result @@ -147,11 +191,13 @@ Both edits are preserved in the final document. **Scenario**: User A deletes a paragraph while User B edits it. **Resolution**: + - OT algorithm prioritizes preservation of content - Insert operation is transformed to account for deletion - Typically results in inserted content appearing nearby **Example**: + ``` Base: "Line 1\nLine 2\nLine 3" @@ -160,6 +206,7 @@ User B: Edit Line 2 → "Line 1\nLine 2 modified\nLine 3" Result: "Line 1\nLine 2 modified\nLine 3" ``` + (Insert takes precedence, preserving user content) ### 2. Overlapping Edits @@ -167,6 +214,7 @@ Result: "Line 1\nLine 2 modified\nLine 3" **Scenario**: Two users edit overlapping regions. **Resolution**: + - OT splits operations into non-overlapping segments - Applies each segment independently - Merges results @@ -176,6 +224,7 @@ Result: "Line 1\nLine 2 modified\nLine 3" **Scenario**: Two users delete overlapping text. **Resolution**: + - Deletes are merged - Final result has the union of deleted ranges removed @@ -184,6 +233,7 @@ Result: "Line 1\nLine 2 modified\nLine 3" **Scenario**: Client loses connection, makes edits offline, reconnects. **Resolution**: + 1. Client queues edits locally 2. On reconnect, sends all queued operations 3. Server applies OT against all operations that happened during partition @@ -206,6 +256,7 @@ Result: "Line 1\nLine 2 modified\nLine 3" ### Optimization VaultLink optimizes for: + - Small, frequent edits (typical typing patterns) - Text documents (not binary files) - Real-time processing (no batching delay) @@ -215,6 +266,7 @@ VaultLink optimizes for: ### Binary Files OT works best for text files. Binary files: + - Cannot be meaningfully merged - Use last-write-wins strategy - May cause data loss on concurrent edits @@ -224,6 +276,7 @@ OT works best for text files. Binary files: ### Large Documents Very large documents (> 1MB) may have: + - Higher transformation costs - Slower sync times - Increased memory usage @@ -233,6 +286,7 @@ Very large documents (> 1MB) may have: ### Complex Formatting Markdown with complex structures may occasionally produce unexpected results: + - Nested lists - Tables - Code blocks @@ -244,6 +298,7 @@ Markdown with complex structures may occasionally produce unexpected results: ### Strong Consistency VaultLink provides **strong eventual consistency**: + - All clients eventually converge to the same state - Operations applied in causal order - No data loss under normal operation @@ -264,32 +319,36 @@ VaultLink provides **strong eventual consistency**: ### Git-style Merging -| Aspect | Git Merge | VaultLink OT | -|--------|-----------|--------------| -| Real-time | No | Yes | -| Manual conflict resolution | Yes | No | -| Branching | Yes | No | -| Automatic merge | Limited | Always | -| Use case | Code changes | Collaborative documents | +| Aspect | Git Merge | VaultLink OT | +| -------------------------- | ------------ | ----------------------- | +| Real-time | No | Yes | +| Manual conflict resolution | Yes | No | +| Branching | Yes | No | +| Automatic merge | Limited | Always | +| Use case | Code changes | Collaborative documents | ### CRDTs (Conflict-free Replicated Data Types) -| Aspect | CRDTs | VaultLink OT | -|--------|-------|--------------| -| Server required | No | Yes | -| Memory overhead | Higher | Lower | -| Complexity | Higher | Lower | -| Deletion handling | Complex (tombstones) | Simple | -| Best for | Distributed systems | Centralized sync | +| Aspect | CRDTs | VaultLink (reconcile-text) | +| ----------------------------- | ------------------------------------ | ------------------------------------------------- | +| **Operation tracking** | Required (every keystroke) | Not required (end states only) | +| **Editor freedom** | Limited (must use CRDT-aware editor) | Unlimited (any text editor works) | +| **Offline editing** | Requires operation log | Works with file comparison | +| **Server required** | No | Yes | +| **Memory overhead** | Higher (tombstones, metadata) | Lower (versions only) | +| **Infrastructure complexity** | Higher | Lower | +| **Best for** | Controlled editing environments | Independent file editing (Obsidian, Vim, VS Code) | + +**Key insight**: CRDTs are superior when you can capture every operation. reconcile-text is superior when users edit files independently with arbitrary tools—exactly VaultLink's scenario. ### Last Write Wins -| Aspect | LWW | VaultLink OT | -|--------|-----|--------------| -| Data loss | Yes | No | -| Simplicity | High | Medium | -| User experience | Poor | Excellent | -| Performance | Best | Good | +| Aspect | LWW | VaultLink OT | +| --------------- | ---- | ------------ | +| Data loss | Yes | No | +| Simplicity | High | Medium | +| User experience | Poor | Excellent | +| Performance | Best | Good | ## Algorithm Details @@ -298,20 +357,20 @@ VaultLink provides **strong eventual consistency**: When transforming operation `A` against operation `B`: 1. **Insert vs Insert**: - - If positions equal: Order by client ID - - If different positions: Adjust positions + - If positions equal: Order by client ID + - If different positions: Adjust positions 2. **Insert vs Delete**: - - If insert in deleted range: Shift insert position - - If insert after delete: Adjust position by deleted length + - If insert in deleted range: Shift insert position + - If insert after delete: Adjust position by deleted length 3. **Delete vs Delete**: - - If ranges overlap: Merge delete ranges - - If ranges disjoint: Adjust positions + - If ranges overlap: Merge delete ranges + - If ranges disjoint: Adjust positions 4. **Retain vs Any**: - - Retain operations don't conflict - - Simply adjust positions + - Retain operations don't conflict + - Simply adjust positions ### Transformation Example diff --git a/docs/config/advanced.md b/docs/config/advanced.md index 25c2e974..4e129a04 100644 --- a/docs/config/advanced.md +++ b/docs/config/advanced.md @@ -13,11 +13,13 @@ While VaultLink handles most SQLite configuration automatically, you can optimiz VaultLink uses Write-Ahead Logging (WAL) mode by default for better concurrency. **Benefits**: + - Readers don't block writers - Writers don't block readers - Better performance for concurrent access **Maintenance**: + ```bash # Checkpoint WAL to main database (run periodically) sqlite3 databases/vault.db "PRAGMA wal_checkpoint(TRUNCATE);" @@ -39,6 +41,7 @@ sqlite3 databases/vault.db "ANALYZE;" ``` **Schedule maintenance**: + ```bash #!/bin/bash # monthly-maintenance.sh @@ -83,6 +86,7 @@ max_connections = (concurrent_users × avg_operations_per_user) + buffer ``` **Example**: + - 20 concurrent users - 2 operations per user on average - 25% buffer @@ -96,30 +100,33 @@ max_connections = (20 × 2) × 1.25 = 50 Adjust timeouts based on network characteristics: **Fast local network**: + ```yaml database: - cursor_timeout_seconds: 30 + cursor_timeout_seconds: 30 server: - response_timeout_seconds: 30 + response_timeout_seconds: 30 ``` **Slow or unreliable network**: + ```yaml database: - cursor_timeout_seconds: 180 + cursor_timeout_seconds: 180 server: - response_timeout_seconds: 120 + response_timeout_seconds: 120 ``` **Mobile clients**: + ```yaml database: - cursor_timeout_seconds: 300 # Longer for intermittent connections + cursor_timeout_seconds: 300 # Longer for intermittent connections server: - response_timeout_seconds: 180 + response_timeout_seconds: 180 ``` ## Reverse Proxy Configuration @@ -232,16 +239,16 @@ Using Docker labels: ```yaml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - labels: - - "traefik.enable=true" - - "traefik.http.routers.vaultlink.rule=Host(`sync.example.com`)" - - "traefik.http.routers.vaultlink.entrypoints=websecure" - - "traefik.http.routers.vaultlink.tls.certresolver=letsencrypt" - - "traefik.http.services.vaultlink.loadbalancer.server.port=3000" - # Middleware for timeouts - - "traefik.http.middlewares.vaultlink-timeout.timeout.request=3600s" + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + labels: + - "traefik.enable=true" + - "traefik.http.routers.vaultlink.rule=Host(`sync.example.com`)" + - "traefik.http.routers.vaultlink.entrypoints=websecure" + - "traefik.http.routers.vaultlink.tls.certresolver=letsencrypt" + - "traefik.http.services.vaultlink.loadbalancer.server.port=3000" + # Middleware for timeouts + - "traefik.http.middlewares.vaultlink-timeout.timeout.request=3600s" ``` ## Docker Optimizations @@ -252,16 +259,16 @@ Limit container resources: ```yaml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - deploy: - resources: - limits: - cpus: '2.0' - memory: 4G - reservations: - cpus: '1.0' - memory: 2G + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + deploy: + resources: + limits: + cpus: "2.0" + memory: 4G + reservations: + cpus: "1.0" + memory: 2G ``` ### Logging Configuration @@ -270,13 +277,13 @@ Optimize Docker logging: ```yaml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - logging: - driver: "json-file" - options: - max-size: "50m" - max-file: "5" + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + logging: + driver: "json-file" + options: + max-size: "50m" + max-file: "5" ``` ### Volume Optimization @@ -285,21 +292,21 @@ Use named volumes for better performance: ```yaml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - volumes: - - vaultlink-data:/data - - vaultlink-logs:/data/logs + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + volumes: + - vaultlink-data:/data + - vaultlink-logs:/data/logs volumes: - vaultlink-data: - driver: local - driver_opts: - type: none - o: bind - device: /mnt/fast-ssd/vaultlink - vaultlink-logs: - driver: local + vaultlink-data: + driver: local + driver_opts: + type: none + o: bind + device: /mnt/fast-ssd/vaultlink + vaultlink-logs: + driver: local ``` ## High Availability @@ -310,14 +317,14 @@ Comprehensive health monitoring: ```yaml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:3000/vaults/health/ping || exit 1"] - interval: 10s - timeout: 5s - retries: 3 - start_period: 30s + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:3000/vaults/health/ping || exit 1"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s ``` Monitor health in production: @@ -375,6 +382,7 @@ find "$BACKUP_DIR" -name "vaultlink-*.tar.gz" -mtime +$RETENTION_DAYS -delete ``` Schedule with cron: + ```cron 0 2 * * * /opt/vaultlink/backup-vaultlink.sh ``` @@ -424,21 +432,21 @@ While VaultLink doesn't expose metrics natively, monitor Docker: ```yaml # docker-compose.yml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - labels: - - "prometheus.io/scrape=true" - - "prometheus.io/port=3000" + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + labels: + - "prometheus.io/scrape=true" + - "prometheus.io/port=3000" - cadvisor: - image: gcr.io/cadvisor/cadvisor:latest - volumes: - - /:/rootfs:ro - - /var/run:/var/run:ro - - /sys:/sys:ro - - /var/lib/docker/:/var/lib/docker:ro - ports: - - 8080:8080 + cadvisor: + image: gcr.io/cadvisor/cadvisor:latest + volumes: + - /:/rootfs:ro + - /var/run:/var/run:ro + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro + ports: + - 8080:8080 ``` ### Log Analysis @@ -484,17 +492,17 @@ Run VaultLink in isolated network: ```yaml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - networks: - - vaultlink-internal - - proxy-external + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + networks: + - vaultlink-internal + - proxy-external networks: - vaultlink-internal: - internal: true - proxy-external: - driver: bridge + vaultlink-internal: + internal: true + proxy-external: + driver: bridge ``` ### Read-Only Root Filesystem @@ -503,12 +511,12 @@ Run with read-only root (mount writable volumes for data): ```yaml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - read_only: true - volumes: - - ./data:/data - - /tmp + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + read_only: true + volumes: + - ./data:/data + - /tmp ``` ### Drop Capabilities @@ -517,12 +525,12 @@ Run with minimal privileges: ```yaml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - security_opt: - - no-new-privileges:true - cap_drop: - - ALL + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + security_opt: + - no-new-privileges:true + cap_drop: + - ALL ``` ## Migration @@ -530,19 +538,22 @@ services: ### Moving to New Server 1. **Backup on old server**: - ```bash - ./backup-vaultlink.sh - ``` + + ```bash + ./backup-vaultlink.sh + ``` 2. **Transfer backup**: - ```bash - scp vaultlink-backup.tar.gz new-server:/tmp/ - ``` + + ```bash + scp vaultlink-backup.tar.gz new-server:/tmp/ + ``` 3. **Restore on new server**: - ```bash - ./restore-vaultlink.sh /tmp/vaultlink-backup.tar.gz - ``` + + ```bash + ./restore-vaultlink.sh /tmp/vaultlink-backup.tar.gz + ``` 4. **Update DNS/clients** to point to new server diff --git a/docs/config/authentication.md b/docs/config/authentication.md index 2437a5ab..944e56f2 100644 --- a/docs/config/authentication.md +++ b/docs/config/authentication.md @@ -5,6 +5,7 @@ VaultLink uses token-based authentication with per-user vault access control. Th ## Overview Authentication in VaultLink: + - **Token-based**: Users authenticate with secure tokens - **Configured in YAML**: All users defined in `config.yml` - **Vault-level access**: Control which vaults each user can access @@ -14,11 +15,11 @@ Authentication in VaultLink: ```yaml users: - user_configs: - - name: alice - token: alice-secure-token-here - vault_access: - type: allow_access_to_all + user_configs: + - name: alice + token: alice-secure-token-here + vault_access: + type: allow_access_to_all ``` ## User Configuration Fields @@ -35,6 +36,7 @@ Human-readable identifier for the user. Used in logs and auditing. ``` **Notes**: + - Must be unique across all users - Used for identification only, not authentication - Appears in server logs @@ -52,6 +54,7 @@ Authentication token for the user. Must be kept secret. ``` **Best practices**: + - Generate with: `openssl rand -hex 32` - Minimum length: 32 characters - Use different token per user @@ -59,6 +62,7 @@ Authentication token for the user. Must be kept secret. - Rotate periodically **Example token generation**: + ```bash # Generate a secure token openssl rand -hex 32 @@ -73,6 +77,7 @@ openssl rand -hex 32 Defines which vaults the user can access. **Three modes**: + 1. `allow_access_to_all`: Access to all vaults 2. `allow_list`: Access to specific vaults only 3. `deny_list`: Access to all vaults except specific ones @@ -85,14 +90,15 @@ Grant access to every vault: ```yaml users: - user_configs: - - name: admin - token: admin-token - vault_access: - type: allow_access_to_all + user_configs: + - name: admin + token: admin-token + vault_access: + type: allow_access_to_all ``` **Use cases**: + - Administrator accounts - Personal single-user deployments - Development/testing @@ -103,23 +109,25 @@ Grant access only to specific vaults: ```yaml users: - user_configs: - - name: alice - token: alice-token - vault_access: - type: allow_list - allowed: - - personal - - shared-team - - project-alpha + user_configs: + - name: alice + token: alice-token + vault_access: + type: allow_list + allowed: + - personal + - shared-team + - project-alpha ``` **Use cases**: + - Multi-user deployments - Restricted access scenarios - Separation of concerns **Notes**: + - User can only access listed vaults - Attempting to access other vaults returns authentication error - Empty list = no access to any vault @@ -130,21 +138,23 @@ Grant access to all vaults except specific ones: ```yaml users: - user_configs: - - name: bob - token: bob-token - vault_access: - type: deny_list - denied: - - restricted - - admin-only + user_configs: + - name: bob + token: bob-token + vault_access: + type: deny_list + denied: + - restricted + - admin-only ``` **Use cases**: + - Users with broad access except sensitive vaults - Simplify configuration when most vaults are accessible **Notes**: + - User can access any vault not in the deny list - Attempting to access denied vaults returns authentication error @@ -154,75 +164,75 @@ users: ```yaml users: - user_configs: - - name: me - token: my-super-secret-token - vault_access: - type: allow_access_to_all + user_configs: + - name: me + token: my-super-secret-token + vault_access: + type: allow_access_to_all ``` ### Small Team (Shared Vaults) ```yaml users: - user_configs: - - name: alice - token: alice-token - vault_access: - type: allow_list - allowed: - - personal-alice - - team-shared - - name: bob - token: bob-token - vault_access: - type: allow_list - allowed: - - personal-bob - - team-shared - - name: charlie - token: charlie-token - vault_access: - type: allow_list - allowed: - - personal-charlie - - team-shared + user_configs: + - name: alice + token: alice-token + vault_access: + type: allow_list + allowed: + - personal-alice + - team-shared + - name: bob + token: bob-token + vault_access: + type: allow_list + allowed: + - personal-bob + - team-shared + - name: charlie + token: charlie-token + vault_access: + type: allow_list + allowed: + - personal-charlie + - team-shared ``` ### Organization (Mixed Access) ```yaml users: - user_configs: - - name: admin - token: admin-token - vault_access: - type: allow_access_to_all + user_configs: + - name: admin + token: admin-token + vault_access: + type: allow_access_to_all - - name: developer - token: dev-token - vault_access: - type: allow_list - allowed: - - engineering-docs - - api-specs - - shared + - name: developer + token: dev-token + vault_access: + type: allow_list + allowed: + - engineering-docs + - api-specs + - shared - - name: designer - token: design-token - vault_access: - type: allow_list - allowed: - - design-docs - - brand-assets - - shared + - name: designer + token: design-token + vault_access: + type: allow_list + allowed: + - design-docs + - brand-assets + - shared - - name: readonly - token: readonly-token - vault_access: - type: allow_list - allowed: - - public-wiki + - name: readonly + token: readonly-token + vault_access: + type: allow_list + allowed: + - public-wiki ``` ## Authentication Flow @@ -231,23 +241,24 @@ users: 1. Client connects via WebSocket 2. Client sends authentication message: - ```json - { - "type": "auth", - "token": "user-token", - "vault": "vault-name" - } - ``` + ```json + { + "type": "auth", + "token": "user-token", + "vault": "vault-name" + } + ``` 3. Server validates: - - Token exists in config - - User has access to requested vault + - Token exists in config + - User has access to requested vault 4. Server responds: - - Success: Connection established - - Failure: Connection closed with error + - Success: Connection established + - Failure: Connection closed with error ### Validation Server checks: + 1. **Token match**: Token exists in `user_configs` 2. **Vault access**: User has permission for vault 3. **Connection limits**: Not exceeding `max_clients_per_vault` @@ -255,16 +266,19 @@ Server checks: ### Errors **Invalid token**: + ``` Authentication failed: Invalid token ``` **No vault access**: + ``` Authentication failed: User does not have access to vault 'restricted' ``` **Connection limit**: + ``` Connection rejected: Maximum clients reached for vault ``` @@ -289,14 +303,16 @@ uuidgen ### Token Storage **In config file**: + ```yaml users: - user_configs: - - name: alice - token: !ENV ALICE_TOKEN # Read from environment variable + user_configs: + - name: alice + token: !ENV ALICE_TOKEN # Read from environment variable ``` **Load from environment**: + ```bash export ALICE_TOKEN="$(openssl rand -hex 32)" ./sync_server config.yml @@ -314,11 +330,13 @@ Periodically change tokens: ### Token Revocation To revoke access: + 1. Remove user from `config.yml` 2. Restart server 3. User's connections will be rejected For immediate revocation: + - Remove user from config - Restart server - Existing connections are terminated @@ -354,6 +372,7 @@ Grant temporary access: 4. Restart server For automation: + ```bash # Add user with expiry comment echo " - name: temp-user # EXPIRES: 2024-12-31" >> config.yml @@ -363,6 +382,7 @@ echo " token: temp-token" >> config.yml ### Shared Tokens (Not Recommended) Multiple users sharing a token: + - All appear as same user in logs - Can't revoke individual access - Security risk if one person leaves @@ -432,25 +452,25 @@ Tokens for automated systems: ```yaml users: - user_configs: - - name: backup-service - token: backup-service-token - vault_access: - type: allow_access_to_all + user_configs: + - name: backup-service + token: backup-service-token + vault_access: + type: allow_access_to_all - - name: ci-pipeline - token: ci-token - vault_access: - type: allow_list - allowed: - - documentation + - name: ci-pipeline + token: ci-token + vault_access: + type: allow_list + allowed: + - documentation - - name: monitoring - token: monitoring-token - vault_access: - type: allow_list - allowed: - - metrics + - name: monitoring + token: monitoring-token + vault_access: + type: allow_list + allowed: + - metrics ``` ### Dynamic Vault Access @@ -462,6 +482,7 @@ VaultLink doesn't support runtime user management. To change access: 3. Users reconnect automatically For frequent changes, consider: + - Over-provision access (deny list) - Use external authentication proxy - Script config updates + reload @@ -471,18 +492,21 @@ For frequent changes, consider: ### Can't connect **Check token**: + ```bash # Verify token in config matches client grep "token:" config.yml ``` **Check vault name**: + ```bash # Ensure vault is in allowed list grep -A 5 "name: alice" config.yml ``` **Check server logs**: + ```bash tail -f logs/*.log | grep -i auth ``` @@ -490,18 +514,20 @@ tail -f logs/*.log | grep -i auth ### Access denied **Verify vault access**: + ```yaml # Check user's vault_access configuration users: - user_configs: - - name: alice - vault_access: - type: allow_list - allowed: - - vault-name # Must match exactly + user_configs: + - name: alice + vault_access: + type: allow_list + allowed: + - vault-name # Must match exactly ``` **Case sensitivity**: + - Vault names are case-sensitive - `Vault` ≠ `vault` - Ensure exact match in config and client @@ -509,11 +535,13 @@ users: ### Token not working **Check for typos**: + - Extra spaces - Hidden characters - Wrong quotes in YAML **Regenerate token**: + ```bash # Generate new token openssl rand -hex 32 diff --git a/docs/config/server.md b/docs/config/server.md index c6632b5e..26eb894a 100644 --- a/docs/config/server.md +++ b/docs/config/server.md @@ -14,40 +14,40 @@ The server is configured using a YAML file passed as a command-line argument: ```yaml database: - databases_directory_path: databases - max_connections_per_vault: 12 - cursor_timeout_seconds: 60 + databases_directory_path: databases + max_connections_per_vault: 12 + cursor_timeout_seconds: 60 server: - host: 0.0.0.0 - port: 3000 - max_body_size_mb: 512 - max_clients_per_vault: 256 - response_timeout_seconds: 60 + host: 0.0.0.0 + port: 3000 + max_body_size_mb: 512 + max_clients_per_vault: 256 + response_timeout_seconds: 60 users: - user_configs: - - name: admin - token: your-secure-random-token - vault_access: - type: allow_access_to_all - - name: alice - token: alice-token - vault_access: - type: allow_list - allowed: - - personal - - shared - - name: bob - token: bob-token - vault_access: - type: deny_list - denied: - - restricted + user_configs: + - name: admin + token: your-secure-random-token + vault_access: + type: allow_access_to_all + - name: alice + token: alice-token + vault_access: + type: allow_list + allowed: + - personal + - shared + - name: bob + token: bob-token + vault_access: + type: deny_list + denied: + - restricted logging: - log_directory: logs - log_rotation: 7days + log_directory: logs + log_rotation: 7days ``` ## Database Section @@ -62,10 +62,11 @@ Directory where SQLite database files are stored. One database file per vault. ```yaml database: - databases_directory_path: /data/databases + databases_directory_path: /data/databases ``` The directory structure: + ``` databases/ ├── vault-1.db @@ -74,6 +75,7 @@ databases/ ``` **Notes**: + - Path is relative to working directory or absolute - Directory must be writable by the server process - Ensure adequate disk space for vault data @@ -90,10 +92,11 @@ Maximum concurrent database connections per vault. ```yaml database: - max_connections_per_vault: 12 + max_connections_per_vault: 12 ``` **Tuning**: + - Higher values: Better performance under load - Lower values: Less memory usage - Typical range: 8-20 @@ -110,10 +113,11 @@ How long to keep database cursors alive for inactive clients. ```yaml database: - cursor_timeout_seconds: 60 + cursor_timeout_seconds: 60 ``` **Notes**: + - Cursors track client sync state - Timeout too short: Clients may need to re-sync frequently - Timeout too long: More memory usage @@ -139,6 +143,7 @@ server: ``` **Common values**: + - `0.0.0.0`: Listen on all network interfaces (production) - `127.0.0.1`: Listen on localhost only (development/testing) - Specific IP: Listen on specific interface @@ -154,10 +159,11 @@ TCP port to listen on. ```yaml server: - port: 3000 + port: 3000 ``` **Notes**: + - Must be available (not in use) - Privileged ports (< 1024) require root - Common ports: 3000, 8080, 8888 @@ -174,16 +180,18 @@ Maximum size of HTTP request body in megabytes. ```yaml server: - max_body_size_mb: 512 + max_body_size_mb: 512 ``` **Usage**: + - Limits file upload size - Prevents memory exhaustion attacks - Must be larger than largest expected file - Consider client `max_file_size_mb` settings **Tuning**: + - Small vaults (mostly text): 100 MB - Medium vaults (some images): 512 MB - Large vaults (many images/PDFs): 1024+ MB @@ -199,16 +207,18 @@ Maximum concurrent clients per vault. ```yaml server: - max_clients_per_vault: 256 + max_clients_per_vault: 256 ``` **Notes**: + - Limits concurrent WebSocket connections - Prevents resource exhaustion - Consider expected number of users - Each client uses memory and file descriptors **Scaling**: + - Personal use: 10-50 - Small team: 50-100 - Large team: 100-500 @@ -224,15 +234,17 @@ Maximum time to wait for client responses. ```yaml server: - response_timeout_seconds: 60 + response_timeout_seconds: 60 ``` **Usage**: + - Timeout for HTTP requests - Timeout for WebSocket operations - Clients disconnected if unresponsive **Tuning**: + - Fast networks: 30 seconds - Slow networks: 90-120 seconds - Large file uploads: Increase proportionally @@ -259,6 +271,7 @@ logging: ``` **Notes**: + - Path is relative to working directory or absolute - Directory must be writable - Logs are rotated based on `log_rotation` @@ -284,10 +297,12 @@ logging: **Format**: `` **Units**: + - `hours`: Hours (e.g., `12hours`, `24hours`) - `days`: Days (e.g., `7days`, `30days`) **Recommendations**: + - Development: `24hours` or `7days` - Production: `7days` or `30days` - High traffic: `24hours` (logs can be large) @@ -298,55 +313,55 @@ logging: ```yaml database: - databases_directory_path: ./databases - max_connections_per_vault: 8 - cursor_timeout_seconds: 30 + databases_directory_path: ./databases + max_connections_per_vault: 8 + cursor_timeout_seconds: 30 server: - host: 127.0.0.1 - port: 3000 - max_body_size_mb: 100 - max_clients_per_vault: 10 - response_timeout_seconds: 30 + host: 127.0.0.1 + port: 3000 + max_body_size_mb: 100 + max_clients_per_vault: 10 + response_timeout_seconds: 30 users: - user_configs: - - name: dev - token: dev-token - vault_access: - type: allow_access_to_all + user_configs: + - name: dev + token: dev-token + vault_access: + type: allow_access_to_all logging: - log_directory: logs - log_rotation: 24hours + log_directory: logs + log_rotation: 24hours ``` ### Production ```yaml database: - databases_directory_path: /data/databases - max_connections_per_vault: 16 - cursor_timeout_seconds: 120 + databases_directory_path: /data/databases + max_connections_per_vault: 16 + cursor_timeout_seconds: 120 server: - host: 0.0.0.0 - port: 3000 - max_body_size_mb: 512 - max_clients_per_vault: 256 - response_timeout_seconds: 90 + host: 0.0.0.0 + port: 3000 + max_body_size_mb: 512 + max_clients_per_vault: 256 + response_timeout_seconds: 90 users: - user_configs: - - name: admin - token: - vault_access: - type: allow_access_to_all - # Additional users... + user_configs: + - name: admin + token: + vault_access: + type: allow_access_to_all + # Additional users... logging: - log_directory: /data/logs - log_rotation: 7days + log_directory: /data/logs + log_rotation: 7days ``` ## Validation @@ -362,6 +377,7 @@ tail -f logs/latest.log ``` **Common errors**: + - Missing required fields - Invalid YAML syntax - Invalid values (negative numbers, etc.) @@ -375,11 +391,11 @@ For many concurrent users: ```yaml database: - max_connections_per_vault: 20 # Increase + max_connections_per_vault: 20 # Increase server: - max_clients_per_vault: 500 # Increase - response_timeout_seconds: 120 # Increase for slow clients + max_clients_per_vault: 500 # Increase + response_timeout_seconds: 120 # Increase for slow clients ``` ### Large Files @@ -388,8 +404,8 @@ For vaults with large files: ```yaml server: - max_body_size_mb: 1024 # Allow larger uploads - response_timeout_seconds: 180 # More time for uploads + max_body_size_mb: 1024 # Allow larger uploads + response_timeout_seconds: 180 # More time for uploads ``` ### Resource-Constrained Systems @@ -398,11 +414,11 @@ For limited CPU/memory: ```yaml database: - max_connections_per_vault: 6 # Reduce + max_connections_per_vault: 6 # Reduce server: - max_clients_per_vault: 50 # Reduce - max_body_size_mb: 256 # Reduce + max_clients_per_vault: 50 # Reduce + max_body_size_mb: 256 # Reduce ``` ## Security Considerations @@ -431,12 +447,14 @@ server: ### Server won't start **Check YAML syntax**: + ```bash # Use a YAML validator python -c 'import yaml, sys; yaml.safe_load(open("config.yml"))' ``` **Check file paths**: + ```bash # Ensure directories exist and are writable mkdir -p databases logs @@ -444,6 +462,7 @@ chmod 755 databases logs ``` **Check port availability**: + ```bash # Verify port is not in use lsof -i :3000 diff --git a/docs/guide/alternatives.md b/docs/guide/alternatives.md new file mode 100644 index 00000000..5e9b8977 --- /dev/null +++ b/docs/guide/alternatives.md @@ -0,0 +1,324 @@ +# Comparison with Alternatives + +VaultLink is one of several solutions for synchronizing Obsidian vaults. This page compares VaultLink with popular alternatives to help you choose the right tool. + +## Key Differentiator: Editor Agnostic + +**VaultLink is not tied to Obsidian.** While it includes an Obsidian plugin for convenience, VaultLink synchronizes plain text files and works with any editor: + +- Edit with **Obsidian desktop** on your laptop +- Edit with **Vim** on your server +- Edit with **VS Code** on your workstation +- Edit with **Obsidian mobile** on your phone +- Use the **CLI client** for automated workflows + +All changes merge automatically without conflict markers, regardless of which editor you use. This is possible because VaultLink uses [reconcile-text](/architecture/sync-algorithm#why-reconcile-text-over-crdts) for differential synchronization rather than requiring operation-level tracking. + +## VaultLink's Core Strengths + +Before diving into comparisons: + +1. **Fully self-hosted**: Server and all components are open source +2. **Collaborative editing**: Real-time sync with operational transformation +3. **Automatic conflict resolution**: No manual intervention or paid features required +4. **Cursor tracking**: See where other users are editing +5. **Extensively tested**: Comprehensive test suite for server and client +6. **Editor freedom**: Use any text editor, not just Obsidian +7. **Production-ready**: Docker images, health checks, monitoring + +## Obsidian Sync Alternatives + +### Self-hosted LiveSync + +**Downloads**: ~300,000 +**Repository**: https://github.com/vrtmrz/obsidian-livesync + +**Overview**: CouchDB/IBM Cloudant-based sync with end-to-end encryption. + +| Aspect | Self-hosted LiveSync | VaultLink | +| ------------------------- | --------------------------- | -------------------------------------- | +| **Self-hosted** | Yes (CouchDB required) | Yes (single binary or Docker) | +| **Conflict resolution** | Manual or automatic (basic) | Automatic (operational transformation) | +| **Collaborative editing** | No | Yes (real-time with cursors) | +| **Editor support** | Obsidian only | Any text editor | +| **Infrastructure** | CouchDB database | SQLite (bundled) | +| **Deployment complexity** | Medium (external DB) | Low (single container) | +| **End-to-end encryption** | Yes | No (transport encryption only) | +| **Out-of-band edits** | Limited support | Full support (edit with any tool) | + +**When to use LiveSync**: + +- Need end-to-end encryption +- Already running CouchDB +- Only use Obsidian (no external editors) + +**When to use VaultLink**: + +- Want collaborative editing with multiple users +- Edit files with various tools (Vim, VS Code, etc.) +- Need simpler deployment (no external database) +- Want operational transformation for better merges + +--- + +### Remotely Save + +**Downloads**: ~1.1M +**Repository**: https://github.com/remotely-save/remotely-save + +**Overview**: Sync to cloud storage providers (S3, Dropbox, OneDrive, WebDAV). + +| Aspect | Remotely Save | VaultLink | +| ------------------------- | ---------------------------- | ------------------------ | +| **Self-hosted** | Partial (uses cloud storage) | Fully self-hosted | +| **Conflict resolution** | Paid Pro feature | Free and automatic | +| **Collaborative editing** | No | Yes | +| **Editor support** | Obsidian only | Any text editor | +| **Storage backend** | Cloud providers | Self-hosted SQLite | +| **Cost** | Free (basic) / Paid (Pro) | Free (open source) | +| **Code quality** | No tests, complex codebase | Comprehensive test suite | +| **Real-time sync** | No (periodic polling) | Yes (WebSocket) | + +**When to use Remotely Save**: + +- Already use cloud storage (S3, Dropbox) +- Don't need real-time sync +- Single-user scenario + +**When to use VaultLink**: + +- Want full control over data +- Need automatic conflict resolution without paying +- Want real-time collaborative editing +- Value code quality and testing + +**Note**: Remotely Save's conflict resolution is a paid feature. VaultLink provides superior automatic merging for free. + +--- + +### Relay + +**Downloads**: ~24,000 +**Repository**: https://github.com/No-Instructions/Relay + +**Overview**: CRDT-based sync with proprietary server component. + +| Aspect | Relay | VaultLink | +| -------------------------- | ---------------------------- | ----------------------- | +| **Self-hosted** | No (proprietary server) | Yes (fully open source) | +| **Conflict resolution** | CRDT (automatic) | OT (automatic) | +| **Collaborative editing** | Yes | Yes | +| **Editor support** | Obsidian only | Any text editor | +| **Out-of-band edits** | No (breaks CRDT consistency) | Yes (differential sync) | +| **Server open source** | No | Yes | +| **Infrastructure control** | Limited | Full | +| **Per-file overhead** | High (CRDT metadata) | Low (version history) | + +**When to use Relay**: + +- Want hosted solution (don't self-host) +- Only edit within Obsidian +- Don't need out-of-band editing + +**When to use VaultLink**: + +- Need fully open source solution +- Want to self-host completely +- Edit files outside Obsidian (Vim, VS Code) +- Value infrastructure control + +**Critical limitation**: Relay's CRDT approach requires tracking every operation within Obsidian. Editing files outside Obsidian breaks the CRDT state. VaultLink's differential sync works regardless of how files are edited. + +--- + +### Obsidian Git + +**Downloads**: ~1.4M +**Repository**: https://github.com/denolehov/obsidian-git + +**Overview**: Uses Git for version control and synchronization. + +| Aspect | Obsidian Git | VaultLink | +| ------------------------- | ----------------------------- | ----------------------- | +| **Self-hosted** | Yes (Git server) | Yes (sync server) | +| **Conflict resolution** | Manual (conflict markers) | Automatic (no markers) | +| **Collaborative editing** | No | Yes (real-time) | +| **Editor support** | Any (it's Git) | Any (differential sync) | +| **Version history** | Full Git history | Document versions | +| **Real-time sync** | No (commit-based) | Yes (instant) | +| **Merge conflicts** | Manual resolution | Automatic | +| **Learning curve** | High (Git knowledge required) | Low | +| **Workflow interruption** | Yes (resolve conflicts) | No | + +**When to use Obsidian Git**: + +- Need full version control (branches, tags, etc.) +- Already familiar with Git workflows +- Want integration with existing Git repos +- Don't mind manual conflict resolution + +**When to use VaultLink**: + +- Want automatic conflict-free merging +- Need real-time collaborative editing +- Don't want workflow interruptions from merge conflicts +- Prefer simpler mental model (sync, not commits) + +**Key difference**: Git requires manual conflict resolution with `<<<<<<<` markers. VaultLink automatically merges all changes using operational transformation, never interrupting your workflow. + +--- + +### Syncthing Integration + +**Downloads**: ~22,600 +**Repository**: https://github.com/LBF38/obsidian-syncthing-integration + +**Overview**: Wrapper around Syncthing for file synchronization. + +| Aspect | Syncthing Integration | VaultLink | +| ------------------------- | ------------------------------ | ----------------- | +| **Self-hosted** | Yes (Syncthing) | Yes (sync server) | +| **Conflict resolution** | Manual | Automatic | +| **Collaborative editing** | No | Yes | +| **Editor support** | Any | Any | +| **Status** | Unfinished | Production-ready | +| **Conflict files** | Creates `.sync-conflict` files | No conflict files | +| **Real-time sync** | Yes | Yes | +| **Automatic merging** | No | Yes | + +**When to use Syncthing Integration**: + +- Already use Syncthing for other files +- Don't need automatic conflict resolution +- Single-user with multiple devices + +**When to use VaultLink**: + +- Want automatic conflict resolution +- Need collaborative editing +- Want production-ready solution +- Don't want to manage conflict files + +**Status note**: Syncthing Integration is marked as unfinished. VaultLink is production-ready with comprehensive testing. + +--- + +### Remotely Sync + +**Downloads**: ~38,000 +**Repository**: https://github.com/sboesen/remotely-sync + +**Overview**: Similar to Remotely Save, syncs to cloud storage. + +| Aspect | Remotely Sync | VaultLink | +| ----------------------- | ----------------------- | ------------------- | +| **Self-hosted** | Partial (cloud storage) | Fully self-hosted | +| **Conflict resolution** | Limited/Paid | Free and automatic | +| **Code quality** | No tests | Comprehensive tests | +| **Maintenance** | Low activity | Active development | + +**Same concerns as Remotely Save**: No test suite, conflict resolution limitations, cloud storage dependency. + +**When to use VaultLink**: See Remotely Save comparison above. + +--- + +### SyncFTP + +**Downloads**: ~5,000 +**Repository**: https://github.com/alex-donnan/SyncFTP + +**Overview**: Simple FTP-based file synchronization. + +| Aspect | SyncFTP | VaultLink | +| ------------------------- | ---------------------- | ---------------- | +| **Conflict resolution** | None (last write wins) | Automatic (OT) | +| **Data loss risk** | High (overwrites) | None (merges) | +| **Collaborative editing** | No | Yes | +| **Sophistication** | Minimal | Production-grade | + +**When to use SyncFTP**: Don't use SyncFTP for any scenario where data integrity matters. + +**When to use VaultLink**: Any scenario requiring reliable synchronization. + +--- + +## Feature Comparison Matrix + +| Feature | VaultLink | LiveSync | Relay | Git | Remotely Save | Syncthing | +| --------------------------------- | --------- | -------- | ----- | --- | ------------- | --------- | +| **Fully open source** | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | +| **Self-hosted** | ✅ | ✅ | ❌ | ✅ | Partial | ✅ | +| **Automatic conflict resolution** | ✅ | Basic | ✅ | ❌ | Paid | ❌ | +| **Real-time sync** | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | +| **Collaborative editing** | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | +| **Cursor tracking** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| **Editor agnostic** | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | +| **Out-of-band edits** | ✅ | Limited | ❌ | ✅ | ❌ | ✅ | +| **No conflict markers** | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | +| **Comprehensive tests** | ✅ | ❌ | ❌ | N/A | ❌ | N/A | +| **Simple deployment** | ✅ | ❌ | N/A | ❌ | ✅ | ❌ | +| **Low infrastructure** | ✅ | ❌ | N/A | ✅ | ✅ | ✅ | + +--- + +## VaultLink's Unique Position + +VaultLink is the **only** solution that combines: + +1. **Fully open source** self-hosted server +2. **Editor agnostic** operation (not locked to Obsidian) +3. **Automatic conflict-free merging** using operational transformation +4. **Real-time collaborative editing** with cursor tracking +5. **Differential synchronization** supporting out-of-band edits +6. **Comprehensive test coverage** ensuring reliability +7. **Simple deployment** via Docker or single binary + +## Use Case Recommendations + +### Choose VaultLink when you: + +- Edit vaults with multiple editors (Obsidian + Vim + VS Code) +- Need real-time collaboration with teammates +- Want automatic conflict resolution without manual intervention +- Value full control over infrastructure +- Need production-ready reliability with comprehensive testing +- Want to edit files while offline and sync later seamlessly + +### Consider alternatives when you: + +- **LiveSync**: Need end-to-end encryption and only use Obsidian +- **Git**: Need full version control with branches and advanced Git features +- **Remotely Save**: Already committed to cloud storage providers +- **Syncthing**: Already use Syncthing and don't need automatic merging + +## Migration from Other Solutions + +VaultLink works with plain Markdown files, making migration simple: + +1. **From Git**: Clone your repo, point VaultLink to the directory +2. **From cloud sync**: Download files, configure VaultLink client +3. **From LiveSync**: Export vault, import to VaultLink +4. **From Syncthing**: Point VaultLink to synced directory + +All solutions work with the same Markdown files—VaultLink just syncs them better. + +## Beyond Obsidian + +Because VaultLink is editor-agnostic, you can use it for: + +- **Documentation teams**: Sync technical docs edited in VS Code +- **Academic writing**: Collaborate on papers with various Markdown editors +- **Personal knowledge bases**: Use Obsidian on mobile, Vim on servers +- **Automated workflows**: CLI client for backup systems and CI/CD +- **Multi-tool workflows**: Different team members use different editors + +VaultLink doesn't lock you into Obsidian—it's a general-purpose differential sync system that happens to work excellently with Obsidian vaults. + +## Next Steps + +Ready to try VaultLink? + +- [Get started →](/guide/getting-started) +- [Understand the architecture →](/architecture/) +- [See how sync works →](/architecture/sync-algorithm) diff --git a/docs/guide/cli-client.md b/docs/guide/cli-client.md index 3beb4b7d..ebb89b18 100644 --- a/docs/guide/cli-client.md +++ b/docs/guide/cli-client.md @@ -67,20 +67,20 @@ Create `docker-compose.yml`: ```yaml services: - vaultlink-cli: - image: ghcr.io/schmelczer/vault-link-cli:latest - restart: unless-stopped - volumes: - - ./vault:/vault - command: - - "-l" - - "/vault" - - "-r" - - "wss://sync.example.com" - - "-t" - - "your-token" - - "-v" - - "default" + vaultlink-cli: + image: ghcr.io/schmelczer/vault-link-cli:latest + restart: unless-stopped + volumes: + - ./vault:/vault + command: + - "-l" + - "/vault" + - "-r" + - "wss://sync.example.com" + - "-t" + - "your-token" + - "-v" + - "default" ``` Start the client: @@ -93,22 +93,22 @@ docker compose up -d ### Required Arguments -| Argument | Short | Description | Example | -|----------|-------|-------------|---------| -| `--local-path` | `-l` | Local directory to sync | `/vault` | -| `--remote-uri` | `-r` | Server WebSocket URI | `wss://sync.example.com` | -| `--token` | `-t` | Authentication token | `abc123...` | -| `--vault-name` | `-v` | Vault name on server | `default` | +| Argument | Short | Description | Example | +| -------------- | ----- | ----------------------- | ------------------------ | +| `--local-path` | `-l` | Local directory to sync | `/vault` | +| `--remote-uri` | `-r` | Server WebSocket URI | `wss://sync.example.com` | +| `--token` | `-t` | Authentication token | `abc123...` | +| `--vault-name` | `-v` | Vault name on server | `default` | ### Optional Arguments -| Argument | Default | Description | -|----------|---------|-------------| -| `--sync-concurrency` | `1` | Concurrent file operations | -| `--max-file-size-mb` | `10` | Max file size in MB | -| `--ignore-pattern` | - | Glob pattern to ignore (repeatable) | -| `--websocket-retry-interval-ms` | `3500` | Reconnection interval | -| `--log-level` | `INFO` | Log level: DEBUG, INFO, WARNING, ERROR | +| Argument | Default | Description | +| ------------------------------- | ------- | -------------------------------------- | +| `--sync-concurrency` | `1` | Concurrent file operations | +| `--max-file-size-mb` | `10` | Max file size in MB | +| `--ignore-pattern` | - | Glob pattern to ignore (repeatable) | +| `--websocket-retry-interval-ms` | `3500` | Reconnection interval | +| `--log-level` | `INFO` | Log level: DEBUG, INFO, WARNING, ERROR | ### Environment Variables @@ -228,6 +228,7 @@ docker inspect --format='{{json .State.Health}}' vaultlink-sync | jq ``` Health check verifies: + - Health file exists - Status updated within last 30 seconds - WebSocket connection is active @@ -236,14 +237,14 @@ Configure custom health check: ```yaml services: - vaultlink-cli: - image: ghcr.io/schmelczer/vault-link-cli:latest - healthcheck: - test: ["CMD", "node", "/app/healthcheck.js"] - interval: 15s - timeout: 5s - retries: 5 - start_period: 20s + vaultlink-cli: + image: ghcr.io/schmelczer/vault-link-cli:latest + healthcheck: + test: ["CMD", "node", "/app/healthcheck.js"] + interval: 15s + timeout: 5s + retries: 5 + start_period: 20s ``` ### Read-Only Vault @@ -351,21 +352,25 @@ services: ### Client won't connect **Check server accessibility**: + ```bash curl https://sync.example.com/vaults/test/ping ``` **Verify WebSocket protocol**: + - Use `ws://` for HTTP servers - Use `wss://` for HTTPS servers **Check authentication**: + - Token must match server config - User must have access to the vault ### Permission errors **Docker volume permissions**: + ```bash # Ensure directory is writable chmod 755 /path/to/vault @@ -375,6 +380,7 @@ docker run --rm ghcr.io/schmelczer/vault-link-cli:latest id ``` **SELinux issues**: + ```bash # Add :z flag to volume mount docker run -v /path/to/vault:/vault:z ... @@ -383,14 +389,17 @@ docker run -v /path/to/vault:/vault:z ... ### Files not syncing **Check ignore patterns**: + - View logs to see which files are skipped - Ensure patterns don't match unintentionally **File size limits**: + - Check `--max-file-size-mb` setting - Large files are skipped with a warning **Check metadata**: + ```bash # View sync metadata cat /path/to/vault/.vaultlink/metadata.json @@ -399,33 +408,39 @@ cat /path/to/vault/.vaultlink/metadata.json ### High memory usage **Reduce concurrency**: + ```bash --sync-concurrency 1 ``` **Limit file sizes**: + ```bash --max-file-size-mb 5 ``` **Check vault size**: + - Very large vaults may need more resources - Consider splitting into multiple vaults ### Connection keeps dropping **Increase retry interval**: + ```bash --websocket-retry-interval-ms 5000 ``` **Check network stability**: + ```bash # Monitor connection docker logs -f vaultlink-sync | grep -i websocket ``` **Server timeout settings**: + - Verify reverse proxy WebSocket timeout - Check server `response_timeout_seconds` @@ -503,6 +518,7 @@ WantedBy=multi-user.target ``` Enable and start: + ```bash sudo systemctl daemon-reload sudo systemctl enable vaultlink-cli diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index a2636069..8282c7b1 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -74,9 +74,9 @@ You can connect to VaultLink using either the Obsidian plugin or the standalone 2. Browse community plugins and search for "VaultLink" 3. Install and enable the plugin 4. Configure the plugin: - - **Server URL**: `ws://localhost:3000` (or your server address) - - **Token**: The token from your `config.yml` - - **Vault Name**: `default` (or any name you choose) + - **Server URL**: `ws://localhost:3000` (or your server address) + - **Token**: The token from your `config.yml` + - **Vault Name**: `default` (or any name you choose) [Read the full Obsidian plugin guide →](/guide/obsidian-plugin) @@ -119,20 +119,20 @@ To add more users or restrict vault access: ```yaml users: - user_configs: - - name: alice - token: alice-secure-token - vault_access: - type: allow_list - allowed: - - personal - - shared - - name: bob - token: bob-secure-token - vault_access: - type: allow_list - allowed: - - shared + user_configs: + - name: alice + token: alice-secure-token + vault_access: + type: allow_list + allowed: + - personal + - shared + - name: bob + token: bob-secure-token + vault_access: + type: allow_list + allowed: + - shared ``` [Learn about authentication configuration →](/config/authentication) @@ -159,11 +159,13 @@ Want to understand how VaultLink works under the hood? ### Server won't start Check Docker logs: + ```bash docker logs vaultlink-server ``` Common issues: + - Port 3000 already in use: Change the port mapping `-p 3001:3000` - Config file errors: Validate YAML syntax - Permission issues: Ensure the volume mount is writable diff --git a/docs/guide/obsidian-plugin.md b/docs/guide/obsidian-plugin.md index dba6cd0e..ed3989b6 100644 --- a/docs/guide/obsidian-plugin.md +++ b/docs/guide/obsidian-plugin.md @@ -27,6 +27,7 @@ After installation, configure the plugin in **Settings → VaultLink**. ### Required Settings #### Server URL + The WebSocket URL of your sync server. - **Development/Local**: `ws://localhost:3000` @@ -37,14 +38,17 @@ Use `ws://` for unencrypted connections and `wss://` for SSL connections (produc ::: #### Authentication Token + Your authentication token from the server's `config.yml`. Generate a secure token: + ```bash openssl rand -hex 32 ``` #### Vault Name + The name of the vault on the server. Can be any string. Multiple Obsidian vaults can sync to the same server vault name (for shared vaults), or use unique names for separate vaults. @@ -52,26 +56,34 @@ Multiple Obsidian vaults can sync to the same server vault name (for shared vaul ### Optional Settings #### Sync Concurrency + Number of files to sync simultaneously. + - **Default**: 1 - **Range**: 1-10 - Higher values = faster initial sync, more resource usage #### Max File Size + Maximum file size to sync (in MB). + - **Default**: 10 - Files larger than this are skipped #### Ignore Patterns + Glob patterns for files to exclude from sync. Examples: + - `*.tmp` - Ignore temporary files - `.trash/**` - Ignore trash folder - `private/**` - Ignore private directory #### WebSocket Retry Interval + Milliseconds between reconnection attempts when disconnected. + - **Default**: 3500ms - Increase for flaky networks to avoid connection spam @@ -172,24 +184,26 @@ Share specific folders while keeping others private: ### Plugin won't connect 1. **Verify server is running**: - ```bash - curl http://your-server:3000/vaults/test/ping - ``` - Should return `pong` + + ```bash + curl http://your-server:3000/vaults/test/ping + ``` + + Should return `pong` 2. **Check URL format**: - - Local: `ws://localhost:3000` - - Remote (SSL): `wss://sync.example.com` - - Don't include `/vault/name` in the URL + - Local: `ws://localhost:3000` + - Remote (SSL): `wss://sync.example.com` + - Don't include `/vault/name` in the URL 3. **Verify token**: - - Must match server config exactly - - No extra spaces or quotes - - Check server logs for authentication errors + - Must match server config exactly + - No extra spaces or quotes + - Check server logs for authentication errors 4. **Check firewall**: - - Ensure port is accessible from your network - - For mobile, server must be publicly accessible or use VPN + - Ensure port is accessible from your network + - For mobile, server must be publicly accessible or use VPN ### Files not syncing diff --git a/docs/guide/server-setup.md b/docs/guide/server-setup.md index 1736aa34..8391522b 100644 --- a/docs/guide/server-setup.md +++ b/docs/guide/server-setup.md @@ -35,21 +35,21 @@ Create `docker-compose.yml`: ```yaml services: - vaultlink-server: - image: ghcr.io/schmelczer/vault-link-server:latest - container_name: vaultlink-server - restart: unless-stopped - ports: - - "3000:3000" - volumes: - - ./data:/data - command: ["/app/sync_server", "/data/config.yml"] - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000/vaults/fake/ping"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 10s + vaultlink-server: + image: ghcr.io/schmelczer/vault-link-server:latest + container_name: vaultlink-server + restart: unless-stopped + ports: + - "3000:3000" + volumes: + - ./data:/data + command: ["/app/sync_server", "/data/config.yml"] + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000/vaults/fake/ping"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s ``` Start the server: @@ -76,6 +76,7 @@ chmod +x sync_server-linux-x86_64 ### Build from Source Requirements: + - Rust 1.89.0 or later - SQLite development headers - SQLx CLI @@ -106,27 +107,27 @@ Create a `config.yml` file with your server configuration: ```yaml database: - databases_directory_path: databases - max_connections_per_vault: 12 - cursor_timeout_seconds: 60 + databases_directory_path: databases + max_connections_per_vault: 12 + cursor_timeout_seconds: 60 server: - host: 0.0.0.0 - port: 3000 - max_body_size_mb: 512 - max_clients_per_vault: 256 - response_timeout_seconds: 60 + host: 0.0.0.0 + port: 3000 + max_body_size_mb: 512 + max_clients_per_vault: 256 + response_timeout_seconds: 60 users: - user_configs: - - name: admin - token: your-secure-random-token-here - vault_access: - type: allow_access_to_all + user_configs: + - name: admin + token: your-secure-random-token-here + vault_access: + type: allow_access_to_all logging: - log_directory: logs - log_rotation: 7days + log_directory: logs + log_rotation: 7days ``` ### Configuration Fields @@ -192,6 +193,7 @@ server { ``` Reload Nginx: + ```bash sudo nginx -t sudo systemctl reload nginx @@ -208,6 +210,7 @@ sync.example.com { ``` Start Caddy: + ```bash caddy run --config Caddyfile ``` @@ -269,6 +272,7 @@ find /backup/vaultlink -type d -mtime +30 -exec rm -rf {} + ``` Run daily via cron: + ```cron 0 2 * * * /opt/vaultlink/backup.sh ``` @@ -293,12 +297,14 @@ For advanced monitoring, collect Docker stats or implement custom metrics. #### Log Monitoring Logs are written to the configured `log_directory`. Monitor for: + - Connection failures - Authentication errors - Database errors - WebSocket disconnections Example log watching: + ```bash tail -f /data/logs/*.log | grep -i error ``` @@ -316,11 +322,13 @@ VaultLink currently uses SQLite, which limits horizontal scaling. For multiple s ### Vertical Scaling Increase resources for the server: + - More CPU for handling concurrent connections - More RAM for database caching - Faster storage (SSD) for database operations Tune configuration: + - Increase `max_clients_per_vault` for more concurrent users - Increase `max_connections_per_vault` for database performance - Adjust `max_body_size_mb` based on typical file sizes diff --git a/docs/guide/what-is-vaultlink.md b/docs/guide/what-is-vaultlink.md index 1d236516..02e0d6cb 100644 --- a/docs/guide/what-is-vaultlink.md +++ b/docs/guide/what-is-vaultlink.md @@ -9,6 +9,7 @@ VaultLink consists of three main components: ### Sync Server A Rust-based WebSocket server that handles: + - Real-time bidirectional synchronization - Document versioning with SQLite - User authentication and vault access control @@ -17,6 +18,7 @@ A Rust-based WebSocket server that handles: ### Obsidian Plugin A native Obsidian plugin that: + - Integrates sync directly into your Obsidian workflow - Provides real-time updates as you edit - Handles file watching and automatic synchronization @@ -25,6 +27,7 @@ A native Obsidian plugin that: ### CLI Client A standalone synchronization client that: + - Syncs vaults without requiring Obsidian - Perfect for servers, automation, or backup systems - Provides file watching and bidirectional sync @@ -39,6 +42,7 @@ Changes are synchronized immediately via WebSocket connections. When multiple us ### Self-Hosted Architecture Run the sync server on your own infrastructure: + - Full control over data storage and access - No dependency on third-party services - Configurable authentication and authorization @@ -47,6 +51,7 @@ Run the sync server on your own infrastructure: ### Operational Transformation VaultLink uses the `reconcile-text` library for intelligent conflict resolution: + - Simultaneous edits are automatically merged - No manual conflict resolution required - Preserves intent of all contributors @@ -55,6 +60,7 @@ VaultLink uses the `reconcile-text` library for intelligent conflict resolution: ### Flexible Authentication Configure user access per vault: + - Token-based authentication - Per-user vault access control - Allow-list or deny-list patterns @@ -65,6 +71,7 @@ Configure user access per vault: ### Personal Sync Synchronize your Obsidian vault across multiple devices: + - Laptop, desktop, and mobile in real-time - No cloud service subscription required - Full privacy and data control @@ -72,6 +79,7 @@ Synchronize your Obsidian vault across multiple devices: ### Team Collaboration Share knowledge bases with teammates: + - Real-time collaborative editing - Granular access control per vault - Self-hosted for enterprise security requirements @@ -79,6 +87,7 @@ Share knowledge bases with teammates: ### Automated Backups Use the CLI client for automated workflows: + - Scheduled backups to remote servers - Integration with existing backup systems - Headless operation without Obsidian @@ -86,6 +95,7 @@ Use the CLI client for automated workflows: ### Development & Testing Synchronize documentation across environments: + - Keep docs in sync with development environments - Automated deployment of documentation - Version control integration diff --git a/docs/index.md b/docs/index.md index b2127b27..569e692c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,39 +2,39 @@ layout: home hero: - name: VaultLink - text: Self-Hosted Sync for Obsidian - tagline: Real-time collaborative file synchronization for your knowledge base - image: - src: /logo.svg - alt: VaultLink - actions: - - theme: brand - text: Get Started - link: /guide/getting-started - - theme: alt - text: View on GitHub - link: https://github.com/schmelczer/vault-link + name: VaultLink + text: Self-Hosted Sync for Obsidian + tagline: Real-time collaborative file synchronization for your knowledge base + image: + src: /logo.svg + alt: VaultLink + actions: + - theme: brand + text: Get Started + link: /guide/getting-started + - theme: alt + text: View on GitHub + link: https://github.com/schmelczer/vault-link features: - - icon: 🚀 - title: Real-Time Synchronization - details: Operational transformation-based conflict resolution ensures your files stay in sync across devices without data loss - - icon: 🔒 - title: Self-Hosted & Private - details: Run your own sync server. Your data stays on your infrastructure with full control over access and privacy - - icon: 🎯 - title: Obsidian Plugin - details: Native integration with Obsidian for seamless synchronization directly within your favorite note-taking app - - icon: 🖥️ - title: CLI Client - details: Sync vaults to any system using the standalone CLI client. Perfect for servers, automation, or headless setups - - icon: ⚡ - title: Built for Performance - details: Rust-powered WebSocket server with SQLite backend delivers blazing-fast sync performance - - icon: 🛠️ - title: Flexible Deployment - details: Deploy via Docker, binary releases, or build from source. Configure authentication and access controls to fit your needs + - icon: 🚀 + title: Real-Time Synchronization + details: Operational transformation-based conflict resolution ensures your files stay in sync across devices without data loss + - icon: 🔒 + title: Self-Hosted & Private + details: Run your own sync server. Your data stays on your infrastructure with full control over access and privacy + - icon: 🎯 + title: Obsidian Plugin + details: Native integration with Obsidian for seamless synchronization directly within your favorite note-taking app + - icon: 🖥️ + title: CLI Client + details: Sync vaults to any system using the standalone CLI client. Perfect for servers, automation, or headless setups + - icon: ⚡ + title: Built for Performance + details: Rust-powered WebSocket server with SQLite backend delivers blazing-fast sync performance + - icon: 🛠️ + title: Flexible Deployment + details: Deploy via Docker, binary releases, or build from source. Configure authentication and access controls to fit your needs --- ## Quick Start diff --git a/docs/package.json b/docs/package.json index 8084f21b..a0d630a4 100644 --- a/docs/package.json +++ b/docs/package.json @@ -6,12 +6,15 @@ "scripts": { "dev": "vitepress dev", "build": "vitepress build", - "preview": "vitepress preview" + "preview": "vitepress preview", + "format": "prettier --write \"**/*.md\" \"**/*.mts\"", + "format:check": "prettier --check \"**/*.md\" \"**/*.mts\"" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { + "prettier": "^3.6.2", "vitepress": "^1.6.4", "vue": "^3.5.24" } diff --git a/docs/public/logo.svg b/docs/public/logo.svg index 6cfc8953..cccc6fd8 100644 --- a/docs/public/logo.svg +++ b/docs/public/logo.svg @@ -1,34 +1,47 @@ + + + + + + + - + - + - - + + - - + + + + - - + + + - - - + + + + + + + + + - - - - - - + + + + + + + + + - - - VaultLink