webdrop-bridge/DEVELOPMENT_PLAN.md
claudi 61aa33633c Add initial project structure and documentation
- Created architecture documentation outlining high-level design, module organization, data flow, security model, performance considerations, testing strategy, and deployment architecture.
- Added pyproject.toml for project metadata and dependencies management.
- Introduced requirements files for development and production dependencies.
- Set up testing configuration with pytest and tox.
- Established basic directory structure for source code and tests, including __init__.py files.
- Implemented a sample web application (index.html) for drag-and-drop functionality.
- Configured VS Code workspace settings for Python development.
2026-01-28 10:48:36 +01:00

20 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]
    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(",")]
        
        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,
            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

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)

from PySide6.QtWidgets import QMainWindow, QVBoxLayout, QWidget
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtCore import QUrl
import logging

logger = logging.getLogger(__name__)

class MainWindow(QMainWindow):
    """Application main window."""
    
    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 web engine view
        self.web_view = QWebEngineView()
        self._configure_web_engine()
        
        # 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 _configure_web_engine(self):
        """Configure WebEngine settings for local file access."""
        settings = self.web_view.settings()
        from PySide6.QtWebEngineCore import QWebEngineSettings
        
        settings.setAttribute(
            QWebEngineSettings.LocalContentCanAccessFileUrls, True
        )
        settings.setAttribute(
            QWebEngineSettings.LocalContentCanAccessRemoteUrls, False
        )

Deliverables:

  • src/webdrop_bridge/ui/main_window.py
  • UI tests

Acceptance Criteria:

  • Window opens with correct title
  • WebEngine loads correctly
  • Responsive to resize events

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 2: Testing & Quality (Weeks 5-6)

2.1 Unit Tests

Files to create:

  • tests/unit/test_config.py
  • tests/unit/test_validator.py
  • tests/unit/test_drag_interceptor.py
  • tests/unit/test_main_window.py

Target Coverage: 80%+ line coverage


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
  • Coverage report: pytest --cov=src/webdrop_bridge
  • Security scan: pip audit

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

3.1 Windows Installer (MSI)

Setup:

pip install pyinstaller

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

  • Compile with PyInstaller
  • Create MSI with WiX (optional: advanced features)
  • Code signing (optional: professional deployment)
  • Output: WebDropBridge-1.0.0-Setup.exe

Acceptance Criteria:

  • Executable runs standalone
  • Installer installs to Program Files
  • Uninstaller removes all files
  • Shortcuts created in Start Menu

3.2 macOS DMG Package

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

  • Compile with PyInstaller
  • Create .app bundle
  • Generate DMG image
  • Code signing (optional)
  • Output: WebDropBridge-1.0.0.dmg

Acceptance Criteria:

  • App bundle signed (if applicable)
  • DMG opens in Finder
  • Drag-to-Applications works
  • Notarization passes (if applicable)

Phase 4: Professional Features (Weeks 9-12)

4.1 Enhanced Logging & Monitoring

Deliverables:

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

4.2 Advanced Configuration

Deliverables:

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

4.3 User Documentation

Deliverables:

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

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

5.1 Auto-Update System

Requirements:

  • Check for updates on startup
  • Download in background
  • Staged rollout support
  • Rollback capability

5.2 Analytics & Monitoring

Metrics:

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

5.3 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)

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
│   │   └── 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.