- Java 36.8%
- TypeScript 30.9%
- C++ 11.1%
- Python 8.9%
- SCSS 6.4%
- Other 5.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .cursor/skills/deploy-personalization-pi | ||
| backend | ||
| config | ||
| deploy | ||
| docs | ||
| esp-code | ||
| frontend | ||
| personalisierungsterminal | ||
| preview | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| README.md | ||
NFC Scan Rallye LinuxTag Villach 2026
Lokale NFC-Scan-Rallye von node-K: Hackspace Klagenfurt für den LinuxTag Villach 2026. Besucher tragen NFC-Anhänger, scannen an 10–15 Ständen (ESP32 + HW-147C Si512), die Stationen mesh’en per painlessMesh, ein Gateway-ESP am Personalisierungsterminal reicht Events per Serial an den Pi, der per REST an ein Spring-Boot-Backend mit PostgreSQL spricht. Live-Visualisierung (Three.js) auf dem 34"-Widescreen, Personalisierung am 15"-Touch.
Das System ist lokal-first: kein Internet nötig. Node→Stand-Zuordnung liegt im Backend, nicht in der Firmware.
Schnellstart (dieser Rechner)
cd deploy/backend
docker compose up --build
Unter Windows legt Docker Desktop network_mode: host nicht auf die Ports dieses PCs. Dort die zweite Datei mitgeben:
cd deploy/backend
docker compose -f docker-compose.yml -f docker-compose.windows.yml up -d --build
Danach im Browser http://localhost:43145/. Postgres 5432, Backend 43145.
Danach:
| Oberfläche | URL |
|---|---|
| Live-Visualisierung | http://127.0.0.1:43145/ |
| Stände (Name & Ort) | http://127.0.0.1:43145/admin/stations |
| Scanner-Geräte (Node → Stand) | http://127.0.0.1:43145/admin/nodes |
| Admin / Leitstand | http://127.0.0.1:43145/admin/ |
| Demo (Neustart) | http://127.0.0.1:43145/admin/#demo |
| Personalisierungs-Kiosk | http://127.0.0.1:43145/kiosk/ |
| API-Health | http://127.0.0.1:43145/actuator/health |
Standard-Tokens (nur LAN, vor dem Event ändern):
- Admin:
linuxtag-admin(HeaderX-Admin-Tokenoder Feld im Admin-UI) - Terminal:
linuxtag-terminal(HeaderX-Terminal-Token)
Scans kommen von den Stationen und vom Personalisierungsterminal. In der Visualisierung: Taste D (Demo-Overlay), R (Demo neu starten, nur bei RALLYE_DEMO_MODE=true). Leitstand: Button Demo neu starten. Ohne Flag werden keine Produktivdaten gelöscht.
Zusammenfassung per Mail
Am Eventende im Leitstand http://127.0.0.1:43145/admin/mail. Empfänger sind personalisierte Tags mit E-Mail und Zustimmung zur Zusammenfassung, eine Mail pro Anhänger: Anzahl Stände, Verlauf, längster Aufenthalt (Zeit bis zum nächsten gezählten Stand), Link auf node-k.at. Schon versendete Adressen bleiben aus, außer „erneut senden“.
Vorlage backend/src/main/resources/mail/summary.html im Browser öffnen und bearbeiten. Die Beispieltexte (Alex, Lötecke) ersetzt der Versand. Eine Datei mail/summary.html im Overlay gewinnt ohne Neubau.
SMTP steht in .env.example. Nach .env im Repo-Root kopieren. Der Prozess liest sie beim Start, Compose lädt sie in den Container. MAIL_ENABLED=true erst mit Host und Absender.
Hardware / Verdrahtung
Reader überall: HW-147C Si512 (kein PN532) per I2C am ESP32. Am Kiosk: ein ESP env:gateway (Mesh-Root); der Pi spricht REST und lädt /kiosk/ live.
| Gerät | PlatformIO-Env | Anbindung | Doku |
|---|---|---|---|
| Stand-Scanner (viele) | station |
I2C + Mesh | esp-code/WIRING.md |
| Personalisierungsterminal (= Gateway, genau eins) | gateway |
I2C + Mesh-Root; Pi REST/nfc-bridge |
personalisierungsterminal/WIRING.md · personalisierungsterminal/FULLPAGEOS.md · esp-code/platformio.ini |
Produktion braucht nur station + gateway. Env terminal ist optionaler Reader-Bring-up ohne Mesh. Flash Gateway: pio run -e gateway (node_id fest node-terminal). Details: personalisierungsterminal/WIRING.md. Überblick: docs/01-wiring.md.
Wo die Zuordnung liegt (verbindlich)
Es gibt zwei Mappings, beide nur im Backend (Postgres), nicht in der Firmware:
| Was | Tabelle | Oberfläche |
|---|---|---|
Station-ID → Name, Website, Farbe, Beschreibung, mapX/Y/Z |
station |
http://127.0.0.1:43145/admin/stations |
ESP node_id (Station: Chip-MAC, Gateway: node-terminal) → Stand |
node_status.station_id |
http://127.0.0.1:43145/admin/nodes |
Seed-Daten stehen in Flyway V2__seed.sql und config/stations.json. Nach dem Start gewinnt die Datenbank. Die 3D-Viz liest Namen und Positionen aus GET /api/v1/config/stations und /api/v1/state/snapshot.
Mapping-Workflow
Stände (Name & Ort) – zuerst, oft schon vor dem Event:
- http://127.0.0.1:43145/admin/stations öffnen (Token
linuxtag-admin). - Stand anlegen: ID (z.B.
stand-loetecke), Anzeigename, Website-URL (Newsletter-CTA), Farbe, Beschreibung. - Lage setzen: Zahlen
mapX / mapY / mapZoder Marker auf dem 2D-Lageplan klicken/ziehen. Speichern schreibt instation. - Unnötige Stände deaktivieren (bleiben in der DB) oder löschen.
Scanner-Geräte (Node → Stand) – am Eventmorgen, wenn die Terminals stehen:
- Firmware überall gleich flashen. Stationen melden sich mit ihrer Chip-MAC, das Gateway als
node-terminal.station_idin der Firmware ist optional und nur ein Hinweis. - http://127.0.0.1:43145/admin/nodes öffnen.
- Node wählen, Stand wählen, Zuordnung speichern.
identifylässt die LED blinken, damit du das Gerät in der Halle findest. - Ab jetzt zählen Scans dieses Nodes für diesen Stand (Cooldown/Duplicate entscheidet das Backend).
set_station per Mesh bleibt als Override in der Firmware, die Backend-Tabelle gewinnt bei der Zählung.
Der Leitstand http://127.0.0.1:43145/admin/ verlinkt nur noch diese zwei Oberflächen (keine alten „(alt)“-Registerkarten). Der Hallengrundriss kommt aus config/map.json (extrudierte Polygone). Optional STL: Admin → Halle / 3D-Modell oder Datei config/venue.stl. Details: docs/06-visualization.md.
Ohne Docker (Dev)
PostgreSQL 16 lokal, dann:
cd frontend && npm install && npm run build
cd ../backend && ./mvnw -DskipTests package
SERVER_PORT=43145 java -jar target/rallye-1.0.0.jar
SPA lokal ohne Docker: cd frontend && npm start (Proxy → :43145). / = Live-Szene, /admin = Leitstand, /kiosk = Personalisierung.
Tests (Testcontainers PostgreSQL, Docker nötig):
cd backend && ./mvnw test
Monorepo
esp-code/ PlatformIO ESP32 (station + gateway); Verdrahtung: esp-code/WIRING.md
backend/ Spring Boot 4.1 / Java 25 / Maven / Flyway / Postgres
frontend/ Angular 22: Live-Szene `/`, Leitstand `/admin`, Kiosk `/kiosk`
personalisierungsterminal/ nfc-bridge (REST-Ingest + Serial + Setup :8083)
config/ stations.json, map.json, game.json (optional venue.stl)
deploy/backend/ docker-compose, Dockerfile, rallye-stack.service
deploy/frontend/ Kiosk-Skript der 34"-Visualisierung
deploy/personalisierungsterminal/ systemd, udev, polkit, Kiosk-Skript
docs/ Verdrahtung, Protokoll, API, Setup, Scanner-Howto, Visualisierung
Lücken gegenüber der PDF-Spezifikation
- OTA-over-Mesh-Empfang ist in
station/gatewayaktiv (Firmware 1.1.0+); Push noch nicht verdrahtet, vor Event nur nach Feldtest. - WS2812/OLED-Feedback ist dokumentiert, Referenzfirmware nutzt die Onboard-LED.
- painlessMesh-Feldtest und 8-h-Dauerlauf müssen vor Ort nachgeholt werden.
- Der öffentliche Mirror linuxtag26.node-k.at ist bewusst out of scope; Export
aggregate.jsonist anonym-aggregiert vorbereitet. - Pi-REST-Ingest + Kiosk Serial/MESH-Pfad End-to-End mit Hardware vor Ort verifizieren.
Ausführliche Hardware- und Protokolldokumente: docs/ (Index: docs/01-wiring.md). Stationen: esp-code/WIRING.md. Personalisierungs-Terminal: personalisierungsterminal/WIRING.md / personalisierungsterminal/README.md.