webdrop-bridge/DEVELOPMENT_PLAN.md
claudi 50ce5abb6f docs: Add detailed UI components for Phase 4.1 auto-update system
- 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
2026-01-29 08:04:01 +01:00

1211 lines
35 KiB
Markdown

# 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`)
```python
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:**
- [x] `src/webdrop_bridge/config.py` - Configuration management
- [x] `.env.example` - Environment template
- [x] 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`)
```python
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`)
```python
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`)
```python
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
```python
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:**
- [x] `src/webdrop_bridge/ui/main_window.py`
- [x] `src/webdrop_bridge/ui/restricted_web_view.py` - URL whitelist enforcement
- [x] 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.
```python
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`)
```python
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:**
- [x] `src/webdrop_bridge/main.py`
- [x] 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:**
- [x] `tests/unit/test_config.py` - 12 tests (Config loading, validation, allowed_urls)
- [x] `tests/unit/test_logging.py` - 9 tests (Console/file logging, rotation, format)
- [x] `tests/unit/test_validator.py` - 16 tests (Path validation, symlinks, traversal attacks)
- [x] `tests/unit/test_restricted_web_view.py` - 15 tests (URL whitelist, patterns, browser fallback)
- [x] `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:**
- [x] `tests/unit/test_config.py` - Complete
- [x] `tests/unit/test_validator.py` - Complete
- [x] `tests/unit/test_drag_interceptor.py` - 25 tests (96% coverage)
- [x] `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:**
- [x] Black formatting: `tox -e format`
- [x] Ruff linting: `tox -e lint`
- [x] Type checking: `tox -e type` (with pragmatic type: ignore for Qt inheritance)
- [x] 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:**
```bash
# 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:**
- [x] Executable builds successfully
- [x] Executable runs standalone (no Python required)
- [x] 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:**
```bash
# 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):**
```bash
# 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:**
- [x] Upload scripts created and tested
- [x] 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`)
```python
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`):
```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:**
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
- [ ] 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:**
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.**