Add initial project structure and documentation

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

777
DEVELOPMENT_PLAN.md Normal file
View file

@ -0,0 +1,777 @@
# 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]
webapp_url: str
window_width: int
window_height: int
enable_logging: bool
@classmethod
def from_env(cls):
"""Load configuration from environment."""
load_dotenv()
allowed_roots_str = os.getenv("ALLOWED_ROOTS", "Z:/,C:/Users/Public")
allowed_roots = [Path(p.strip()) for p in allowed_roots_str.split(",")]
return cls(
app_name=os.getenv("APP_NAME", "WebDrop Bridge"),
app_version=os.getenv("APP_VERSION", "1.0.0"),
log_level=os.getenv("LOG_LEVEL", "INFO"),
allowed_roots=allowed_roots,
webapp_url=os.getenv("WEBAPP_URL", "file:///./webapp/index.html"),
window_width=int(os.getenv("WINDOW_WIDTH", "1024")),
window_height=int(os.getenv("WINDOW_HEIGHT", "768")),
enable_logging=os.getenv("ENABLE_LOGGING", "true").lower() == "true",
)
```
**Deliverables:**
- [ ] `src/webdrop_bridge/config.py` - Configuration management
- [ ] `.env.example` - Environment template
- [ ] Validation for all config parameters
**Acceptance Criteria:**
- Config loads from `.env` file
- All environment variables have sensible defaults
- Invalid values raise `ConfigurationError`
---
#### 1.1.2 Logging System (`src/webdrop_bridge/utils/logging.py`)
```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`)
```python
from PySide6.QtWidgets import QMainWindow, QVBoxLayout, QWidget
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtCore import QUrl
import logging
logger = logging.getLogger(__name__)
class MainWindow(QMainWindow):
"""Application main window."""
def __init__(self, config):
super().__init__()
self.config = config
self.setWindowTitle(config.app_name)
self.setGeometry(100, 100, config.window_width, config.window_height)
# Create web engine view
self.web_view = QWebEngineView()
self._configure_web_engine()
# Set as central widget
self.setCentralWidget(self.web_view)
logger.info(f"Loading webapp from: {config.webapp_url}")
self.web_view.load(QUrl(config.webapp_url))
def _configure_web_engine(self):
"""Configure WebEngine settings for local file access."""
settings = self.web_view.settings()
from PySide6.QtWebEngineCore import QWebEngineSettings
settings.setAttribute(
QWebEngineSettings.LocalContentCanAccessFileUrls, True
)
settings.setAttribute(
QWebEngineSettings.LocalContentCanAccessRemoteUrls, False
)
```
**Deliverables:**
- [ ] `src/webdrop_bridge/ui/main_window.py`
- [ ] UI tests
**Acceptance Criteria:**
- Window opens with correct title
- WebEngine loads correctly
- Responsive to resize events
---
### 1.4 Application Entry Point
**Tasks:**
#### 1.4.1 Main Entry (`src/webdrop_bridge/main.py`)
```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:**
- [ ] `src/webdrop_bridge/main.py`
- [ ] Entry point tested
**Acceptance Criteria:**
- Application starts without errors
- Configuration loaded correctly
- Logging initialized
---
## Phase 2: Testing & Quality (Weeks 5-6)
### 2.1 Unit Tests
**Files to create:**
- [ ] `tests/unit/test_config.py`
- [ ] `tests/unit/test_validator.py`
- [ ] `tests/unit/test_drag_interceptor.py`
- [ ] `tests/unit/test_main_window.py`
**Target Coverage**: 80%+ line coverage
---
### 2.2 Integration Tests
**Files to create:**
- [ ] `tests/integration/test_drag_workflow.py`
- [ ] `tests/integration/test_webapp_loading.py`
- [ ] `tests/integration/test_end_to_end.py`
**Test Scenarios:**
1. Start app → Load webapp → Verify ready
2. Initiate drag → Validate → Drop file → Verify received
3. Invalid path → Reject → No file created
---
### 2.3 Code Quality
**Checklist:**
- [ ] Black formatting: `tox -e format`
- [ ] Ruff linting: `tox -e lint`
- [ ] Type checking: `tox -e type`
- [ ] Coverage report: `pytest --cov=src/webdrop_bridge`
- [ ] Security scan: `pip audit`
---
## Phase 3: Build & Distribution (Weeks 7-8)
### 3.1 Windows Installer (MSI)
**Setup:**
```bash
pip install pyinstaller
```
**Build Script** (`build/scripts/build_windows.py`):
- Compile with PyInstaller
- Create MSI with WiX (optional: advanced features)
- Code signing (optional: professional deployment)
- Output: `WebDropBridge-1.0.0-Setup.exe`
**Acceptance Criteria:**
- Executable runs standalone
- Installer installs to Program Files
- Uninstaller removes all files
- Shortcuts created in Start Menu
---
### 3.2 macOS DMG Package
**Build Script** (`build/scripts/build_macos.sh`):
- Compile with PyInstaller
- Create `.app` bundle
- Generate DMG image
- Code signing (optional)
- Output: `WebDropBridge-1.0.0.dmg`
**Acceptance Criteria:**
- App bundle signed (if applicable)
- DMG opens in Finder
- Drag-to-Applications works
- Notarization passes (if applicable)
---
## Phase 4: Professional Features (Weeks 9-12)
### 4.1 Enhanced Logging & Monitoring
**Deliverables:**
- [ ] Structured logging (JSON format option)
- [ ] Log rotation/archival
- [ ] Performance metrics collection
- [ ] Crash reporting (optional)
---
### 4.2 Advanced Configuration
**Deliverables:**
- [ ] UI settings dialog
- [ ] Configuration validation schema
- [ ] Profile support (work, personal, etc.)
- [ ] Export/import settings
---
### 4.3 User Documentation
**Deliverables:**
- [ ] User manual (PDF, HTML)
- [ ] Video tutorials
- [ ] Troubleshooting guide
- [ ] API documentation for developers
---
## Phase 5: Post-Release (Months 2-3)
### 5.1 Auto-Update System
**Requirements:**
- Check for updates on startup
- Download in background
- Staged rollout support
- Rollback capability
---
### 5.2 Analytics & Monitoring
**Metrics:**
- App usage statistics
- Error/crash reporting
- Feature usage tracking
---
### 5.3 Community Support
**Channels:**
- GitHub Issues
- Discussions forum
- Community Slack
- Email support
---
## Technical Specifications
### Supported Platforms
```
┌─────────────────┬──────────┬────────┬────────────┐
│ Platform │ Version │ Arch │ Status │
├─────────────────┼──────────┼────────┼────────────┤
│ Windows │ 10, 11 │ x64 │ Primary │
│ macOS │ 12-14 │ Intel │ Primary │
│ macOS │ 12-14 │ ARM64 │ Primary │
│ Linux │ Ubuntu │ x64 │ Experimental│
└─────────────────┴──────────┴────────┴────────────┘
```
---
### Dependencies
**Core:**
- PySide6 6.6.0+
- Python 3.10+
**Optional:**
- PyInstaller (building)
- Sphinx (documentation)
- pytest (testing)
---
### Directory Structure
```
webdrop-bridge/
├── src/webdrop_bridge/
│ ├── __init__.py
│ ├── main.py ← Entry point
│ ├── config.py ← Configuration
│ ├── core/
│ │ ├── __init__.py
│ │ ├── validator.py ← Path validation
│ │ ├── drag_interceptor.py ← Drag handling
│ │ └── errors.py ← Custom exceptions
│ ├── ui/
│ │ ├── __init__.py
│ │ ├── main_window.py ← Main UI
│ │ ├── widgets.py ← Reusable widgets
│ │ └── styles.py ← UI styling
│ └── utils/
│ ├── __init__.py
│ ├── logging.py ← Logging setup
│ ├── constants.py ← App constants
│ └── helpers.py ← Utility functions
├── tests/
│ ├── __init__.py
│ ├── conftest.py ← Pytest fixtures
│ ├── unit/ ← Unit tests
│ ├── integration/ ← Integration tests
│ └── fixtures/ ← Test data
├── build/
│ ├── windows/ ← Windows build config
│ ├── macos/ ← macOS build config
│ └── scripts/
│ ├── build_windows.py
│ └── build_macos.sh
├── webapp/ ← Embedded web app
│ └── index.html
├── resources/
│ ├── icons/ ← App icons
│ └── stylesheets/ ← Qt stylesheets
├── docs/ ← Documentation
│ ├── architecture.md
│ ├── api.md
│ └── troubleshooting.md
└── Configuration Files
├── pyproject.toml ← Modern Python packaging
├── setup.py ← Backwards compatibility
├── pytest.ini ← Test config
├── tox.ini ← Automation config
└── .github/workflows/ ← CI/CD
```
---
## Risk Analysis & Mitigation
| Risk | Probability | Impact | Mitigation |
|------|-------------|--------|-----------|
| Qt/PySide6 API changes | Low | High | Lock versions, monitor releases |
| macOS code signing | Medium | Medium | Use Apple Developer account, automate |
| Drag performance issues | Low | Medium | Performance testing early, profiling |
| Cross-platform bugs | Medium | Medium | Extensive testing on both platforms |
| Security vulnerabilities | Low | High | Regular audits, dependency scanning |
| User adoption | Medium | Medium | Clear documentation, community engagement |
---
## Success Metrics
| Metric | Target | Timeline |
|--------|--------|----------|
| Code coverage | 80%+ | Week 6 |
| Test pass rate | 100% | Continuous |
| Build time | <2 min | Week 8 |
| Application startup | <1 sec | Week 8 |
| Installer size | <150 MB | Week 8 |
| Documentation completeness | 100% | Week 12 |
| Community contributions | 5+ | Month 3 |
---
## Milestones & Timeline
```
January 2026
├── Week 1-2: Core Architecture (config, logging, validator)
├── Week 3-4: UI Components (main window, drag interceptor)
├── Week 5-6: Testing & Quality Assurance
├── Week 7-8: Build & Installer Creation
├── Week 9-10: Advanced Features & Polish
├── Week 11-12: Documentation & Release
February 2026
└── Post-release: Auto-updates, Analytics, Community Support
```
---
## Open Questions & Decisions
### Decision: Embedded Web App vs. External URL
**Options:**
1. Embed static web app (current PoC approach)
2. Load from remote server
3. Hybrid: Support both
**Decision**: **Hybrid approach**
- Default: Load from `WEBAPP_URL` (local file)
- Configurable: Allow remote URLs for advanced users
- Security: Validate origins against whitelist
---
### Decision: Update Mechanism
**Options:**
1. Manual downloads from website
2. Auto-update with staged rollout
3. Package manager (Chocolatey, Brew)
**Decision**: **GitHub Releases + PyInstaller**
- Phase 1: Manual downloads
- Phase 5: Auto-update via custom launcher
---
### Decision: Telemetry
**Options:**
1. No telemetry
2. Anonymous usage statistics
3. Detailed crash reporting
**Decision**: **Opt-in telemetry**
- No data collection by default
- Users can enable for error reporting
- Full transparency about data collected
---
## Next Steps
1. **Immediate** (This week):
- [ ] Set up project directories ✅
- [ ] Create configuration system
- [ ] Implement path validator
- [ ] Set up CI/CD
2. **Near term** (Next 2 weeks):
- [ ] Complete core components
- [ ] Write comprehensive tests
- [ ] Build installers
3. **Medium term** (Weeks 5-8):
- [ ] Code review & QA
- [ ] Performance optimization
- [ ] Documentation
4. **Long term** (Months 2-3):
- [ ] Advanced features
- [ ] Community engagement
- [ ] Auto-update system
---
## Document Control
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | Jan 28, 2026 | Team | Initial plan |
---
## Appendices
### A. Technology Stack Justification
**PySide6 over PyQt5/6:**
- Modern LGPL licensing
- Excellent Windows & macOS support
- Strong community and documentation
- Built-in WebEngine
**PyInstaller over Briefcase/Nuitka:**
- Mature, stable, well-tested
- Excellent one-file executable support
- Cross-platform build scripts
**pytest over unittest:**
- Modern, expressive syntax
- Powerful fixtures and plugins
- Better integration with CI/CD
---
### B. Security Considerations
**Path Validation:**
- Only allow whitelisted directories
- Resolve paths to prevent symlink attacks
- Validate file existence before drag
**Web Engine:**
- Disable remote URL loading by default
- Implement CSP headers
- Regular security audits
**User Data:**
- No personally identifiable information stored
- Configuration stored locally
- Encrypted settings (future)
---
### C. Performance Targets
```
- Application startup: < 1 second
- Drag interception: < 10ms
- File drag initiation: < 50ms
- Memory usage: < 200MB baseline
- Memory/file size ratio: < 2MB per 100 files
```
---
**For updates or clarifications, see the main README.md or open an issue on GitHub.**