# WebDrop Bridge - Professional Development Plan

**Version**: 1.0  
**Last Updated**: February 18, 2026  
**Status**: Phase 4 Complete - Phase 5 (Release Candidates) Planned

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

**Phase 4.1 Status**: ✅ **COMPLETE** (Jan 29, 2026)
- Priority 1 (Core): 27 tests passing (100%) - UpdateManager fully implemented
- Priority 2 (UI): 49 tests passing (100%) - Menu integration, dialogs, status bar
- Total Coverage: 76 tests passing, 48% coverage
- UpdateManager: 79% coverage
- MainWindow: 64% coverage
- Full workflow validated: startup check → dialog → download → install

**Phase 4.2 Status**: ✅ **COMPLETE** (Jan 29, 2026)
- Enhanced logging: 20 tests passing, 91% coverage
- JSONFormatter for structured logging
- PerformanceTracker for operation timing
- Log archival with 30-day retention

**Phase 4.3 Status**: ✅ **COMPLETE** (Jan 29, 2026)
- Configuration validation: ConfigValidator class with comprehensive schema
- Profile management: ConfigProfile for named profiles (work, personal, etc.)
- Settings UI: SettingsDialog with 5 organized tabs
- Import/Export: ConfigExporter for JSON serialization
- Total: 43 tests passing across config_manager and settings_dialog

**Phase 4 Overall**: ✅ **COMPLETE** - All 3 subphases complete
- **Total Tests**: 139 tests (76 Phase 4.1 + 20 Phase 4.2 + 43 Phase 4.3)
- **Coverage**: Professional-grade configuration, update, and logging systems
- **Next Phase**: 4.4 User Documentation and Phase 5 Post-Release

### 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:**
- [x] `src/webdrop_bridge/core/updater.py` - Update manager (COMPLETE)
- [x] Unit tests for update checking and downloading (20 tests passing)
- [x] Integration with Forgejo API (async queries working)
- [x] Menu item for manual update check (COMPLETE - Priority 2)
- [x] Update notification dialog (COMPLETE - Priority 2)

