← Tilbage til The Vault
Open Sourcelive

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.

#typescript#react#nfc#cbor

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:

ModulRolle
lib/nfc.tsTynd wrapper over Web NFC API — isNfcSupported, startScan, writeTag
lib/openprinttag.tsCBOR encode/decode, pakning/udpakning af NDEF-records, encodedSize()
types/openprinttag.tsMaterialType-enum, OpenPrintTagData-interface, tag-kapacitetskonstanter
components/TagReader.tsxScan-flow og visning af afkodet data, med en raw-record-fallback-visning
components/TagWriter.tsxSkriveformular, live byte-budget-indikator, tag-størrelse-vælger
components/NfcStatus.tsxAdvarselsbanner 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

  1. 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.
  2. 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.
  3. Kræv en plan før kode, selv på et lille projekt. At SPEC.md beder om PLAN.md først er en letvægtsudgave af samme review-port der betyder mere jo større et projekt bliver; vanen er billig at starte tidligt.
  4. 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.