Erstumsetzung: OAMC Turnierauswertung (AP 0–7, 9)
* Datenmodell + Alembic-Initialmigration (Plan §4), Seed Saison 2026 * Wertungs-Engine (Plan §3.3), regelbasiert je Kategorie/Saison - Abnahmetest gegen die Ergebnisliste 2026-05-31 * Meisterschaftsberechnung mit Streichresultaten + Tie-Break (PLATZHALTER-Punktetabelle, O-1 offen) * Ingest-API (idempotent, dry_run) inkl. Excel-Leser und Fahrer-Matching/Merge * Zeitmessungs-Endpoint (Batch, idempotent, unzugeordnet/unplausibel) + SSE-Anzeige - Mess-Pi-Client bewusst NICHT enthalten (docs/zeitmessung-endpoint.md) * Frontend: öffentliche Seiten + internes Backend (Jinja2/HTMX, kein Build) * Auslieferung: Docker (multi-arch) + docker-compose sowie Debian-Paket/APT-Repo * 57 Tests grün gegen echte PostgreSQL-Testdatenbank Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
# OAMC Turnierauswertung
|
||||
|
||||
Webanwendung zur Auswertung von **ADAC Motorrad-Turnieren** des OAMC Reinheim e.V.:
|
||||
Ergebnisse (Fehlerpunkte + Zeit → Platzierung), Fahrerdatenbank mit Historie,
|
||||
Meisterschaftswertung und ein **Endpoint für die Lichtschranken-Zeitmessung**.
|
||||
|
||||
Fachliche Grundlagen, offene Fragen und Architekturbegründung: **[`plan.md`](plan.md)**.
|
||||
|
||||
> Der Mess-Pi-Client (GPIO/Lichtschranke) ist **nicht** Teil dieses Repos — die
|
||||
> Anwendung stellt nur den Endpoint bereit. Contract:
|
||||
> [`docs/zeitmessung-endpoint.md`](docs/zeitmessung-endpoint.md).
|
||||
|
||||
---
|
||||
|
||||
## Stack
|
||||
|
||||
| Schicht | Wahl |
|
||||
|---|---|
|
||||
| DB | PostgreSQL 17 (JSONB, ARRAY, `pg_trgm`) |
|
||||
| Backend | Python 3.11+ · FastAPI · SQLAlchemy 2 · Alembic · Pydantic v2 |
|
||||
| Frontend | serverseitig gerendertes Jinja2 + HTMX (kein Node, kein Build) |
|
||||
| Live | Server-Sent Events (`sse-starlette`) |
|
||||
| Auslieferung | **Docker-Image** *und* **Debian-Paket** (`.deb` / eigenes APT-Repo) |
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
```
|
||||
src/oamc/
|
||||
models/ ORM (§4 im Plan)
|
||||
wertung/ Wertungs-Engine — der Kern (§3.3). engine.py + service.py
|
||||
meisterschaft/ Punkte, Streichresultate, Tie-Break, Endlaufquali (§3.4)
|
||||
matching/ Fahrer-Dublettenerkennung + Merge (§6.4)
|
||||
importer/ Bulk-Ingest + Excel-Leser
|
||||
geraete/ Zeitmessungs-Endpoint-Logik (§3.6)
|
||||
api/v1/ read.py · ingest.py · geraete.py · admin.py
|
||||
frontend/ public.py · intern.py + templates/ static/
|
||||
migrations/ Alembic
|
||||
tests/ pytest gegen echte PostgreSQL-Testdatenbank
|
||||
docker/ Dockerfile · nginx.conf · entrypoint.sh
|
||||
debian/ .deb-Paketierung (venv unter /opt/oamc-turnier)
|
||||
deploy/ systemd-Unit · nginx-vHost · Backup-Skript (bare metal)
|
||||
packaging/apt-repo/ reprepro-Konfiguration + Build-Skript
|
||||
```
|
||||
|
||||
## Entwicklung
|
||||
|
||||
```sh
|
||||
python3 -m venv .venv && . .venv/bin/activate
|
||||
pip install -e ".[dev]"
|
||||
cp .env.example .env # DATABASE_URL anpassen
|
||||
|
||||
createdb oamc_dev # PostgreSQL-Rolle mit CREATEDB nötig
|
||||
alembic upgrade head
|
||||
oamc-turnier seed # Stammdaten Saison 2026
|
||||
oamc-turnier benutzer-anlegen admin --rolle admin
|
||||
oamc-turnier serve --reload # http://127.0.0.1:8000 · /docs
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
Brauchen eine erreichbare PostgreSQL-Testdatenbank (`OAMC_DATABASE_URL`, Default
|
||||
`…/oamc_test`). Das Schema wird pro Lauf frisch migriert, jeder Test läuft in einer
|
||||
zurückgerollten Transaktion.
|
||||
|
||||
```sh
|
||||
createdb oamc_test
|
||||
pytest
|
||||
```
|
||||
|
||||
Der **Abnahmetest der Wertungs-Engine** (`tests/test_wertung_regression_2026_05_31.py`)
|
||||
rechnet die im Plan §3.3 zitierten Zeilen der realen Ergebnisliste vom 31.05.2026 nach.
|
||||
|
||||
## Auslieferung 1 — Docker / „docker repo"
|
||||
|
||||
```sh
|
||||
cp .env.example .env # OAMC_SECRET_KEY setzen!
|
||||
docker compose up -d # db + app + nginx → http://localhost:8080
|
||||
docker compose exec app oamc-turnier seed
|
||||
|
||||
# Image für eine Registry bauen/pushen:
|
||||
docker build -t <registry>/oamc-turnier:0.1.0 -f docker/Dockerfile .
|
||||
docker push <registry>/oamc-turnier:0.1.0
|
||||
```
|
||||
|
||||
Multi-Arch für den Raspberry Pi 4:
|
||||
|
||||
```sh
|
||||
docker buildx build --platform linux/arm64,linux/amd64 \
|
||||
-t <registry>/oamc-turnier:0.1.0 -f docker/Dockerfile --push .
|
||||
```
|
||||
|
||||
Migrationen laufen automatisch beim Containerstart (`docker/entrypoint.sh`).
|
||||
|
||||
## Auslieferung 2 — Debian-Paket / eigenes APT-Repo
|
||||
|
||||
```sh
|
||||
sudo apt install build-essential debhelper devscripts python3-venv
|
||||
./packaging/apt-repo/build-deb.sh # → ../oamc-turnier_0.1.0_*.deb
|
||||
sudo apt install ../oamc-turnier_0.1.0_*.deb
|
||||
```
|
||||
|
||||
Das Paket bringt ein eigenes virtualenv unter `/opt/oamc-turnier/venv`, eine
|
||||
systemd-Unit und Beispielkonfiguration mit. Danach:
|
||||
|
||||
```sh
|
||||
sudoedit /etc/oamc-turnier/oamc-turnier.env # DATABASE_URL, SECRET_KEY
|
||||
sudo systemctl enable --now oamc-turnier
|
||||
sudo -u oamc /opt/oamc-turnier/venv/bin/oamc-turnier seed
|
||||
```
|
||||
|
||||
Eigenes signiertes APT-Repo aufsetzen: [`packaging/apt-repo/README.md`](packaging/apt-repo/README.md).
|
||||
|
||||
## API-Überblick (`/docs` für die vollständige OpenAPI-Doku)
|
||||
|
||||
| Bereich | Auth | Beispiele |
|
||||
|---|---|---|
|
||||
| **Read** | – | `GET /api/v1/turniere/{id}/ergebnisse`, `/api/v1/fahrer?q=`, `/api/v1/meisterschaften/{id}/stand` |
|
||||
| **Ingest** | `X-API-Key` | `POST /api/v1/turniere/{id}/ergebnisse` (idempotent, `?dry_run=true`), `POST …/import/xlsx` |
|
||||
| **Geräte** | `Authorization: Bearer <geräte-token>` | `POST /api/v1/zeitmessungen` (Batch, idempotent), SSE `GET /api/v1/turniere/aktiv/anzeige` |
|
||||
| **Admin** | interne Session | `POST /api/v1/admin/geraete`, `…/zeitmessungen/{id}/zuordnen`, `…/meisterschaften/{id}/berechnen`, `…/fahrer/merge` |
|
||||
|
||||
## Bekannte offene Punkte (aus `plan.md` §10)
|
||||
|
||||
Diese sind **im Code klar markiert** und blockieren einen offiziellen Produktivgang:
|
||||
|
||||
* **O-1** — echte Meisterschafts-Punktetabelle fehlt. Es läuft eine
|
||||
`PLATZHALTER_PUNKTETABELLE`; jeder berechnete Stand trägt einen Warnhinweis.
|
||||
* **O-2** — Zuordnung `S 1`–`S 9` / `A 1`–`A 4` → Fahrzeugtyp: Klassen sind
|
||||
angelegt, `fahrzeugtyp` bleibt `NULL`.
|
||||
* **Wertungsregeln §3.3** sind aus PDFs *abgeleitet* — vor Produktivgang gegen die
|
||||
ADAC-Turnierordnung 2026 zu verifizieren. Die Engine ist regelbasiert
|
||||
konfigurierbar (`oamc.wertung.engine.REGELN`), nicht fest verdrahtet.
|
||||
* **O-13/O-14/O-16** — Details der Zeitmessung (was wird gemessen, Zuordnung zum
|
||||
Fahrer, Genauigkeit): siehe `docs/zeitmessung-endpoint.md`.
|
||||
* **§11 Datenschutz** — Fahrerprofile sind `noindex` + `robots.txt`-gesperrt,
|
||||
Geburts*jahr* statt -datum, Opt-out-Anonymisierung (`fahrer.anzeige_anonymisiert`)
|
||||
ist umgesetzt; die Vorstandsentscheidung zur öffentlichen Darstellung von
|
||||
Jugenddaten steht noch aus.
|
||||
Reference in New Issue
Block a user