# 07 - Firmy a prava ## Dve ruzne "firmy" Snadno se pletou, proto hned na zacatku: - **Tenant** je firma, ktera portal pouziva. Ma v nem svuj tym, svoje tickety a svoje automatizace. Je to hranice viditelnosti. - **`ticket.customer`** je zakaznik toho tenanta, tedy kdo pozadavek poslal. S pravy nema nic spolecneho. Tenanti jsou v `src/data/tenants.ts`. ## Uzivatel muze byt ve vic firmach Proto `memberships`, ne jedno `tenantId`. Typicky externista, ktery dela servicedesk dvema klientum a v kazdem ma jinou roli. ```ts interface User { id: string; email: string; name: string; platformAdmin: boolean; // vidi napric vsemi firmami memberships: Membership[]; // { tenantId, role } } type TenantRole = 'admin' | 'agent'; ``` **Role je vzdy az uvnitr firmy.** Pristup napric firmami je zvlast jako `platformAdmin` - to je nase pravo, ne zakaznicke. Kdyby byla role jen jedna globalni, nesla by tahle situace vubec zapsat. ## Tri pohledy na tickety | Pohled | Co ukazuje | Kdo smi | | -------- | ------------------------- | ------------------------------ | | `all` | napric vsemi firmami | jen `platformAdmin` | | `tenant` | cela jedna firma | kdokoliv, kdo do ni patri | | `mine` | jen tickety prihlaseneho | kdo ma navazaneho resitele | Posilaji se jako query: `?scope=tenant&tenantId=tnt_automia`. U `tenant` a `mine` je potreba vedet **kterou** firmu, protoze uzivatel jich muze mit vic. Bez `tenantId` se pouzije prvni. ## Server je autorita Vsechno rozhoduje `src/data/access.ts`, jedno misto pro cely portal. Kdyby se to rozlezlo po routach, driv nebo pozdeji vznikne endpoint, ktery filtr zapomene. `GET /api/dashboard/access` vraci, co uzivatel smi: ```json { "scopes": ["all", "tenant", "mine"], "tenants": [{ "id": "tnt_automia", "name": "Automia" }], "defaultTenantId": "tnt_automia", "canAssignOthers": true, "personId": "ppl_uhlir" } ``` Klient podle toho kresli prepinac. **Nesmi si to dovozovat sam** - jinak by se prava pocitala na dvou mistech a jednou se rozejdou. ## Nikdy tise nezuzujeme Pozadavek na pohled nebo firmu, na kterou uzivatel nema pravo, vraci **chybu**, ne potichu zuzeny vysledek: | Situace | Odpoved | | -------------------------------- | ------- | | pohled bez opravneni | 403 | | firma, do ktere nepatri | 404 | | ucet bez firmy | 403 | | prirazeni ostatnim bez prava | 403 | Duvod: kdyby se pozadavek na cizi firmu jen prepnul na vlastni, uzivatel by koukal na cizi cisla v domneni, ze jsou spravna. To je horsi nez chyba. ## Filtr v ulozisti je povinny `listTickets`, `listPeople` a `listAutomations` maji `tenantIds` jako **povinny** argument, ne volitelny. Zapomenuty filtr tak neznamena "vse", ale nezkompiluje se. Zapis (`assignTicket`, `updateTicketStatus`, `addComment`, `updateAutomation`, `deleteAutomation`) bere `tenantIds` taky. Cizi zaznam se chova jako neexistujici, tedy 404, ne 403 - z odpovedi nemá jit poznat, ze takove ID vubec existuje. Vyjimka je verejny webhook. Ten se autorizuje tokenem v adrese, ne prihlasenim, takze si automatizaci najde pres vsechny firmy. ## Prirazeni jen v ramci firmy `assignTicket` odmitne resitele z jine firmy. Jinak by ticket zmizel z prehledu sve firmy a objevil se nekomu, kdo do ni nepatri. Prehazovat praci mezi lidmi smi jen `admin`. `agent` si smi vzit ticket na sebe, ale nemuze ho poslat kolegovi - to hlida `canAssignOthers`. ## Demo ucty Heslo je u vsech `demo1234`. | E-mail | Kdo je | | ------------------------- | ----------------------------------------------- | | `admin@automia.cz` | spravce platformy, vidi vsechny tri firmy | | `karel.vomacka@automia.cz`| agent v Automii, admin u Nordisu - dve firmy | | `martin.kriz@automia.cz` | bezny resitel jedne firmy | Druhy ucet je ten zajimavy: ukazuje prepinac firem i to, ze prava se lisi podle toho, ktera firma je prave zvolena. ## Co chybi | Chybi | Poznamka | | ------------------------ | ---------------------------------------------------- | | Sprava clenstvi z portalu| memberships jdou zmenit jen v kodu | | Pozvanky uzivatelu | zadny onboarding | | Tenant u incidentu | incidenty jsou zatim spolecne, nefiltruji se | | Tenant u konektoru | katalog je spolecny, napojeni se zatim neeviduje | | Audit pristupu | odepreni se jen loguje, nikde se neuklada |