# Scan- und Check-in-System: Prinzip aus SIMproducts, Vorlage für mitfit

Stand: 01.10.2026. Quelle: Repo `system-sim-products` (Backend `stationController.js`, Check-in-App `checkin/`).

## Worum es geht

In SIMproducts (simsales.de) bekommt jeder Käufer nach der Zahlung einen PDF-Gutschein per Mail. Darauf stehen ein individueller QR-Code und darunter derselbe Code als Zeichenfolge. Am Eingang scannt das Personal den QR-Code mit einem vorher registrierten Gerät, und der Gutschein wird im System entwertet.

Dieses Prinzip soll in mitfit nachgebaut werden, für Fitness- und Golfkurse: Die Teilnahme wird online gekauft, der Käufer bekommt seinen Voucher, vor Ort wird er eingescannt.

**Der Unterschied in mitfit:** Der Käufer ist dort bereits als Lead vorhanden. Der Scan soll deshalb nicht nur den Voucher entwerten, sondern am Lead vermerken, dass er teilgenommen hat, also vor Ort war.

## Die drei Bausteine

1. **Voucher mit Code:** entsteht beim Kauf, gehört zu genau einem Anbieter (Studio oder Golfanlage).
2. **Registrierte Scan-Geräte ("Stationen"):** nur freigeschaltete Geräte dürfen Codes nachschlagen und entwerten.
3. **Check-in-App:** eine Web-App im Browser des Geräts, mit Kamera-Scan und Handeingabe.

## 1. Voucher und Code

- Beim erfolgreichen Kauf wird je gekaufter Einheit ein Voucher mit zufälligem Code angelegt. Format `XXXX-XXXX` (8 Hex-Zeichen, Großbuchstaben), je Voucher eindeutig.
- Der QR-Code enthält keinen Datensatz, sondern nur einen Link mit dem Code: `https://<checkin-app>/scan?code=XXXX-XXXX`. Die Scan-Ansicht liest daraus den Parameter `code` und kommt auch mit einem nackten Code zurecht.
- Der Code steht zusätzlich lesbar unter dem QR-Code, als Rückfallweg für die Handeingabe (zerknitterter Ausdruck, schlechtes Licht).
- Der Code allein gibt nichts preis und berechtigt zu nichts. Wer ihn mit einem fremden Handy scannt, landet in der App ohne Geräte-Freigabe und kommt nicht weiter.
- Status am Voucher: `active`, `redeemed`, `cancelled`. Dazu optional ein Ablaufdatum und eine Anzahl erlaubter Einlösungen (1 = normal, 10 = Zehnerkarte). Beides wird beim Kauf als Schnappschuss auf den Voucher kopiert, spätere Produktänderungen wirken nicht rückwirkend.

## 2. Geräte registrieren

Ziel: Ein Tablet oder Handy am Empfang wird einmalig freigeschaltet, ohne dass dort jemand Benutzername und Passwort eintippt.

Ablauf:

1. Der Admin des Anbieters klickt im Dashboard auf "Neues Gerät" und vergibt einen Namen, zum Beispiel "Tablet Tresen".
2. Das Backend erzeugt einen **Registrierungs-Token**: zufällig, nur einmal verwendbar, 15 Minuten gültig, an Anbieter und Gerätenamen gebunden. Das Dashboard zeigt ihn als QR-Code mit dem Link `https://<checkin-app>/setup?token=...`.
3. Das neue Gerät scannt diesen QR-Code mit der normalen Kamera, die Check-in-App öffnet sich und schickt den Token ans Backend (`POST /station/register`, ohne Anmeldung).
4. Das Backend prüft den Token (vorhanden, unbenutzt, nicht abgelaufen), legt die Station an, markiert den Token als verbraucht und gibt einen langlebigen, zufälligen **Geräte-Token** zurück, dazu Name, Logo und Farbe des Anbieters für die Oberfläche.
5. Die App speichert den Geräte-Token lokal im Browser (LocalStorage). Ab jetzt schickt sie ihn bei jeder Anfrage im Header `X-Station-Token` mit.
6. Direkt danach legt das Personal eine vierstellige PIN fest. Sie wird nur als Hash lokal gespeichert und ist eine reine Bildschirmsperre, damit nicht jeder am Tresen die App bedienen kann. Die eigentliche Sicherheit ist der Geräte-Token.

Verwaltung:

- Der Admin sieht alle Geräte mit Name, Registrierungsdatum und "zuletzt gesehen" (wird bei jeder Anfrage aktualisiert).
- Geräte lassen sich deaktivieren, etwa bei Verlust. Der Token ist dann sofort ungültig, die Station bleibt für die Historie erhalten.
- Praxis-Hinweis: Die App sollte auf dem Gerät als App auf dem Startbildschirm installiert werden, sonst räumt vor allem iOS den Browser-Speicher irgendwann auf und das Gerät "vergisst" seine Registrierung. Die App zeigt einen Hinweis, solange sie nicht installiert läuft.

