diff --git a/README.md b/README.md index 7aec89f..3218e90 100644 --- a/README.md +++ b/README.md @@ -102,3 +102,41 @@ https://www.mvg.de/api/bgw-pt/v3/departures?globalId=de:09162:910&limit=10&trans | `/` | HTML-Ansicht, mobile-optimiert, Auto-Refresh alle 60s | | `/api/departures` | JSON-Liste aller gefilterten Abfahrten | | `/healthz` | Healthcheck fuer Docker/Watchtower | + +## Projektstruktur + +``` +mvg-departures/ +├── app/ +│ ├── main.py # FastAPI-App, Endpunkte, Caching +│ ├── config.py # Config-Loader (YAML → Dataclasses) +│ └── templates/ +│ └── index.html # Jinja2-Template (Mobile-UI) +├── config.yaml # Stationskonfiguration +├── requirements.txt # Python-Dependencies +├── Dockerfile +└── .github/workflows/ + └── build.yml # CI/CD: Docker-Build + GHCR-Push +``` + +## Tech-Stack + +- **Runtime**: Python 3.12 +- **Framework**: FastAPI + Uvicorn +- **Templating**: Jinja2 (server-seitig) +- **MVG-API**: `mvg` Python-Client (oeffentlich, kein Auth noetig) +- **Config**: YAML via `pyyaml` +- **Container**: Docker (python:3.12-slim) + +## Caching + +- **Station-ID**: In-memory Dict, lifetime=Session (loest Station-Namen auf) +- **Abfahrten**: In-memory Dict, TTL=`cache_seconds` (Default: 20s) pro Station+Typ +- Keine Persistenz → Neustart = Cache-Verlust + +## Einschraenkungen + +- Kein WebSocket/Live-Updates (nur periodischer Meta-Refresh) +- Keine Datenbank (nur In-Memory) +- Kein Test-Framework vorhanden +- Ein `config.yaml` pro Deployment (kein Multi-Tenancy) diff --git a/app/templates/index.html b/app/templates/index.html index 37feb6a..e270dfa 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -13,16 +13,16 @@ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #111417; color: #eaeaea; - font-size: 15px; + font-size: 20px; } h1 { - font-size: 16px; + font-size: 24px; margin: 4px 0 10px 4px; color: #9aa5b1; font-weight: 500; } .updated { - font-size: 11px; + font-size: 14px; color: #6b7280; margin-left: 4px; } @@ -34,18 +34,18 @@ border-bottom: 1px solid #23272d; } td { - padding: 8px 4px; + padding: 12px 6px; vertical-align: middle; } .icon { display: inline-block; - width: 26px; - height: 26px; - line-height: 26px; + width: 32px; + height: 32px; + line-height: 32px; text-align: center; border-radius: 6px; font-weight: 700; - font-size: 13px; + font-size: 16px; color: #111417; } .icon-U { background: #005ca9; color: #fff; } @@ -54,21 +54,21 @@ .icon-B { background: #55545a; color: #fff; } .line { font-weight: 700; - font-size: 14px; + font-size: 18px; display: block; } .station { - font-size: 11px; + font-size: 14px; color: #6b7280; } .destination { - font-size: 14px; + font-size: 18px; } .time { - text-align: right; + text-align: center; white-space: nowrap; font-weight: 700; - font-size: 15px; + font-size: 20px; } .delay { font-size: 12px;