Files
myworkspace/LinkSyncExtension/design.md

12 KiB

LinkSyncExtension - Design Documentation

Architecture Overview

LinkSyncExtension is a Firefox browser extension that synchronizes bookmarks with LinkSyncServer. It runs as a background service worker with popup and settings interfaces.

Component Architecture

┌─────────────────────────────────────────────────────┐
│                  LinkSyncExtension                  │
│                                                   │
│  ┌─────────────────┐  ┌─────────────────────────┐ │
│  │   Background    │  │     Popup UI            │ │
│  │   Service       │  │   (Add/Edit Bookmarks)  │ │
│  │   Worker        │  │                         │ │
│  └─────────────────┘  └─────────────────────────┘ │
│  ┌─────────────────┐  ┌─────────────────────────┐ │
│  │   Storage       │  │     Settings UI         │ │
│  │   Manager       │  │   (Configuration)       │ │
│  └─────────────────┘  └─────────────────────────┘ │
│  ┌─────────────────┐  ┌─────────────────────────┐ │
│  │   Sync Engine   │  │   Query Engine          │ │
│  │   (3 modes)     │  │   (Parser + Executor)   │ │
│  └─────────────────┘  └─────────────────────────┘ │
│  ┌─────────────────┐  ┌─────────────────────────┐ │
│  │   Bookmark      │  │   API Client            │ │
│  │   Manipulator   │  │   (REST calls)          │ │
│  └─────────────────┘  └─────────────────────────┘ │
│                                                   │
│  ┌───────────────────────────────────────────┐   │
│  │         Browser Bookmarks API             │   │
│  └───────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────┘

File Structure

LinkSyncExtension/
├── manifest.json              # Extension manifest v2
├── popup.html                 # Bookmark add/edit UI
├── popup.css                  # Popup styling
├── popup.js                   # Popup logic
├── background.html            # Settings page
├── background.js              # Service worker
├── content/
│   └── content.js             # Content script (optional)
├── utils/
│   ├── bookmark.js           # Bookmark manipulation
│   ├── collection.js         # Collection management
│   ├── query-engine.js       # Query parsing/execution
│   └── sync.js               # Sync logic
├── icons/
│   ├── icon-48.png           # 48x48 icon
│   └── icon-96.png           # 96x96 icon
└── styles/
    ├── base.css              # Common styles
    └── theme.css             # Theme variables

Manifest Design

manifest.json

{
    "manifest_version": 2,
    "name": "LinkSync",
    "version": "1.0.0",
    "description": "Sync bookmarks with LinkSyncServer",
    "permissions": [
        "bookmarks",
        "storage",
        "activeTab",
        "http://*/*",
        "https://*/*"
    ],
    "browser_action": {
        "default_icon": {
            "48": "icons/icon-48.png",
            "96": "icons/icon-96.png"
        },
        "default_title": "LinkSync"
    },
    "background": {
        "page": "background.html"
    },
    "browser_specific_settings": {
        "gecko": {
            "id": "{linksync-id}",
            "strict_min_version": "109.0"
        }
    }
}

Permissions

  • bookmarks - Read/write Firefox bookmarks
  • storage - Store settings, API keys, state
  • activeTab - Get current page data
  • HTTP/HTTPS - API communication

Background Worker Design

Responsibilities

  1. Sync Loop

    • Check for pending syncs
    • Compare browser vs server bookmarks
    • Apply sync mode rules
    • Handle conflicts
  2. Event Handlers

    • onMessage - UI requests
    • onInstall - Initialization
    • onUpdate - Handle version changes
  3. State Management

    • Store collection mapping
    • Track sync timestamps
    • Monitor pending changes

Code Structure

// background.js
const Background = {
    // Constants
    SYNC_CHECK_INTERVAL: 60000,  // 1 minute
    
    // Storage keys
    STORAGE: {
        API_KEY: 'linksync_api_key',
        COLLECTION: 'linksync_collection',
        MODE: 'linksync_sync_mode',
        DELETIONS: 'linksync_deletions',
        AUTO_SYNC: 'linksync_auto_sync'
    },
    
    // Methods
    init(),              // Initialize on install/update
    checkSync(),         // Run sync loop
    handleSyncAction(),  // Process sync actions
    handleEvent(),       // Event handlers
    sendMessage(),       // UI communication
    authenticate()        // Handle auth
};

Sync Logic

async function handleSync() {
    const config = await loadConfig();
    
    // Get browser bookmarks
    const browserBookmarks = await getBrowserBookmarks();
    
    // Get server bookmarks via API
    const serverBookmarks = await fetchServerBookmarks();
    
    // Apply sync mode
    const actions = applySyncMode(config.mode, browserBookmarks, serverBookmarks);
    
    // Process deletions if enabled
    if (config.deletions) {
        actions = applyDeletions(actions);
    }
    
    // Apply actions
    await applyActions(actions);
    
    // Update sync timestamp
    await saveSyncTimestamp();
}

Sync Modes

