--- title: RFID výdej obědů order: 80 summary: Jak operátor zprovozní a spravuje RFID výdej - architektura autentizace, hardware, spárování terminálu, onboarding obsluhy, čipy strávníků, údržba a audit. --- # RFID výdej obědů RFID výdej slouží k rychlému a auditovatelnému potvrzení, že strávník skutečně dostal své jídlo. Strávník přiloží čip ke čtečce u výdejního okénka, systém okamžitě označí dnešní objednávku jako vydanou a zapíše událost do auditu. Tato stránka popisuje, jak **operátor** RFID výdej zprovozní a spravuje. Pro denní provoz _obsluhy_ (kuchařky) máme samostatnou stránku [Obsluha -- výdej obědů](/docs/kitchen-staff). ## Architektura: tři vrstvy autentizace Pochopení vrstev pomáhá řešit problémy a navrhovat tok zaměstnanců: | Vrstva | Co identifikuje | Token / heslo | Kde žije | | --- | --- | --- | --- | | User JWT | Operátora kuchyně (admin akce) | Email + heslo → JWT + refresh cookie | Memory (access) + httpOnly cookie (refresh) | | Device token | Konkrétní kuchyňské PC = terminál | `X-Device-Token` | localStorage prohlížeče (klíč `edumeal.scan-config.v1`) | | Staff session | Konkrétní směnu obsluhy | `X-Staff-Session` | localStorage prohlížeče (klíč `edumeal.staff-session.v1`), TTL 8 hodin | Pickup endpointy (`POST /pickups`, `POST /pickups/manual`, `POST /pickups/{id}/void`) ověřují **device token + staff session**, ne user JWT. Obsluha tedy _nemá_ uživatelské jméno + heslo -- místo toho má PIN nebo služební čip, kterými otevírá staff session přímo na terminálu. Operátor user JWT používá jen pro _nastavení_ (pairing zařízení, vystavení PINu, přiřazení čipu). ## Co RFID výdej řeší - **Kontrola, kdo si jídlo skutečně vyzvedl** -- objednávky bez výdeje lze dohledat v reportech. - **Zamezení dvojitému výdeji** -- partial unique index na úrovni DB blokuje druhý aktivní pickup pro stejnou objednávku, i přes manuální cestu. - **Audit pro spory** -- každý sken (úspěšný i odmítnutý) je zaznamenán s časem, místem a obsluhou, která jej provedla. - **Rychlý provoz u okénka** -- jeden tap čipem, žádné papíry ani podpisové archy. ## Hardware a předpoklady ### Čtečka Edumeal podporuje USB RFID čtečky pracující v režimu emulace klávesnice (HID keyboard wedge). Čtečka po přiložení čipu "napíše" UID čipu do aktivního pole jako sekvenci znaků zakončenou Enterem -- nepotřebuje žádný ovladač ani instalaci. Ověřené modely (HF 13,56 MHz + LF 125 kHz, USB HID keyboard wedge): | Model | Frekvence | Poznámka | | --- | --- | --- | | **ACS ACR1281U-C2** | 125 kHz + 13,56 MHz | Doporučená čtečka. Dual-frekvence, plug & play HID keyboard mód (žádný ovladač), podporuje MIFARE Classic 1K/4K, DESFire, NTAG, ISO 14443A/B i ISO 15693 -- pokryje ISIC i běžné kuchyňské čipy bez zvláštní konfigurace. | | **[R20DC](https://www.gme.cz/v/1516873/r20dc-usb-rfid-ctecka-125khz-a-1356mhz)** | 125 kHz + 13,56 MHz | Levná dual-frekvenční alternativa, plug & play HID keyboard mód (žádný ovladač), pípák a LED potvrzují sken. Čte MIFARE Classic 1K/4K (S50/S70) a čipy typu EM4100 na 125 kHz. **Výstup přepněte na hex** (dodávaná Windows utilita umí i desetinný formát, ten se s uloženými UID nesejde). Podporu ISIC karet výrobce neuvádí, ověřte si ji přiložením karty v **Testu čtečky** níže. | > **Tip:** Edumeal je _tolerantní k formátu UID_. Čtečka může vysílat UID jako čistý hex (`044E2EAA031C90`) nebo se separátory mezi byte páry (`04 4E 2E AA 03 1C 90`, `04:4E:2E:AA:03:1C:90`, `04-4E-2E-AA-03-1C-90`). Frontend i backend separátory stripují a UID ukládají kanonicky uppercase hex bez separátorů, takže scan i ručně zadaný UID se vždy match-ují. ### Čipy Strávník může použít: - **Vlastní RFID čip** nebo náramek vydaný kuchyní (typicky MIFARE Classic 1K, NTAG, nebo DESFire). - **ISIC kartu**, pokud ji strávník vlastní -- edumeal umí ISIC číst přes UID, není potřeba žádná dodatečná aplikace. (ISIC vydává ISIC ČR, ne kuchyně.) > **Pozor:** Edumeal čte pouze UID (sériové číslo) čipu, nikdy nepřistupuje k chráněným sektorům karty. ISIC ani jiné karty nejsou nijak modifikovány. ### Síť Kuchyňské PC potřebuje LAN/Wi-Fi připojení do internetu. Edumeal má vestavěný režim pro krátké výpadky sítě (5--15 minut) -- výdej pokračuje lokálně a po obnovení sítě se data automaticky doplní. Pro plně offline provoz bez připojení edumeal navržen není. ## Krok 1: Spárování terminálu Každé výdejní okénko má v systému svůj vlastní **terminál** vázaný na konkrétní výdejní místo. Tato vazba je trvalá -- terminál nelze sdílet mezi výdejními místy. Pokud máte v jedné kuchyni dvě okénka, vytvořte dva terminály na dvou PC. 1. Na kuchyňském PC zapojte USB čtečku. 1. Otevřete prohlížeč a přihlaste se jako **operátor** e-mailem + heslem. 1. Jděte na **Výdej** v sidebar → pokud PC ještě není spárované, edumeal vás přesměruje na **Spárovat terminál** (cesta `/operator/scan-setup`). 1. Vyberte **výdejní místo** z rozbalovacího seznamu a zadejte popisný **název terminálu** (např. "Hlavní okénko -- ZŠ Dlouhá"). 1. V sekci **Test čtečky** přiložte testovací čip ke čtečce. Pod inputy se hned objeví přečtené UID -- to znamená, že čtečka i klávesnicový layout fungují správně. 1. Klikněte na **Spárovat**. Systém vytvoří záznam terminálu v API a vrátí **device token**, který se okamžitě uloží do localStorage tohoto prohlížeče. 1. Po spárování se UI automaticky přesune na `/scan/start` -- to je obrazovka pro obsluhu, na které se kuchařka přihlásí. Operátor se může nyní odhlásit -- terminál pojede dál bez něj. > **Tip:** Device token se po spárování nikde nezobrazuje -- žije pouze v localStorage daného prohlížeče. Pokud PC nebo prohlížecí profil vyměníte, projděte setup znovu a v UI vytvořte nový terminál (starý zneplatněte z **RFID → Zařízení**). ### Klávesnicový layout Edumeal čte stisknuté klávesy přes fyzické scan kódy (`KeyboardEvent.code`), ne přes znaky, které OS vygeneruje. Díky tomu funguje výdej i na české klávesnici -- fyzická "0" je vždy `Digit0`, i když ji OS jinak mapuje na `é`. Žádná konfigurace klávesnice ani čtečky není potřeba pro hex UID. > **Pozor -- platí jen dokud nemáte zaostřené (klikem aktivované) textové pole.** Toto čtení scan kódů funguje, když stránka jen "poslouchá" čtečku na pozadí (test čtečky, přiřazení čipu při _nezaostřeném_ poli). Jakmile _kliknete přímo do input pole_ a snímáte/píšete do něj, znaky už jdou normální cestou přes OS layout -- a na české klávesnici se číselná řada změní na `+ěščřžýáíé` (přežijí jen písmena A--F). Pokud tedy v poli vidíte české znaky místo číslic, buď do pole **neklikejte** (nechte čtečku, ať ho vyplní sama), nebo si pro ruční zadání **přepněte klávesnici do angličtiny**. ## Krok 2: Onboarding obsluhy Každá kuchařka má v systému vlastní uživatelský účet s rolí **kitchen_staff**. Tato role je oddělená od role **operator** -- obsluha nevidí ceny, recepty ani uživatele, vstupuje pouze do výdejního UI a autentizuje se PINem nebo čipem. 1. V levé navigaci **RFID** → **Obsluha** (cesta `/operator/kitchen-staff`) → klikněte **+ Přidat uživatele obsluhy**. 1. Vyplňte jméno, příjmení, e-mail a heslo. Heslo je technický seed účtu -- obsluha se nepřihlašuje do aplikace e-mailem, ale heslo musí být platné kvůli interní konzistenci uživatelských záznamů. 1. Po uložení se otevře detail panel obsluhy. Zde nastavíte buď čip, nebo PIN, nebo oba (záleží, jak chcete, aby se obsluha přihlašovala). ### Přiřazení služebního čipu V detail panelu obsluhy je sekce **Čip obsluhy**: 1. Přiložte čip ke čtečce -- pole _UID nového čipu_ se vyplní automaticky tím, co reader emituje (uppercase hex). **Neklikejte do pole** -- musí zůstat nezaostřené, aby čtení fungovalo nezávisle na klávesnici. (Na přihlašovací obrazovce terminálu tohle omezení neplatí, čtečka tam čte i přes zaostřené pole; sem se to zatím nepřeneslo.) Alternativně lze UID napsat ručně v jakémkoli formátu (lowercase, s mezerami atd.) -- edumeal ho znormalizuje při uložení; pro ruční zadání na české klávesnici si přepněte layout do angličtiny (viz [Klávesnicový layout](#klávesnicový-layout)). 1. Klikněte **Přiřadit**. 1. V seznamu se objeví aktivní čip. Vedle něj je tlačítko **Odebrat** pro zneplatnění (ztráta, výměna). > **Pozor:** Služební čip musí být _fyzicky jiný_ než čip strávníka. Edumeal udržuje služební čipy v separátní tabulce `identity.staff_chips` oddělené od `identity.diner_chips` -- stejný fyzický čip nelze přiřadit zároveň jako služební a jako strávnický (chrání před záměnou v auditu). ### Vystavení PINu (fallback) 1. V detail panelu obsluhy sekce **PIN obsluhy**. 1. Zadejte 4--8 číslicový PIN. 1. Klikněte **Vydat PIN** (nebo **Rotovat PIN**, pokud už existuje aktivní). PIN se hashuje (bcrypt) a uloží -- raw hodnotu si zapamatujte teď, později ji systém znovu nezobrazí. 1. Předejte PIN obsluze osobně. > **PIN musí být v rámci provozu unikátní.** Pokud zadáte PIN, který už používá > jiný člen obsluhy, edumeal ho odmítne. Není to formalita: přihlášení na směnu > se dělá **jen podle PINu**, bez výběru jména, takže dva stejné PINy se nedají > rozlišit -- směna i všechny výdeje v ní by se připsaly tomu, koho databáze > vrátí první. Rotace PINu na stejnou hodnotu u téhož člověka je v pořádku. > **Ochrana proti hádání PINu:** po **5 neúspěšných pokusech** se další pokusy > na daném terminálu na **15 minut** odmítnou (obsluha vidí hlášku, že má > vyčkat). Totéž platí pro PIN vyžadovaný u storna, tam se > počítadlo vede per člen obsluhy. Zámek se počítá zvlášť pro každý terminál, > takže zablokované okénko neblokuje druhé. Služební čip zámek neomezuje -- > pokud si obsluha PIN nepamatuje, přihlásí se čipem a nemusí čekat. > **Tip:** PIN i čip mohou pro stejnou obsluhu koexistovat. Obsluha pak má fallback -- když zapomene čip doma, přihlásí se PINem. Na přihlašovací obrazovce jsou obě cesty vedle sebe, nepřepíná se mezi nimi. > **Ověření u storna.** Stornování už zapsaného výdeje mění historii, takže si vyžádá čerstvé ověření obsluhy -- **služebním čipem, nebo PINem**, jedno za celý výběr. **Manuální výdej ověření nevyžaduje**: PIN u něj dřív byl, ale u okénka znamenal psát ho pokaždé, když někdo zapomněl čip. Zapsaný výdej dál nese, kdo ho pořídil, na jaké směně a s jakým důvodem. ## Krok 3: Přiřazení čipu strávníkovi Strávník dostane svůj RFID čip a operátor ho jednorázově spáruje s profilem strávníka v systému: 1. Sekce **RFID → Čipy** (cesta `/operator/chips`). 1. Vyhledejte strávníka -- **jméno, příjmení, nebo variabilní symbol** (stejné hledání jako v seznamu strávníků; celé jméno naráz nefunguje, hledejte jedním slovem). U nalezených strávníků se vpravo ukazuje VS, takže poznáte, kterého vybíráte. 1. Klikněte na strávníka ve výsledcích. 1. Sekce **Přiřadit čip**: přiložte čip ke čtečce. Pole se vyplní automaticky uppercase hex hodnotou. **Neklikejte do pole** -- nechte ho nezaostřené, jinak na české klávesnici dostanete místo číslic `+ěščřžýáíé` (viz [Klávesnicový layout](#klávesnicový-layout)). 1. Klikněte **Přiřadit**. Jeden strávník může mít vždy maximálně _jeden aktivní_ čip. Při ztrátě nebo výměně: 1. U aktivního čipu klikněte **Odebrat**. 1. Zadejte důvod (_ztracen_, _poškozen_, _vrácen_, _jiné_). 1. Přiřaďte nový čip stejným postupem. > **Pozor:** Zneplatnění je okamžité -- od té chvíle už ztracený čip nikdo nemůže použít k cizímu výdeji. Do reportu anomálií se pak promítne, pokud se ztracený čip přiloží. ## Krok 4: Předání terminálu obsluze Po krocích 1--3 je vše nachystané. Operátor se z kuchyňského PC odhlásí (nebo zavře prohlížeč). Když přijde kuchařka, otevře edumeal -- systém vidí, že je PC spárované, a přesměruje rovnou na `/scan/start` (Přihlášení obsluhy). Detailní popis flow obsluhy je v sekci [Obsluha -- výdej obědů](/docs/kitchen-staff). ## Údržba ### Ztráta služebního čipu obsluhy 1. `/operator/kitchen-staff` → detail obsluhy → **Odebrat** u aktivního čipu. 1. Přiřaďte nový čip. ### Rotace PINu obsluhy Pokud má kuchařka podezření, že její PIN někdo zná: 1. `/operator/kitchen-staff` → detail obsluhy → sekce **PIN obsluhy** → **Rotovat PIN**. 1. Zadejte nový PIN -- starý se okamžitě zneplatní. ### Revoke / přepárování terminálu Pokud potřebujete terminál přesunout, vyřadit, nebo měnit přiřazení k výdejnímu místu: 1. **RFID → Zařízení** (cesta `/operator/devices`). 1. U konkrétního terminálu klikněte **Zneplatnit**, zadejte důvod. 1. Od té chvíle device token na příslušném PC vrací 401 -- obsluha dostane na `/scan/start` hlášku "Terminál není spárovaný nebo bylo jeho oprávnění odebráno". 1. Pro znovu-použití PC projděte krok 1 (Spárování) znovu. ### Lokální unpair (PC bez admin zásahu) Operátor přímo na kuchyňském PC může terminál odpárovat bez revoke v admin UI: 1. Přihlaste se na PC jako operátor. 1. `/operator/scan-setup` → sekce **Browser už je spárovaný** → tlačítko **Odpárovat**. 1. Localstorage se vymaže. Záznam terminálu v API zůstane platný -- můžete nyní stejný token namapovat na jiný browser/PC (přes API, ne přes UI), nebo nechat token expirovat. ## Reporty a audit RFID výdej generuje data do několika reportů v sekci **Kuchyně**: - **Denní výdejka** -- kolik porcí bylo vydáno, kolik objednaných, kolik nevybraných. Rozděleno podle výdejního místa, slotu a věkové kategorie. - **Anomálie** -- strávníci s vysokým podílem manuálních výdejů, strávníci s opakovaným "Již vydáno", ztracené čipy, které se znovu objevily. - **Audit log** -- kompletní historie každého skenu (i odmítnutého) s časem, obsluhou, terminálem a důvodem. Zdroj pravdy pro řešení sporů s rodiči. ### Řešení sporů Pokud rodič tvrdí, že dítě dnes nedostalo oběd: 1. V auditu vyhledejte strávníka a datum. 1. Zkontrolujte, zda existuje záznam `pickup.created` nebo `pickup.rejected`. 1. Pokud existuje úspěšný výdej s časem, sdělte rodiči čas a obsluhu. 1. Pokud existují jen odmítnuté pokusy (např. "Žádná objednávka"), zkontrolujte historii objednávek -- objednávka mohla být zrušena nebo nikdy nevznikla. ## Časté otázky ### Můžeme provozovat dvě okénka současně na jednom výdejním místě? Ano. Vytvořte dva samostatné terminály (každý na svém PC s vlastní čtečkou). Každá kuchařka má vlastní směnu a vlastní službu, audit pak ukáže, kdo a na kterém okénku vydal. ### Funguje výdej i pro hromadné objednávky organizací (mateřinky)? Hromadné objednávky organizace se aktuálně nevydávají přes RFID, protože organizace nemá fyzické čipy. Vydávají se obvykle hromadně podle dodacího listu na výdejním místě organizace. ### Mohu změnit služební čip kuchařce, aniž bych vystavoval nový PIN? Ano. Sekce **Čip obsluhy** a **PIN obsluhy** v detailu kuchařky jsou nezávislé -- můžete měnit jednu věc, aniž byste sahali na druhou. ### Je možné používat ISIC kartu jako čip? Ano, edumeal čte ISIC karty na frekvenci 13,56 MHz a ukládá jejich UID stejně jako u jakéhokoli jiného čipu. Při výměně ISIC karty (např. po prodloužení platnosti) UID zůstává stejné -- není potřeba čip znovu přiřazovat. ### Co když operátor nemá fyzický přístup k kuchyňskému PC? Spárování vyžaduje fyzický přístup, protože device token se ukládá do localStorage konkrétního prohlížeče. Pro remote setup (vzdálená kuchyně) musí někdo na místě otevřít edumeal a potvrdit pairing. Lze to udělat například přes vzdálenou plochu, ale localStorage musí zůstat v _browseru na PC_, ne ve vaší relaci. ### Kuchařka tvrdí, že po reloadu obrazovky ji to odhlásilo. Co teď? V dnešní verzi staff session přežívá reload (uloženo v localStorage s 8h TTL). Pokud reload obsluhu odhlásí, něco není v pořádku -- možnosti: - localStorage prohlížeče byl vyčištěn (privátní okno, restart prohlížeče s "mazat data" nastavením). - Session reálně vypršela (8h od přihlášení). - Operátor mezitím revoke-nul device -- session už nemá platný terminál. Ve scanning mode obrazovce by se objevil toast "Směna vypršela, přihlas se znovu" a UI by skočilo na `/scan/start`. Pokud obsluha tvrdí něco jiného, požádejte ji o screenshot a kontaktujte support.