update README.md

This commit is contained in:
2026-08-01 21:22:34 +02:00
parent 8506cfc83f
commit 102a2eb585
2 changed files with 51 additions and 13 deletions
+38
View File
@@ -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 | | `/` | HTML-Ansicht, mobile-optimiert, Auto-Refresh alle 60s |
| `/api/departures` | JSON-Liste aller gefilterten Abfahrten | | `/api/departures` | JSON-Liste aller gefilterten Abfahrten |
| `/healthz` | Healthcheck fuer Docker/Watchtower | | `/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)
+13 -13
View File
@@ -13,16 +13,16 @@
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #111417; background: #111417;
color: #eaeaea; color: #eaeaea;
font-size: 15px; font-size: 20px;
} }
h1 { h1 {
font-size: 16px; font-size: 24px;
margin: 4px 0 10px 4px; margin: 4px 0 10px 4px;
color: #9aa5b1; color: #9aa5b1;
font-weight: 500; font-weight: 500;
} }
.updated { .updated {
font-size: 11px; font-size: 14px;
color: #6b7280; color: #6b7280;
margin-left: 4px; margin-left: 4px;
} }
@@ -34,18 +34,18 @@
border-bottom: 1px solid #23272d; border-bottom: 1px solid #23272d;
} }
td { td {
padding: 8px 4px; padding: 12px 6px;
vertical-align: middle; vertical-align: middle;
} }
.icon { .icon {
display: inline-block; display: inline-block;
width: 26px; width: 32px;
height: 26px; height: 32px;
line-height: 26px; line-height: 32px;
text-align: center; text-align: center;
border-radius: 6px; border-radius: 6px;
font-weight: 700; font-weight: 700;
font-size: 13px; font-size: 16px;
color: #111417; color: #111417;
} }
.icon-U { background: #005ca9; color: #fff; } .icon-U { background: #005ca9; color: #fff; }
@@ -54,21 +54,21 @@
.icon-B { background: #55545a; color: #fff; } .icon-B { background: #55545a; color: #fff; }
.line { .line {
font-weight: 700; font-weight: 700;
font-size: 14px; font-size: 18px;
display: block; display: block;
} }
.station { .station {
font-size: 11px; font-size: 14px;
color: #6b7280; color: #6b7280;
} }
.destination { .destination {
font-size: 14px; font-size: 18px;
} }
.time { .time {
text-align: right; text-align: center;
white-space: nowrap; white-space: nowrap;
font-weight: 700; font-weight: 700;
font-size: 15px; font-size: 20px;
} }
.delay { .delay {
font-size: 12px; font-size: 12px;