Getting a player back in¶
A player cannot sign in. Before anything else, one rule: nobody sets a PIN for
somebody else, and admins are no exception
(ADR-0007,
ADR-0008). A PIN that somebody else
knows is not a PIN. /admin has no button for it, and SQL is not the way round
it. The player always sets their PIN themselves. What we can do is help them
get back to the point where they can set it.
This page is the how. It was written on 2026-09-21, when the office needed it for the first time and had to switch the kiosk on first. The record of that is at the end.
Which case is it?¶
| The player still has | The way back |
|---|---|
| a device that is still signed in | profile page → PIN → set a new one. Done. |
| their recovery code | sign in with the code in the PIN oder Wiederherstellungscode field, then set a new PIN on the profile page |
| neither | the kiosk issues a new recovery code, below |
The third case is the only one that needs an operator. The proof of identity is the room: the player stands next to the kiosk, and the people there know them (ADR-0006). That is why this does not work remotely, and why nothing in this page tries to make it work remotely.
Is the kiosk on?¶
Look at /admin → Diese Instanz → Kiosk am Tisch. It says an or
aus. The page reads the value when the application starts, and it shows
the start time underneath. A kiosk that was just switched on in a manifest
stays aus until the pod restarts. Versions up to v0.12.0 do not have this
section.
If you have no admin session, or the version is older, run curl -s -o /dev/null -w '%{http_code}'
https://<host>/kiosk: 200 means on, 404 means off.
Switching the kiosk on¶
The application needs SP_KIOSK_TOKEN. If it is unset, /kiosk is not even
registered. How the variable gets there depends on the environment:
| Environment | Setting |
|---|---|
| Docker Compose | SP_KIOSK_TOKEN in .env (task office:setup asks for it), then task office:up |
| kcl | -D config.kioskEnabled=true + property kiosk-token in the Vault entry |
| Terraform (Azure) | kiosk_token in terraform.tfvars |
| argocd catalog | kiosk.enabled: true in the schmetterpause values (argocd#514) |
On homerun2-dev2¶
homerun2-dev2 has been the office's cluster since 2026-09-28; homerun2-test1,
where the record below was taken, was torn down that day. On homerun2-dev2 the
kiosk is on (checked 2026-10-08: SP_KIOSK_TOKEN in the Secret, /kiosk
answers 200). There are four steps, and every one of them has to be in
place:
- The Vault entry
schmetterpause/homerun2-dev2-kiosk, propertytoken. Nobody writes it by hand: the ClusterStack creates it from theschmetterpauseAppSecretProfile (suffix-kiosk,clusters/labda/vsphere/machinery-fleet-state/appsecretprofiles.yamlinstuttgart-things), managed on the machinery cluster as theSecretV2homerun2-dev2-kiosk. If the entry is missing, that object is where to look; a hand-written entry would be overwritten or fought over. - Read access for the office. The ClusterSecretStore
vault-schmetterpauselogs in through the cluster's own Kubernetes auth mount (homerun2-dev2-eso, roleeso), and the ClusterStack derives the policy behind it. An entry the policy does not cover is refused with 403. - The switch: the annotations
tabletennis-platform.stuttgart-things.com/kiosk-enabled: 'true'andtabletennis-platform.stuttgart-things.com/kiosk-vault-path: homerun2-dev2-kioskinstuttgart-thingsclusters/labda/vsphere/machinery-xrs/homerun2-dev2.yaml. ThetabletennisApplicationSet instuttgart-things/argocdmaps them ontokiosk.enabledandkiosk.vaultPath; there is no default path, so both are needed. Argo appendsSP_KIOSK_TOKENto the ExternalSecretschmetterpause-app. Merging a change to that file is what changes the cluster — read themachinery-xrsREADME there first. - A restart. The Deployment does not restart by itself when the Secret
changes. Reloader runs on the cluster, but this Deployment carries no
Reloader annotation:
sh export KUBECONFIG=~/.kube/homerun2-dev2 kubectl -n schmetterpause rollout restart deploy/schmetterpause kubectl -n schmetterpause rollout status deploy/schmetterpauseThe office has one replica with theRecreatestrategy, so it is unreachable for a few seconds.
Check each step before you move on:
# 2 and 3: the ExternalSecret synced, and the Secret holds the key (names only)
kubectl -n schmetterpause get externalsecret schmetterpause-app
kubectl -n schmetterpause get secret schmetterpause-app -o json | jq -r '.data | keys[]'
# SP_KIOSK_TOKEN
# SP_SCOREBOARD_TOKEN
# SP_SESSION_KEY
# 4: the kiosk exists
curl -s -o /dev/null -w '%{http_code}\n' https://<host>/kiosk # 200
The trap in step 2. A kiosk key that cannot be read stops the whole
ExternalSecret, not just the kiosk: SecretSyncedError, 403 permission
denied. The running application keeps working, because ESO leaves the last
Secret in place. But while the sync fails, nothing else in that Secret can
change either, the session key included. To force a new sync after fixing
the policy:
kubectl -n schmetterpause annotate externalsecret schmetterpause-app \
force-sync=$(date +%s) --overwrite
At the table¶
You need the kiosk token once. Put it straight into the clipboard and do not print it into the terminal history:
kubectl -n schmetterpause get secret schmetterpause-app \
-o jsonpath='{.data.SP_KIOSK_TOKEN}' | base64 -d | xclip -sel clip
Without cluster access you can read it from Vault instead:
curl -sS -H "X-Vault-Token: $VAULT_TOKEN" https://vault.infra.sthings-vsphere.labul.sva.de/v1/schmetterpause/data/homerun2-dev2-kiosk | jq -r .data.data.token | xclip -sel clip.
- Unlock the machine. On the device at the table, open
https://<host>/kiosk?token=<token>. The token becomes a cookie and disappears from the address bar. The device stays a kiosk for twelve hours. - Name who is typing. The kiosk asks this before it offers anything else
(ADR-0014). An observer such as
timobollmay be the operator. - Issue the code. Go to Zugang wiederherstellen, choose the player, and press Neuen Code ausgeben. The code is shown once, on this screen only. From this moment the player's old code no longer works.
- The player signs in on their own phone: Anmelden, their name, and the code in the PIN oder Wiederherstellungscode field.
- The player sets their PIN on their profile page: at least six digits, chosen by them, and not seen by anybody else.
The log records step 3 as recovery code issued at the kiosk, with the
player's id and the operator's id.
Afterwards¶
- Take the device back: go to
/admin→ Freigeschaltete Kiosk-Geräte → Zurücknehmen. Otherwise it stays a kiosk until the twelve hours run out, and anybody who walks past it can enter results for everybody. - Leave the kiosk on or switch it off. Leaving it on is fine. The token is
the lock, and no device is a kiosk until somebody types the token. To switch
it off on homerun2-dev2, set the
kiosk-enabledannotation in the ClusterStack order to'false', restart the pod once Argo has synced, and check that Diese Instanz says aus. Leavekiosk-vault-pathand the Vault entry in place: they cost nothing, and switching back on is then one annotation.
Record: homerun2-test1, 2026-09-21¶
| Step | What happened |
|---|---|
| Case | A player had neither a PIN nor a recovery code, and no device signed in. The kiosk was off. |
| Vault entry | schmetterpause-kiosk created at 13:24Z |
| Switch | argocd#514 added kiosk.* to the catalog chart; stuttgart-things#3101 set enabled: true |
| 403 | The ExternalSecret failed with permission denied on schmetterpause/data/schmetterpause-kiosk. The app kept running on the old Secret. |
| Policy | The kiosk path was added to read-schmetterpause live through the API, then in the tfvars (stuttgart-things#3104). terraform plan showed no changes. |
| Restart | rollout restart; /kiosk answered 200 |
| At the table | Still to be done at the time of writing |