webdrop-bridge/DEVELOPMENT_PLAN.md

35 KiB

WebDrop Bridge - Professional Development Plan

Version: 1.0
Last Updated: January 2026
Status: Pre-Release Development

Executive Summary

This document outlines the development roadmap for WebDrop Bridge, a professional Qt-based desktop application that converts web-based drag-and-drop text paths into native file operations for seamless integration with professional desktop software (InDesign, Word, Notepad++, etc.).

Key Differences from PoC

Aspect PoC Production
Structure Monolithic Modular, scalable
Testing Ad-hoc Comprehensive (unit/integration/e2e)
Documentation Minimal Full API docs, user guides
Error Handling Basic Robust with recovery
Logging Console only File + structured logging
Security Basic validation Enhanced, configurable
Distribution Source code MSI (Windows), DMG (macOS)
CI/CD Manual Automated GitHub Actions
Versioning Single version Semantic versioning, auto-updates

Phase 1: Foundation (Weeks 1-4)

1.1 Core Architecture Refinement

Objectives:

  • Refactor PoC code into production-quality modules
  • Implement proper logging and error handling
  • Create configuration management system

Tasks:

1.1.1 Configuration System (src/webdrop_bridge/config.py)

from dataclasses import dataclass
from pathlib import Path
from typing import List
import os
from dotenv import load_dotenv

@dataclass
class Config:
    """Application configuration."""
    app_name: str
    app_version: str
    log_level: str
    allowed_roots: List[Path]
    allowed_urls: List[str]  # Empty = no restriction, non-empty = Kiosk-mode
    webapp_url: str
    window_width: int
    window_height: int
    enable_logging: bool
    
    @classmethod
    def from_env(cls):
        """Load configuration from environment."""
        load_dotenv()
        allowed_roots_str = os.getenv("ALLOWED_ROOTS", "Z:/,C:/Users/Public")
        allowed_roots = [Path(p.strip()) for p in allowed_roots_str.split(",")]
        
        # URL whitelist (empty = no restriction)
        allowed_urls_str = os.getenv("ALLOWED_URLS", "")
        allowed_urls = [url.strip() for url in allowed_urls_str.split(",") if url.strip()]
        
        return cls(
            app_name=os.getenv("APP_NAME", "WebDrop Bridge"),
            app_version=os.getenv("APP_VERSION", "1.0.0"),
            log_level=os.getenv("LOG_LEVEL", "INFO"),
            allowed_roots=allowed_roots,
            allowed_urls=allowed_urls,
            webapp_url=os.getenv("WEBAPP_URL", "file:///./webapp/index.html"),
            window_width=int(os.getenv("WINDOW_WIDTH", "1024")),
            window_height=int(os.getenv("WINDOW_HEIGHT", "768")),
            enable_logging=os.getenv("ENABLE_LOGGING", "true").lower() == "true",
        )

Deliverables:

  • src/webdrop_bridge/config.py - Configuration management
  • .env.example - Environment template
  • Validation for all config parameters

Configuration Variables:

  • ALLOWED_ROOTS - Comma-separated file paths (drag-drop whitelist)
  • ALLOWED_URLS - Comma-separated URL patterns for Kiosk-mode (empty = unrestricted)
    • Examples: localhost,127.0.0.1,*.example.com
    • Supports wildcards: *.domain.com
    • File URLs always allowed: file://

Acceptance Criteria:

  • Config loads from .env file
  • All environment variables have sensible defaults
  • Invalid values raise ConfigurationError

1.1.2 Logging System (src/webdrop_bridge/utils/logging.py)

import logging
from pathlib import Path
from typing import Optional

def setup_logging(
    level: str = "INFO",
    log_file: Optional[Path] = None,
    format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
) -> logging.Logger:
    """Configure application-wide logging."""
    logger = logging.getLogger("webdrop_bridge")
    logger.setLevel(getattr(logging, level))
    
    # Console handler
    console = logging.StreamHandler()
    console.setFormatter(logging.Formatter(format))
    logger.addHandler(console)
    
    # File handler (if enabled)
    if log_file:
        log_file.parent.mkdir(parents=True, exist_ok=True)
        file_handler = logging.FileHandler(log_file)
        file_handler.setFormatter(logging.Formatter(format))
        logger.addHandler(file_handler)
    
    return logger

