# 05 - Dashboard, builder automatizaci a simulace ## Stranky portalu ``` /dashboard prehled: dlazdice, graf za 14 dni, posledni tickety a incidenty /dashboard/automatizace seznam a zalozeni nove /dashboard/automatizace/:id builder: strom akci /dashboard/konektory katalog sluzeb, jejich spousteču a akci /dashboard/tickety seznam, filtry, prehled vytizeni tymu /dashboard/tickety/:id detail ticketu: prubeh a log, resitel, zakaznik /dashboard/incidenty prehled incidentu /dashboard/nastaveni udaje o uctu ``` V postrannim menu je pod Nastavenim tlacitko **Simulace**. ## Zivy dashboard Portal drzi jedno SSE spojeni pro celou aplikaci. Zajistuje ho `EventStreamProvider` v `web/src/components/dashboard/`. - Stav spojeni ukazuje `LiveIndicator` v horni liste. Uzivatel musi poznat, ze data nejsou ziva. - Prichozi udalosti ukazuje `EventToasts` jako bubliny vpravo dole. - Data se obnovuji sama. `useApiQuery` ma volitelny `refetchOn` se seznamem typu udalosti, po kterych se ma dotaz zopakovat. Vice udalosti tesne po sobe se slouci do jednoho nacteni. Pri vypadku se stream znovu pripojuje s exponencialne rostoucim odstupem az do 15 sekund, aby pri vypadku serveru neubijel provoz. ## Simulace provozu Modalni okno se otevre tlacitkem Simulace. Umoznuje: - zalozit ticket z vybraneho kanalu vcetne celeho logu, ktery k nemu vede, a s prepinacem, jestli se zakaznik v CRM dohleda nebo ne, - vyvolat incident s vlastnim popisem, sluzbou a zavaznosti, - vyresit prvni nevyrizeny ticket nebo bezici incident, - spustit automatizaci uspesne nebo s chybou. Kazda akce opravdu meni data na serveru, takze se projevi i v seznamech a v souhrnu, ne jen v bublinach. ## Strom akci Automatizace se sklada z **spoustece** a **kroku**. Krok je bud akce nad konektorem, nebo podminka se dvema vetvemi - proto je to strom, ne seznam. ```ts interface AutomationFlow { trigger: { connectorId: string; operationId: string; fields: TriggerField[]; // vstupni parametry webhookToken?: string; // generuje vyhradne server } | null; steps: FlowStep[]; } type FlowStep = | { id: string; kind: 'action'; connectorId: string; operationId: string } | { id: string; kind: 'condition'; fieldId: string; operator: string; value?: string; yes: FlowStep[]; no: FlowStep[] }; ``` Podminka odkazuje na `field.id`, ne na nazev. Prejmenovani parametru proto existujici podminky nerozbije. Misto vlozeni urcuje `FlowPath` v `web/src/lib/flow.ts`: prazdne pole je hlavni sekvence, `[{ stepId, branch }]` je vetev konkretni podminky. ## Odkud se berou vstupni parametry Jsou dva druhy spousteču a lisi se tim, kdo urcuje jejich parametry. **Parametry deklaruje uzivatel** (webhook, formular). V katalogu maji `customPayload: true`. V builderu se pridavaji rucne: nazev, typ (text, cislo, ano-ne, datum) a povinnost. **Parametry urcuje sluzba** (e-mail, WhatsApp, hlasova linka, ticket). V katalogu je nese `providedFields`. Builder je ukazuje jen ke cteni a server je pri ulozeni stromu vzdy dosadi z katalogu, jeste pred validaci. Podrobnosti a duvody jsou v [06-tickety.md](06-tickety.md), sekce "Parametry od sluzby". U spoustece typu webhook vygeneruje server pri ulozeni adresu `POST /webhook/`. Podminky pak porovnavaji hodnotu parametru, napriklad `score >= 15`. Nabidka operatoru se ridi typem, na cislo nejde pustit "obsahuje". Tabulka operatoru je na obou stranach - `src/data/conditions.ts` a `web/src/lib/flow.ts`. Server je autorita, kopie na klientovi existuje jen proto, aby UI nenabidlo nesmysl. **Pri zmene upravit obe.** Dokud spoustec nema zadny parametr, nejde pridat podminka - nebylo by podle ceho se rozhodovat. Dialog to vysvetli. ## Sirka karet pri zanoreni Vetve ANO a NE jsou vedle sebe jen tehdy, kdyz je na to v dane karte misto. Rozhoduje **sirka karty, ne sirka okna** - pouzivaji se container queries (`@container` a `@2xl:grid-cols-2` v `FlowCanvas.tsx`). Duvod: kazde zanoreni pulí dostupnou sirku. S beznym `lg:grid-cols-2` vypadal strom na sirokem monitoru dobre v prvni urovni a ve treti uz mel karty siroke par desitek pixelu, takze se popisy lamaly po jednom slove. Container query se od urcite hloubky sama prepne na vetve pod sebou. Ze stejneho duvodu se v uzke karte skryva popis akce (`hidden @xs:block`), zmensuje ikona a ovladaci tlacitka se skladaji do sloupce. Nazev kroku a nastaveni poli zustavaji vzdy videt - to je to podstatne. **Pri uprave stromu nepouzivat `sm:` / `lg:` na veci uvnitr karet.** Reaguji na okno a v zanoreni lzou. ## 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, nastaveni pole, ktere akce nema. **Nedodelky** se ulozi, jen brani zapnuti: chybi spoustec, zadny krok, webhook 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 1. Pridat zaznam do `connectors` v `src/data/connectors.ts` vcetne `triggers` a `actions`. 2. Pokud pouziva novou ikonu, doplnit klic do `web/src/lib/connectorIcons.ts`. Musi existovat v `lucide-react`. 3. Pokud patri do nove kategorie, doplnit ji do `connectorCategories` a do typu `ConnectorCategory` na obou stranach. 4. Pokud spoustec predava vlastni data, deklarovat je v `providedFields`. ID parametru musi zustat stabilni, odkazuji se na ne podminky v ulozenych stromech. Builder i katalog ji vezmou automaticky. ## Co chybi | Chybi | Poznamka | | --------------------------- | -------------------------------------------------------- | | `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 | | 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 | | Drag and drop | presouvani je zatim tlacitky nahoru a dolu |