# 99 - Zaznam zmen Nejnovejsi nahore. ## 2026-08-26 - prava plati za firmu, ne za cloveka `permissionsOf(user)` scitalo role pres vsechna clenstvi. Kdo byl spravce v jedne firme, jednal jako spravce ve vsech, kam patril. Uzivatel ve dvou firmach je vzacny, dusledek ne - to neni edge case, to je diera v pravech. ### Zmeneno - **Firma je povinny argument** u `permissionsOf`, `hasPermission` i `hasAnyPermission`. Zamerne povinny: kdyby byl nepovinny, prvni volani bez nej by tise vratilo vsechna prava. Prekladac tim rovnou nasel vsech ctrnact mist, ktera se ptaji. - **Kazde misto se pta za tu spravnou firmu.** Akce nad ticketem za firmu toho ticketu, uprava zaznamu za firmu toho zaznamu, zalozky a helpdesk za firmu, kterou ma clovek prepnutou. Kdo edituje zaznam jine firmy, musi mit pravo tam, ne tam, kde je zrovna prepnuty. - **Cizi firemni role se ignoruje**, i kdyby na ni clenstvi odkazovalo. Jinak by stacilo pripsat si ji do clenstvi v jine firme a prava by se prenesla. - **Cache prav ma v klici firmu.** Bez toho by prvni dotaz odpovedel i na druhou. - **`readScope` cte z jedne firmy, te prepnute**, ne ze vsech, kam clovek patri. V nastaveni se driv michaly typy ticketu a role napric firmami bez ohledu na vyber - stejna vada jako u prepinace, jen na jinem miste. ### Opraveno - **Systemove role se pri startu srovnaji s kodem** (`syncSystemRoles`). Vychozi sada se pouzije jen do prazdneho uloziste, takze nove pravo v katalogu se k uz bezici instalaci nikdy nedostalo - `ticket.create` a obe prava helpdesku by spravci firmy nikdy nenabehla a zalozka by se neobjevila. Meni se jen prava, jen u nasich roli, nazvu se to netyka. ## 2026-08-26 - prepinac firmy plati pro cely portal Prepinac byl stav uvnitr stranky Prehled. Prepnuti na LogiTrans zmenilo prehled a nic jineho: ostatni stranky volaly API bez `tenantId` a server sahnul po vychozi firme, takze v Lidech zustali lide Automie. To neni nepohodli, to jsou cizi data pod hlavickou jine firmy. ### Zmeneno - **Vybrana firma je jedna hodnota pro cely dashboard** (`web/src/lib/tenant.ts`), ne stav stranky. Prezije obnoveni stranky. - **`tenantId` doplnuje `apiFetch`**, ne jednotlive stranky. Kdyz si to mela pridavat kazda stranka sama, vetsina na to zapomnela - a zapomnetlivost byla prave ta chyba. Nedoplnuje se, kdyz cesta uz firmu nese (proklik z widgetu), u `scope=all` a mimo `/api/dashboard`. - **`useApiQuery` se pri prepnuti zepta znovu.** Bez toho by na strance zustala cisla predchozi firmy, dokud by ji nekdo neobnovil. - **Prepinac je v hlavicce nad obsahem.** Driv byl v Prehledu, ted plati viditelne pro vsechno. Nahradil i text, ktery ukazoval natvrdo prvni firmu ze seznamu bez ohledu na to, co bylo vybrane. - **Ulozena firma, do ktere uzivatel uz nepatri, spadne na vychozi.** Jinak by po odchodu z firmy koncil kazdy dotaz na 403. ### Zjisteno u toho - **Prava se scitaji pres vsechny firmy**, neprepocitavaji se podle vybrane. Kdo je spravce v jedne firme a resitel v druhe, ma po prepnuti porad prava spravce. Data se tim neprolomi, server je filtruje dal podle firmy, ale tlacitka ukazuji vic, nez by mela. Zapsane v [07-firmy-a-prava.md](07-firmy-a-prava.md), sekce Co chybi. ## 2026-08-26 - helpdesk: pozadavek, ktery vidi zadavatel i resitel Zakaznik nemel jak poslat pozadavek. Ticket pritom patri jedne firme, kdezto u helpdesku figuruji dve - ta, ktera se pta, a ta, ktera to resi. ### Pridano - **Pole `Ticket.helpdeskSourceId`** s firmou, ktera pozadavek poslala. Vlastnikem (`tenantId`) zustava ta, ktera ho **resi**. Zamerne tak: kdyby byl vlastnikem zadavatel, mel by resitel pozadavek jen jako cizi ticket a nemel by ho ve sve fronte, ve statistikach ani v prirazovani. Takhle je to na jeho strane obycejny ticket a nemuselo se sahnout na nic, co uz funguje. - **`Tenant.helpdeskProviderId`**, tedy komu firma posila pozadavky. Nastavuje spravce platformy v Nastaveni, Firmy. Kdo koho obsluhuje je obchodni vztah, ne volba klienta - kdyby si dodavatele vybiral uzivatel, poslal by pozadavek nekomu, s kym nema smlouvu. Bez vyplneneho dodavatele se pozadavek nezalozi a rekne se to nahlas. - **Sekce Helpdesk** (`/dashboard/helpdesk`) a router `/api/dashboard/helpdesk`: seznam vlastnich pozadavku, zalozeni, detail s prubehem a komentar. Zamerne to **neni druhy seznam ticketu** - chybi tu filtry, prirazovani i fronta, protoze zadavatele nezajima, kdo to ma u sebe. - **Prava `helpdesk.view` a `helpdesk.create`.** Prideluje je admin te firmy pres role, stejne jako u ostatnich prav. ### Zmeneno - **`listTickets` umi filtrovat podle zdroje** (`helpdeskSourceIds`). Vyplnene **nahrazuje** filtr podle vlastnika, protoze zadavatel vlastnikem neni. Bezny seznam ticketu se nezmenil. - **`getTicket` a `addComment` maji druhou cestu dovnitr.** Firma, ktera pozadavek poslala, ho smi cist a pripsat k nemu komentar, i kdyz ho nevlastni. Komentar je jedina zmena, kterou nad nim smi: stav, resitele a typ urcuje ten, kdo to resi. ## 2026-08-26 - portal prestal ukazovat provozni veci a ticket jde zalozit rucne Sada oprav podle toho, co v portalu drhlo. ### Zmeneno - **Hlasky o ulozisti a o odchozi IP adrese vidi jen spravce platformy.** Kam se uklada a z jake adresy volame ven resime my, ne zakaznik. "Data se ukladaji do souboru na serveru" na nej navic pusobi jako priznani, ze mu tu praci muzeme ztratit. Nemazou se, jen se schovavaji - nam poradi porad. Totez plati pro radek "volano z IP" v historii overeni. - **Typ ticketu se v automatizaci vybira ze seznamu.** Bylo to textove pole, do ktereho mel clovek opsat ID typu odjinud. Novy druh pole `lookup` je **ciselnik a volny text zaroven**: bud se vybere ze seznamu typu te firmy, nebo se hodnota dosadi z dat (`{{data.typ}}`). Typy ticketu jsou vlastnost firmy, takze nabidka chodi za tu, ve ktere clovek je. - **Stav ticketu je otevreny naseptavac, ne ciselnik.** Stav je volny retezec a vzdycky byl - ticket muze prijit z cizi aplikace s jejim vlastnim stavem. Vyber ze seznamu tomu odporoval. Ted je to textove pole s nabidkou toho, co firma uz pouziva (`GET /api/dashboard/tickets/statuses`), a nova hodnota projde stejne dobre. Zapisuje se az pri opusteni pole, ne po kazdem pismenu. - **"Kanal" se prejmenoval na "Odkud pozadavek prisel"** a rika o sobe, ze je nepovinny a slouzi jen k filtrovani a ikone v seznamu. - **Vstupni parametry u webhooku jsou oznacene jako nepovinne.** Webhook prijme cokoliv; rucne vypsany seznam parametru neni podminka, ale pohodli pro podminky - a vyplni se sam z vlepene ukazky tela. Prazdny seznam uz nehlasi, ze "bez nich nelze pridat podminku". ### Pridano - **Zalozeni ticketu rucne** (`POST /api/dashboard/tickets`, pravo `ticket.create`, tlacitko Novy ticket na strance Tickety). Dosud ticket vznikal jen z automatizace nebo z prichozi udalosti, takze pozadavek prijaty telefonem nemel jak do systemu. - **Zakaznik u ticketu je nepovinny.** Rucne zalozeny ticket je casto ukol, ne pozadavek od nekoho zvenku; povinna firma a kontakt by znamenaly, ze si je clovek vymysli. Ve formulari je zakaznik schovany pod odkazem. ### Co z teze davky jeste neni - **Sekce Helpdesk** pro zakaznika vcetne sdileni ticketu mezi admin firmou a tim, kdo ho zalozil. - **Prepinac firmy nad celym dashboardem.** Dnes je to stav uvnitr stranky Prehled, takze se prepnuti neprojevi v Lidech ani jinde - ostatni stranky volaji API bez `tenantId` a server pouzije vychozi firmu. Ma to doplnovat API vrstva na jednom miste, ne kazda stranka zvlast. ## 2026-08-26 - odesilani e-mailu ze schranky firmy Sluzba E-mail byla v katalogu jako popis: bez udaju, bez vykonne casti. Ted se odesila doopravdy, ze schranky, kterou si firma vyplni v konektoru. ### Pridano - **Sluzba E-mail pres SMTP.** V konektoru server, port, sifrovani, uzivatel, heslo, adresa a jmeno odesilatele a adresa pro odpovedi. Zadne udaje v prostredi - kazda firma odesila ze sve schranky. - **Vnitrni krok `email/send`.** SMTP neni HTTP a skript umi jen `ctx.http`, takze operaci vykonava vnitrni krok stejne jako zalozeni ticketu. Pristupove udaje pritom zustavaji v konektoru. - **Druh pole `html`.** Telo zpravy se pise jako HTML a builder ho vykresli jako vysoke pole s neproporcionalnim pismem. Runtime v nem **escapuje dosazene hodnoty**: znacky autora sablony jsou zamer, ostre zavorky v hodnote od zakaznika ne. Bez toho by text ticketu s `` prepsal rozvrzeni zpravy a `