Compare commits

..

No commits in common. "da287c2aec9cca3867bd82dd9042757690d3571a" and "1b8db5e4a7932bd39d3108beb4e956aaef1a40fb" have entirely different histories.

7 changed files with 0 additions and 411 deletions

View File

@ -736,29 +736,6 @@ DSN sadrži `multiStatements=true` — neophodno za izvršavanje migracija sa vi
- Faza 8 (Light-Ticket): Integracija sa license serverom - Faza 8 (Light-Ticket): Integracija sa license serverom
- ARV: Integracija sa license serverom - ARV: Integracija sa license serverom
- ESIR: Integracija sa license serverom - ESIR: Integracija sa license serverom
- **ASP-Terminia (4. proizvod):** vidi `docs/asp-terminia/` — radni paket Z1Z6
---
## 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 Z1Z6, 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.
--- ---

View File

@ -1,97 +0,0 @@
# 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:<base64>"` 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` RSASHA256
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`).

View File

@ -1,72 +0,0 @@
# 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:<sha256hex od 'AA:BB:CC:DD:EE:FF'>",
"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:<base64 potpisa nad SIROVIM bajtovima license objekta>"
}
```
**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 |

View File

@ -1,102 +0,0 @@
# 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 P1P4 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/)
```

View File

@ -1,41 +0,0 @@
# 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`.

View File

@ -1,16 +0,0 @@
# 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.

View File

@ -1,60 +0,0 @@
# ASP-Terminia — licenciranje (radni paket)
> **Misija:** dovesti licenciranje ASPTerminia 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
> <https://git.terminia.net/djuka/asp-terminia>.
## 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 E1E6 za vlasnika: šta uređaj radi bez licence |
## Kontekst u 5 redova
1. **Šta se licencira:** ESP32S3 terminal za kontrolu prolaza (bazeni/spa), proizvod
**„ASPTerminia"** (Autonomni Sistem Prolaza). Licenca je vezana za **MAC** čipa
(eFuse, nepromenljiv) preko `machine_fingerprint`.
2. **Server već postoji:** `dal-license-server` (Go, MySQL, RSA2048/SHA256) 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 IPa 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):** <https://git.terminia.net/djuka/asp-terminia>
(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).