Commit Graph
20 Commits
Author SHA1 Message Date
JiriUhlirandClaude Fable 5.1 ea9387bea9 Seed z repozitare, zatezove testy, worker bez spanku, dialogy bez rozmazani
Nastaveni prezije nasazeni: seed/records.json se pri prazdnem ulozisti
nacte misto ukazkovych dat (zive uloziste se nikdy neprepisuje). Soubor
nese soucasny stav produkce (firmy s provozovatelem, role, typ ticketu,
akce, widgety, skupiny, rozlozeni). Novy GET /api/admin/export a skript
npm run seed:export pro dalsi exporty, Dockerfile slozku kopiruje.

Vykonnostni testy (npm run test:perf) nad 200 firmami a 10 000 tickety
a zatezovy skript (npm run load) proti bezici instanci vcetne davky
udalosti na webhook. Mereni odhalilo strop workeru: po obsazeni vsech
mist spal sekundu, takze fronta odbavila nejvys 4 behy za sekundu. Ted
ceka na prvni dokonceny beh: 500 udalosti za 1,3 s (395 behu/s). Strop
posluchacu streamu zvednut na 2 000.

Dialogy: prekryv modalu a menu v portalu bez backdrop-blur, tecka Zive
pulzuje jen pri navazovani spojeni - rozmazani cele obrazovky pod trvalou
animaci sekalo video vedle portalu. Bublina udalosti drzi 0,5 s.

Dokumentace 14, 19, 20, 22, 04, 01, 03, 15 a 99 aktualizovana.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 20:41:42 +02:00
JiriUhlir c25e826766 Poptavka z webu je ticket, prilohy, udaje provozovatele, kolacovy graf
Provozovatel portalu: firma s priznakem portalOperator (jen jedna, zapnuti
odebere ostatnim) a novymi poli contactEmail, contactPhone, website vedle
ico, dic, adresy a pravni formy. Verejny GET /api/public/brand vraci jeji
udaje a web je bere pres useBrand() na kontaktu, v paticce, O nas,
prihlaseni i v titulku; brand.ts je jen zaloha.

Poptavka z webu zaklada u provozovatele ticket kanalu form: predmet
"Poptavka: tema", telo JSON s poli formulare, tag Poptavka plus tema,
zakaznik z formulare, poznamka v logu. Bez provozovatele se jen zaloguje.

Prilohy ticketu: formular az 3 soubory po 5 MB, ticket az 10; nahrani,
seznam, stazeni a smazani (pravo ticket.comment, strop viditelnosti,
poznamky v logu, audit). Soubor jde v JSON jako Base64 a lezi v beznem
ulozisti, bez nove zavislosti; strop tela jen na techto cestach.

Vlastni widget s kreslenim Graf umi i pocet ticketu se seskupenim jako
kolac (PieChart.tsx, ciste SVG, osm barev z tokenu, zbytek jako ostatni).

OpenAPI rozdelene na mensi soubory (102 cest, 28 schemat overeno shodnych),
28 novych testu (135 celkem), dokumentace aktualizovana.
2026-09-09 19:35:00 +02:00
JiriUhlir 22dda2d139 Struktura podle zasad: rozdeleni souboru, lint, testy, prisny TypeScript
Projekt srovnan se zasadami v D:\GitHubRepository\CLAUDE.md bez zmeny chovani.

