Files

414 lines
11 KiB
Markdown

# 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": "<existing text here>",
"autoTags": [],
"bundleTag": "<from config>"
}
```
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 <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/<id>/` - Update bookmark
- `DELETE /api/bookmarks/<id>/` - 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)