feat(tags): QR-Aufkleber, Geraeteseite, Etikettendruck und Scanner
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s

Der Einstieg, fuer den die Anwendung gebaut ist: scannen, sehen was zu tun ist,
loslegen. `/t/<tagCode>` kennt drei Faelle — registriertes Geraet, vorgedruckter
Tag, unbekannter Code —, die Geraeteseite zeigt Zuweisungen, Schnellstart und
Historie, und beides ist am Handy bedienbar.

Im QR steht ausschliesslich `{APP_URL}/t/{tagCode}`: kein Name, keine
Seriennummer, kein Besitzer. Ein Aufkleber haengt jahrelang sichtbar am Geraet
und wird von jedem Telefon gelesen; was darauf steht, ist veroeffentlicht. Die
Masse sind gemessen, nicht behauptet: ein echtes PDF liefert 62 x 29 mm und A4,
und ein bei 300 dpi gerastertes Etikett wird mit demselben Decoder
zurueckgelesen, den auch der Scanner benutzt.

Drei Defekte zeigte erst der gebaute Stand, alle an den Naehten zwischen den
parallel gebauten Teilen: „Starten“ setzte IN_ARBEIT und sprang nicht, „Vorlage
zuweisen“ bot Vorlagen an, die der Dienst danach ablehnte, und die Geraeteliste
verlinkte nichts. Der unabhaengige Review fand drei Blocker — darunter, dass der
Scanner nie die native BarcodeDetector-API benutzte und dass ein Unterpfad in
APP_URL aus dem gedruckten QR herausfiel.

Closes #14

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #28.
This commit is contained in:
2026-09-25 19:30:50 +00:00
co-authored by Claude Opus 5
parent c78a6ac1af
commit e7a2e2d5c7
58 changed files with 4828 additions and 54 deletions
+61 -2
View File
@@ -16,11 +16,12 @@ als Unterpunkte mit Aufgabe und Dauer.
| #011 | M6 – Mitarbeiter, Abteilungen, Geräte | 2 h 15 min |
| #012 | M7 – Platzhalter, Namensregeln, Escaping | 2 h 30 min |
| #013 | M8 – Läufe: Service und Abarbeitung | 3 h 05 min |
| | **Summe** | **16 h 50 min** |
| #014 | M9 – QR-Tags, Geräteseite, Etiketten, Scanner | 3 h 35 min |
| | **Summe** | **20 h 25 min** |
| Meilenstein | Tatsächlich | Status |
|---|---|---|
| v0.1.0 | 16 h 50 min | in Arbeit |
| v0.1.0 | 20 h 25 min | in Arbeit |
---
@@ -566,3 +567,61 @@ als Unterpunkte mit Aufgabe und Dauer.
- #014 QR-Tags, Geräteseite, Etiketten und Scanner — der Einstieg, für den die ganze Anwendung
gebaut ist: Code scannen, Geräteseite öffnen, loslegen.
---
## 2026-09-25 · Sitzung 10 · 18:50–21:30
**Issue:** #014 (M9)
**Version:** 0.1.0
### Erledigt
- **Zwei Sub-Agenten parallel**, auf getrennten Dateien: QR, Etiketten und Tag-Stapel der eine,
Geräteseite und `/t/<code>` der andere. Der Scanner kam von Hand dazu.
- `/t/<tagCode>` als Weiche, Registrierformular, Geräteseite mit Zuweisungen, Schnellstart,
„Vorlage zuweisen“ und Historie
- Etikettendruck in zwei Formaten, QR ausschließlich mit `{APP_URL}/t/{tagCode}`
- Scanner mit der BarcodeDetector-API des Browsers, WebAssembly als Rückfall, Eingabefeld als
Ersatzweg
- Unabhängiger Review: **drei Blocker**, elf Befunde, mehrere Anmerkungen — alle abgearbeitet
- **930 Tests** (vorher 879) und **54 Ende-zu-Ende-Tests** grün
### Entscheidungen
- **Parallel arbeiten heißt Dateien trennen, nicht Aufgaben.** Beide Agenten bekamen eine Liste
der Dateien, die ihnen gehören, und je eine eigene Testdatenbank. Es gab keinen einzigen
Schreibkonflikt — die Fehler saßen stattdessen an den **Nähten**, und zwar alle drei.
- **Das WebAssembly des QR-Lesers wird kopiert, nicht eingecheckt.** `zxing-wasm` lädt es sonst
aus einem CDN: die Content-Security-Policy erlaubt `connect-src 'self'`, und eine selbst
gehostete Anwendung soll ohne Internet laufen. 1,1 MB gehören nicht ins Repository, also legt
`scripts/wasm-bereitstellen.mjs` sie vor jedem Bau bereit.
- **`'wasm-unsafe-eval'` statt `unsafe-eval`.** Die schmale Erlaubnis, WebAssembly zu übersetzen —
ohne sie läuft die Kamera und erkennt nie etwas. Der Test prüft jetzt auf die **Marke**, nicht
auf das Wort: `wasm-unsafe-eval` enthält „unsafe-eval“ und ist doch etwas anderes.
- **Eine Route ohne Aufrufer wird entfernt, nicht dokumentiert.** `/api/qr/[tagCode]` war sauber
gebaut, hatte aber keinen Nutzer, keinen Test und eine abweichende Groß-/Kleinschreibung. Die
Geräteseite setzt das SVG jetzt direkt ein.
### Probleme
- **Drei Defekte, die nur der gebaute Stand zeigt.** „Starten“ setzte `IN_ARBEIT` und sprang
nicht (der Knopf verschwindet beim Neuaufbau, bevor sein Effekt läuft); „Vorlage zuweisen“ bot
Vorlagen an, die der Dienst danach ablehnte; die Geräteliste verlinkte nichts. Kein einziger
davon wäre durch Lesen aufgefallen.
- **Der Scanner benutzte nie die native API.** `barcode-detector/ponyfill` gibt **immer** die
eigene Klasse zurück — der Kommentar behauptete das Gegenteil, und die Auftragszeile „native
BarcodeDetector-API mit Polyfill-Fallback“ war damit unerfüllt. Ein Blick in `node_modules`
hätte genügt; ich habe der Paketbeschreibung geglaubt.
- **Ein Unterpfad in `APP_URL` fiel aus dem QR heraus.** `new URL("/t/…", "https://firma.de/app")`
verschluckt `/app`. Für eine Umleitung fällt das nie auf, weil der Reverse Proxy den Pfad wieder
anhängt — auf einem geklebten Aufkleber ist es das Ende. Der Test dazu hieß „nimmt APP_URL mit
Pfad ernst“ und prüfte nur einen Schrägstrich.
- **Sechster Meilenstein in Folge mit Zusagen ohne Deckung:** archivierte Geräte im Druck, „1 von
2 fehlt“ bei doppelten Codes, eine Vorbelegung, die nicht kam, ein Kommentarblock über der
falschen Funktion.
### Nächster Schritt
- #015 Dashboard und Archiv — die Übersicht für den Alltag und die Volltextsuche über alles, was
abgearbeitet wurde.