Deliverables:

  • src/webdrop_bridge/utils/logging.py - Logging utilities
  • Logs directory with .gitkeep
  • Log rotation policy

Acceptance Criteria:

  • Logs written to logs/webdrop_bridge.log
  • Console output matches log file
  • Log level configurable via environment

1.2 Drag Interceptor Component

Objectives:

  • Implement robust drag-and-drop interception
  • Validate paths against whitelist
  • Create MimeData with proper file URLs

Tasks:

1.2.1 Path Validator (src/webdrop_bridge/core/validator.py)

from pathlib import Path
from typing import List

class PathValidator:
    """Validates file paths against security policies."""
    
    def __init__(self, allowed_roots: List[Path]):
        self.allowed_roots = [p.resolve() for p in allowed_roots]
    
    def is_allowed(self, path: Path) -> bool:
        """Check if path is within allowed roots."""
        try:
            resolved = path.resolve()
            return any(
                self._is_relative_to(resolved, root) 
                for root in self.allowed_roots
            )
        except (ValueError, OSError):
            return False
    
    def is_valid_file(self, path: Path) -> bool:
        """Check if path is allowed and exists as file."""
        return self.is_allowed(path) and path.exists() and path.is_file()
    
    @staticmethod
    def _is_relative_to(path: Path, other: Path) -> bool:
        """Backcompat for Path.is_relative_to (Python 3.9+)."""
        try:
            path.relative_to(other)
            return True
        except ValueError:
            return False

Deliverables:

  • src/webdrop_bridge/core/validator.py - Path validation
  • Unit tests for PathValidator
  • Security documentation

Acceptance Criteria:

  • All paths resolved to absolute
  • Whitelist enforcement working
  • Symlink handling documented

1.2.2 Drag Interceptor Widget (src/webdrop_bridge/core/drag_interceptor.py)

from PySide6.QtCore import Qt, QUrl, QMimeData, pyqtSignal
from PySide6.QtGui import QDrag
from PySide6.QtWidgets import QWidget
from pathlib import Path
import logging

logger = logging.getLogger(__name__)

class DragInterceptor(QWidget):
    """Intercepts and converts text drags to file drags."""
    
    file_dropped = pyqtSignal(Path)
    
    def __init__(self, validator, parent=None):
        super().__init__(parent)
        self.validator = validator
        self.setAcceptDrops(True)
    
    def dragEnterEvent(self, event):
        """Handle drag enter."""
        if event.mimeData().hasText():
            text = event.mimeData().text().strip()
            path = Path(text.replace("\\", "/"))
            
            if self.validator.is_valid_file(path):
                event.acceptProposedAction()
                logger.debug(f"Drag accepted: {path}")
                self._start_file_drag(path)
            else:
                event.ignore()
                logger.warning(f"Invalid path rejected: {text}")
    
    def _start_file_drag(self, path: Path):
        """Convert to native file drag."""
        mime_data = QMimeData()
        url = QUrl.fromLocalFile(str(path))
        mime_data.setUrls([url])
        
        drag = QDrag(self)
        drag.setMimeData(mime_data)
        
        # Use move for typical file operations
        drag.exec(Qt.MoveAction | Qt.CopyAction)
        self.file_dropped.emit(path)
        logger.info(f"File dragged: {path}")

Deliverables:

  • src/webdrop_bridge/core/drag_interceptor.py - Drag handling
  • Unit tests with mocking
  • Platform-specific tests (Windows/macOS)

Acceptance Criteria:

  • Drag events properly intercepted
  • File URLs created correctly
  • Signals emit appropriately
  • Cross-platform compatibility verified

1.3 Main Application Window

Tasks:

1.3.1 Main Window (src/webdrop_bridge/ui/main_window.py)

Features:

  • Qt QMainWindow with WebEngine integration
  • Navigation toolbar (Home, Back, Forward, Refresh) for Kiosk-mode
  • URL whitelist enforcement for restricted browsing
  • Drag-and-drop file path integration
from PySide6.QtWidgets import QMainWindow, QVBoxLayout, QWidget, QToolBar
from PySide6.QtCore import QUrl, QSize, Qt
import logging

logger = logging.getLogger(__name__)

