Obsah ticketu, nastaveni kroku a vystupy kroku

Ticket dostal telo (body) a odkaz na zdrojovou zpravu. Predmet je shrnuti,
telo je cely text pozadavku.

Akce maji nastavitelna pole (inputs) se sablonami {{parametr}}. Zatim ticket,
kanaly, CRM a AI, ostatni maji jen napovedu.

Krok vidi parametry spoustece plus vystupy kroku pred nim, takze jde vlozit
predvalidaci a vetvit se podle jejiho vysledku. Vetev podminky nepridava nic
do sekvence za podminkou.

Nove konektory Facebook Messenger a Instagram, nova akce RAYNET Dohledat firmu.

Ctyri vzorove automatizace v rozdeleni jedna na kanal pro prijem
a jedna spolecna pro smerovani na resitele.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
JiriUhlir
2026-08-03 12:29:26 +02:00
parent 52b190bfbc
commit dd021b5f69
24 changed files with 1651 additions and 80 deletions
+12 -6
View File
@@ -17,15 +17,18 @@ React aplikaci ze slozky `dist/public`.
| Dashboard | hotovo | prehled, tickety, incidenty, automatizace, nastaveni |
| Zivy dashboard pres SSE | hotovo | zmeny se projevi bez obnoveni stranky |
| Simulace provozu | hotovo | tlacitko v postrannim menu portalu |
| Katalog konektoru | hotovo | 26 sluzeb, 9 kategorii |
| Katalog konektoru | hotovo | 29 sluzeb, 9 kategorii |
| Builder automatizaci | hotovo | strom akci, vetveni podminkou |
| Webhook s registrovanou adresou | hotovo | token generuje server, verejny endpoint validuje data |
| Tickety na konkretni lidi | hotovo | resitel, filtr moje, prehled vytizeni tymu |
| Log ticketu ve strome | hotovo | vcetne toho, co ktera sluzba vratila |
| Kanaly do ticketu | hotovo | WhatsApp, e-mail, hlas a formular jako spoustece |
| Parametry od sluzby | hotovo | katalog je deklaruje, server je dosazuje pri ulozeni |
| Nastaveni poli akci | castecne | ticket, e-mail a WhatsApp ano, ostatni jen napoveda |
| Obsah ticketu a sablony | hotovo | `{{parametr}}` ze spoustece do poli akce |
| Vystupy kroku a predvalidace | hotovo | podminka se umi zeptat, co vratil predchozi krok |
| Kanaly WhatsApp, FB, Instagram | hotovo | vcetne vzorovych automatizaci na prijem |
| Bugs a wishes | chybi | vyvojarska agenda, samostatna evidence vedle ticketu |
| Nastaveni poli akci | chybi | akce zatim neumi cerpat z parametru spoustece |
| Beh automatizaci | chybi | ulozeny strom se nevykonava, neni runtime |
| Databaze | chybi | data jsou v pameti, restart je vrati na vychozi stav |
| Odesilani e-mailu z formulare | chybi | poptavka se zatim jen loguje |
@@ -47,10 +50,13 @@ ale nevznikly vykonanim ulozeneho stromu - runtime neexistuje.
## Dalsi krok
Nejuzitecnejsi pristavek je nastaveni poli akci a s nim predavani dat mezi kroky,
aby slo rict "do e-mailu dej parametr customer ze spoustece". Parametry spoustece
uz existuji na obou stranach, chybi jen jejich pouziti v akcich. Podrobnosti
Nejuzitecnejsi pristavek je runtime. Strom uz nese vsechno potrebne: spoustec
s parametry, podminky a u ticketu i kanalu nastavena pole se sablonami. Chybi
jen to, co ho vykona. Do te doby je ulozena automatizace popis zameru, ne provoz.
Vedle toho zbyva prevest na `inputs` i ostatni konektory a doplnit odkazy
na vystup predchoziho kroku, ne jen na spoustec. Podrobnosti
v [05-dashboard-a-builder.md](05-dashboard-a-builder.md).
Vedle toho stoji za rozmysleni evidence bugs a wishes. Zamerne to nejsou tickety,
Za rozmysleni stoji evidence bugs a wishes. Zamerne to nejsou tickety,
duvod je v [06-tickety.md](06-tickety.md).
+12 -1
View File
@@ -45,6 +45,8 @@ image jen `dist`, takze staci jedna slozka.
| `src/data/automationStore.ts` | automatizace, strom akci, tokeny webhooku |
| `src/data/connectors.ts` | katalog konektoru, jejich spousteču a akci |
| `src/data/conditions.ts` | typy parametru a operatory podminek |
| `src/data/templates.ts` | sablony `{{parametr}}` v nastaveni kroku |
| `src/data/flowScope.ts` | co je videt v kterem miste stromu |
| `src/data/users.ts` | demo uzivatele |
| `src/data/mock.ts` | souhrn pro prehled a casova rada grafu |
@@ -61,7 +63,7 @@ image jen `dist`, takze staci jedna slozka.
| `web/src/lib/useApiQuery.ts` | nacitani dat vcetne obnoveni pri udalosti |
| `web/src/lib/flow.ts` | ciste funkce nad stromem automatizace |
| `web/src/components/dashboard/` | shell portalu, dlazdice, graf, stream, simulace |
| `web/src/components/dashboard/flow/` | strom akci a vyber kroku |
| `web/src/components/dashboard/flow/` | strom akci, vyber kroku, nastaveni poli akce |
| `web/src/components/dashboard/TicketTrace.tsx` | log ticketu jako strom |
| `web/src/components/dashboard/TicketWorkload.tsx` | prehled, kdo co ma u sebe |
| `web/src/components/home/` | sekce homepage |
@@ -92,4 +94,13 @@ podrobnosti v [06-tickety.md](06-tickety.md).
**Filtrovani ticketu dela server.** Klient posila query parametry a dostane hotovy
seznam. Kdyby filtroval sam, ukazoval by jina cisla nez prehled vytizeni.
**Krok vidi jen to, co je pred nim.** Parametry spoustece plus vystupy
predchozich kroku. Vetev podminky nepridava nic do sekvence za podminkou, protoze
nemusela probehnout. Vypocet je v `flowScope.ts`, priklady
v [06-tickety.md](06-tickety.md).
**Sablony odkazuji jmenem, ne ID.** Opak podminek, a je to zamer: `{{subject}}`
uzivatel napise a precte, `{{f_42}}` ne. Rozbite odkazy po prejmenovani se hlasi
jako nedodelek.
**Zadna ticha selhani.** Kazdy `catch` loguje a uzivatel se o chybe dozvi.
+2 -2
View File
@@ -144,8 +144,8 @@ Zamerne meni skutecna data, ne jen posila falesnou notifikaci.
Akce: `ticket.created`, `ticket.resolved`, `incident.started`,
`incident.resolved`, `automation.run`.
U `ticket.created` urcuje `channel`, odkud pozadavek prisel, a podle toho se
poskladá i log ticketu. `knownCustomer: false` znamena, ze CRM firmu nedohleda -
U `ticket.created` urcuje `channel` (whatsapp, facebook, instagram, email, voice,
form, portal), odkud pozadavek prisel, a podle toho se poskladá i log ticketu. `knownCustomer: false` znamena, ze CRM firmu nedohleda -
ticket zustane bez zakaznika i bez resitele a v logu je videt proc.
Nevyplnena pole server doplni ukazkovou hodnotou. U akci s "resolved" se bez
+33 -5
View File
@@ -96,17 +96,46 @@ autorita, kopie na klientovi existuje jen proto, aby UI nenabidlo nesmysl.
Dokud spoustec nema zadny parametr, nejde pridat podminka - nebylo by podle ceho
se rozhodovat. Dialog to vysvetli.
## Co je v kterem kroku videt
Krok vidi parametry spoustece **plus vystupy vsech kroku pred nim**. Akce muze
v katalogu deklarovat `outputFields`, napriklad "Dohledat firmu" vraci
`customerKnown` a `companyName`. Podminka i sablona se na ne muzou odkazat.
Vetev podminky nepridava nic do sekvence za podminkou, protoze nemusela
probehnout. Vypocet je v `src/data/flowScope.ts`, kopie pro UI ve `flow.ts`.
Odkaz na parametr, ktery ve strome vubec neni, je **chyba 400**. Odkaz na
parametr, ktery vznika az v pozdejsim kroku (typicky po presunuti kroku), je
**nedodelek** - ulozi se a rekne se, ze podminku staci posunout niz.
## Nastaveni kroku
Akce muze mit nastavitelna pole (`inputs` v katalogu). Vyplnuji se primo na karte
kroku ve strome. Hodnota je sablona, `{{nazev}}` se nahradi parametrem spoustece,
takze jde rict "do obsahu ticketu dej text zpravy z WhatsApp".
Pod poli je nabidka parametru, kliknuti vlozi odkaz na pozici kurzoru.
Zatim to maji ticket, e-mail a WhatsApp. Ostatni akce maji jen `fields`, coz je
pouha napoveda - builder u nich napise, ze je zatim nejde nastavit. Cilovy stav
je prevest vsechny.
Podrobnosti vcetne toho, proc se odkazuje jmenem a ne ID, jsou
v [06-tickety.md](06-tickety.md), sekce "Sablony".
## Validace
Rozlisuji se dve veci:
**Chyby** vraci 400 a neulozi se: neexistujici konektor nebo operace, operace
spatneho druhu, podminka na neexistujici parametr, operator nesedici na typ,
duplicitni nebo nevalidni nazev parametru.
duplicitni nebo nevalidni nazev parametru, nastaveni pole, ktere akce nema.
**Nedodelky** se ulozi, jen brani zapnuti: chybi spoustec, zadny krok, webhook
bez adresy, podminka bez hodnoty. Vraci se v poli `issues` a builder je vypise.
Rozdelana prace se nikdy nezahazuje.
bez adresy, podminka bez hodnoty, nevyplnene povinne pole akce, sablona
odkazujici na parametr, ktery uz neexistuje. Vraci se v poli `issues` a builder
je vypise. Rozdelana prace se nikdy nezahazuje.
## Pridani konektoru
@@ -125,9 +154,8 @@ Builder i katalog ji vezmou automaticky.
| Chybi | Poznamka |
| --------------------------- | -------------------------------------------------------- |
| Nastaveni poli akci | `fields` u akci se zobrazuji jen jako napoveda |
| `inputs` u zbylych konektoru| zatim ticket, kanaly, CRM a AI, ostatni maji jen `fields` |
| Vazba logu ticketu na beh | log plni simulace, ne vykonany strom |
| Predavani dat do akci | chybi syntaxe odkazu, navrh je `{{trigger.customer}}` |
| Kombinovane podminky | jedna podminka je jedno porovnani, AND a OR jen vnorenim |
| Beh automatizaci | ulozeny strom se nevykonava |
| Historie behu a logy | prazdne, chybi runtime |
+155 -4
View File
@@ -2,9 +2,9 @@
## Co ticket je a co neni
Ticket je **prichozi pozadavek odkudkoliv**. Prisla zprava na WhatsApp, prisel
e-mail, nekdo zavolal na hlasovou linku, odeslal formular. Z toho vznikne ticket,
ktery ma sveho cloveka a dohledatelny prubeh.
Ticket je **prichozi pozadavek odkudkoliv**. Prisla zprava na WhatsApp, Messenger
nebo Instagram, prisel e-mail, nekdo zavolal na hlasovou linku, odeslal formular.
Z toho vznikne ticket, ktery ma sveho cloveka a dohledatelny prubeh.
Ticket **neni** bug ani wish. Vyvojarska agenda je jina vec s jinym zivotnim
cyklem a v prototypu zatim neexistuje. Michat je do jedne evidence by znamenalo,
@@ -31,6 +31,8 @@ a **co ktera sluzba vratila**. Kdyz neco nesedi, neni potreba hadat.
interface Ticket {
id: string;
subject: string;
body: string; // cely text pozadavku, prazdny = krok ho nenaplnil
sourceRef: string | null; // odkaz na zdrojovou zpravu u poskytovatele
channel: 'whatsapp' | 'email' | 'voice' | 'form' | 'portal';
customer: TicketCustomer;
status: 'new' | 'open' | 'waiting' | 'resolved';
@@ -53,6 +55,11 @@ interface TicketCustomer {
ve strome automatizace. Bez toho by nesla postavit vetev "firmu neznam, zaloz
obchodni pripad a nekomu to dej".
`subject` je kratke shrnuti do seznamu, `body` je cely text pozadavku. Do `body`
patri telo e-mailu, zprava z WhatsApp nebo prepis hovoru. Kdyz je prazdne,
znamena to, ze krok "Zalozit ticket" nemel nastavene pole Obsah - detail ticketu
to napise nahlas misto toho, aby ukazal prazdne misto.
Uvnitr ulozista se drzi jen `assigneeId`, jmeno se dopocitava pri cteni. Kdyz
resitel ze seznamu zmizi, ticket nespadne - jen se zaloguje a tvari se jako
neprirazeny.
@@ -146,6 +153,125 @@ Prijata zprava z WhatsApp
NE Zalozit ticket, Zalozit obchodni pripad, Upozornit servicedesk
```
## Co se ticketu preda
Akce "Zalozit ticket" ma nastavitelna pole. Klikni na krok ve strome a vyplnis
je primo tam. Hodnota je **sablona**: `{{nazev}}` se nahradi parametrem
spoustece.
| Pole | Typicka hodnota u WhatsApp |
| ------------ | --------------------------------- |
| Predmet | `Zprava od {{profileName}}` |
| Obsah | `{{text}}` |
| Firma | necha se prazdne, doplni CRM krok |
| Kontakt | `{{profileName}}` |
| Odpoved na | `{{phone}}` |
| Priorita | vyber ze seznamu |
| Resitel | vyber ze seznamu lidi |
Nabidka parametru je pod poli. Kliknuti vlozi `{{nazev}}` na pozici kurzoru,
takze se nemusi psat rucne a neudela se preklep.
Vyber resitele se plni ze seznamu v `people.ts`, ne z rucne psaneho ID. Novy
clovek v tymu se v nabidce objevi sam.
## Co je kde videt
Krok vidi **parametry spoustece plus vystupy vsech kroku, ktere jsou pred nim**.
Diky tomu jde do stromu vlozit predvalidaci a vetvit se podle jeji odpovedi.
Dve pravidla:
- krok vidi to, co je pred nim ve stejne sekvenci, a to, co videl jeho rodic,
- **vetev podminky nepridava nic do sekvence za podminkou**. Vetev nemusela
probehnout, spolehat se na jeji vystup by byla past.
Vystupy akci deklaruje katalog v `outputFields`. Ma je napriklad "Dohledat firmu"
(`customerKnown`, `companyId`, `companyName`), "Zaradit do kategorie"
(`category`, `confidence`) nebo "Zalozit ticket" (`newTicketId`).
Vypocet je v `src/data/flowScope.ts`, kopie pro UI v `web/src/lib/flow.ts`.
## Jak udelat podminku
Tri ruzne pripady, kazdy se resi jinak.
**Na prichozi zpravu.** `text` je parametr spoustece, funguje rovnou:
```
Prijata zprava z WhatsApp
text obsahuje "faktura"
ANO ...
```
**Na vysledek mezikroku.** Tohle je ta predvalidace. Krok "Dohledat firmu" vrati
`customerKnown` a podminka se na nej zepta:
```
Prijata zprava z WhatsApp
Dohledat firmu Telefon {{phone}}
customerKnown je splneno
ANO Zalozit ticket Firma {{companyName}}, Obsah {{text}}
NE Zalozit ticket bez firmy
Zalozit obchodni pripad
```
`{{companyName}}` je uvnitr vetve dostupne, protoze krok "Dohledat firmu" je
pred podminkou. Presne tenhle strom je ve vzorovych automatizacich.
**Na obsah uz zalozeneho ticketu.** Ve stejnem strome nejde, ticket v tu chvili
teprve vznika a "Zalozit ticket" vraci jen `newTicketId`, ne cely ticket. Dela se
**druhou automatizaci** se spoustecem "Zalozen ticket":
```
Zalozen ticket
assigned neni splneno
ANO body obsahuje "faktur"
ANO Priradit resiteli ID {{ticketId}}, Martin Kriz
NE body obsahuje "voicebot"
ANO Priradit Eva Novakova
NE Priradit Karel Vomacka
```
Rozdeleni neni obchazeni omezeni, ale zamer. Prijem z kanalu je jedna
automatizace na kanal, smerovani je jedna spolecna nad vsemi tickety.
## Vzorove automatizace
V `automationStore.ts` jsou nasazene presne v tomhle rozdeleni:
| Automatizace | Co ukazuje |
| -------------------------------- | --------------------------------------------- |
| WhatsApp: zprava do ticketu | predvalidace v CRM a vetveni podle vysledku |
| Facebook: zprava do ticketu | prijem bez predvalidace, nemame podle ceho hledat |
| E-mail: pozadavky do ticketu | dohledani podle `{{from}}`, plus odpoved zadavateli |
| Smerovani ticketu na resitele | jedna spolecna logika nad vsemi tickety |
Prijmove automatizace zamerne **neprirazuji resitele**. Nechavaji ticket ve
fronte a smerovani si ho prevezme. Podminka `assigned neni splneno` na zacatku
smerovani zaridi, ze rucni prirazeni se neprepise.
## Sablony
Odkazuje se **jmenem** parametru (`{{subject}}`), ne jeho ID. Jmeno uzivatel
vidi a pise, `{{f_42}}` by nikdo neprecetl.
Cenou je, ze prejmenovani parametru sablonu rozbije. Proto se to hlida:
- builder podtrhne pole a napise, ktery parametr chybi,
- server to vraci mezi `issues`, tedy jako **nedodelek**, ne jako chybu.
Rozdelana prace se ulozi, jen automatizace nepujde zapnout.
Naopak **chyba (400)** je nastaveni pole, ktere akce v katalogu nema. To uz neni
nedodelek, ale rozbity strom - ulozit ho by znamenalo drzet data, ktera nikdo
neprecte.
Chybejici parametr se pri behu dosadi jako prazdny retezec a zaloguje. Nechat
v textu `{{neco}}` by znamenalo poslat to zakaznikovi.
Akce, ktere `inputs` zatim nemaji, to v builderu napisou primo na karte kroku.
Lepsi nez nechat cloveka hledat nastaveni, ktere neexistuje.
## Parametry od sluzby
Nektere spoustece si data urcuji samy. E-mail posila `from`, `subject`, `body`.
@@ -173,12 +299,37 @@ parametry si deklaruje uzivatel.
/dashboard/tickety/:id detail: prubeh a log, resitel, zakaznik, puvod
```
## Otevrene rozhodnuti pro runtime
Model nema zadne "prvni shoda vyhrava". **Vsechny automatizace se stejnym
spoustecem se spusti, vsechny.** Podminka je uvnitr stromu, ne na spousteci,
takze automatizaci nezastavi pred prvnim krokem.
Doporucene rozdeleni (jedna automatizace na kanal, jedna spolecna na smerovani)
na to nenarazi, protoze kazdy prijem ma jiny spoustec a smerovani je jen jedno.
Problem vznikne, jakmile nekdo udela vic automatizaci nad stejnym spoustecem:
- tri automatizace na "Prijat e-mail", kazda s jinym `obsahuje`, udelaji
z jednoho e-mailu tri tickety,
- dve smerovaci automatizace provedou dve prirazeni a poradi neni dane.
Dnes se to neprojevi, protoze runtime neexistuje. Az se bude psat, je potreba
to rozhodnout vedome, ne omylem. Varianty od nejlevnejsi:
1. **Nechat jak je** a drzet se pravidla jedna automatizace na spoustec.
Funguje dnes, nic se nemeni, ale nikdo to nevynucuje.
2. **Filtr na spousteci.** Automatizace by umela rict "tenhle e-mail neni muj"
jeste pred prvnim krokem. Umozni jednu automatizaci na pravidlo.
3. **Poradi a prvni shoda vyhrava.** Nejmocnejsi, ale chovani zavisle
na neviditelnem poradi se spatne ladi. Nedoporucuje se.
## Co chybi
| Chybi | Poznamka |
| ---------------------------- | ------------------------------------------------------- |
| Bugs a wishes | vyvojarska agenda, samostatna evidence |
| Skutecny beh automatizaci | log ticketu zatim plni simulace, ne runtime |
| Skutecny beh automatizaci | sablony se ukladaji, ale nikdo je nevyhodnocuje |
| `inputs` u zbylych konektoru | zatim ticket, kanaly, CRM a AI, ostatni maji jen napovedu |
| Napojeni logu na beh | `automationId` je odkaz, historie behu ale neexistuje |
| Odpoved zakaznikovi z detailu| akce `send` u kanalu se z portalu nevola |
| SLA a eskalace | zadne lhuty, `capacity` je jen orientacni |
+53
View File
@@ -44,6 +44,59 @@ Popis modelu je v [06-tickety.md](06-tickety.md).
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.
### 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.