# 99 - Zaznam zmen
Nejnovejsi nahore.
## 2026-08-03
Tickety predelane na plnohodnotny konektor. Prestavaji byt polozkou v seznamu
a stavaji se prichozim pozadavkem, ktery ma sveho cloveka a dohledatelny prubeh.
Popis modelu je v [06-tickety.md](06-tickety.md).
### Pridano
- Kanaly do ticketu: WhatsApp jako novy konektor, e-mail a hlasova linka
jako plnohodnotne spoustece.
- Konektor Tickety presunut do nove kategorie `servicedesk`, rozsiren
o spoustece `created`, `unknown-customer`, `assigned`, `status-changed`
a akce `assign`, `set-status`, `link-customer`.
- Resitele (`src/data/people.ts`) oddelene od uzivatelu portalu, spojka e-mailem.
- Log ticketu ve strome vcetne toho, co ktera volana sluzba vratila.
- Prehled vytizeni tymu, kdo co ma u sebe, zaroven jako filtr seznamu.
- Detail ticketu `/dashboard/tickety/:id`: prubeh a log, prirazeni, stav,
zakaznik, komentare.
- Filtry seznamu ticketu na serveru: resitel (vcetne `me` a `unassigned`),
stav, kanal.
- `providedFields` v katalogu konektoru: parametry, ktere spoustec predava sam.
- Udalost `ticket.assigned` na sbernici i v portalu.
- Endpointy `/api/dashboard/people`, `/tickets/workload`, `/tickets/:id`
a POST varianty pro assign, status a comment. Vse ve Swaggeru.
### Zmeneno
- `Ticket` ma misto volneho `requester` strukturovaneho `customer` s nullable
`id` firmy v CRM, k tomu `channel`, `assignee` jako odkaz na cloveka
a `automationId`.
- `customer.id === null` je nosna informace, ne chybejici udaj. Prave na ni se
pta podminka "mame zakaznika?" ve strome automatizace.
- Simulace ticketu bere kanal a prepinac, jestli se zakaznik dohleda.
Zakladany ticket dostane cely realisticky log.
- Builder ukazuje parametry od sluzby jen ke cteni. Server je pri ulozeni
vzdy dosadi z katalogu, a to jeste pred validaci stromu.
### Vedome neudelano
Bugs a wishes zustavaji mimo. Vyvojarska agenda ma jiny zivotni cyklus a slucovat
ji s tickety by znamenalo, ze ani jedna evidence nefunguje poradne.
### Doplneno pote
Puvodni verze mela diru: ticket nemel zadny obsah a krok "Zalozit ticket" nesel
nastavit. Slo tedy rict "z WhatsApp udelej ticket", ale ne uz co se ma kam ulozit.
- `Ticket.body` a `Ticket.sourceRef`. Predmet je shrnuti, telo je cely text
pozadavku. `body` vystaveno i ve spoustecich `created` a `unknown-customer`,
takze na obsah ticketu jde udelat podminka v navazne automatizaci.
- Nastavitelna pole akci (`OperationField` a `FlowStep.inputs`). Ticket, e-mail
a WhatsApp maji skutecna pole misto pouhe napovedy.
- Sablony `{{parametr}}` v hodnotach poli (`src/data/templates.ts`) vcetne
nabidky parametru, ktera je vklada na pozici kurzoru.
- Vyber resitele u akci se plni ze seznamu lidi, ne z rucne psaneho ID.
- Nevyplnene povinne pole a odkaz na neexistujici parametr se hlasi jako
nedodelek. Nastaveni pole, ktere akce nema, je chyba 400.
- Akce bez `inputs` to v builderu napisou primo na karte kroku.
### Vystupy kroku a predvalidace
Druha dira: kroky slo vkladat kamkoliv, ale podminka videla jen parametry
spoustece. Slo tedy pridat krok "zeptej se CRM", ale ne se vetvit podle toho,
co vratil. Bez toho byla predvalidace k nicemu.
- `outputFields` v katalogu: co akce vrati dalsim krokum. Ma je "Dohledat firmu"
(`customerKnown`, `companyId`, `companyName`), "Zaradit do kategorie",
"Zalozit obchodni pripad" i "Zalozit ticket".
- Nova akce RAYNET "Dohledat firmu". Nic nezaklada, jen odpovi, jestli
odesilatele zname. Presne pro predvalidaci.
- `src/data/flowScope.ts` pocita, co je videt v kterem miste stromu. Krok vidi
spoustec plus vystupy kroku pred nim. Vetev nepridava nic do sekvence
za podminkou, protoze nemusela probehnout.
- Builder nabizi v podmince i v polich akce presne ty parametry, ktere v danem
miste doopravdy jsou.
- Odkaz na parametr, ktery ve strome neni, je chyba 400. Odkaz na parametr,
ktery vznika az pozdeji, je nedodelek s radou posunout podminku niz.
- Duplicitni jmeno parametru ve scope je nedodelek. V sablone by nesl poznat,
ktery se dosadi.
### Kanaly a vzorove automatizace
- Konektory Facebook Messenger a Instagram, kanaly `facebook` a `instagram`
u ticketu.
- Ctyri nove vzorove automatizace v rozdeleni, ktere odpovida zameru: jedna
na kanal pro prijem, jedna spolecna pro smerovani na resitele.
Prijmove zamerne neprirazuji, smerovani si ticket prevezme a podminkou
`assigned neni splneno` neprepise rucni rozhodnuti.
### Firmy a prava
Treti a nejvazneji dira: portal nemel zadnou tenanci. Kterykoliv prihlaseny
uzivatel videl vsechny tickety vsech firem a cely seznam resitelu, `requireRole`
se nikde nevolal. Popis v [07-firmy-a-prava.md](07-firmy-a-prava.md).
- Tenant jako hranice viditelnosti. `tenantId` na ticketu, resiteli
i automatizaci.
- Uzivatel muze patrit do **vic firem**, v kazde s jinou roli (`memberships`).
Pristup napric firmami je zvlast jako `platformAdmin`.
- Tri pohledy na tickety: `all`, `tenant`, `mine`. Admin mezi nimi prepina,
vcetne vyberu firmy.
- `src/data/access.ts` jako jedine misto, kde se rozhoduje o pravech.
`GET /api/dashboard/access` rekne klientovi, co smi kreslit.
- Filtr na firmu je v ulozistich **povinny argument**. Zapomenuty filtr
neznamena "vse", ale nezkompiluje se.
- Nikdy tise nezuzujeme. Cizi firma vraci 403 nebo 404.
- Prirazeni jen v ramci firmy. Prehazovat praci mezi lidmi smi jen admin,
agent si smi vzit ticket na sebe.
- `requireRole` nahrazen `requirePlatformAdmin`. Prava uvnitr firmy resi
`access.ts`, protoze zavisi na tom, ktera firma pozadavek zajima.
- Demo ucty pokryvaji vsechny tri situace vcetne cloveka ve dvou firmach.
### Nastavitelny dashboard
Prehled byl pevne dany. Ted si ho kazdy sklada sam, popis
v [08-dashboard-widgety.md](08-dashboard-widgety.md).
- Katalog widgetu na serveru vcetne toho, ktere sirky ktery widget unese.
Graf v tretine sloupce se necte, proto se tam ani nenabizi.
- Rezim uprav na `/dashboard`: pridani z nabidky, vyber sirky, poradi sipkami,
odebrani. Ulozi se az tlacitkem, Zrusit vrati puvodni stav.
- Rozlozeni se uklada za **dvojici uzivatel a firma**, ne jen za uzivatele.
- Data nacita prehled a rozdava je widgetum. Deset dlazdic tak neznamena
deset stejnych dotazu.
- Server rozlozeni overuje proti katalogu. Neznamy widget nebo nepodporovana
sirka se neulozi, widget zmizely z katalogu se v prehledu ukaze jako chyba,
ne ze tise zmizi.
### Zapsano jako otevrene rozhodnuti
Vsechny automatizace se stejnym spoustecem se spusti. Doporucene rozdeleni na to
nenarazi, ale az se bude psat runtime, musi se to rozhodnout vedome. Varianty
a doporuceni v [06-tickety.md](06-tickety.md).
## 2026-07-31
Prvni nasazeni aplikace do repozitare csbot-prototype.
Puvodni sablona byla holy Express s endpointy `/` a `/health`. Nahradil ji
kompletni web a klientsky portal.
### Pridano
- Verejny web: homepage se sekcemi, sluzby, o nas, kontakt s formularem, 404.
- Prihlaseni pres JWT s demo ucty.
- Klientsky portal: prehled s grafem, tickety, incidenty, automatizace,
konektory, nastaveni.
- Builder automatizaci: strom akci, spoustec, vetveni podminkou.
- Katalog 25 konektoru v 8 kategoriich.
- Webhook s registrovanou adresou, token generuje server.
- Zivy dashboard pres SSE, vcetne indikatoru spojeni a bublin s udalostmi.
- Simulace provozu pod tlacitkem v postrannim menu portalu.
- Swagger UI na `/docs` a OpenAPI definice na `/openapi.json`.
- Dokumentace ve slozce `documentation/`.
- `.gitignore`, ktery drzi `node_modules` a `dist` mimo repozitar.
### Zmeneno oproti sablone
- Aplikace prepnuta na ESM (`"type": "module"`) a `module: NodeNext`.
- Jeden container obsluhuje API i zbuildovanou React aplikaci z `dist/public`.
- Dockerfile buildu je server i web, vysledny image dostava jen `dist`.
- Port zustava 3000, naslouchani na `0.0.0.0` beze zmeny.
### Reseni reverse proxy
- `ROOT_PATH` se cte z prostredi, nikde neni hardcoded.
- Aplikace se mountuje na koren i na prefix, funguje tedy at Caddy prefix
odstrani nebo ne.
- Server vklada do `index.html` znacku `` a `window.__BASE_PATH__`,
aby SPA nasla soubory i na vnorenych cestach.
- OpenAPI `servers` obsahuje prefix, takze Swagger Try it out vola spravnou adresu.
- Router ma `strict: true`, jinak by se presmerovani `/docs` na `/docs/` zacyklilo.
### Overeno lokalne
S `ROOT_PATH=/apps/csbot-prototype`:
- `/apps/csbot-prototype/health` i `/health` vraci 200,
- `/apps/csbot-prototype/docs` presmeruje na `/docs/`, ta vraci Swagger UI,
- `swagger-ui.css` se nacte pres prefix,
- OpenAPI `servers` obsahuje `/apps/csbot-prototype`,
- `index.html` na vnorene ceste obsahuje spravny ``,
- prihlaseni pres prefix vraci token,
- neexistujici cesta pod `/api` vraci JSON, ne HTML aplikace.
### Znama omezeni
Data jsou v pameti, restart je vrati do vychoziho stavu. Obsah webu je ukazkovy.
Ulozeny strom automatizace se nevykonava.