124-webapp/.github/copilot-instructions.md
2025-10-07 13:02:29 +02:00

144 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copilot Instructions for Studio EinsZwoVier Web Application
## Project Overview
This is a **FastAPI-based web application** serving as a multi-service hub for Studio EinsZwoVier, a collaborative print studio. The main app provides a PDF print cost calculator with automated ink coverage analysis, integrated with a Matrix server for order collection and payment tracking.
## Architecture & Service Boundaries
### Core FastAPI Application (`main.py`, port 80→8000)
- **Landing page** (`/`) with presence state management (studio open/closed indicator)
- **Cost calculator** (`/cost`) for PDF analysis and price estimation
- **About page** (`/about`)
- **Order submission** via Matrix integration
### Multi-Container Stack (Docker Compose)
The application orchestrates 7+ containerized services:
- **web**: FastAPI app (this repo's code)
- **synapse**: Matrix server for print job collection (port 8008)
- **ollama**: Local LLM inference (port 11434)
- **open-webui**: LLM chat interface (port 8080)
- **bookstack + mariadb**: Documentation wiki
- **docmost + postgres + redis**: Knowledge management system
- **watchtower**: Auto-updates all containers every 24h
### PDF Processing Pipeline (`cost_calculator.py`)
1. **Upload** → Validate `.pdf` extension only
2. **Page-by-page analysis**:
- Extract dimensions from `CropBox` (preferred) or `MediaBox`
- Convert PDF points to meters: `(points / 72.0) * 0.0254`
- Render at 150 DPI using `pdf2image`
- Calculate ink coverage: pixels with RGB < 250 = ink
- Detect color vs B&W: HSV saturation analysis (>0.1% pixels with sat>10 = color)
3. **Cost calculation**: area (m²) × rate (from env vars `RATE_PER_M2_BLACK`/`COLOR`)
### Matrix Integration (`mailer.py`)
- Uses `matrix-nio` async client to send orders
- **Critical**: Must set `MATRIX_USER`, `MATRIX_PASS`, `MATRIX_HOMESERVER` env vars
- Sends structured summary (German language) + PDF upload to hardcoded room ID
- **Synchronous wrapper** `send_order_sync()` bridges async/sync contexts for FastAPI
## Developer Workflows
### Local Development
```bash
# Option 1: Direct Python execution (auto-reload)
python run_app.py
# Option 2: Full stack with Docker Compose
docker-compose up --build -d
# Access at: http://localhost (or einszwovier.local in local network)
```
### Environment Configuration
Create `.env` file with:
```bash
# Print rates (€/m²)
RATE_PER_M2_BLACK=4.0
RATE_PER_M2_COLOR=5.0
# Matrix integration
MATRIX_USER=@bot:homeserver
MATRIX_PASS=secret
MATRIX_HOMESERVER=http://einszwovier.local:8008
# Service ports
SYNAPSE_PORT=8008
OLLAMA_PORT=11434
OPENWEBUI_PORT=8080
BOOKSTACK_PORT=6875
# BookStack/DB configs (see docker-compose.yml for full list)
```
### Debugging Matrix Integration
Use `get_room_id.py` to discover Matrix room IDs:
```python
# Connects to local Matrix server, joins room, prints room IDs
python get_room_id.py
```
Then update the hardcoded room ID in `main.py` line 127: `room_id="!eFW..."`
## Project-Specific Conventions
### Presence State Management
- In-memory global `presence_state` dict tracks studio open/closed status
- API endpoints: `GET /presence`, `POST /presence`, `POST /presence/toggle`
- Background task `update_presence_periodically()` runs every 5 min (currently no-op placeholder)
### German UI/UX
- Templates use German language exclusively
- Error/success messages in German (e.g., "Dein Auftrag wurde erfolgreich gesendet!")
- Cost calculator displays "S/W" (Schwarz/Weiß) vs "Farbe" (color)
### File Organization
- **Uploads persist** in `data/uploads/` (mounted volume in Docker)
- **Templates** in `templates/` (Jinja2, extending `base.html`)
- **Static assets** in `static/` (CSS, fonts, images)
- **Service data** in dedicated dirs: `bookstack/`, `docmost/`, `matrix/`, `ollama/`, `open-webui/`
### Docker Production Command
The `Dockerfile` uses **Gunicorn with Uvicorn workers** for production:
```bash
gunicorn main:app -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 --workers 4 --timeout 120
```
But `docker-compose.yml` overrides with `--reload` for dev convenience.
## Critical Integration Points
### PDF Analysis Return Structure
`analyze_pdf()` returns:
```python
{
"filename": str,
"pages": [{"page": int, "width_m": float, "height_m": float,
"area_m2": float, "ink_pct": float, "is_color": bool, "cost": float}],
"total_area_black": float,
"total_area_color": float,
"total_cost_black": float,
"total_cost_color": float,
"grand_total": float
}
```
### Matrix Room ID Hardcoding
⚠️ **Known technical debt**: Room ID is hardcoded in `send_order_endpoint()`. Update when Matrix server changes or for different deployment environments.
### Async/Sync Bridge Pattern
Matrix client is async, but FastAPI endpoint is sync. Pattern used:
```python
def send_order_sync(...):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(send_order(...))
loop.close()
```
## External Dependencies
- **Poppler** (system): Required for `pdf2image` (installed in Dockerfile)
- **OpenCV** (system): Requires `libgl1`, `libglib2.0-0` (installed in Dockerfile)
- **Font files**: Custom fonts in `static/fonts/` (BauPro, HealTheWebA/B, SISTEMAS)
## Testing & Utilities
- `test_send_pdf.py`: Manual test script for Matrix integration
- No automated test suite currently implemented