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>
11 KiB
03 - Architektura a mapa kodu
Technologie
| Vrstva | Technologie |
|---|---|
| Server | Node.js 20, Express 4, TypeScript, ESM |
| Web | React 18, Vite 6, TypeScript, Tailwind 4, React Router 6 |
| Auth | JWT (jsonwebtoken), hesla bcrypt |
| Validace | zod |
| Docs | swagger-ui-express nad rucne psanou OpenAPI definici |
Jeden package.json. Runtime zavislosti jsou v dependencies, nastroje pro build
webu v devDependencies - runtime image je pak instaluje pres --omit=dev.
Build
tsc src/**.ts -> dist/*.js
vite web/ -> dist/public/
Server obsluhuje dist/public jako statiku. Dockerfile kopiruje do vysledneho
image jen dist, takze staci jedna slozka.
Mapa kodu - server
| Cesta | K cemu je |
|---|---|
src/index.ts |
vstupni bod: middleware, mount routeru, statika, SPA, Swagger |
src/config.ts |
cteni environment variables, normalizace ROOT_PATH |
src/openapi.ts |
OpenAPI definice vcetne servers s prefixem proxy |
src/types.ts |
typy uzivatele a JWT payloadu |
src/shared/ |
ciste typove moduly API, jediny zdroj typu pro server i web |
src/middleware/auth.ts |
requireAuth, requireRole, requirePlatformAdmin |
src/middleware/asyncHandler.ts |
wrap, safeRouter: odchyceni odmitnute promise v handleru |
src/middleware/tenant.ts |
attachAccess, tenantOrDeny, scopeOrDeny: firma requestu na jednom miste |
src/middleware/rateLimit.ts |
limit requestu v pameti, 429 s Retry-After |
src/middleware/validation.ts |
validationError, jeden tvar chyby validace |
src/lib/secure.ts |
timingSafeEqualString pro tokeny v adrese |
src/net/guard.ts |
kontrola adresy, cteni tela s limitem, popis chyby site - pro vsechno, co vola ven |
src/events/bus.ts |
sbernice udalosti, ze ktere cerpa SSE stream, udalost nese firmu |
src/routes/auth.ts |
prihlaseni, odhlaseni, kdo jsem |
src/routes/dashboard.ts |
data portalu, tickety, behy, CRUD automatizaci |
src/routes/ticketActions.ts |
akce nad ticketem vcetne vestavenych, pravo za firmu ticketu |
src/routes/settings.ts |
CRUD entit pres crud.ts, uzivatele, ARES |
src/routes/ares.ts |
firma z registru ARES, jen spravce platformy |
src/routes/connectors.ts |
konektory firmy, overeni, nastroje MCP |
src/routes/stream.ts |
SSE stream zmen, filtr podle firem uzivatele |
src/routes/webhook.ts |
verejny prijem dat do automatizace |
src/routes/contact.ts |
poptavkovy formular z webu |
src/ares/client.ts |
klient verejneho API ARES |
src/data/store/ |
tri rezimy uloziste, withCache, withMirror, initStores |
src/data/snapshot.ts |
atomicky zapis JSONu pro rezim file |
src/data/ticketStore.ts |
tickety, jejich resitele, log prubehu, prehled vytizeni |
src/data/people.ts |
resitele ticketu - oddeleni od uzivatelu portalu |
src/data/tenants.ts |
firmy, ktere portal pouzivaji, vcetne udaju z ARES |
src/data/access.ts |
kdo co vidi - jedno misto pro cely portal |
src/data/widgets.ts |
katalog widgetu prehledu |
src/data/dashboardLayouts.ts |
rozlozeni dashboardu za dvojici uzivatel a firma |
src/data/incidentStore.ts |
incidenty vcetne zmen a udalosti, filtr na firmu povinny |
src/data/automationStore.ts |
automatizace, strom akci, tokeny webhooku |
src/data/services.ts |
katalog sluzeb, 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 |
uzivatele portalu, demo ucty |
src/data/mock.ts |
souhrn pro prehled a casova rada grafu |
src/runtime/ |
fronta, worker, executor stromu, vestavene kroky, sandbox skriptu firmy |
src/scripts/ |
skripty konektoru: registr, runner, HTTP, pomocne funkce |
src/mcp/ |
klient MCP, prihlaseni, dialekty, errors.ts se spolecnou chybou prihlaseni |
Mapa kodu - web
| Cesta | K cemu je |
|---|---|
web/src/main.tsx |
vstupni bod, basename routeru podle prefixu proxy |
web/src/App.tsx |
routovani, portal se nacita lazy |
web/src/index.css |
design tokeny a vlastni utility Tailwindu |
web/src/config/brand.ts |
vsechny firemni udaje na jednom miste |
web/src/lib/api.ts |
fetch wrapper, sprava tokenu, skladani adres, auth:expired na 401 |
web/src/lib/eventStream.ts |
cteni SSE streamu pres fetch |
web/src/lib/useApiQuery.ts |
nacitani dat, cache, spolecny debounce, refreshing misto odmontovani |
web/src/lib/collections.tsx |
klientsky sklad ciselniku za firmu, opravovany z udalosti |
web/src/lib/ticketEvents.ts |
oprava seznamu ticketu z payload.ticket bez dotazu |
web/src/lib/useSubmit.ts |
odeslani formulare: saving, chyba, reset na jednom miste |
web/src/lib/options.ts |
pevne ciselniky (priority) |
web/src/lib/useUnsavedChanges.ts |
varovani pri odchodu z rozepsaneho formulare |
web/src/lib/flow.ts |
ciste funkce nad stromem automatizace |
web/src/types/ |
fasada nad src/shared (alias @shared/*), zadne vlastni typy API |
web/src/components/ui/ |
zakladni prvky, Chip |
web/src/components/ui/form/ |
Field, Input, Select, Textarea, controlClass: jedna sada trid |
web/src/components/dashboard/ |
shell portalu, dlazdice, graf, stream, TicketCard |
web/src/components/dashboard/flow/ |
strom akci: FlowCanvas a karty ActionCard, ConditionCard, ForeachCard, StepControls |
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 |
web/src/pages/ |
jedna stranka je jeden soubor |
web/src/pages/dashboard/connectors/ |
casti stranky Konektory: karta, editor, log, nastroje |
Klicova rozhodnuti
Jeden container misto dvou. AppFactory nasazuje jednu aplikaci, proto Express obsluhuje i statiku. Odpada CORS i druha deploy jednotka.
SSE misto WebSocketu. Tok dat je jednosmerny, server ke klientovi. Klient posila zmeny beznym REST volanim. SSE prochazi reverse proxy bez zvlastni konfigurace.
Stream pres fetch, ne pres EventSource. EventSource neumi poslat hlavicku
Authorization a token by musel byt v adrese, odkud se dostane do access logu.
Cenou je rucni parsovani a rucni znovupripojeni v web/src/lib/eventStream.ts.
Ceske cesty v URL. /sluzby, /o-nas, /prihlaseni, /dashboard/tickety.
Kod zustava anglicky.
Uloziste je za rozhranim. Tri rezimy (Postgres, soubor, pamet), jedno
rozhrani a jedno rozhodnuti v initStores. Routy nevedi, ktery rezim jede.
Podrobnosti v 14-databaze.md.
Typy API jsou jednou. Ciste typove moduly v src/shared ctou server i web,
web pres alias @shared/*. Kopie typu na klientovi se jednou rozejde se
serverem a prekladac to nepozna. web/src/types/ je jen fasada, ktera je
re-exportuje; ucet uzivatele bere i AuthContext ze @shared/users.
Kazdy async handler je odchyceny. Routy vznikaji pres safeRouter,
odmitnuta promise skonci jako 500 s logem, ne padem procesu. Bez toho stacil
jeden zapomenuty try a AppFactory restartovala container.
Firma requestu se pocita jednou. attachAccess da do req.access, co
uzivatel smi, a tenantOrDeny z toho odvodi firmu. Kazda route, ktera si to
pocitala sama, to delala trochu jinak.
Filtr na firmu je povinny argument. listTickets, listPeople
i listAutomations vyzaduji tenantIds. Zapomenuty filtr tak neznamena "vse",
ale nezkompiluje se. Podrobnosti v 07-firmy-a-prava.md.
Prava se nikdy nedovozuji na klientovi. Server vraci GET /api/dashboard/access
s tim, co uzivatel smi. Kdyby si to klient pocital sam, pocitalo by se to na dvou
mistech a jednou se to rozejde.
Resitel neni uzivatel. Uzivatel se prihlasuje do portalu, resitel ma u sebe tickety. Technik muze mit tickety a ucet nikdy nemit. Spojka je e-mail, podrobnosti v 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.
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.