- Add 4.1.2 section for update manager UI - Specify all dialogs (checking, available, downloading, install, failed, no updates) - Include status bar integration with update indicators - Define menu structure for Help menu updates - Add background behavior specifications - List async/non-blocking implementation requirements - Include UI testing acceptance criteria
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://
- Examples:
Acceptance Criteria:
- Config loads from
.envfile - 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.pysrc/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- Completetests/unit/test_validator.py- Completetests/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.pytests/integration/test_webapp_loading.pytests/integration/test_end_to_end.py
Test Scenarios:
- Start app → Load webapp → Verify ready
- Initiate drag → Validate → Drop file → Verify received
- 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:packagescope - 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- Menu item for manual update check
- Update notification dialog
- Unit tests for update checking and downloading
- Integration with Forgejo API
Acceptance Criteria:
- Can query Forgejo releases API
- Detects new versions correctly
- Downloads and verifies checksums
- Prompts user for restart
- Manual check works from menu
- Gracefully handles network errors
- Version comparison uses semantic versioning
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:
-
"Checking for Updates..." Dialog
- Animated spinner/progress
- "Cancel" button
- Message: "Checking for updates..."
- Timeout: 10 seconds
-
"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"
-
"Downloading Update..." Dialog
- Progress bar (download %)
- File size info: "Downloading 195 MB..."
- "Cancel Download" button
- Cancel option reverts to "Later"
-
"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
-
"No Updates Available" Dialog
- Message: "You're running the latest version (X.X.X)"
- Button: "OK"
- Optional: "Check again" button
-
"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- Update menu item integration
- Status bar update indicator
- All dialogs with error handling
- Tests for UI interactions
Acceptance Criteria:
- Menu item works and triggers check
- All dialogs display correctly
- Progress shown during download
- Restart options work
- Network errors handled gracefully
- Cancel operations work safely
- Status bar updates in real-time
- No blocking operations on main thread
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:
- Embed static web app (current PoC approach)
- Load from remote server
- 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:
- Manual downloads from website
- Auto-update with staged rollout
- Package manager (Chocolatey, Brew)
Decision: GitHub Releases + PyInstaller
- Phase 1: Manual downloads
- Phase 5: Auto-update via custom launcher
Decision: Telemetry
Options:
- No telemetry
- Anonymous usage statistics
- 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
-
Immediate (This week):
- Set up project directories ✅
- Create configuration system
- Implement path validator
- Set up CI/CD
-
Near term (Next 2 weeks):
- Complete core components
- Write comprehensive tests
- Build installers
-
Medium term (Weeks 5-8):
- Code review & QA
- Performance optimization
- Documentation
-
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.