Struktura: scripts/ (skripty konektoru) -> connectors/, src/scripts ->
src/runtime/scripts; src/index.ts jen startuje, novy src/app.ts s createApp();
routes/dashboard.ts a routes/settings.ts rozdeleny do slozek; openapi.ts
rozdelen na openapi/{index,helpers,components} a paths/* (98 cest overeno
shodnych); ticketStore, automationStore a services jsou fasady nad slozkami
data/tickets, data/automations a data/services/catalog. process.env se cte
jen v config.ts. Web: hooky v hooks/, sdilena ui/Table a ui/ServiceIcon,
surove inputy nahrazeny komponentami, sedm velkych souboru rozdeleno.

Nastroje: eslint (typescript-eslint, react-hooks v7), prettier, editorconfig,
nvmrc, .env.example, vitest; skripty lint, format, test. Lint je cisty bez
jedineho eslint-disable (nove hooky useLatest a useSyncFromSource, odvozeny
stav misto setState v effectu). noUncheckedIndexedAccess v obou tsconfig,
84 mist zuzeno bez non-null operatoru; odhalilo zalohu backoffu fronty pri
nule pokusu a Retry-After NaN pri max 0. Cely kod naformatovan prettierem.

Testy: 8 souboru, 105 testu (prava, viditelnost, podminky a opakovani
v executoru, redaktor tajemstvi, sitove guardy, migrace resitelu, tickety,
health a prihlaseni pres supertest). Testy odhalily dve chyby ve vyhodnoceni
podminek, obe opravene: chybejici castka se porovnavala jako nula a podminka
nad vystupem druheho kroku cetla hodnotu prvniho se stejnym nazvem.

Pojmenovane konstanty misto magickych hodnot, ctx.util.base64 pro skripty
konektoru, README a dokumentace aktualizovany vcetne znamych odchylek.
2026-09-09 15:11:02 +02:00
JiriUhlirandClaude Fable 5.1 42b3da8303 Incident jde otevrit a posunout do dalsiho stavu
Seznam incidentu ukazoval jen titulek a casy, server pritom posilal impact
i diagnostiku. Novy detail /dashboard/incidenty/🆔 co to znamena, ticket,
zdroj, pro spravce platformy cela diagnostika s kopirovanim. Stav jde
posunout (zkoumame, pricina znama, sledujeme, vyreseno), vyreseny vratit
do sledovani. Nove pravo incident.manage, platformni incident meni jen
spravce platformy, zmena jde do auditu. Endpointy GET /incidents/:id
a PATCH /incidents/:id/status, OpenAPI a dokumentace.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 13:30:46 +02:00
JiriUhlirandClaude Fable 5.1 bc6508e1f3 Resitel je clenstvi uctu, firma z ARES, prepinani jazyku schovane
Resitel uz neni vlastni zaznam spojeny s uctem pres e-mail: je to
clenstvi uctu ve firme a jeho ID je ID uctu. Popisek, kapacita, externi
ID a zapnuti visi na clenstvi, takze clovek ve dvou firmach je v kazde
jinak a spravce firmy ho vypne jen u sebe. Odebrani z firmy odebere jen
clenstvi. Stara data se pri startu jednou prevedou (migratePeople.ts),
vcetne odkazu v ticketech, skupinach, automatizacich, akcich a widgetech.
Sprava lidi v zalozce Lide zaklada ucty, pozvanka uz nema volbu resitele.

Zalozeni firmy z registru ARES: hledani podle IC nebo nazvu, dotazeni
IC, DIC, sidla a pravni formy, vyber soucasnych statutarnich zastupcu
a prokury, ucty spravce firmy s nahradnim e-mailem IC-poradi@placeholder.cz.
Vychozi rozlozeni dashboardu bez resitele neobsahuje list.myTickets.

Prepinani jazyku je docasne schovane (MULTILANG_ENABLED), web je cesky.
Dokumentace aktualizovana.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 13:09:35 +02:00
JiriUhlirandClaude Fable 5.1 104ae36783 Revize projektu: prava, vykon, runtime, portal a ARES
Prava a bezpecnost: spravce firmy uz nemuze nastavit priznak spravce
platformy ani clenstvi v cizi firme; pozvanky, konektory a automatizace
kontroluji sve pravo; cizi firma v query je 404; zivy stream posila
udalosti jen firmam, kterych se tykaji; akce nad ticketem maji kontrolu
prava za firmu ticketu a strop viditelnosti; tokeny se nelogujou; limit
pokusu na prihlaseni, kontakt a pozvanky; bezpecnostni hlavicky;
zachyceni chyb v async handlerech; timing-safe porovnani tokenu.

Vykon: audit neskenuje celou kolekci pri kazdem zapisu a konecne maze
firemni zaznamy; ticket se uklada jednou misto trikrat; zapisy do
Postgresu jsou serializovane podle ID; prava se pocitaji jednou na
request; widgety nacitaji tickety jednou; strankovani seznamu; worker
je pool misto kol; na webu udalost ze streamu neodmontuje stranku,
dotazy maji spolecny debounce a cache, ciselniky drzi typovany sklad.

Runtime: opakuji se jen chyby oznacene retryable; smycka nenarazi na
strop 50 kroku (novy strop 1000 akci); podminka nad datem funguje;
vystup MCP nastroje neprepisuje spoustec; sandbox skriptu firmy nejde
opustit; MCP session id se drzi mezi volanimi; incident z kroku patri
firme; jedno rozhodnuti o rezimu uloziste; snapshot neprepise soubor
po chybe cteni.

Refaktory: sdilene typy API v src/shared (web nic nekopiruje, osm
rozjetych tvaru sjednoceno); spolecny modul net/guard pro volani ven;
formularova vrstva ui/form; rozdeleni Connectors a FlowCanvas; jeden
helper pro firmu z query, validaci a CRUD udalosti; pomucky ctx.util
pro skripty konektoru; i18n verejneho webu vcetne anglictiny.

Nova funkce: zalozeni firmy z registru ARES v Nastaveni (IC nebo nazev,
dotazeni IC, DIC, sidla a pravni formy, vyber soucasnych statutarnich
zastupcu a prokury, ucty spravce firmy s nahradnim e-mailem
IC-poradi@placeholder.cz).

Dokumentace: zaznam v 99-zmeny.md a aktualizace 15 dalsich dokumentu.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 10:26:07 +02:00
JiriUhlirandClaude Opus 5 a771834e57 Realne sluzby, OpenAI, odesilani e-mailu a helpdesk
Katalog srovnany s tim, co opravdu bezi na services.csbot.cz/apps:
trinact sluzeb dostalo pristupove udaje a levne cteci overeni, opravena
appId, ktera nikam nevedla (ppl, microsoft365, transcription), a GA4,
Search Console, Google Ads i Sklik ted stoji na aplikaci analytics,
kazda s vlastnimi udaji. Nove sluzby SAP Business One, Google Workspace
a Meta Ads. K tomu 23 skriptu, ktere s nimi opravdu neco delaji.

OpenAI jako prvni sluzba, ktera nebezi u nas: Service.baseUrl s absolutni
adresou, prepis pres <SLUZBA>_BASE_URL nebo adresu u konektoru, predpona
hlavicky u pole udaju (uzivatel vlepi holy klic, Bearer dopise runtime).
Dotaz na model, nahrani souboru, otazka nad souborem, prepis zvuku.
Skript umi odeslat soubor pres ctx.http.postForm (multipart, obsah Base64).

Sluzba E-mail pres SMTP. Neni to skript, ale vnitrni krok - SMTP neni HTTP.
Konektor nese schranku firmy, krok ma HTML telo, ve kterem se dosazene
hodnoty escapuji (znacky autora sablony jsou zamer, ostre zavorky od
zakaznika ne). Overeni konektoru se prihlasi na server a nic neodesle.

Helpdesk: Ticket.helpdeskSourceId drzi firmu, ktera pozadavek poslala,
vlastnikem zustava ta, ktera ho resi - jinak by ho resitel nemel ve sve
fronte. Komu pozadavek pripadne, urcuje Tenant.helpdeskProviderId.
Zadavatel vidi jen svoje pozadavky a smi k nim pripsat komentar.

Opravy v portalu:
- hlasky o ulozisti a odchozi IP vidi jen spravce platformy
- typ ticketu se v automatizaci vybira ze seznamu firmy, nebo dosadi z dat
- stav ticketu je otevreny naseptavac, ne ciselnik
- ticket jde zalozit rucne, zakaznik u nej neni povinny
- kanal se prejmenoval a parametry u webhooku jsou oznacene jako nepovinne
- srovnane markdown tabulky v cele dokumentaci

Co z teto davky jeste neni: prepinac firmy je porad jen stav uvnitr stranky
Prehled, takze se prepnuti neprojevi v Lidech ani jinde.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 07:40:16 +02:00
JiriUhlirandClaude Opus 5 f1e8253169 Log rekne co zpusobilo jakou zmenu, prevzeti ticketu a pozvanky
Nalezeno na bezicim serveru: TK-4946 mel 177 udalosti a 620 radku logu,
pritom se skoro nic nestalo. Zmereno proti fronte: ve stejnem okne vzniklo
presne tolik behu, kolik prislo udalosti (22 a 22), kazdy s jednim pokusem.
Fronta nenasobi nic, odesilatel poslal 177 POSTu. Nase vina byla, ze to
z historie neslo poznat.

- Data udalosti se ukladaji. Kdyz krok nema vlastni, ulozi se to, cim beh
  zacal - u webhooku prijate telo. Prazdna udalost je horsi nez zadna.
- Shodna udalost se pocita (repeats, lastAt), nezaklada dalsi radek. Ticket
  se pritom nemeni, takze duplikat nerozblika dashboard ani nespusti
  automatizaci na zmenu ticketu. Zahodit ji nejde, jinak by nikdo nezjistil,
  ze proti nam neco tluce.
- Zmeny se radi pod udalost, ktera je zpusobila, a u udalosti stoji jmeno
  automatizace. Log se cte jako "prislo tohle -> zmenilo to tohle".
- Poznamka o stavu jen kdyz se stav zmenil. "z in-progress na in-progress"
  u kazde zpravy byl zdroj tech 620 radku.
- runsToday konecne znamena dnes: behy po dnech, k tomu vcera a celkem.
  Dosud to byl citac od zalozeni automatizace, jen se jmenoval "dnes".

Vedle toho prace, o kterou slo predtim:
- Prevzeti ticketu ze skupiny (POST /tickets/:id/claim) a krok Predat skupine
  s prepinacem automatickeho prideleni nejvolnejsimu.
- Pozvanky do firmy: odkaz s nahodnym kodem, heslo si nastavi pozvany.
- Resitele, skupiny a pozvanky presunuty z Nastaveni do zalozky Lide, cleny
  skupiny se vybiraji klikanim.
- Ctyri AI znaky, ktere zbyvaly v kodu, pryc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 15:54:34 +02:00
JiriUhlirandClaude Opus 5 a57eca123e Fronta a worker: webhook odpovi hned, praci udelaji workeri
Webhook uz nic nevykonava v requestu. Zapise udalost do fronty a odpovi 202
do jednotek milisekund; strom vykona worker na pozadi. Za konektory nerucime,
takze cekat na cizi sluzbu v requestu znamena ztracet udalosti pri timeoutu.

Fronta ma opakovani s rostouci prodlevou (30 s, 2 min, 10 min, hodina),
spravedlive poradi po firmach (jedna firma s tisicem udalosti nezablokuje
ostatni), navrat zaseknutych behu po restartu a uklid hotovych. Marna chyba
se neopakuje - chybejici skript za minutu existovat nezacne.

Tri druhy spoustecu: push (webhook), vnitrni udalost (vznik a zmena ticketu)
a pull, tedy pravidelne dotazovani u sluzeb bez webhooku (posta, zpravy).
Planovac jen rekne "je cas", samotny dotaz je prvni krok stromu, takze ma
zaznam v logu a opakuje se pri chybe jako cokoliv jineho.

Kontrakt tela webhooku: kazdy parametr ma cestu (data.order.id,
errors.0.message), takze jde napojit i odesilatel s vnorenym modelem.
U adresy je metoda, ukazka tela a kopiruje se cela adresa vcetne domeny.

Vnitrni kroky, ktere sahaji do naseho uloziste: ticket/upsert (zaloz nebo
dopln podle externiho ID), assign-least-busy, assign-by-external, set-type,
set-stage, add-tags, set-status, incident/create, flow/pause a flow/log.

Faze ticketu jako treti osa vedle stavu a stitku. Stav je zivotni cyklus
a pocitaji se z nej statistiky, faze je workflow daneho typu a muze byt jen
jedna, takze se na ni da spolehnout v podmince.

ID z cizich aplikaci u resitele: voicebot posle voicebotId a ticket skonci
u toho, komu patri. Vazba je na jednom miste, ne v kazde automatizaci.

Kazda chyba zaklada incident se dvema urovnemi: impact cte klient a je
srozumitelny, detail cte admin a je v nem cely beh, ktery krok selhal, cele
hlaseni a data na vstupu. Detail vidi jen spravce platformy.

Ochrana proti smycce: automatizace navazana na zmenu ticketu ticket meni,
cimz se spousti znovu - pri vyvoji to server polozilo. Resi to oznaceni behu
pres AsyncLocalStorage a strop peti behu na jeden ticket za minutu.

Upozorneni pri prideleni prace vcetne cisla u zalozky Tickety. Zivy dashboard:
dlazdice nad nasimi daty na udalost, data z konektoru podle ttlSec s moznosti
vynutit nacteni znovu.

Opraveno: path a intervalSec u spoustece se pri ulozeni zahazovaly; nad
seznamem neslo pouzit contains, takze na stitky neslo postavit podminku;
novejsi vystup kroku ted prekryje starsi misto hlaseni konfliktu.

Overeno dvema scenari proti bezicimu serveru, 34 kontrol: firma se skladem,
expedici a IT, a hovory z voicebota (callSid do externiho ID, status do faze,
prirazeni podle voicebotId, tri zpravy = jeden ticket se tremi udalostmi).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 16:41:02 +02:00
JiriUhlirandClaude Opus 5 5d186dcd2e Runtime vykonava strom, prokliky z widgetu, oprava ukladani rozlozeni
Runtime: `src/runtime/executor.ts` jde krok po kroku, u podminky se vetvi,
do poli dosadi parametry, akci pusti pres runScript a vystupy pripise do
kontextu pro dalsi krok. Cely prubeh jde do logu ticketu vcetne toho, co
sluzba vratila. Pouzivaji ho obe cesty: akce na ticketu i webhook.

Opraveno: rozlozeni dashboardu s vlastnim widgetem se NEDALO ULOZIT.
`validateLayout` znala jen vestaveny katalog, takze kazdy pokus skoncil
hlaskou "widget v katalogu neexistuje" - presne to, co hlasil uzivatel.
Katalog je ted jedna funkce a pouziva ji nabidka i kontrola. Zaroven je
za konkretni firmu, driv slo polozit dlazdici jedne firmy na dashboard druhe.

Prokliky: z widgetu lidi na cloveka, ze seskupeni na vyfiltrovany seznam
ticketu. Odkazy sklada server, protoze on jediny zna filtr widgetu. Seznam
ticketu cte filtr z adresy a umi filtrovat na typ, tag a skupinu.

Tabulky: spolecna `TicketTable` pro seznam i detail osoby. Na mobilu se
neposouva do strany, uzka obrazovka dostane karty. Detail osoby ma velkou
tabulku se zalozkami "ma u sebe" a "vyresil" a prepinacem pohledu.

Odebrano: simulace vcetne tlacitka, dialogu i endpointu. Trojice pohledu
nad tickety - vyber firmy je select, "moje" je prepinac, driv to delalo
totez dvakrat.

Pridan zmereny rozbor kapacity pro 200 firem (19-kapacita-200-firem.md):
soucasny stav to nezvladne, protoze data jsou v pameti a vypis je linearni.
Zmereno na 5 000 ticketech, vcetne toho, co s tim a kolik serveru to chce.

Overeno 7 kontrolami proti bezicimu serveru.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 15:54:17 +02:00
JiriUhlirandClaude Opus 5 29de584df8 Ticketovaci system: udalosti, externi ID, statistiky a widgety nad konektory
Jakakoliv udalost se muze stat ticketem. Prijem je verejny endpoint na firmu
(`POST /webhook/ticket/:token`), takze zalozit ticket jde i bez stavby stromu.

Externi ID je unikatni V RAMCI FIRMY: dalsi zprava se stejnym ID se navesi na
existujici ticket misto zalozeni druheho, a stejne ID u jine firmy je jiny
ticket. Cislo a retezec jsou tentyz klic. Udalosti se drzi cele vcetne
prijatych dat a jdou rozbalit v detailu - je to neco jineho nez log.

Ticket nove nese firstResponseAt, resolvedAt, resolvedById a reopenCount.
Bez nich neslo rict, kdo kolik odbavil ani jak dlouho zakaznik cekal.
`getAgentStats` z toho pocita vykon resitelu vcetne medianovych casu
a vracenych ticketu. Pocet vyresenych sam o sobe odmenuje toho, kdo tickety
zaviral predcasne, proto je vraceni videt vedle nej.

Widgety: klient konecne vola /widget-data. Endpoint existoval, ale nikdo ho
nepouzival, takze vlastni widget hlasil "nepodarilo se zobrazit". Pribyl zdroj
`connector` - co umi zjistit napojena sluzba, jde vytahnout do dlazdice pres
tentyz skript, ktery pouziva krok automatizace. Vysledek se cachuje.

Akce a widgety uz nejsou v nastaveni, maji vlastni zalozku vedle automatizaci.
Telo akce se sklada stromem, ne JSONem v textarei - je to tentyz editor,
jen misto karty spoustece je "spousti clovek tlacitkem na ticketu".

Nova zalozka Lide se seznamem a detailem osoby. Seznam ticketu i lidi ma dva
pohledy, tabulku a dlazdice.

Opraveno: createTicket bral typeId, fields, tags i assigneeGroupId, ale nikdy
je neukladal. Ticket zalozeny s typem zustaval bez typu a bez vlastnich poli.

Dlouhe pomlcky, sipky, vypustky a bullety pryc z celeho projektu.

Overeno 21 kontrolami proti bezicimu serveru v rezimu souboru.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 15:13:09 +02:00
JiriUhlirandClaude Opus 5 afbe948da3 Uloziste pro vsechna data, oprava .gitignore, dodelany navrh rozsireni
.gitignore mel vzorec `data/`, ktery se shodl i se `src/data/`. Sestnact
zdrojovych souboru tim tise chybelo v gitu vcetne cele slozky
`src/data/store/`. Opraveno na `/data/`, stejne v .dockerignore.

Tickety vcetne logu, automatizace, incidenty a rozlozeni dashboardu se po
kazde zmene ukladaji. Pomocnik `withMirror` je opak `withCache`: data se meni
v pameti a zapisuji cela, misto aby se po zapisu znovu nacitala. Citace ID se
pri startu dopocitaji z ulozenych zaznamu, takze novy ticket neprepise stary.

Detail ticketu umi typ, tagy, vlastni pole typu a prehozeni na skupinu.
Nastaveni ma prepnuti spravce na jiny ucet, vychozi jen pro cteni.
Skupiny resitelu chodi spolu s lidmi jednim requestem.

Dokumentace: rejstrik znovupouzitelnych funkci (15), navrh monetizace
a ceny za krok (16), popis nastaveni a prav (17). Doplneny endpointy
do openapi.ts, petice CRUD rout se generuje jednou funkci.

Overeno v rezimu souboru: zmeny prezily tvrde ukonceni procesu a po restartu
byly zpatky vcetne logu ticketu.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 07:46:22 +02:00
JiriUhlirandClaude Opus 5 78e7f99d60 Konektory do Postgresu, pristupove udaje sifrovane
Pristupove udaje konektoru se ukladaji do databaze a prezijou restart. Popis
v documentation/14-databaze.md.

Databaze je volitelna a rezimy jsou oddelene:
- postgres kdyz je DATABASE_URL i SECRETS_KEY
- memory jinak, tedy pri nasazenem mockupu a lokalnim vyvoji bez DB

Rozhodnuti je jen na jednom miste (src/data/connectorStore.ts). Nikde jinde se
nezjistuje, jestli databaze je - kdyby se to rozlezlo po kodu, jedno misto by se
zapomnelo a chovalo by se pak jinak nez zbytek.

Chybejici databaze nesmi shodit start: container, ktery nenastartuje, je pro
AppFactory nefunkcni sluzba. Misto toho se do logu napise proc a portal to ukaze
na strance Konektory. Stejne tak kdyz migrace selzou - psat do rozbiteho
schematu je horsi nez neukladat.

Databaze potrebuje oboji. Bez SECRETS_KEY by se udaje ukladaly v plaintextu
a to je horsi nez ztratit je pri restartu: tabulku vidi kazda zaloha a kazdy
dump pri ladeni.

Pridano:
- pool v src/db/pool.ts vcetne transakci a dbFor(tenantId) jako sev pro budouci
  oddelenou databazi jednoho klienta
- migrace ze src/db/migrations/*.sql pod pg_advisory_lock, jinak je pri rolling
  deployi pusti vsechny instance naraz. Jeden soubor je jedna transakce
- sifrovani AES-256-GCM s nahodnym IV a verzi klice. Nerozsifrovatelna hodnota
  nepada, chova se jako nevyplnena a zaloguje se - jeden rozbity konektor nesmi
  shodit seznam ostatnich
- /health/ready s pingem do DB. /health na databazi zamerne nezavisi, kratky
  vypadek by jinak vedl k restartovani containeru
- GET /api/dashboard/storage a hlaska v portalu o tom, ze data jsou jen v pameti
- jediny vychozi konektor na firmu a sluzbu hlida castecny unikatni index, ne jen
  kod. Dva soubezne zapisy by jinak udelaly dva vychozi

Zmeneno: cteni i zapis konektoru je asynchronni, vcetne validace stromu.

Overeno proti Postgresu 16 v kontejneru: migrace, sifrovani v tabulce, preziti
restartu, rozsifrovani spravnym klicem, degradace pri spatnem klici, PATCH bez
tajneho pole, prepnuti a smazani vychoziho konektoru, pametovy rezim bez
DATABASE_URL. Kontejner po overeni smazan.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 15:08:25 +02:00
JiriUhlirandClaude Opus 5 8ad91a6c28 Rozdeleni na sluzby a konektory, pristupove udaje do konektoru
Slovo "konektor" v kodu znamenalo katalog toho, co umime. Ted znamena napojeni
jedne firmy, tedy to, co tim mysli i uzivatel. Popis modelu je
v documentation/12-sluzby-a-konektory.md.

Tri vrstvy:
- Sluzba: ze iDoklad existuje, co umi a co potrebuje k napojeni. Nase.
- Skript: kod, ktery jednu operaci sluzby opravdu vykona. Nas.
- Konektor: ucet firmy vcetne jejich pristupovych udaju. Firemni.

Pristupove udaje se prestaly cist z environment variables. Cela instance by
mela jedny udaje spolecne a dve firmy by fakturovaly z jednoho uctu. Napojeni
je vlastnost firmy, ne prostredi. Z prostredi zustava jen SERVICES_BASE_URL.

Pridano:
- src/data/services.ts: sluzba nese general, appId, visibility, credentials
  a verifyPath. Kategorie "obecne" sdruzuje veci, ktere ma kazdy a nepotrebuji
  konektor: webhook, planovac, tickety, transformace dat, HTTP pozadavek,
  pauza, zapis do logu
- viditelnost sluzby: vsichni, jen uvedene firmy a lide, nebo jen spravce
  platformy. Neviditelna sluzba se z API nevraci vubec, ne se stavem 403 -
  firma nema poznat, ze takova sluzba existuje
- src/data/connectorStore.ts: konektory za firmu vcetne hodnot udaju. Hodnoty
  se z API nikdy nevraci, jen filled a missing. Prazdne pole hodnotu nemeni,
  takze ulozeni formularu bez tajnych hodnot nic nepresepe
- FlowStep.connectorId: krok rika, pod kterym napojenim volat. null = vychozi
  konektor firmy, diky tomu je vzorovy strom prenositelny mezi firmami
- overeni konektoru pres verifyPath, tedy cteci volani vyzadujici autorizaci.
  U sluzby bez nej se overi jen dostupnost a odpoved to rekne nahlas, jinak by
  zeleny vysledek uzivateli lhal
- stranky /dashboard/sluzby a /dashboard/konektory vcetne formularu udaju
- endpointy /api/dashboard/services a CRUD /api/dashboard/connectors ve Swaggeru
- predvyplnene prihlaseni spravcem platformy a prepinac demo uctu na login
  strance, kvuli testovani prototypu

Zmeneno:
- stav "napojeno" se prestal cist z katalogu a zacal pocitat z konektoru firmy.
  Sluzba ma jen available nebo planned
- validace stromu overuje i konektor. Cizi konektor je chyba, chybejici
  napojeni nedodelek - rozdelana prace se nezahazuje
- prejmenovani napric kodem: Connector na Service, FlowStep.connectorId na
  serviceId, GET /connectors na GET /services, connectorIcons na serviceIcons,
  stranka Konektory (katalog) na Sluzby. Prevodni tabulka je v dokumentu 12

Overeno: npm run typecheck prochazi na serveru i webu.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 14:11:50 +02:00
JiriUhlirandClaude Opus 5 6f6b287d7e Skripty konektoru: vykonna cast s manifestem a kontrolou parametru
Konektory dostaly vykonnou cast. Jeden skript je jeden soubor, ktery nese
manifest (vstupni a vystupni parametry) i kod. Diky manifestu s nim umi
pracovat strom automatizace, aniz by o kodu cokoliv vedel.

Soubory jsou zamerne obycejny JavaScript, ne TypeScript. TypeScript by se
musel prelozit a to je presne to otaceni, ktere tady nema byt. Registr
sleduje cas zmeny souboru, takze uprava v portalu, rucni uprava souboru
i novy soubor ve slozce funguji stejne a bez restartu.

Pridano:
- scripts/ se skripty konektoru, nazev souboru je zaroven ID operace
- kontrola vstupu i vystupu proti manifestu, jedna funkce pro obe strany.
  Chybejici povinny vystup je chyba skriptu, ne uzivatele - jinak by strom
  veril parametru, ktery nikdy nedosel
- ctx predavany skriptu: http nad adresou napojeni, util, log, config,
  idempotencyKey, fail a retry. Skript nedostane pristupove udaje
- rozliseni opakovatelne a koncove chyby. Runner nikdy nevyhodi vyjimku,
  vzdy vraci vysledek vcetne retryable
- redakce tajnych hodnot pred zapisem do logu. Cizi API rado vraci prijaty
  token v chybove zprave a log ticketu vidi klient
- napojeni z environment variables vcetne iDokladu
- sest ukazkovych skriptu pro iDoklad proti skutecnemu API sluzby
  services.csbot.cz/apps/idoklad, kazdy na jiny vzor
- stranka /dashboard/skripty: seznam, manifest, editor, zkusebni spusteni.
  Formular testu se sklada z manifestu, nepise se pro kazdy skript
- endpointy /api/dashboard/scripts vcetne Swaggeru

Zmeneno:
- katalog konektoru uz neni jen staticky seznam. Akce ze skriptu se domeruji
  prekryvem v src/data/connectors.ts, takze se naraz objevi ve validaci
  stromu, ve vypoctu scope i v sablonach. Pri stejnem ID vyhrava skript
- ConnectorOperation ma implementation a scriptId
- ApiError na klientovi nese cele telo odpovedi a umi z nej vytahnout issues
- Dockerfile kopiruje scripts/ do vysledneho image

Ukladani nemuze rozbit fungujici skript: kod se nejdriv zapise do docasneho
souboru, ten se nacte a overi, a az pak prepise puvodni.

K tomu tri dokumenty navrhu dalsich kroku: 09 datove modely a prava,
10 runtime a rozpocet na 150 klientu, 11 popis skriptu konektoru.

Overeno: npm run typecheck prochazi na serveru i webu.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 13:37:58 +02:00
JiriUhlir bbc2236c0d dashboard widgets 2026-08-03 13:10:41 +02:00
JiriUhlirandClaude Opus 5 2a3d75c85e Firmy a prava: tenance napric portalem
Portal nemel zadnou tenanci. Kterykoliv prihlaseny uzivatel videl vsechny
tickety vsech firem i cely seznam resitelu, requireRole se nikde nevolal.

Tenant je hranice viditelnosti, tenantId na ticketu, resiteli i automatizaci.
Uzivatel muze patrit do vic firem, v kazde s jinou roli. Pristup napric firmami
je zvlast jako platformAdmin.

Tri pohledy na tickety: all, tenant, mine. Admin mezi nimi prepina vcetne
vyberu firmy. O pravech rozhoduje jedine data/access.ts, klient si nic
nedovozuje a bere je z GET /api/dashboard/access.

Filtr na firmu je v ulozistich povinny argument, takze zapomenuty filtr
neznamena vse, ale nezkompiluje se. Cizi firma vraci 403 nebo 404, nikdy
tise zuzeny vysledek.

Prirazeni jen v ramci firmy. Prehazovat praci mezi lidmi smi jen admin,
agent si smi vzit ticket na sebe.

Zmena prihlasovani: ucet klient@firma.cz zanikl, demo ucty jsou nove.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 12:59:30 +02:00
JiriUhlirandClaude Opus 5 dd021b5f69 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>
2026-08-03 12:29:26 +02:00
JiriUhlir 52b190bfbc updated tickets 2026-08-03 11:45:35 +02:00
JiriUhlir 7b045a9f20 Nahrazeni sablony kompletnim webem a klientskym portalem
Web a portal Automia v jednom containeru. Express obsluhuje API
i zbuildovanou React aplikaci z dist/public.

Obsah:
- verejny web: homepage, sluzby, o nas, kontakt, 404
- prihlaseni pres JWT, demo ucty
- portal: prehled s grafem, tickety, incidenty, automatizace, konektory
- builder automatizaci: strom akci, vetveni podminkou
- katalog 25 konektoru v 8 kategoriich
- webhook s registrovanou adresou, token generuje server
- zivy dashboard pres SSE vcetne simulace provozu
- Swagger UI na /docs a OpenAPI na /openapi.json

Soulad s AGENTS.md:
- ROOT_PATH z prostredi, prefix proxy nikde nehardcodovan
- mount na koren i na prefix, funguje s handle_path i bez nej
- base tag a window.__BASE_PATH__ vkladane do index.html za behu
- OpenAPI servers obsahuje prefix, Try it out vola spravnou adresu
- povinne /health a /docs, port 3000, naslouchani na 0.0.0.0
- secrets jen z environment variables, nikdy v logu

Dokumentace ve slozce documentation/.
2026-07-31 17:00:37 +02:00