class MainWindow(QMainWindow):
    """Application main window with restricted browsing."""
    
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.setWindowTitle(config.app_name)
        self.setGeometry(100, 100, config.window_width, config.window_height)
        
        # Create restricted web engine view (with URL whitelist)
        from webdrop_bridge.ui.restricted_web_view import RestrictedWebEngineView
        self.web_view = RestrictedWebEngineView(config.allowed_urls)
        self._create_navigation_toolbar()
        
        # Set as central widget
        self.setCentralWidget(self.web_view)
        
        logger.info(f"Loading webapp from: {config.webapp_url}")
        self.web_view.load(QUrl(config.webapp_url))
    
    def _create_navigation_toolbar(self):
        """Create Kiosk-mode navigation toolbar."""
        toolbar = QToolBar("Navigation")
        toolbar.setMovable(False)
        toolbar.setIconSize(QSize(24, 24))
        self.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar)
        
        # Add Back, Forward, Home, Refresh buttons
        toolbar.addAction(self.web_view.pageAction(self.web_view.WebAction.Back))
        toolbar.addAction(self.web_view.pageAction(self.web_view.WebAction.Forward))
        toolbar.addSeparator()
        home_action = toolbar.addAction("Home")
        home_action.triggered.connect(self._navigate_home)
        toolbar.addAction(self.web_view.pageAction(self.web_view.WebAction.Reload))
    
    def _navigate_home(self):
        """Navigate to home (startup) URL."""
        self.web_view.load(QUrl(self.config.webapp_url))

URL Whitelist (Kiosk-Mode):

