# LinkdingSync Extension - Design Document ## Overview `linkdingsync` is a Firefox browser extension that synchronizes bookmarks with a self-hosted Linkding instance. It supports folder hierarchy, bi-directional sync, configurable sync modes, and tag-based bundle management. ## Project Location ``` Linkding Browser Extension/LinkdingSync/ ``` ## Extension Name **`linkdingsync`** - Firefox extension name (manifest.json) --- ## 1. Data Storage Structure ### Configuration (stored in browser.storage.local) ```json { "serverUrl": "https://links.blabber1565.com", "apiKey": "your-api-token-here", "bundleTag": "bundle_personal_firefox_1", "syncMode": "bi-directional", "autoGenerateTags": false, "lastSyncTimestamp": 1715012345678 } ``` ### Storage Areas - **`browser.storage.local`** - Persistent data per browser profile - **`browser.storage.session`** - Temporary session data ### Supported Values | Value | Description | |-------|------| | `bi-directional` | Replicate both directions; keep both versions | | `write-only` | Browser is authoritative source; update Linkding only | | `read-only` | Linkding is authoritative source; download only | **Default:** `bi-directional` --- ## 2. Bookmark Notes Structure The `notes` field uses a JSON-compatible structure with versioning for forward compatibility: ```json { "version": 1.0, "path": "Work/Resources/Development", "userNotes": "Development resources and references", "autoTags": [ {"name": "Work"}, {"name": "Resources"}, {"name": "Development"} ], "bundleTag": "bundle_personal_firefox_1" } ``` ### Display Format - Only show `userNotes` in the UI - `path` and `autoTags` are hidden from regular users ### Version Handling - **version 1.0**: Basic structured format with path, userNotes, autoTags - **version 2.0**: Adds bundleTag field for tag-based bundle identification - **Extension version tracking**: Uses extension version number for notes version - **Backward compatibility**: - Old bookmarks without structured notes are detected - Non-JSON notes are migrated to structured format - Old notes get `version: 1.0` and existing text in `userNotes` - Future fields are ignored by older versions ### Auto-generate Tags Setting - **Default:** `false` (disabled) - When `true`, extracts folder names from `path` as tag suggestions - User must organize folders intentionally for tag auto-generation to work correctly --- ## 3. Bundle/Tag Configuration Instead of creating actual Linkding bundles, we use Linkding's "required tags" feature: ### Bundle Tag Convention All bookmarks in a bundle must have the bundle tag. The bundle tag name follows this pattern: ``` bundle_{BUNDLE_NAME}_{BROWSER} ``` Examples: - `bundle_personal_firefox_1` - `bundle_work_chrome_1` - `bundle_personal_edge_1` ### Linkding Query Parameters In Linkding, create a bundle with these parameters: - **Search:** (empty) - **Required tags:** `{bundleTag}` - **Any tags:** (empty) - **All tags:** (empty) - **Excluded tags:** (empty) This means all bookmarks with the bundle tag appear in this bundle. ### Updating Extension Version The extension version is used as the notes version: - Extension v1.0.x → notes version 1.0 - Extension v2.0.x → notes version 2.0 - Extension v1.0.1 → notes version 1.0 (patch versions don't change notes version) --- ## 4. Extension File Structure ``` LinkdingSync/ ├── manifest.json # Firefox manifest v2 ├── popup.html # Main extension popup ├── popup.css # Popup styling ├── popup.js # Popup UI logic ├── background.html # Settings/config page ├── background.js # Service worker ├── README.md # User documentation ├── docs/ │ ├── design.md # Design document │ └── TODOs.txt # Version compatibility notes └── icons/ ├── icon-48.svg # 48x48 icon └── icon-96.svg # 96x96 icon ``` --- ## 5. Key Features ### Popup UI - Quick bookmark add with optional notes - Sync status indicator - Settings button → opens config page ### Config Page (`background.html`) - Server URL input (with validation) - API key input (with "Get from Linkding Settings" guidance) - Bundle tag input (e.g., "bundle_personal_firefox_1") - Sync mode selector (`bi-directional` | `write-only` | `read-only`) - Auto-generate tags toggle - Last sync timestamp (human-readable with timezone) - Test connection button - Save Settings button - Reset config button ### Background Service - Monitor bookmark events (add, remove, modify) - Perform sync operations with Linkding API - Cache recent API responses - Handle errors and show notifications - Apply bundle tag to all new bookmarks - Migrate old notes to structured format --- ## 6. Sync Logic Flow ``` 1. Browser bookmark change detected ↓ 2. Check syncMode: - read-only: download from Linkding only - write-only: sync to Linkding only - bi-directional: sync both directions ↓ 3. For new bookmarks: - Add bundleTag to notes - Check if URL already in Linkding - If no → create new bookmark with bundle tag - If yes + different URL → create new bookmark - If yes + same URL → update notes (keep title/description) ↓ 4. For updates (same URL, different folder): - Update path in notes - Merge with existing notes - Apply sync mode rules ↓ 5. For deletions: - write-only → delete from Linkding - read-only → ignore (keep Linkding version) - bi-directional → delete from Linkding ↓ 6. Migrate old notes: - If notes not JSON or lacks version field → treat as old notes - Convert to structured format with version 1.0 - Preserve existing content in userNotes ``` --- ## 7. Notes Migration ### Old Notes Detection Old notes are detected if: - `notes` is not valid JSON, OR - `notes` doesn't contain a `version` field ### Migration Process 1. Parse existing notes 2. If invalid/non-JSON → create structured notes with: ```json { "version": 1.0, "path": "", "userNotes": "", "autoTags": [], "bundleTag": "" } ``` 3. If valid but old version → update version field 4. If same or newer version → keep as-is ### Forward Compatibility When new fields are added to notes structure: - Older extension versions ignore unknown fields - Newer extension versions add new fields - This allows gradual feature rollouts --- ## 8. API Endpoints Used ### Authentication ``` Authorization: Token ``` ### Bookmarks - `GET /api/bookmarks/` - List bookmarks - `GET /api/bookmarks/check/?url=...` - Check if URL is already bookmarked - `POST /api/bookmarks/` - Create bookmark - `PUT/PATCH /api/bookmarks//` - Update bookmark - `DELETE /api/bookmarks//` - Delete bookmark --- ## 9. Implementation Status ### Phase 1: Core Setup - [x] Create manifest.json with options_ui - [x] Create popup HTML/CSS/JS - [x] Create background service worker - [x] Implement storage helpers ### Phase 2: Sync Logic - [x] Implement bookmark manipulation - [x] Implement notes parser with versioning - [x] Implement sync logic - [x] Implement conflict resolution ### Phase 3: Configuration UI - [x] Create config page - [x] Implement config form logic - [x] Add API key guidance ### Phase 4: Polish - [x] Add icons - [x] Add error handling - [x] Add notifications - [x] Implement notes migration - [x] Implement tag-based bundle approach --- ## 10. Version History | Version | Date | Changes | |---------|------|---------| | 0.1.0 | 2026-05-06 | Initial design document | | 1.0.0 | 2026-05-06 | Initial implementation | | 1.0.1 | TBD | Tag-based bundle support | | 1.0.2 | TBD | Notes version migration | --- ## 11. Notes This document should be referenced during implementation to ensure all requirements are met. Any deviations from this design should be documented here. --- **Last Updated:** 2026-05-06 # LinkdingSync - Version Compatibility Notes ## Version 1.0.x - Basic Structured Notes ### Notes Structure ```json { "version": "1.0", "path": "", "userNotes": "", "autoTags": [], "bundleTag": "bundle_links_blabber1565_firefox_42", "keyword": "" } ``` ### Auto-Generate Tags Feature When `autoGenerateTags` is **enabled** in settings: - Tags are automatically derived from the `path` folder structure - Example: `path = "Work/Resources/Development"` → `autoTags = ["Work", "Resources", "Development"]` - These tags are added to the bookmark on Linkding - **Important**: Tags are only auto-generated if this setting is enabled - Tags will always be present in the structured notes field When `autoGenerateTags` is **disabled** (default): - Tags array remains empty (`[]`) - Only `bundleTag` is added to the bookmark - Old bookmarks without structured notes are migrated without tags ### Bundle Tag Behavior **Always Applied:** - The `bundleTag` (e.g., `bundle_links_blabber1565_firefox_42`) is **always** added to new bookmarks - This enables Linkding bundle filtering via the `all=` API parameter - When viewing bookmarks in Linkding UI with this tag filter, you'll see only bookmarks from this browser - Bundle feature works as expected: queries by tag filter, UI shows filtered results **Not Applied:** - `path` field is used for folder organization - `userNotes` stores user-provided notes - `autoTags` is populated only when `autoGenerateTags` is enabled - `keyword` field is used for Firefox-style quick-access bookmarks ### Migrations **Old Non-JSON Notes:** ``` "old text notes" ``` → Migrated to: ```json { "version": "1.0", "path": "", "userNotes": "old text notes", "autoTags": [], "bundleTag": "bundle_...", "keyword": "" } ``` **Old Structured Notes (no version field):** ```json { "path": "", "userNotes": "notes", "autoTags": [] } ``` → Migrated to: ```json { "version": "1.0", "path": "", "userNotes": "notes", "autoTags": [], "bundleTag": "bundle_...", "keyword": "" } ``` ## Version 2.x - Future Features Version 2.x will add new fields while maintaining backward compatibility. Older extension versions will continue to work but won't use new fields. --- ## Implementation Notes ### Current State (v1.0.x) - `bundleTag` is **always** added to bookmarks (enables bundle filtering) - `autoTags` is only populated when `autoGenerateTags` setting is enabled - Old bookmarks get migrated with empty `autoTags` array - Firefox tags (`autoTags`) are stored in Linkding bookmarks when present in Firefox ### Bundle Feature - Linkding bundle is created with `all_tags` set to the `bundleTag` - All bookmarks with this tag appear in the bundle - Bundle filtering uses `all=` API parameter (exact match on all tags) - Querying works correctly with pagination for large bookmark sets ### Cross-Browser Sync - All browsers share the same Linkding collection via tag filtering - Firefox bookmarks with tags sync to Linkding - Other browsers read from Linkding with same tag filter - Keywords are preserved in structured notes but not synced (Linkding doesn't support keywords)