NFC Tag Manager
Mobil-first TypeScript-webapp til læsning og skrivning af OpenPrintTag NFC-tags på filamentspolar. CBOR-kodet tag-data, live byte-budget-indikator og graceful fallback til ikke-understøttede browsere. Kræver ingen installation.
Selvinitieret, selvhostet projekt. Bygget og drevet af mig som arkitekt, produktejer og reviewer, med AI som superviseret "lærling" i udviklingsprocessen.
DEL 1: Resume
NFC Tag Manager er en mobil-først webapp til at læse og skrive OpenPrintTag NFC-tags på 3D-printer filamentspoler — et browser-værktøj, ikke en native app, så der er intet at installere. Den læser og skriver NTAG213/NTAG215-tags direkte fra Chrome på Android via Web NFC API'et, afkoder spolens materiale, farve, mærke, temperaturer, vægt og resterende filament i procent, og viser en live byte-budget-indikator mens man udfylder et nyt tag, så man er garanteret at recorden kan være der, før en skrivning overhovedet forsøges.
Teknologistak
- Frontend: React 18 + TypeScript, Vite 5, Tailwind CSS 3 (class-baseret dark mode)
- NFC: Web NFC API (
NDEFReader) via tynde, typede wrapper-funktioner - Serialisering: CBOR via
cbor-x, kodet som et positionelt array frem for et map - Ingen backend — appen er fuldt klient-side; HTTPS er påkrævet i produktion, fordi Web NFC ellers nægter at køre
Største resultat
At vælge wire-formatet før en eneste linje UI-kode blev skrevet. OpenPrintTag-data kodes som et CBOR-array med faste feltpositioner i stedet for et map med streng-nøgler — én byte array-header frem for ti gentagne feltnavne — hvilket holder en typisk payload på 30–60 bytes mod en NTAG213's ca. 111-byte budget. Den beslutning er det der gør den live byte-budget-indikator i skriveformularen meningsfuld frem for kosmetisk: encodedSize() kører den rigtige encoder mod den igangværende formular ved hvert tastetryk, så en bruger opdager at tagget er fyldt mens de stadig taster — ikke efter en fejlet skrivning mod et fysisk tag.
DEL 2 — Dybdegående baggrund
Problemet
OpenPrintTag giver filamentspoler en standard NFC-record, men at læse eller skrive én fra en telefon betyder normalt enten at stole på en generisk NFC-app med et uigennemskueligt hex-dump, eller slet ikke at have et værktøj. En enkeltformåls-opgave som "mærk denne spole" eller "tjek hvad der står på dette tag" retfærdiggør ikke en native app — det kræver noget der åbner øjeblikkeligt fra et link, virker offline når det først er loadet, og fortæller brugeren tydeligt når telefonen eller browseren simpelthen ikke kan NFC, i stedet for at fejle i stilhed.
Arkitektur og løsning
Overordnet form. Én statisk React-app uden nogen server-komponent:
| Modul | Rolle |
|---|---|
lib/nfc.ts | Tynd wrapper over Web NFC API — isNfcSupported, startScan, writeTag |
lib/openprinttag.ts | CBOR encode/decode, pakning/udpakning af NDEF-records, encodedSize() |
types/openprinttag.ts | MaterialType-enum, OpenPrintTagData-interface, tag-kapacitetskonstanter |
components/TagReader.tsx | Scan-flow og visning af afkodet data, med en raw-record-fallback-visning |
components/TagWriter.tsx | Skriveformular, live byte-budget-indikator, tag-størrelse-vælger |
components/NfcStatus.tsx | Advarselsbanner ved ikke-understøttet browser |
Designbeslutninger værd at fremhæve
- Array frem for map til payload. Ti positionelle felter i stedet for ti navngivne nøgler bytter en smule skema-rigiditet (feltrækkefølgen er nu del af formatet) for en payload der nemt passer på det mindst understøttede tag.
- Feature-detect én gang, gate alt på det.
isNfcSupported()er den ene sandhedskilde for om resten af appens NFC-funktioner overhovedet renderes; banneret for ikke-understøttet platform er en førsteklasses UI-tilstand, ikke en fejl-toast. - Scan-oprydningsfunktionen er en dokumenteret workaround, ikke en forglemmelse. Web NFC API'et har ingen måde at annullere et igangværende scan på;
startScan()returnerer i stedet en funktion der fjerner event-listenerne, med begrænsningen skrevet i en kommentar frem for overladt til den næste læser at genopdage. - Decode-fejl kaster med en specifik besked.
decodeTag()tjekker array-formen før den stoler på noget felt, så et tag skrevet af noget andet end denne app fejler med "Invalid OpenPrintTag payload" i stedet for stille at returnere ragelse.
AI som lærling
AI inde i produktet. Ingen. NFC-læsning, -skrivning og -afkodning er deterministiske operationer mod et fast binært format — der er ingen vurdering her for en model at træffe.
AI i udviklingsprocessen (human-in-the-loop). Briefet, kravene og processen blev specificeret på forhånd i SPEC.md — inklusive den eksplicitte instruks om at udkaste en plan i PLAN.md til godkendelse før nogen implementering begyndte, og at holde en STATUS.md opdateret så en senere session kunne genoptage uden at genudlede kontekst. En AI-kodeassistent implementerede mod den plan; jeg reviewede resultatet.
Lederens refleksion
- En formatbeslutning taget før koden er ofte det reelle designarbejde. At vælge et CBOR-array frem for et map afgjorde projektets vigtigste tekniske begrænsning (byte-budgettet) før en eneste komponent eksisterede.
- Feature-detection er en UI-beslutning, ikke bare en guard clause. At behandle "denne platform kan ikke NFC" som en reel, designet tilstand — ikke en eftertanke-fejl — er det der gør et enkeltformålsværktøj brugbart uden for sin ene understøttede platform.
- Kræv en plan før kode, selv på et lille projekt. At
SPEC.mdbeder omPLAN.mdførst er en letvægtsudgave af samme review-port der betyder mere jo større et projekt bliver; vanen er billig at starte tidligt. - En live begrænsnings-indikator lærer formatet til brugeren. Byte-budget-baren forhindrer ikke bare en fejl — den gør tagets 111-byte-virkelighed synlig mens nogen stadig er ved at beslutte hvad der skal udfyldes.
Ærlige begrænsninger. Dette var en enkelt-session-bygning (én commit, 26. marts 2026) og er, ifølge projektets egen STATUS.md, endnu ikke testet mod et fysisk NFC-tag — næste punkt på listen er præcis dét. Der findes ingen automatiseret testsuite. Byte-budget-beregningen estimerer NDEF-header-overhead frem for at måle det eksakt. Og det loft der betyder mest, er slet ikke en kodebegrænsning: Web NFC findes kun i Chrome for Android 89+, så enhver anden platform er — og forbliver — uunderstøttet på browser-niveau.