When ALLOWED_URLS is configured, the application enforces strict browsing:

  • Whitelisted URLs load in the WebView
  • Non-whitelisted URLs open in system default browser
  • File URLs (file://) always allowed
  • Empty whitelist = unrestricted (all URLs allowed)

Deliverables:

  • src/webdrop_bridge/ui/main_window.py
  • src/webdrop_bridge/ui/restricted_web_view.py - URL whitelist enforcement
  • UI tests

Acceptance Criteria:

  • Window opens with correct title
  • WebEngine loads correctly
  • Toolbar displays with Home, Back, Forward, Refresh buttons
  • URL whitelist enforces restrictions
  • Non-whitelisted URLs open in system browser

1.3.2 Restricted Web View (src/webdrop_bridge/ui/restricted_web_view.py)

Purpose: Enforce URL whitelist for Kiosk-mode browsing security.

from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtGui import QDesktopServices
import fnmatch

class RestrictedWebEngineView(QWebEngineView):
    """Web view with URL whitelist enforcement."""
    
    def __init__(self, allowed_urls: List[str] = None):
        super().__init__()
        self.allowed_urls = allowed_urls or []
        self.page().navigationRequested.connect(self._on_navigation_requested)
    
    def _on_navigation_requested(self, request):
        """Enforce URL whitelist on navigation."""
        if not self.allowed_urls:
            # No restrictions
            return
        
        if not self._is_url_allowed(request.url):
            # Reject and open in system browser
            request.reject()
            QDesktopServices.openUrl(request.url)
    
    def _is_url_allowed(self, url):
        """Check if URL matches whitelist patterns."""
        # file:// URLs always allowed
        if url.scheme() == "file":
            return True
        
        # Check wildcard patterns (*.example.com, localhost, etc.)
        for pattern in self.allowed_urls:
            if fnmatch.fnmatch(url.host(), pattern):
                return True
        
        return False

Features:

  • Wildcard pattern support: *.example.com
  • Exact domain matching: example.com
  • Port-aware: localhost:8000
  • File URL bypass: file:// always allowed
  • Fallback to system browser for blocked URLs

1.4 Application Entry Point

Tasks:

1.4.1 Main Entry (src/webdrop_bridge/main.py)

import sys
import logging
from pathlib import Path

from PySide6.QtWidgets import QApplication
from webdrop_bridge.config import Config
from webdrop_bridge.utils.logging import setup_logging
from webdrop_bridge.core.validator import PathValidator
from webdrop_bridge.core.drag_interceptor import DragInterceptor
from webdrop_bridge.ui.main_window import MainWindow

logger = logging.getLogger(__name__)

def main():
    """Application entry point."""
    # Load configuration
    config = Config.from_env()
    
    # Setup logging
    log_file = Path("logs") / "webdrop_bridge.log" if config.enable_logging else None
    setup_logging(config.log_level, log_file)
    
    logger.info(f"Starting {config.app_name} v{config.app_version}")
    
    # Create application
    app = QApplication(sys.argv)
    app.setApplicationName(config.app_name)
    
    # Create validator and interceptor
    validator = PathValidator(config.allowed_roots)
    interceptor = DragInterceptor(validator)
    
    # Create main window
    window = MainWindow(config)
    window.show()
    
    logger.info("Application started")
    sys.exit(app.exec())

if __name__ == "__main__":
    main()

Deliverables:

  • src/webdrop_bridge/main.py
  • Entry point tested

Acceptance Criteria:

  • Application starts without errors
  • Configuration loaded correctly
  • Logging initialized

Phase 1.5: Comprehensive Unit Testing

1.5.1 Unit Test Suite

Objective: Achieve high code coverage with comprehensive unit tests

Test Files:

  • tests/unit/test_config.py - 12 tests (Config loading, validation, allowed_urls)
  • tests/unit/test_logging.py - 9 tests (Console/file logging, rotation, format)
  • tests/unit/test_validator.py - 16 tests (Path validation, symlinks, traversal attacks)
  • tests/unit/test_restricted_web_view.py - 15 tests (URL whitelist, patterns, browser fallback)
  • tests/unit/test_project_structure.py - 3 structural validation tests

Test Coverage Achieved:

  • Config: 95%
  • Logging: 100%
  • Validator: 94%
  • RestrictedWebEngineView: 95%
  • Total: 53 tests passing, 48%+ overall coverage

Key Testing Features:

  • Pytest with pytest-qt for Qt components
  • Fixtures for temp directories and environment isolation
  • Mock usage for external services (QDesktopServices)
  • Platform-specific tests (Windows symlinks, path handling)

Phase 2: Testing & Quality (Weeks 5-6)

2.1 Extended Unit Tests

Files to create/extend:

  • tests/unit/test_config.py - Complete
  • tests/unit/test_validator.py - Complete
  • tests/unit/test_drag_interceptor.py - 25 tests (96% coverage)
  • tests/unit/test_main_window.py - 38 tests (88% coverage)

Target Coverage: 80%+ line coverage ACHIEVED (85% overall)

Test Suite Results:

  • Total Tests: 99 passing
  • Overall Coverage: 85%
  • Config: 95%
  • DragInterceptor: 96%
  • Validator: 94%
  • MainWindow: 88%
  • RestrictedWebEngineView: 95%
  • Logging: 100%

2.2 Integration Tests

Files to create:

  • tests/integration/test_drag_workflow.py
  • tests/integration/test_webapp_loading.py
  • tests/integration/test_end_to_end.py

Test Scenarios:

  1. Start app → Load webapp → Verify ready
  2. Initiate drag → Validate → Drop file → Verify received
  3. Invalid path → Reject → No file created

2.3 Code Quality

Checklist:

  • Black formatting: tox -e format
  • Ruff linting: tox -e lint
  • Type checking: tox -e type (with pragmatic type: ignore for Qt inheritance)
  • Coverage report: pytest --cov=src/webdrop_bridge (85% achieved)
  • Security scan: pip audit (optional future)
  • Coverage report: pytest --cov=src/webdrop_bridge
  • Security scan: pip audit

Phase 3: Build & Distribution (Weeks 7-8)

3.1 Windows Installer (Executable + MSI)

Build Script (build/scripts/build_windows.py):

  • PyInstaller compilation with proper spec file
  • Standalone executable generation
  • Optional WiX MSI installer creation
  • Optional code signing support
  • Clean build management

Features:

  • Automatic dependency bundling (PySide6, Qt, Chromium)
  • Resource embedding (webapp, icons, stylesheets)
  • Hidden imports configuration for Qt Web Engine
  • Output validation and size reporting
  • WiX support for professional MSI creation

PyInstaller Configuration (build/webdrop_bridge.spec):

  • Bundles all dependencies (PySide6, Qt6 libraries)
  • Includes webapp files and resources
  • Sets up GUI mode (no console window)
  • Cross-platform compatible

Usage:

# Build executable only
python build/scripts/build_windows.py

# Build with MSI installer (requires WiX)
python build/scripts/build_windows.py --msi

# Build with code signing (requires certificate)
python build/scripts/build_windows.py --sign

Build Results:

  • Executable: WebDropBridge.exe (195.66 MB)
  • Output Directory: build/dist/windows/
  • Contains all dependencies including Chromium engine

Acceptance Criteria:

  • Executable builds successfully
  • Executable runs standalone (no Python required)
  • All dependencies bundled correctly
  • MSI installer creation (requires WiX installation)
  • Code signing (requires certificate)

3.2 macOS DMG Package

Build Script (build/scripts/build_macos.sh):

  • PyInstaller for .app bundle creation
  • DMG image generation
  • Professional DMG styling (optional via create-dmg)
  • Code signing and notarization support
  • Comprehensive error handling

Features:

  • Creates proper macOS .app bundle
  • DMG image for distribution
  • Professional volume icon and layout
  • Code signing with signing identities
  • Apple notarization support
  • Checksum verification

Usage:

# Build .app bundle and DMG
bash build/scripts/build_macos.sh

# With code signing
bash build/scripts/build_macos.sh --sign

# With notarization
bash build/scripts/build_macos.sh --notarize

Configuration (Environment Variables):

# For code signing
export APPLE_SIGNING_ID="Developer ID Application: Company Name"

# For notarization
export APPLE_ID="your@apple.id"
export APPLE_PASSWORD="app-specific-password"
export APPLE_TEAM_ID="XXXXXXXXXX"

Acceptance Criteria:

  • .app bundle builds successfully
  • DMG image creates without errors
  • DMG mounts and shows contents properly
  • Code signing works
  • Notarization passes

3.3 Forgejo Packages Distribution

Approach: Instead of CI/CD runners, use Forgejo Packages for manual releases

Upload Scripts:

  • Windows: build/scripts/upload_to_packages.ps1

    • Uploads WebDropBridge.exe to Packages
    • Uploads SHA256 checksum
    • Requires Forgejo personal access token
  • macOS: build/scripts/upload_to_packages.sh

    • Uploads WebDropBridge.dmg to Packages
    • Uploads SHA256 checksum
    • Requires Forgejo personal access token

Release Workflow:

1. Build locally on Windows:
   python build/scripts/build_windows.py
   
2. Build locally on macOS:
   bash build/scripts/build_macos.sh
   
3. Upload to Forgejo Packages:
   .\build\scripts\upload_to_packages.ps1 -Version 1.0.0 -ForgejoToken $token
   bash build/scripts/upload_to_packages.sh -v 1.0.0 -t $token
   
4. Tag release:
   git tag -a v1.0.0 -m "Release version 1.0.0"
   git push upstream v1.0.0
   
5. Users download from:
   https://git.him-tools.de/HIM-public/webdrop-bridge/packages

Package Structure:

https://git.him-tools.de/HIM-public/webdrop-bridge/packages/
├─ webdrop-bridge/
│  ├─ 1.0.0/
│  │  ├─ WebDropBridge.exe
│  │  ├─ WebDropBridge.exe.sha256
│  │  ├─ WebDropBridge.dmg
│  │  └─ WebDropBridge.dmg.sha256
│  └─ 1.0.1/
│     └─ ...

Setup Requirements:

  • Forgejo personal access token with write:package scope
  • Build scripts for Windows and macOS
  • Local builds on each platform

Acceptance Criteria:

  • Upload scripts created and tested
  • Documentation complete (FORGEJO_PACKAGES_SETUP.md)
  • Create GITEA_TOKEN with package permissions
  • Test upload: Build locally, upload to Packages
  • Verify files appear on Packages page
  • Verify checksums are correct
  • Test download and verify integrity

Advantages over CI/CD:

  • Simpler: No runner installation needed
  • Flexible: Build on your schedule
  • Reliable: Forgejo handles storage
  • Secure: Token-based authentication
  • Integrated: Ready for UpdateManager (Phase 4.1)

Status: Scripts created | First test pending


Phase 4: Professional Features & Auto-Update (Weeks 9-12)

4.1 Auto-Update System with Forgejo Integration

Forgejo Configuration:

Host: https://git.him-tools.de
Organization: HIM-public
Repository: webdrop-bridge
API Endpoint: https://git.him-tools.de/api/v1/repos/HIM-public/webdrop-bridge

Tasks:

4.1.1 Update Manager (src/webdrop_bridge/core/updater.py)

class UpdateManager:
    """Manages auto-updates via Forgejo releases."""
    
    def __init__(self, config: Config):
        self.forgejo_url = "https://git.him-tools.de"
        self.repo = "HIM-public/webdrop-bridge"
        self.current_version = config.app_version
    
    async def check_for_updates(self) -> Optional[Release]:
        """Query Forgejo API for latest release.
        
        Returns:
            Release info if newer version available, None otherwise
        """
        # GET https://git.him-tools.de/api/v1/repos/HIM-public/webdrop-bridge/releases/latest
        # Compare version semantic versioning
        
    async def download_update(self, release: Release) -> Path:
        """Download MSI/DMG from Forgejo release artifacts.
        
        Args:
            release: Release information from API
            
        Returns:
            Path to downloaded installer file
        """
        # Download from release assets
        # Verify checksums
        
    def install_update(self, installer_path: Path) -> bool:
        """Launch installer and schedule restart.
        
        Args:
            installer_path: Path to MSI or DMG file
            
        Returns:
            True if installation scheduled, False otherwise
        """

Configuration (.env):

# Auto-Update Settings
FORGEJO_URL=https://git.him-tools.de
FORGEJO_REPO=HIM-public/webdrop-bridge
AUTO_UPDATE_CHECK=true
AUTO_UPDATE_INTERVAL=86400  # 24 hours in seconds
AUTO_UPDATE_NOTIFY=true

Features:

  • Check on startup (with 24h cache)
  • Manual "Check for Updates" menu option
  • Background download (non-blocking)
  • User notification with changelog
  • Automatic restart capability
  • Rollback to previous version (optional)
  • Security: HTTPS-only, checksum verification

Deliverables:

  • src/webdrop_bridge/core/updater.py - Update manager (COMPLETE)
  • Unit tests for update checking and downloading (20 tests passing)
  • Integration with Forgejo API (async queries working)
  • Menu item for manual update check (TODO: Priority 2)
  • Update notification dialog (TODO: Priority 2)

Acceptance Criteria:

  • Can query Forgejo releases API
  • Detects new versions correctly
  • Downloads and verifies checksums
  • Gracefully handles network errors
  • Version comparison uses semantic versioning
  • Manual check works from menu (TODO: Priority 2)
  • Prompts user for restart (TODO: Priority 2)

4.1.2 Update UI Components (src/webdrop_bridge/ui/update_manager_ui.py)

Menu Integration:

Help Menu
├─ Check for Updates...     (manual trigger)
├─ ─────────────────────
└─ About WebDrop Bridge     (show current version)

Dialogs:

  1. "Checking for Updates..." Dialog

    • Animated spinner/progress
    • "Cancel" button
    • Message: "Checking for updates..."
    • Timeout: 10 seconds
  2. "Update Available" Dialog

    • Current version: X.X.X
    • New version: Y.Y.Y
    • Changelog/release notes (scrollable)
    • Buttons: "Update Now", "Later", "Skip This Version"
    • Checkbox: "Show next update reminder"
  3. "Downloading Update..." Dialog

    • Progress bar (download %)
    • File size info: "Downloading 195 MB..."
    • "Cancel Download" button
    • Cancel option reverts to "Later"
  4. "Install & Restart?" Dialog

    • Message: "Update downloaded and ready to install"
    • Buttons: "Install Now", "Install on Next Restart"
    • Checkbox: "Save my work before installing"
    • Shows warning if unsaved changes exist
  5. "No Updates Available" Dialog

    • Message: "You're running the latest version (X.X.X)"
    • Button: "OK"
    • Optional: "Check again" button
  6. "Update Failed" Dialog

    • Error message with reason
    • Buttons: "Retry", "Download Manually", "OK"
    • Manual download link to Forgejo releases

Status Bar Integration:

┌─────────────────────────────────────┐
│ Ready  🔄 Checking for updates...  │  (during check)
│ Ready  ✅ Update available (v1.1.0) │  (when found)
│ Ready  ⬇️ Downloading update (45%)  │  (during download)
└─────────────────────────────────────┘

Background Behavior:

  • Startup: Check for updates automatically (no UI blocking)
  • If newer version found: Show notification badge on Help menu
  • Silent background download when user is idle
  • Notification when download complete
  • Prompt for restart when convenient

Implementation:

  • Signal/slot architecture for async operations
  • Non-blocking UI (all operations async)
  • Graceful degradation if network unavailable
  • Thread pool for download operations
  • Cancel-safe download handling

Deliverables:

  • src/webdrop_bridge/ui/update_manager_ui.py - UI dialogs (skeleton complete)
  • Status bar update indicator (COMPLETE - emoji + status text)
  • Update menu item integration (TODO: Priority 2)
  • All dialogs with signal hookups (TODO: Priority 2)
  • Tests for UI interactions (TODO: Priority 2)

Acceptance Criteria:

  • Status bar updates in real-time (DONE)
  • No blocking operations on main thread (async/await)
  • Network errors handled gracefully (try/except with logging)
  • Menu item works and triggers check (TODO: Priority 2)
  • All dialogs display correctly (TODO: Priority 2)
  • Progress shown during download (TODO: Priority 2)
  • Restart options work (TODO: Priority 2)
  • Cancel operations work safely (TODO: Priority 2)

4.2 Enhanced Logging & Monitoring

Deliverables:

  • Structured logging (JSON format option)
  • Log rotation/archival
  • Performance metrics collection
  • Crash reporting (optional)

4.3 Advanced Configuration

Deliverables:

  • UI settings dialog
  • Configuration validation schema
  • Profile support (work, personal, etc.)
  • Export/import settings

4.4 User Documentation

Deliverables:

  • User manual (PDF, HTML)
  • Video tutorials
  • Troubleshooting guide
  • API documentation for developers

Phase 5: Post-Release (Months 2-3)

5.1 Analytics & Monitoring

Requirements:

  • App usage statistics
  • Error/crash reporting
  • Feature usage tracking

5.2 Community Support

Channels:

  • GitHub Issues
  • Discussions forum
  • Community Slack
  • Email support

Technical Specifications

Supported Platforms

┌─────────────────┬──────────┬────────┬────────────┐
│ Platform        │ Version  │ Arch   │ Status     │
├─────────────────┼──────────┼────────┼────────────┤
│ Windows         │ 10, 11   │ x64    │ Primary    │
│ macOS           │ 12-14    │ Intel  │ Primary    │
│ macOS           │ 12-14    │ ARM64  │ Primary    │
│ Linux           │ Ubuntu   │ x64    │ Experimental│
└─────────────────┴──────────┴────────┴────────────┘

Dependencies

Core:

  • PySide6 6.6.0+
  • Python 3.10+

Optional:

  • PyInstaller (building)
  • Sphinx (documentation)
  • pytest (testing)
  • aiohttp (auto-update downloads)
  • packaging (version comparison)

Directory Structure

webdrop-bridge/
│
├── src/webdrop_bridge/
│   ├── __init__.py
│   ├── main.py                 ← Entry point
│   ├── config.py               ← Configuration
│   ├── core/
│   │   ├── __init__.py
│   │   ├── validator.py        ← Path validation
│   │   ├── drag_interceptor.py ← Drag handling
│   │   ├── updater.py          ← Auto-update system (Phase 4)
│   │   └── errors.py           ← Custom exceptions
│   ├── ui/
│   │   ├── __init__.py
│   │   ├── main_window.py      ← Main UI
│   │   ├── widgets.py          ← Reusable widgets
│   │   └── styles.py           ← UI styling
│   └── utils/
│       ├── __init__.py
│       ├── logging.py          ← Logging setup
│       ├── constants.py        ← App constants
│       └── helpers.py          ← Utility functions
│
├── tests/
│   ├── __init__.py
│   ├── conftest.py             ← Pytest fixtures
│   ├── unit/                   ← Unit tests
│   ├── integration/            ← Integration tests
│   └── fixtures/               ← Test data
│
├── build/
│   ├── windows/                ← Windows build config
│   ├── macos/                  ← macOS build config
│   └── scripts/
│       ├── build_windows.py
│       └── build_macos.sh
│
├── webapp/                     ← Embedded web app
│   └── index.html
│
├── resources/
│   ├── icons/                  ← App icons
│   └── stylesheets/            ← Qt stylesheets
│
├── docs/                       ← Documentation
│   ├── architecture.md
│   ├── api.md
│   └── troubleshooting.md
│
└── Configuration Files
    ├── pyproject.toml          ← Modern Python packaging
    ├── setup.py                ← Backwards compatibility
    ├── pytest.ini              ← Test config
    ├── tox.ini                 ← Automation config
    └── .github/workflows/      ← CI/CD

Risk Analysis & Mitigation

Risk Probability Impact Mitigation
Qt/PySide6 API changes Low High Lock versions, monitor releases
macOS code signing Medium Medium Use Apple Developer account, automate
Drag performance issues Low Medium Performance testing early, profiling
Cross-platform bugs Medium Medium Extensive testing on both platforms
Security vulnerabilities Low High Regular audits, dependency scanning
User adoption Medium Medium Clear documentation, community engagement

Success Metrics

Metric Target Timeline
Code coverage 80%+ Week 6
Test pass rate 100% Continuous
Build time <2 min Week 8
Application startup <1 sec Week 8
Installer size <150 MB Week 8
Documentation completeness 100% Week 12
Community contributions 5+ Month 3

Milestones & Timeline

January 2026
├── Week 1-2: Core Architecture (config, logging, validator)
├── Week 3-4: UI Components (main window, drag interceptor)
├── Week 5-6: Testing & Quality Assurance
├── Week 7-8: Build & Installer Creation
├── Week 9-10: Advanced Features & Polish
├── Week 11-12: Documentation & Release
│
February 2026
└── Post-release: Auto-updates, Analytics, Community Support

Open Questions & Decisions

Decision: Embedded Web App vs. External URL

Options:

  1. Embed static web app (current PoC approach)
  2. Load from remote server
  3. Hybrid: Support both

Decision: Hybrid approach

  • Default: Load from WEBAPP_URL (local file)
  • Configurable: Allow remote URLs for advanced users
  • Security: Validate origins against whitelist

Decision: Update Mechanism

Options:

  1. Manual downloads from website
  2. Auto-update with staged rollout
  3. Package manager (Chocolatey, Brew)

Decision: GitHub Releases + PyInstaller

  • Phase 1: Manual downloads
  • Phase 5: Auto-update via custom launcher

Decision: Telemetry

Options:

  1. No telemetry
  2. Anonymous usage statistics
  3. Detailed crash reporting

Decision: Opt-in telemetry

  • No data collection by default
  • Users can enable for error reporting
  • Full transparency about data collected

Next Steps

  1. Immediate (This week):

    • Set up project directories
    • Create configuration system
    • Implement path validator
    • Set up CI/CD
  2. Near term (Next 2 weeks):

    • Complete core components
    • Write comprehensive tests
    • Build installers
  3. Medium term (Weeks 5-8):

    • Code review & QA
    • Performance optimization
    • Documentation
  4. Long term (Months 2-3):

    • Advanced features
    • Community engagement
    • Auto-update system

Document Control

Version Date Author Changes
1.0 Jan 28, 2026 Team Initial plan

Appendices

A. Technology Stack Justification

PySide6 over PyQt5/6:

  • Modern LGPL licensing
  • Excellent Windows & macOS support
  • Strong community and documentation
  • Built-in WebEngine

PyInstaller over Briefcase/Nuitka:

  • Mature, stable, well-tested
  • Excellent one-file executable support
  • Cross-platform build scripts

pytest over unittest:

  • Modern, expressive syntax
  • Powerful fixtures and plugins
  • Better integration with CI/CD

B. Security Considerations

Path Validation:

  • Only allow whitelisted directories
  • Resolve paths to prevent symlink attacks
  • Validate file existence before drag

Web Engine:

  • Disable remote URL loading by default
  • Implement CSP headers
  • Regular security audits

User Data:

  • No personally identifiable information stored
  • Configuration stored locally
  • Encrypted settings (future)

C. Performance Targets

- Application startup: < 1 second
- Drag interception: < 10ms
- File drag initiation: < 50ms
- Memory usage: < 200MB baseline
- Memory/file size ratio: < 2MB per 100 files

For updates or clarifications, see the main README.md or open an issue on GitHub.