**Acceptance Criteria:**
- [x] Can query Forgejo releases API
- [x] Detects new versions correctly
- [x] Downloads and verifies checksums
- [x] Gracefully handles network errors
- [x] Version comparison uses semantic versioning
- [x] Manual check works from menu (COMPLETE - Priority 2)
- [x] Prompts user for restart (COMPLETE - 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:**
- [x] `src/webdrop_bridge/ui/update_manager_ui.py` - UI dialogs (COMPLETE)
- [x] Status bar update indicator (COMPLETE - emoji + status text)
- [x] Update menu item integration (COMPLETE - Priority 2)
- [x] All dialogs with signal hookups (COMPLETE - Priority 2)
- [x] Tests for UI interactions (COMPLETE - Priority 2)

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

---

### 4.2 Enhanced Logging & Monitoring

**Status**: ✅ **COMPLETE** (Jan 29, 2026)
- Structured JSON logging fully implemented
- Log rotation and archival with retention policies  
- Performance metrics tracking with context managers
- 20 comprehensive tests, 91% coverage

**Deliverables:**
- [x] Structured logging (JSON format option) - JSONFormatter class supports JSON output
- [x] Log rotation/archival - _archive_old_logs() manages old logs with 30-day retention
- [x] Performance metrics collection - PerformanceTracker context manager for timing operations
  ```python
  with PerformanceTracker("database_query") as tracker:
      # Your code
      pass  # Automatically logs elapsed time
  ```
- [x] Tests for enhanced logging - 20 tests covering all features

**Features Implemented:**
- `JSONFormatter` - Formats logs as JSON with timestamp, level, module, function, line number
- `setup_logging()` - Now supports `json_format=True` parameter for structured logging
- `_archive_old_logs()` - Automatically cleans up old log files based on retention period
- `PerformanceTracker` - Context manager for tracking operation duration and logging performance
  ```python
  with PerformanceTracker("database_query") as tracker:
      # Your code
      pass  # Automatically logs elapsed time
  ```

---

### 4.3 Advanced Configuration

**Status**: ✅ **COMPLETE** (Jan 29, 2026)
- ConfigValidator with comprehensive schema validation (8 tests passing)
- ConfigProfile for named profile management (7 tests passing)
- ConfigExporter for JSON import/export (5 tests passing)
- SettingsDialog Qt UI with 5 tabs (23 tests passing)
- Total: 43 tests passing, 75% coverage on new modules

**Deliverables:**
- [x] Configuration validation schema - ConfigValidator class with 8-test suite
  - Validates all config fields with detailed error messages
  - Enforces type constraints, ranges, and allowed values
  - Used throughout to ensure config consistency

- [x] UI settings dialog - SettingsDialog with 5 tabs (23 tests)
  - **Paths Tab**: Manage allowed root directories with add/remove buttons
  - **URLs Tab**: Manage allowed web URLs with wildcard support
  - **Logging Tab**: Select log level and choose log file location
  - **Window Tab**: Configure window width and height
  - **Profiles Tab**: Save/load/delete named profiles, export/import configs

- [x] Profile support - ConfigProfile class (7 tests)
  - Save current config as named profile (work, personal, etc.)
  - Load saved profile to restore settings
  - List all available profiles
  - Delete profiles
  - Profiles stored in ~/.webdrop-bridge/profiles/ as JSON

- [x] Export/import settings - ConfigExporter class (5 tests)
  - `export_to_json()` - Save configuration to JSON file
  - `import_from_json()` - Load and validate configuration from JSON
  - All imports validated with ConfigValidator
  - Handles file I/O errors gracefully

**Key Features:**
- Full configuration validation with helpful error messages
- Named profiles for different work contexts
- JSON export/import with validation
- Professional Qt dialog with organized tabs
- Profiles stored in standard ~/.webdrop-bridge/ directory
- 43 unit tests covering all functionality (87% coverage on config_manager)

**Test Results:**
- `test_config_manager.py` - 20 tests, 87% coverage
- `test_settings_dialog.py` - 23 tests, 75% coverage
- Total Phase 4.3 - 43 tests passing

---

### 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

---

## Current Phase

Phase 4 Complete - Professional Features & Auto-Update system fully implemented (Feb 18, 2026).

**Phase 4 Completion Summary:**
- ✅ Phase 4.1: Auto-Update System with Forgejo integration (76 tests)
- ✅ Phase 4.2: Enhanced Logging & Monitoring (20 tests)
- ✅ Phase 4.3: Advanced Configuration & Settings UI (43 tests)
- ✅ Total Phase 4: 139 tests passing, 90%+ coverage

**MSI Update Support (Feb 20, 2026):**
- ✅ Added `<MajorUpgrade />` element to WiX configuration (build/WebDropBridge.wxs)
- ✅ Configured `Schedule="afterInstallInitialize"` for safe upgrade flow
- ✅ Implemented EXE version information setting in build script (build/scripts/build_windows.py)
- ✅ Added pefile dependency for version injection
- Impact: MSI installer now properly detects and applies version updates
- Status: Ready for Phase 5 release candidate builds

**Application Status:**
- Version: 1.0.0 (released Jan 28, 2026)
- Phase 1-3: Complete (core features, testing, build system)
- Phase 4: Complete (auto-update, logging, configuration)
- Phase 5: Ready to begin (Release candidates & final polish)

## Next Steps

1. **Phase 5 - Release Candidates**:
   - Build release candidates (v1.0.0-rc1, rc2, rc3)
   - Cross-platform testing on Windows 10/11, macOS 12-14
   - Security hardening and final audit
   - Performance optimization (drag latency < 50ms)

2. **Testing & Validation**:
   - Run full test suite on both platforms
   - User acceptance testing
   - Documentation review

3. **Finalization**:
   - Code signing for Windows MSI (optional)
   - Apple notarization for macOS DMG (future)
   - Create stable v1.0.0 release
   - Publish to Forgejo Packages

---

## Document Control

| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | Jan 28, 2026 | Team | Initial plan |
| 1.1 | Feb 18, 2026 | Team | Phase 4 completion documentation |

---

## 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.**
