feat(tags): QR-Aufkleber, Geraeteseite, Etikettendruck und Scanner
Prüfung / pruefung (pull_request) Canceled after 0s
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (pull_request) 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 is contained in:
Florian Wilde
2026-09-25 21:30:12 +02:00
co-authored by Claude Opus 5
parent c78a6ac1af
commit 5f1b0d1435
58 changed files with 4828 additions and 54 deletions
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env node
/**
* Legt das WebAssembly des QR-Lesers neben die statischen Dateien (#014).
*
* Der Scanner benutzt `barcode-detector` als Polyfill der BarcodeDetector-API.
* Dessen Unterbau `zxing-wasm` laedt sein `.wasm` von sich aus **aus einem CDN**
* — das verbietet hier zweierlei: die Content-Security-Policy erlaubt
* `connect-src 'self'`, und eine selbst gehostete Anwendung soll ohne Internet
* laufen. Deshalb wird die Datei aus `node_modules` unter `public/zxing/`
* bereitgelegt und von dort geladen.
*
* Kopiert statt eingecheckt: 1,1 MB Binaerdatei gehoeren nicht ins Repository,
* und die Fassung muss zur installierten Paketversion passen. Laeuft vor jedem
* `pnpm build` und `pnpm dev`.
*/
import { copyFile, mkdir } from "node:fs/promises";
import { createRequire } from "node:module";
import { dirname, join } from "node:path";
const require = createRequire(import.meta.url);
let wasm;
try {
/*
* Aufgeloest **von barcode-detector aus**, nicht von hier: pnpm legt jedes
* Paket unter `.pnpm/<name>@<version>` ab und verlinkt nur die direkten
* Abhaengigkeiten nach `node_modules`. `zxing-wasm` ist keine davon — es
* haengt an `barcode-detector`, und nur von dort ist es auffindbar. Ein fest
* geschriebener Pfad ginge beim naechsten Versionssprung kaputt.
*/
const vonBarcodeDetector = createRequire(require.resolve("barcode-detector"));
// Die Datei steht selbst in der Exportkarte – kein Raten am Verzeichnis.
wasm = vonBarcodeDetector.resolve("zxing-wasm/reader/zxing_reader.wasm");
} catch (fehler) {
console.error(
"Das WebAssembly des QR-Lesers ist nicht auffindbar. Es kommt über barcode-detector — " +
"erst `pnpm install` laufen lassen.",
);
console.error(fehler instanceof Error ? fehler.message : fehler);
process.exit(1);
}
const ziel = join(process.cwd(), "public", "zxing", "zxing_reader.wasm");
await mkdir(dirname(ziel), { recursive: true });
await copyFile(wasm, ziel);
console.log(`QR-Leser bereitgelegt: ${ziel}`);