Mode Browser→Server Server→Browser
Bi-directional Push Push
Browser Authoritative Push Overwrite
Server Authoritative Download Overwrite

Popup Design

Components

  1. Add/Edit Form

    • URL (auto-filled)
    • Title (auto-filled)
    • Description (auto-filled)
    • Notes
    • Tags input
    • Folder path
    • Actions (Add, Edit, Delete)
  2. Bookmark List

    • Paginated list of synced bookmarks
    • Search filter
    • Select for batch operations
  3. Collections Panel

    • View all collections
    • Execute query
    • Create dynamic collection
  4. Settings Modal

    • Server URL
    • API Key
    • Collection name
    • Sync mode
    • Auto-sync toggle

HTML Structure

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="popup.css">
</head>
<body>
    <!-- Header -->
    <header>
        <h1>LinkSync</h1>
    </header>
    
    <!-- Add/Edit Form -->
    <section id="bookmark-form">
        <form id="bookmark-form">
            <input id="url" type="url">
            <input id="title" type="text">
            <textarea id="description"></textarea>
            <textarea id="notes"></textarea>
            <input id="tags" placeholder="comma-separated">
            <input id="folder" placeholder="path">
            <button id="submit">Add Bookmark</button>
        </form>
    </section>
    
    <!-- Bookmark List -->
    <section id="bookmark-list">
        <!-- Bookmarks -->
    </section>
    
    <!-- Footer with actions -->
    <footer>
        <button id="sync-btn">Sync Now</button>
        <button id="settings-btn">Settings</button>
    </footer>
</body>
</html>

Storage Design

localStorage Keys

Key Type Description
linksync_api_key string JWT API token
linksync_collection string Collection name
linksync_sync_mode string Sync mode
linksync_deletions boolean Enable deletions
linksync_auto_sync boolean Auto-sync toggle
linksync_last_sync timestamp Last sync time
linksync_pending number Pending changes count

Encrypted Storage

API keys should be encrypted before storage:

async function saveEncryptedKey(key) {
    const iv = crypto.getRandomValues(new Uint8Array(16));
    const encrypted = await window.crypto.subtle.encrypt(
        { name: "AES-GCM", length: 256 },
        await window.crypto.subtle.importKey(
            "raw",
            encryptionKey,
            { name: "AES-GCM" },
            false
        ),
        key
    );
    // Store iv + encrypted data
}

Query Engine Design

Query Syntax

('term1', 'term2') OR tagA AND tagB XOR url:example.com

Parser

class QueryParser {
    parse(expression) {
        // Tokenize
        const tokens = this.tokenize(expression);
        
        // Build AST
        const ast = this.buildAST(tokens);
        
        // Validate
        this.validate(ast);
        
        return this.serialize(ast);
    }
}

Executor

class QueryExecutor {
    async execute(ast) {
        // Build SQL
        const sql = this.buildSQL(ast);
        
        // Execute
        const result = await fetch(`/api/links/?sql=${sql}`);
        
        return await result.json();
    }
}

API Client Design

REST API Integration

const API = {
    baseUrl: '',
    headers: {
        'Authorization': 'Token {key}',
        'Content-Type': 'application/json'
    },
    
    async login() {
        const response = await fetch(`${this.baseUrl}/api/auth/login/`, {
            method: 'POST',
            body: JSON.stringify({ username, password })
        });
        const data = await response.json();
        this.storeApiKey(data.token);
        return data;
    },
    
    async listLinks() {
        return await this.request('/api/links/');
    },
    
    async createLink(link) {
        return await this.post('/api/links/', link);
    },
    
    async executeQuery(expression) {
        return await this.post('/api/queries/execute/', { expression });
    }
};

UI/UX Design

Color Scheme

:root {
    --primary: #3b82f6;
    --secondary: #6b7280;
    --success: #10b981;
    --warning: #f59e0b;
    --error: #ef4444;
    --background: #ffffff;
    --surface: #f9fafb;
    --border: #e5e7eb;
    --text: #111827;
    --text-secondary: #6b7280;
}

Typography

  • Font family: System UI
  • Base size: 14px
  • Heading: 18px
  • Form labels: 12px

Responsive Design

  • Mobile-first approach
  • Breakpoint: 480px for landscape
  • Touch-friendly tap targets (44px minimum)

Security Design

API Key Handling

  1. Storage

    • Encrypted in localStorage
    • Never logged or exposed
  2. Transmission

    • HTTPS preferred
    • Token in Authorization header
    • No tokens in URL params
  3. Validation

    • Verify response signatures
    • Check rate limits
    • Handle 401/403 gracefully

Data Privacy

  • No bookmarks stored locally after sync
  • API keys user-managed
  • No telemetry or analytics

Testing Strategy

Unit Tests

  • Sync logic modes
  • Conflict detection
  • Query parsing
  • Storage operations

Integration Tests

  • API endpoint calls
  • Background worker events
  • Popup communication

Manual Testing

  • Add/edit/delete bookmarks
  • Collection creation
  • Query execution
  • Conflict scenarios