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

5.3 KiB
Raw Blame History

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

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

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

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

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:

{
    "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:

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