diff --git a/CLAUDE.md b/CLAUDE.md index 1031468..d8f7298 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -736,6 +736,29 @@ DSN sadrži `multiStatements=true` — neophodno za izvršavanje migracija sa vi - Faza 8 (Light-Ticket): Integracija sa license serverom - ARV: Integracija sa license serverom - ESIR: Integracija sa license serverom +- **ASP-Terminia (4. proizvod):** vidi `docs/asp-terminia/` — radni paket Z1–Z6 + +--- + +## Radni paket: ASP-Terminia (ESP32 terminal) + +Četvrti proizvod na ovom serveru — **ASP-Terminia** (Autonomni Sistem Prolaza), +ESP32-S3 terminal za kontrolu prolaza (bazeni/spa). Licenca je vezana za **MAC** +čipa (eFuse) preko `machine_fingerprint`, a ne za računar. + +**Klijentska strana je već gotova** — firmware modul `licenca.h/.cpp` (od FW +0.10.0) radi aktivaciju, offline verifikaciju RSA potpisa i UI. Čeka samo da +proizvod i ključ postoje ovde na serveru. + +Kompletan paket (postojeće stanje, tačan API ugovor koji firmware očekuje, +zadaci Z1–Z6, pravila rada na produkciji, enforcement pitanja za vlasnika): + +**[`docs/asp-terminia/README.md`](docs/asp-terminia/README.md)** — čitati prvo. + +Razlika u odnosu na ESIR/ARV/LIGHT_TICKET koja se mora poštovati: +- fingerprint je MAC uređaja, ne hash računara; +- uređaj radi **offline** — mrežna greška NIKAD ne sme da ga obori; +- postojeći proizvodi su ŽIVI u produkciji (~140 licenci) — ništa se ne lomi. --- diff --git a/docs/asp-terminia/01-postojece-stanje.md b/docs/asp-terminia/01-postojece-stanje.md new file mode 100644 index 0000000..b9cef61 --- /dev/null +++ b/docs/asp-terminia/01-postojece-stanje.md @@ -0,0 +1,97 @@ +# Postojeće stanje (provereno na serveru 2026-07-24, read-only) + +## 1. Server 151 — pristup i raspored + +- **SSH:** `ssh root@157.180.119.151` (host se javlja kao `MCLaud`, Ubuntu; ključ + `~/.ssh/id_ed25519` sa razvojne mašine; samo root). Hetzner, van LAN-a. +- Na ISTOM serveru žive i drugi sistemi — **ne dirati**: + - `terminia` SaaS platforma za klubove (portovi 8091/8092) — IME SLIČNO, ali + NIJE naš proizvod; + - Gitea; + - ESIR backend (fiskalizacija). + +## 2. `dal-license-server` (naš deo) + +- **Kod:** `/root/projects/dal-license-server` — Go, bez frameworka, MySQL. +- **Port:** 8090 lokalno; javno preko nginx sajta **`arv`**. +- **Javni URL (ovo firmware već koristi):** `https://157.180.119.151/license/api/v1/` + - HTTPS 443, cert `/etc/nginx/ssl/arv.crt`, `server_name` = IP → **self-signed** + (zato firmware koristi `setInsecure()`; odluku štiti RSA potpis odgovora). + - Na portu 80 je izložen samo validator API; ostalo redirect na 443. +- **Produkcioni obim:** 3 proizvoda (ESIR, ARV, LIGHT_TICKET — seed u + `migrations/002_seed_products.sql`), ~140 licenci, ~19 aktivacija. **ŽIVO.** + +### Kripto + +- **RSA-2048**, potpis **RSA-SHA256**. +- Privatni ključ: na serveru (`crypto/` + `.env` konfiguracija) — **NE čitati, NE + kopirati, NE logovati.** +- Javni ključ: `crypto/public.pem` — VEĆ ugrađen u firmware (`licenca.cpp`, + `LIC_PUBKEY`). Ako se ključ ikad rotira, MORA i novi firmware — to je krupna + odluka, ne radi se usput. +- Potpis stiže kao string: `"signature": "RSA-SHA256:"` uz `license` objekat. + **Potpisuje se serijalizacija license objekta kakvu server pošalje** — klijent + verifikuje SIROVE bajtove (ne re-serijalizuje). Svaka izmena serijalizacije na + serveru lomi sve klijente u polju. + +### Klijentski API (bez autentikacije, rate-limited) + +| Ruta | Telo zahteva | Odgovor | +|---|---|---| +| `POST /api/v1/activate` | `{license_key, machine_fingerprint, app_version, os, hostname}` | `{license:{... expires_at, grace_days, limits, features, customer ...}, signature}` | +| `POST /api/v1/validate` | `{license_key, machine_fingerprint}` | `{valid, expires_at, revoked}` | +| `POST /api/v1/deactivate` | (transfer/oslobađanje) | — | + +Greške (JSON `error` polje): `INVALID_KEY`, `ALREADY_ACTIVATED`, `KEY_EXPIRED`, +`KEY_REVOKED`, `PRODUCT_MISMATCH`. + +### Admin API + +- Header `X-API-Key` (ključ u `.env` — od vlasnika se traži ključ ili da on sam + klikne u dashboardu; agent NE vadi ključ iz `.env` bez izričite dozvole). +- Kreira proizvode i licence. Postoji i htmx admin dashboard. + +## 3. Firmware klijent — GOTOV (od FW 0.10.0) + +Fajlovi u firmware repou (`firmware/10_terminia/`): + +| Šta | Gde | +|---|---| +| Modul | `licenca.h` / `licenca.cpp` | +| Ugrađen javni ključ | `licenca.cpp` → `LIC_PUBKEY` (PEM) | +| NVS | namespace `lic`: `raw` (sirovi license JSON) + `sig`; ključ/URL u configu: `licKey`, `licUrl` (podrazumevano `https://157.180.119.151/license/api/v1`) | +| Web API (SPA) | `/api/license` (status), `/api/license-save` (ključ/URL), `/api/license-activate`, `/api/license-check` — sve samo admin | +| UI | SPA → Podešavanja → Uređaj → kartica „Licenca" (status, izdanje, korisnik, važi do, otisak uređaja, unos ključa, Aktiviraj, Proveri na serveru) | + +### Kako klijent radi (bitno za server stranu) + +1. **Otisak:** `machine_fingerprint = "sha256:" + sha256hex(MAC)` gde je MAC oblika + `AA:BB:CC:DD:EE:FF` (velika slova, dvotačke). ⚠️ **PRETPOSTAVKA** — proveriti u + Go kodu servera kako računa fingerprint za poređenje; ako se razlikuje, uskladiti + NA SERVERU dokumentaciju/verifikaciju za ASP proizvod ILI javiti pa menjamo FW + (zadatak Z2). +2. **Aktivacija:** POST `/activate`; iz odgovora isecₐ SIROVE bajtove `license` + objekta (brojanje zagrada, string-safe), verifikuje `signature` RSA‑SHA256 + javnim ključem, čuva sirovo+potpis u NVS. +3. **Svaki start (offline):** ponovo verifikuje potpis iz NVS + poredi + `machine_fingerprint` iz licence sa svojim + proverava `expires_at` + (poređenje po datumu `YYYY-MM-DD`; prazno = trajna; nepouzdan sat → grejs, + nikad pad). +4. **Statusi na uređaju:** `nema / vazi / grejs / los-potpis / drugi-uredjaj / istekla`. +5. **ENFORCEMENT NE POSTOJI** — uređaj samo prikazuje status. Gašenje funkcija bez + licence je odluka vlasnika (zadatak Z4). + +### Polja koja klijent čita iz `license` objekta + +`edition`, `customer` (ili `customer_name`), `expires_at`, `license_id` (ili `key`), +`grace_days`, `machine_fingerprint`. Nepoznata dodatna polja ne smetaju (parsira se +ciljano). `limits`/`features` se JOŠ ne čitaju — planirano uz enforcement. + +## 4. Šta NE postoji (i pripada zadacima) + +- Proizvod **„ASP-Terminia"** na serveru — ne postoji (zadatak Z1). +- Nijedan ASP ključ — ne postoji (Z1/Z2). +- Domen `licenca.terminia.net` + Let's Encrypt — ne postoji (Z3; domen kupuje vlasnik). +- Enforcement na uređaju + `features`/`limits` semantika za ASP (Z4/Z5). +- FW potpisivanje `.bin` + katalog firmvera (Z6; preduslov za auto-OTA, vidi i + ASP repo: `serviseri/03-provisioning-i-fw-katalog.md`). diff --git a/docs/asp-terminia/02-api-ugovor-firmware.md b/docs/asp-terminia/02-api-ugovor-firmware.md new file mode 100644 index 0000000..00c2e6c --- /dev/null +++ b/docs/asp-terminia/02-api-ugovor-firmware.md @@ -0,0 +1,72 @@ +# API ugovor koji FIRMWARE očekuje (merodavno za server stranu) + +> Ovo je ugovor kakav je VEĆ implementiran u firmveru (0.10.0+). Server strana se +> usklađuje sa OVIM (ili se promena dogovara pa se menja i firmware — nikad tiho). + +## 1. Aktivacija + +``` +POST {licUrl}/activate +Content-Type: application/json + +{ + "license_key": "ASP-XXXX-XXXX-XXXX", + "machine_fingerprint": "sha256:", + "app_version": "0.11.0", + "os": "esp32s3", + "hostname": "TERM-001" +} +``` + +Očekivan odgovor `200`: + +``` +{ + "license": { + ... polja licence, među njima: + "machine_fingerprint": "sha256:...", ← ako postoji, MORA biti otisak uređaja + "expires_at": "2027-01-01T00:00:00Z", ← ili prazno/odsutno = trajna + "grace_days": 14, + "edition": "...", "customer": "...", "license_id": "..." + }, + "signature": "RSA-SHA256:" +} +``` + +**Kritično:** potpis se računa nad TAČNIM bajtovima `license` objekta onako kako su +poslati u HTTP telu (od `{` do para `}`). Firmware iseca taj isečak iz sirovog tela +(string-safe brojanje zagrada) i verifikuje. **Nikakvo „lepše" formatiranje odgovora +naknadno** — menja bajtove → lomi potpis. + +## 2. Provera + +``` +POST {licUrl}/validate +{ "license_key": "...", "machine_fingerprint": "sha256:..." } +``` + +Očekivano: `{"valid": true/false, "expires_at": "...", "revoked": true/false}`. +Firmware tumači: `revoked` → poruka „licenca OPOZVANA na serveru"; `!valid` → +„server kaže da licenca ne važi". Mrežna/HTTP greška NE dira lokalno stanje. + +## 3. Greške + +HTTP ≠ 200 → firmware čita JSON polje `"error"` i prikazuje ga korisniku uz HTTP kod +(npr. `HTTP 403 (KEY_REVOKED)`). Poželjno je da server uvek vraća `{"error":"KOD"}`. + +## 4. Ponašanje klijenta koje server sme da računa + +- Klijent NIKAD ne šalje privatne podatke — samo gore navedena polja. +- Klijent poštuje odgovor samo ako je potpis valjan; HTTP 200 bez valjanog potpisa + se odbacuje (zaštita i od MITM na self-signed kanalu). +- Nakon uspešne aktivacije klijent NE zove server pri svakom startu — offline + verifikacija iz NVS. `validate` se zove ručno iz UI (kasnije: periodično uz sync). + +## 5. Otvorena pitanja za usklađivanje (uneti odgovore ovde) + +| # | Pitanje | Status | +|---|---|---| +| P1 | Tačna formula `machine_fingerprint` u Go kodu (ulazni string, velika/mala slova, dvotačke?) | ⬜ proveriti u kodu servera | +| P2 | Da li `activate` na VEĆ aktiviran ključ + ISTI fingerprint vraća licencu ponovo (re-aktivacija posle brisanja NVS) ili `ALREADY_ACTIVATED`? Za teren nam treba: isti uređaj sme ponovo. | ⬜ proveriti/podesiti | +| P3 | Tačan skup polja `license` objekta za ASP proizvod (limits/features imena) | ⬜ definisati uz Z1 | +| P4 | `expires_at` format (ISO8601?) — firmware poredi prvih 10 znakova (`YYYY-MM-DD`) | ⬜ potvrditi | diff --git a/docs/asp-terminia/03-zadaci.md b/docs/asp-terminia/03-zadaci.md new file mode 100644 index 0000000..912e038 --- /dev/null +++ b/docs/asp-terminia/03-zadaci.md @@ -0,0 +1,102 @@ +# Zadaci (redom; svaki ima kriterijum prihvatanja) + +> Redosled je namerno ovakav: prvo ono što odblokira kraj-do-kraja test sa pravim +> uređajem, pa infrastruktura (domen), pa odluke, pa katalog firmvera. +> **Pre svakog write-a na produkciju: backup + izričita dozvola vlasnika** +> (vidi 04-pravila-rada.md). + +## Z1 — Proizvod „ASP-Terminia" na serveru + +**Šta:** kroz migraciju (SQL u `migrations/`, po uzoru na `002_seed_products.sql`) +ili admin API/dashboard napraviti proizvod: + +- `code`/`name`: **ASP-Terminia** (linija: ASP — Autonomni Sistem Prolaza) +- `key_prefix`: **`ASP-`** +- limiti (predlog, potvrditi sa vlasnikom): `max_citaca` (npr. basic 2 / pro 8), + `max_kartica` (basic 2000 / pro 30000) +- features (predlog bitova, uskladiti sa ASP repo docs/18 §6.3): provera karte, izdavanje, + štampa, katalog-sa-servera, anti-passback, sync, OTA + +**Kako:** pogledati kako su postojeći proizvodi definisani (tabela `products` + +seed migracija) i uraditi ISTIM šablonom. Ne menjati postojeće redove. + +**Prihvatanje:** proizvod vidljiv u dashboardu; postojeći proizvodi netaknuti +(COUNT pre = posle za njihove licence/aktivacije); backup fajl postoji. + +## Z2 — Test ključ + kraj-do-kraja aktivacija sa uređajem + +**Šta:** izdati 1 test licencu ASP-Terminia (trajnu ili 90 dana) i proći ceo tok sa +PRAVIM uređajem (MAC `1C:DB:D4:A6:A4:60`, dostupan vlasniku): + +1. Odgovoriti na P1–P4 iz 02-api-ugovor-firmware.md (čitanjem Go koda). +2. Ako se fingerprint formula razlikuje od FW pretpostavke → zapisati TAČNU formulu + u 02 i javiti (menja se FW, jedna linija). +3. Vlasnik unese ključ u SPA (Podešavanja → Uređaj → Licenca) → Aktiviraj. +4. Proveriti: status „važi" na uređaju; restart uređaja → i dalje „važi" (offline); + `Proveri na serveru` → potvrda. +5. Negativni testovi: pogrešan ključ (INVALID_KEY prikazan), opozvan ključ + (revoked prikazan), ključ aktiviran na drugom fingerprint-u (PRODUCT/ALREADY + ponašanje po P2). + +**Prihvatanje:** svih 5 koraka dokumentovano (šta je poslato/vraćeno, bez tajni). + +## Z3 — Domen `licenca.terminia.net` + Let's Encrypt + +**Preduslov:** vlasnik kupi/podesi `terminia.net` (A rekord → 157.180.119.151). +Dok toga nema, zadatak stoji — NE blokira Z1/Z2 (ide se preko IP-a). + +**Šta:** +- nginx: novi `server_name licenca.terminia.net` blok koji proksira ISTI backend + (port 8090) — **ne dirati postojeći `arv` sajt** (postojeći klijenti ostaju na IP). +- certbot (Let's Encrypt) za taj domen; auto-obnova. +- Provera da `https://licenca.terminia.net/api/v1/validate` radi sa validnim lancem. +- U firmware repou: `cfg.licUrl` podrazumevana vrednost se menja na domen, a + `setInsecure()` se zamenjuje validacijom lanca (ugraditi ISRG root CA) — to je + FW izmena: pripremiti tačan diff/uputstvo, primenu radi firmware strana. + +**Prihvatanje:** domen služi API sa validnim certom; stari IP pristup i dalje radi. + +## Z4 — Odluke o enforcement-u (PRIPREMA, vlasnik odlučuje) + +**Šta:** pripremiti kratak dokument sa predlogom (na bazi ASP repo docs/18 §5) i KONKRETNIM +pitanjima za vlasnika: + +1. Bez licence: potpuno odbijanje ILI ograničen rad (predlog: web/konfiguracija/ručno + upravljanje rade; izdavanje+štampa+provera karata ne rade uz jasnu poruku)? +2. Grejs: 14 dana posle isteka (podesivo)? +3. Nepouzdan sat = grejs (nikad pad) — potvrda? +4. Koje funkcije vezati za `features` bite, koje za `limits`? + +**Prihvatanje:** dokument `05-enforcement-odluke.md` u ovom folderu sa odgovorima +vlasnika upisanim (ne pretpostavkama). Implementacija enforcement-a u FW ide TEK +posle toga (firmware strana). + +## Z5 — Obnova/opoziv tok (sloj B) + +**Šta:** definisati i (posle Z4) implementirati periodičnu proveru na uređaju: +`validate` na N sati (podesivo), `revoked` → od kad važi ograničenje (posle grejsa), +server može vratiti NOVU licencu (produženje) — proveriti da li postojeći server to +podržava kroz `activate` re-poziv ili treba dorada (`check` endpoint po ASP repo docs/18 §4). + +**Prihvatanje:** opisan tačan tok + potvrđeno na test ključu (produženje + opoziv). + +## Z6 — Potpisivanje firmvera + veza sa katalogom + +**Šta:** `.bin` slike se potpisuju RSA lancem (ODVOJEN ključ od licenci — preporuka +ASP repo docs/18 §7.1; ako vlasnik odluči isti, dokumentovati). Server strana: skripta za +potpis + čuvanje potpisa uz artefakt. Katalog (nginx `fw.terminia.net`) i +kratkotrajni download URL su u paketu `ASP repo: serviseri/03` — ovde samo potpisni deo. + +**Prihvatanje:** komanda za potpis + format potpisa dokumentovan + probni potpisan +`.bin` verifikovan javnim ključem. + +--- + +## Redosled i zavisnosti (sažetak) + +``` +Z1 (proizvod) ──► Z2 (kraj-do-kraja) ──► Z4 (odluke) ──► [FW enforcement — firmware strana] + └──► Z5 (obnova/opoziv) +Z3 (domen) — čim vlasnik obezbedi DNS (nezavisno) +Z6 (potpis .bin) — pre auto-OTA kataloga (koordinacija sa ASP repo: serviseri/) +``` diff --git a/docs/asp-terminia/04-pravila-rada.md b/docs/asp-terminia/04-pravila-rada.md new file mode 100644 index 0000000..540d452 --- /dev/null +++ b/docs/asp-terminia/04-pravila-rada.md @@ -0,0 +1,41 @@ +# Pravila rada — PROČITATI PRE PRVOG SSH-a + +> Server 151 je **PRODUKCIJA** sa živim klijentima (fiskalizacija ESIR, ARV, +> LIGHT_TICKET licence, terminia SaaS). Greška ovde košta prave korisnike. + +## Tvrda pravila (bez izuzetka) + +1. **Read-only dok se ne odobri write.** Istraživanje (čitanje koda, šeme, + nginx konfiga) je slobodno. SVAKI write na produkciju (SQL, fajl, nginx reload, + restart servisa) traži **izričito DA vlasnika za taj konkretan korak**. +2. **Backup pre svake izmene.** Minimum: + - baza: `mysqldump` ciljanih tabela (ili cele baze) u `/root/backup/` sa datumom; + - fajl/konfig: kopija sa `.bak-YYYYMMDD` sufiksom pre izmene. + U izveštaju navesti tačnu putanju backupa. +3. **Migracije, ne ad-hoc SQL.** Izmene šeme/podataka idu kao numerisan fajl u + `migrations/` (šablon = postojeće migracije), idempotentno gde je moguće. +4. **Tajne se ne diraju:** `.env`, privatni ključevi (`crypto/` osim `public.pem`), + lozinke — ne čitati sadržaj, ne ispisivati u logove/izveštaje. Ako je za posao + potreban admin API ključ — **tražiti od vlasnika**, ne vaditi ga iz `.env`. +5. **Ne dirati tuđe servise:** `terminia` SaaS (8091/8092), Gitea, ESIR — ni + konfiguraciju, ni bazu, ni portove. Nginx: menjati SAMO dodavanjem novih + server blokova; postojeći `arv` sajt ostaje kakav jeste. +6. **Nikad destruktivno:** bez DROP/DELETE nad postojećim podacima; bez rotacije + ključeva; bez gašenja servisa duže od reload-a. +7. **Kompatibilnost klijenata u polju:** serijalizacija `license` objekta i format + potpisa se NE menjaju (lome verifikaciju na uređajima). Nova polja se DODAJU, + postojeća se ne preimenuju. + +## Kako se testira bez rizika + +- Novi proizvod (ASP-Terminia) i test ključevi su IZOLOVANI redovi — ne dodiruju + postojeće. Test aktivacije gađaju samo ASP ključeve. +- Za probe API-ja koristiti `curl` sa test ključem; nikad tuđe ključeve. +- Ako postoji mogućnost lokalnog pokretanja (Go build + test MySQL šema) — poželjno + prvo lokalno, pa migracija na produkciju. + +## Izveštavanje + +Posle svake sesije: šta je pročitano, šta je menjano (tačne putanje/tabele), +gde je backup, šta je sledeće, otvorena pitanja za vlasnika. Odgovore na pitanja +upisivati u `02-api-ugovor-firmware.md` §5 i `05-enforcement-odluke.md`. diff --git a/docs/asp-terminia/05-enforcement-odluke.md b/docs/asp-terminia/05-enforcement-odluke.md new file mode 100644 index 0000000..dd39f89 --- /dev/null +++ b/docs/asp-terminia/05-enforcement-odluke.md @@ -0,0 +1,16 @@ +# Enforcement — odluke vlasnika (popunjava se, NE pretpostavlja) + +> Uređaj trenutno licencu samo PRIKAZUJE. Pre nego što ijedna funkcija sme da se +> gasi bez licence, vlasnik odgovara na sledeće (predlozi iz ASP repo docs/18 §5 u zagradi): + +| # | Pitanje | Predlog | ODLUKA VLASNIKA | +|---|---|---|---| +| E1 | Ponašanje bez važeće licence? | Ograničen rad: web/konfiguracija/ručno upravljanje izlazima RADE (bezbednost + mogućnost unosa licence); izdavanje karata, štampa i provera karata NE RADE uz jasnu poruku „Uređaj nije licenciran". Alternativa: potpuno odbijanje (rizik zaglavljene rampe). | ⬜ | +| E2 | Grejs period posle isteka? | 14 dana, podesivo (`licGraceDays`); tokom grejsa pun rad + uporno upozorenje u UI i logu. | ⬜ | +| E3 | Nepouzdan sat (RTC bez baterije)? | Tretirati kao grejs (radi + upozorava), NIKAD pad — inače nestanak struje bez NTP obara ispravan terminal. | ⬜ | +| E4 | `features` biti — šta se licencira? | provera-karte / izdavanje / štampa / katalog-sa-servera / anti-passback / sync / OTA (servisni kanal, AP, web, prijava NIKAD ne zavise od licence). | ⬜ | +| E5 | `limits` — šta se ograničava? | max_kartica u katalogu, max_citaca u registru; „basic" vs „pro" izdanje. | ⬜ | +| E6 | Model prodaje? | Trajna (expires prazno) i pretplata (30/60/90 d uz obnovu kroz validate/check) — podržati oba. | ⬜ | + +Kad su odluke upisane: implementacija ide u firmware (`licenca` modul + provere u +`tickets/cards/printer` putanjama) — radi firmware strana, uz host testove. diff --git a/docs/asp-terminia/README.md b/docs/asp-terminia/README.md new file mode 100644 index 0000000..e4cc10c --- /dev/null +++ b/docs/asp-terminia/README.md @@ -0,0 +1,60 @@ +# ASP-Terminia — licenciranje (radni paket) + +> **Misija:** dovesti licenciranje ASP‑Terminia terminala do produkcije na +> postojećem `dal-license-server`-u (server 151), bez lomljenja ijednog +> postojećeg klijenta (ESIR/ARV/LIGHT_TICKET su ŽIVI u produkciji). +> +> **Jezik projekta:** srpski (ekavica), latinica. Kod/komentari na serveru su Go — +> komentari srpski ASCII. + +> **Poreklo:** paket je nastao u firmverskom repou (`asp-terminia/licence/`) i +> prebačen ovde 2026-07-24, jer je sav posao serverski. Firmverska strana je +> gotova i ne dira se. „**ASP repo**" u tekstu znači +> . + +## Sadržaj foldera + +| Fajl | Šta je unutra | +|---|---| +| [01-postojece-stanje.md](01-postojece-stanje.md) | šta VEĆ postoji: server (Go/MySQL/nginx/kripto) i firmware klijent (gotov!) | +| [02-api-ugovor-firmware.md](02-api-ugovor-firmware.md) | tačan ugovor koji firmware očekuje — polja, potpis, greške | +| [03-zadaci.md](03-zadaci.md) | šta treba uraditi, redom, sa kriterijumima prihvatanja | +| [04-pravila-rada.md](04-pravila-rada.md) | **OBAVEZNO pročitati prvo** — produkcija, backup, tajne, granice | +| [05-enforcement-odluke.md](05-enforcement-odluke.md) | pitanja E1–E6 za vlasnika: šta uređaj radi bez licence | + +## Kontekst u 5 redova + +1. **Šta se licencira:** ESP32‑S3 terminal za kontrolu prolaza (bazeni/spa), proizvod + **„ASP‑Terminia"** (Autonomni Sistem Prolaza). Licenca je vezana za **MAC** čipa + (eFuse, nepromenljiv) preko `machine_fingerprint`. +2. **Server već postoji:** `dal-license-server` (Go, MySQL, RSA‑2048/SHA‑256) na + `157.180.119.151`, u produkciji sa 3 proizvoda / ~140 licenci / ~19 aktivacija. +3. **Firmware klijent je GOTOV** (modul `licenca.h/.cpp` u firmveru, od verzije 0.10.0): + aktivacija, offline verifikacija potpisa javnim ključem, UI. Čeka samo proizvod + i ključ na serveru. +4. **Dva sloja:** potpisana lokalna licenca (radi offline) + serverska provera/obnova + (opoziv). Mrežna greška NIKAD ne obara uređaj. +5. **Domeni (kupuje vlasnik):** `licenca.terminia.net` → 157.180.119.151 (Let's + Encrypt). Dok domena nema, uređaj radi preko IP‑a sa `setInsecure()` — odluku + ionako štiti RSA potpis, ne TLS kanal. + +## Šta agent NE radi + +- Ne donosi odluku o **ponašanju uređaja bez licence** (gašenje funkcija) — to je + odluka vlasnika (pitanja u 03-zadaci.md §Z4). Priprema se predlog, čeka se DA. +- Ne dira postojeće proizvode (ESIR, ARV, LIGHT_TICKET) niti `terminia` SaaS + (portovi 8091/8092 na istom serveru — TO NIJE OVAJ POSAO). +- Ne čita niti loguje tajne (`.env`, privatni ključ) — vidi 04-pravila-rada.md. + +## Veze ka ostatku projekta + +- **Firmware repo (ASP repo):** + (klijent: `firmware/10_terminia/licenca.h`, `licenca.cpp`; javni ključ ugrađen). + Firmverska strana je GOTOVA od FW 0.10.0 — ovaj paket je ne dira. +- Dizajn/istorijat: `ASP repo docs/18-licenciranje-po-mac.md` (pisan PRE nego što je pravi + API poznat — gde se razlikuju, **ovaj folder je merodavan**), `ASP repo docs/21-platforma-i-provisioning.md`. +- Serviserska strana (RBAC, uređaji, LoggerService): `ASP repo: serviseri/` — + isti backend, drugi radni paket; koordinacija preko šeme baze (vidi tamo 01). + *(Taj paket se seli u ovaj repo posebno — vidi dogovor od 2026-07-24.)* +- Serverski kod i konvencije: [../../CLAUDE.md](../../CLAUDE.md), + [../ARCHITECTURE.md](../ARCHITECTURE.md), [../../API.md](../../API.md).