## 3. Scannen und entwerten

1. Personal öffnet die App, gibt die PIN ein und landet in der Scan-Ansicht: Kamera-Scan oder Code von Hand.
2. Die App schlägt den Code nach (`GET /station/voucher/:code`). Das Backend ermittelt aus dem Geräte-Token die Station und deren Anbieter und sucht **nur unter den Vouchern dieses Anbieters**. Fremde Codes ergeben "nicht gefunden".
3. Angezeigt wird, was das Personal braucht: Status, Produkt beziehungsweise Kurs, Name des Käufers, Angaben aus dem Kauf, Gültigkeit, bisherige Einlösungen. Keine Preise oder Umsätze.
4. Entwertet wird erst nach einem bewussten Tipp auf "Einlösen" plus Bestätigung, nie automatisch beim Scan.
5. Das Backend bucht die Einlösung atomar (ein einziges UPDATE mit den Bedingungen "aktiv, Limit nicht erreicht, nicht abgelaufen"), damit zwei gleichzeitige Scans nicht doppelt buchen. Der zweite bekommt "bereits eingelöst".
6. Jede Einlösung landet zusätzlich in einer Historie mit Zeitpunkt und Station. Daraus kann ein Fehlscan einzeln rückgängig gemacht werden. Der Eintrag wird dabei nicht gelöscht, sondern als storniert markiert.
7. Optional je Produkt: eine kurze Info-Mail an den Käufer nach der Einlösung. Ein Fehler beim Mailversand darf die Einlösung nie blockieren.

## Datenmodell in Kurzform

| Tabelle | Zweck | Wichtigste Felder |
|---|---|---|
| `vouchers` | ein Datensatz je Eintrittskarte | Anbieter, Bezug zur Bestellposition, Code, Status, erlaubte und verbrauchte Einlösungen, Ablaufdatum |
| `station_registration_tokens` | Einmal-Token fürs Anmelden eines Geräts | Anbieter, Token, Gerätename, Ablauf, benutzt ja/nein |
| `redemption_stations` | registrierte Geräte | Anbieter, Name, Geräte-Token, aktiv, zuletzt gesehen |
| `voucher_redemptions` | Historie der Einlösungen | Voucher, Station, Zeitpunkt, Notiz, storniert am / von |

## Schnittstellen in Kurzform

Für den Admin (mit normaler Anmeldung):

- Geräte auflisten
- Registrierungs-Token für ein neues Gerät erzeugen
- Gerät deaktivieren

Für die Check-in-App:

- Gerät registrieren (offen, nur mit gültigem Registrierungs-Token)
- Voucher per Code nachschlagen (mit Geräte-Token)
- Voucher einlösen (mit Geräte-Token)
- Einzelne Einlösung rückgängig machen (mit Geräte-Token)
- Name, Logo und Farbe des Anbieters holen (mit Geräte-Token)

## Was in mitfit anders ist

- **Lead statt nur Voucher:** Der Voucher hängt an Kauf und Lead. Beim Einlösen wird am Lead vermerkt, dass er teilgenommen hat: welcher Kurs oder Termin, wann, an welchem Gerät. Das ist das eigentliche Ziel des Scans.
- **Rückgängig gilt auch für den Lead:** Wird ein Fehlscan zurückgenommen, muss der Teilnahme-Vermerk am Lead mit verschwinden. Am saubersten ist es, wenn der Vermerk aus der Einlöse-Historie abgeleitet wird, statt als eigenes Häkchen zu existieren.
- **Anbieter-Trennung:** Was in SIMproducts der Händler ist, ist in mitfit das Studio oder die Golfanlage. Geräte und Voucher sind immer daran gebunden, das Nachschlagen ist immer darauf eingeschränkt.
- **Anzeige beim Scan:** Name des Teilnehmers, Kurs und Termin reichen. Keine weiteren Lead-Daten auf dem Tresen-Gerät.

## Offene Punkte, in mitfit zu klären

- Wo entsteht der Voucher im Kaufablauf, und wie kommt das PDF mit QR-Code zum Käufer?
- Kurse mit mehreren Terminen: ein Voucher mit mehreren Einlösungen (wie die Mehrfachkarte) oder ein Vermerk je Termin?
- Wie und wo wird die Teilnahme am Lead sichtbar (Status, Merkmal, Verlauf), und soll sie Folgeaktionen auslösen, etwa eine Nachfass-Strecke?
- Wo sitzt die Geräteverwaltung in der mitfit-Oberfläche?
