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.
This commit is contained in:
@@ -33,7 +33,7 @@ Ctyri pojmy. Plete se to a z te zamneny vznikaji nejhorsi chyby.
|
||||
| Pojem | Co to je | Ciji je |
|
||||
| ------------ | ----------------------------------------------- | ------------ |
|
||||
| **Sluzba** | co umime: iDoklad, e-mail, MCP server, webhook | nase |
|
||||
| **Skript** | vykonna cast operace, obycejny JS ve `scripts/` | nase |
|
||||
| **Skript** | vykonna cast operace, obycejny JS v `connectors/` | nase |
|
||||
| **Konektor** | pristupove udaje jedne firmy k jedne sluzbe | firmy |
|
||||
| **Krok** | jedno pouziti operace v automatizaci | automatizace |
|
||||
|
||||
@@ -46,6 +46,46 @@ jeden pristupovy udaj.
|
||||
|
||||
## Pravidla, ktera plati vsude
|
||||
|
||||
Obecne zasady (struktura projektu, lint, testy, navrh kodu) jsou
|
||||
v `D:\GitHubRepository\CLAUDE.md` a tenhle projekt se jimi ridi. Tady je jen
|
||||
to, co je specificke pro portal, a par zasad, ktere se tu nejvic porusovaly.
|
||||
Kde se projekt od zasad lisi, je to zapsane jako znamy stav
|
||||
v [01-prehled-a-stav.md](01-prehled-a-stav.md).
|
||||
|
||||
**`process.env` se cte jen v `src/config.ts`.** Kazda promenna ma vychozi
|
||||
hodnotu, komentar a radek v `.env.example`. Jedina vyjimka s dynamickym nazvem
|
||||
je `config.serviceBaseUrlOverride('<SLUZBA>_BASE_URL')`, protoze sluzby
|
||||
pribyvaji v katalogu a vypisovat kazdou do konfigurace by znamenalo dve mista.
|
||||
`process.env` jinde v `src/` je chyba, i kdyz "je to jen jedna promenna".
|
||||
|
||||
**Testy lezi v `tests/` se stejnou cestou jako modul.**
|
||||
`tests/data/tickets.test.ts` testuje `src/data/tickets/`. Bezi v rezimu pameti
|
||||
(`tests/setup.ts`), bez databaze a bez site; co potrebuji ven, dostanou vstrikle.
|
||||
Aspon na logiku, ktera rozhoduje o pravech, penezich a datech. Aplikace se
|
||||
v testu stavi pres `createApp()` ze `src/app.ts`, ne pres `index.ts`, aby se
|
||||
neotevrel port.
|
||||
|
||||
**Pred predanim prace lint a typecheck.** `npm run lint` a `npm run typecheck`
|
||||
maji byt ciste, bez `eslint-disable`. Spousti se ale jen se svolenim
|
||||
uzivatele (pravidlo 2 v CLAUDE.md), takze se o ne pozada, nespusti se "pro
|
||||
kontrolu".
|
||||
|
||||
**Sdilene UI prvky jsou komponenty v `components/ui`.** Pole formulare,
|
||||
tlacitka, odznaky, tabulky, dialogy. Stranka, ktera si kresli vlastni `<input>`
|
||||
nebo vlastni `<table>`, je chyba, i kdyz je to poprve - presne tak vzniklo
|
||||
13 verzi `inputClass` a ctyri tabulky v jinem odstinu.
|
||||
|
||||
**Pravidlo tri.** Stejny kus se poprve napise, podruhe se snese kopie,
|
||||
potreti se vytahne. Vytahnout se ma **tentyz pojem**, ne jen podobny kod:
|
||||
`Table` v `ui/` vznikl ze ctyr seznamu, ale huste tabulky ticketu a vykonu
|
||||
zustavaji zvlast, protoze jsou to jine tabulky.
|
||||
|
||||
**Soubor nad 500 radku je signal k rozdeleni.** Route, uloziste i stranka
|
||||
se deli podle odpovednosti, ne podle delky; puvodni cesta zustava jako fasada
|
||||
(`ticketStore.ts`, `automationStore.ts`, `services.ts`), aby se nemusely
|
||||
menit importy. Ktere soubory limit stale prekracuji a proc, je
|
||||
v [03-architektura-a-mapa-kodu.md](03-architektura-a-mapa-kodu.md).
|
||||
|
||||
**Filtr na firmu je povinny argument.** `listTickets(tenantIds)`,
|
||||
`getConnector(id, tenantIds)`, `listConnectors(tenantIds)`. Zapomenuty filtr tak
|
||||
neznamena "vse", ale nezkompiluje se. Cizi zaznam se chova jako neexistujici
|
||||
@@ -68,7 +108,7 @@ cely strom a zustane bila plocha. Obsah portalu je proto v pojistce
|
||||
v konzoli prohlizece uzivatele. Pomocna funkce, ktera jen neco vykresluje,
|
||||
si navic ma chybu osetrit sama a degradovat, ne spadnout.
|
||||
|
||||
**Katalog je zdroj pravdy.** Co neni v `src/data/services.ts`, to nejde ulozit
|
||||
**Katalog je zdroj pravdy.** Co neni v `src/data/services/catalog/`, to nejde ulozit
|
||||
do stromu. Validace pri ukladani se pta katalogu, ne klienta.
|
||||
|
||||
**Ve strome je vsechno retezec.** Hodnota kroku je sablona (`{{subject}}`),
|
||||
@@ -132,8 +172,8 @@ Tri cesty, kazda ma svuj duvod:
|
||||
|
||||
| Cesta | Kdy | Kde |
|
||||
| -------------------- | --------------------------------------- | ----------------------------- |
|
||||
| **Zapis v katalogu** | popis toho, co umime nebo budeme umet | `src/data/services.ts` |
|
||||
| **Skript** | volani cizi sluzby pres HTTP | `scripts/*.js` + manifest |
|
||||
| **Zapis v katalogu** | popis toho, co umime nebo budeme umet | `src/data/services/catalog/` |
|
||||
| **Skript** | volani cizi sluzby pres HTTP | `connectors/*.js` + manifest |
|
||||
| **Vnitrni krok** | sahá do naseho uloziste, nebo neni HTTP | `src/runtime/builtinSteps.ts` |
|
||||
|
||||
Runtime zkousi **nejdriv vnitrni krok, pak skript**. Kdyz operace nema ani
|
||||
@@ -202,7 +242,8 @@ prvni misto, kam se divat.
|
||||
**Novou sluzbu** popiste v katalogu vcetne `credentials` a `verifyPath`. Bez
|
||||
`verifyPath` overeni konektoru nerika nic o udajich, jen ze neco odpovida.
|
||||
|
||||
**Novy endpoint** patri do `src/openapi.ts`. Neni to volitelne, vyzaduje to
|
||||
**Novy endpoint** patri do `src/openapi/paths/<router>.ts` (jeden soubor na
|
||||
router, sklada je `src/openapi/index.ts`). Neni to volitelne, vyzaduje to
|
||||
`AGENTS.md`, a nezdokumentovany endpoint neexistuje pro nikoho krome toho, kdo
|
||||
ho napsal.
|
||||
|
||||
|
||||
@@ -77,6 +77,10 @@ React aplikaci ze slozky `dist/public`.
|
||||
| Formularova vrstva | hotovo | `ui/form`, `useSubmit`, `options`, jedna sada trid |
|
||||
| Firma z registru ARES | hotovo | IC nebo nazev, statutari jako ucty, jen spravce platformy |
|
||||
| Sdilene typy `src/shared` | hotovo | web je re-exportuje pres `@shared/*`, nic nekopiruje |
|
||||
| Struktura podle zasad | hotovo | `index.ts` a `app.ts`, routy a data po slozkach, `connectors/` |
|
||||
| Lint a formatovani v repu | hotovo | eslint a prettier, `npm run lint` cisty bez vyjimek |
|
||||
| Prisny TypeScript | hotovo | `noUncheckedIndexedAccess` v obou tsconfig, zadne `!` |
|
||||
| Testy | castecne | vitest v `tests/`, 8 souboru a 105 testu: prava, tickety, executor, sit, health |
|
||||
|
||||
## Znama omezeni
|
||||
|
||||
@@ -114,6 +118,19 @@ Log ticketu uz plni skutecny beh: kazdy krok stromu se do nej zapise vcetne
|
||||
toho, co sluzba vratila. Ukazkova sada ticketu ma log psany rucne, aby bylo
|
||||
co ukazat i na prazdne instanci.
|
||||
|
||||
### Znamy stav proti zasadam
|
||||
|
||||
Projekt se ridi `D:\GitHubRepository\CLAUDE.md`. Kde se od nej lisi, je to
|
||||
zamer nebo odlozena prace, ne opomenuti:
|
||||
|
||||
| Odchylka | Proc a co s tim |
|
||||
| ------------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| jeden `package.json` pro server i web | mala aplikace v jednom containeru; workspaces az bude mit kazda strana vlastni build |
|
||||
| logovani `console.*` s prefixem modulu | strukturovany logger (`pino`) zatim neni potreba, prefix `[modul]` staci k dohledani |
|
||||
| zadny soubor CI | lint, typecheck a testy se spousti rucne se svolenim (pravidlo 2) |
|
||||
| testy jen na cast logiky | pokryta prava, tickety, executor, cteni tela a health; routy nastaveni a runtime fronty cekaji |
|
||||
| ctyri soubory nad 500 radku | `AutomationDetail`, `TicketDetail`, `MappingEditor`, `catalog/ticket.ts`; duvod v [03-architektura-a-mapa-kodu.md](03-architektura-a-mapa-kodu.md) |
|
||||
|
||||
## Dalsi krok
|
||||
|
||||
Runtime je hotovy: fronta, worker jako pool, opakovani jen u chyb, ktere
|
||||
|
||||
@@ -99,7 +99,7 @@ shodovala i s `/docs/` a presmerovani by se zacyklilo.
|
||||
```
|
||||
|
||||
Diky tomu tlacitko Try it out vola endpointy pres prefix, ne na koreni domeny.
|
||||
Definici sestavuje `src/openapi.ts`.
|
||||
Definici sestavuje `src/openapi/paths/*.ts`.
|
||||
|
||||
Pozn.: `/api/dashboard/stream` je Server-Sent Events. Swagger UI streamovanou
|
||||
odpoved rozumne nezobrazi, testuje se prohlizecem nebo curlem.
|
||||
|
||||
@@ -10,10 +10,11 @@
|
||||
| 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`.
|
||||
Jeden `package.json` pro server i web (znamy stav, viz nize). Runtime zavislosti
|
||||
jsou v `dependencies`, nastroje pro build webu v `devDependencies` - runtime
|
||||
image je pak instaluje pres `--omit=dev`.
|
||||
|
||||
## Build
|
||||
## Build a kontroly
|
||||
|
||||
```
|
||||
tsc src/**.ts -> dist/*.js
|
||||
@@ -21,17 +22,52 @@ vite web/ -> dist/public/
|
||||
```
|
||||
|
||||
Server obsluhuje `dist/public` jako statiku. Dockerfile kopiruje do vysledneho
|
||||
image jen `dist`, takze staci jedna slozka.
|
||||
image `dist` a `connectors/` - skripty konektoru se ctou za behu ze souboru,
|
||||
ne z buildu.
|
||||
|
||||
| Prikaz | Co dela |
|
||||
| ---------------------- | ------------------------------------------------------------- |
|
||||
| `npm run build` | server (`tsc`) a web (`vite build`) |
|
||||
| `npm run typecheck` | `tsc --noEmit` pro oba `tsconfig`, nic nezapisuje |
|
||||
| `npm run lint` | `eslint .`: server, web, testy i `connectors/` |
|
||||
| `npm run format` | `prettier --write .`; `format:check` jen kontroluje |
|
||||
| `npm run test` | `vitest run` nad `tests/**`; `test:watch` pri vyvoji |
|
||||
|
||||
Build, lint i testy se spousti **jen se svolenim uzivatele** (pravidlo 2
|
||||
v `D:\GitHubRepository\CLAUDE.md`).
|
||||
|
||||
Oba `tsconfig` maji `strict`, `noUncheckedIndexedAccess`, `noUnusedLocals`
|
||||
a `noFallthroughCasesInSwitch`. Index do pole nebo slovniku je tak
|
||||
`T | undefined` a kod to musi osetrit; `!` na umlceni se nepouziva. Prave
|
||||
tahle volba odhalila dve skryte chyby (prodleva fronty a `Retry-After`),
|
||||
viz [99-zmeny.md](99-zmeny.md).
|
||||
|
||||
## Nastroje v korenu
|
||||
|
||||
| Soubor | K cemu |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `eslint.config.js` | typescript-eslint, `react-hooks` v7 pro web, `connectors/**` jako obycejny JS bez globalu; zadne `any`, zadny prazdny `catch` |
|
||||
| `.prettierrc`, `.prettierignore` | jednotne formatovani (jednoduche uvozovky, sirka 100) |
|
||||
| `.editorconfig` | odsazeni, konce radku a kodovani pro editor |
|
||||
| `.nvmrc` | Node 20, stejne jako `engines` v `package.json` |
|
||||
| `.env.example` | vsechny promenne prostredi s popisem; `.env` neni v gitu |
|
||||
| `vitest.config.ts` | testy z `tests/**/*.test.ts`, alias `@shared`, `tests/setup.ts` pred kazdym souborem |
|
||||
| `tests/tsconfig.json` | typecheck testu nad `src/` bez emitu |
|
||||
| `Dockerfile` | vicefazovy build, runtime jen s `--omit=dev`, kopiruje `dist` a `connectors` |
|
||||
|
||||
## 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/index.ts` | start: nacteni dat, worker, `listen`, signaly, `process.on`; nic jineho |
|
||||
| `src/app.ts` | `createApp()`: middleware, routery, health, Swagger, statika, SPA. Bez `listen`, aby sla postavit v testu (supertest) |
|
||||
| `src/config.ts` | **jedine misto, kde se cte `process.env`**; `serviceBaseUrlOverride(variable)` pro `<SLUZBA>_BASE_URL` |
|
||||
| `src/openapi/index.ts` | `buildOpenApiDocument()`: sklada dokument, `servers` s prefixem proxy |
|
||||
| `src/openapi/helpers.ts` | `crudPaths` a opakujici se parametry, tela a odpovedi |
|
||||
| `src/openapi/components.ts` | schemata a zabezpeceni |
|
||||
| `src/openapi/paths/*.ts` | cesty po routerech: `ops`, `auth`, `dashboard`, `tickets`, `automations`, `settings`, `connectors`, `scripts`, `helpdesk`, `invites`, `admin`, `contact`, `webhook` |
|
||||
| `src/types.ts` | typy uzivatele a JWT payloadu |
|
||||
| `src/shared/` | ciste typove moduly API, jediny zdroj typu pro server i web |
|
||||
| `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 |
|
||||
@@ -41,18 +77,34 @@ image jen `dist`, takze staci jedna slozka.
|
||||
| `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/crud.ts` | `crudRouter`: fabrika CRUD nad jednou entitou |
|
||||
| `src/routes/dashboard/index.ts` | mount routeru dashboardu, `attachAccess` jednou za request |
|
||||
| `src/routes/dashboard/misc.ts` | prava, prehled, uloziste, katalog sluzeb |
|
||||
| `src/routes/dashboard/tickets.ts` | seznam s filtrem, rucni zalozeni, stavy, vytizeni, detail |
|
||||
| `src/routes/dashboard/people.ts` | resitele pro nabidky a detail cloveka |
|
||||
| `src/routes/dashboard/automations.ts` | strom akci, validace, webhook, fronta behu |
|
||||
| `src/routes/dashboard/incidents.ts` | incidenty: seznam, detail, posun stavu |
|
||||
| `src/routes/dashboard/layout.ts` | katalog widgetu a ulozene rozlozeni |
|
||||
| `src/routes/dashboard/intake.ts` | adresa prijmu udalosti a jeji obnova |
|
||||
| `src/routes/dashboard/notifications.ts` | upozorneni a pocet otevrenych ticketu |
|
||||
| `src/routes/dashboard/clientCrash.ts` | hlaseni padu portalu, z nej incident |
|
||||
| `src/routes/dashboard/shared.ts` | strankovani: `pageFrom`, `paginate` |
|
||||
| `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/settings/index.ts` | mount routeru nastaveni |
|
||||
| `src/routes/settings/{tenants,users,roles,people,groups,features,ticketTypes,actions,widgets}.ts` | jedna entita = jeden soubor nad `crudRouter`; `people` a `users` maji vlastni handlery |
|
||||
| `src/routes/settings/catalog.ts` | co jde v nastaveni zvolit: prava, moduly, limity, widgety |
|
||||
| `src/routes/settings/shared.ts` | `memberOf` pro ucty a resitele |
|
||||
| `src/routes/ares.ts` | firma z registru ARES, jen spravce platformy |
|
||||
| `src/routes/connectors.ts` | konektory firmy, overeni, nastroje MCP |
|
||||
| `src/routes/scripts.ts`, `tenantScripts.ts` | skripty konektoru a skripty firmy |
|
||||
| `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/ticketStore.ts` | fasada nad `src/data/tickets/`, importy zustavaji |
|
||||
| `src/data/tickets/` | `index` (verejne API), `model` (tvar, `toTicket`), `state` (pamet a indexy), `persist` (zapis, `initTickets`), `queries` (seznam, detail, strop viditelnosti), `store` (zapisy: zalozeni, stav, resitel, typ, tagy, skupina, komentar), `intake` (udalost zvenku), `trace` (log prubehu), `stats` (vytizeni a vykon), `seed`, `remap` |
|
||||
| `src/data/people.ts` | resitele jako pohled na clenstvi uctu (`personView`), skupiny |
|
||||
| `src/data/migratePeople.ts` | jednorazovy prevod starych zaznamu resitelu `ppl_` na ucty |
|
||||
| `src/data/tenants.ts` | firmy, ktere portal pouzivaji, vcetne udaju z ARES |
|
||||
@@ -60,16 +112,21 @@ image jen `dist`, takze staci jedna slozka.
|
||||
| `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/automationStore.ts` | fasada nad `src/data/automations/` |
|
||||
| `src/data/automations/` | `index`, `model` (tvar, `rulesOf`, `matchOf`), `state` (pamet, citac ID), `persist` (zapis, `initAutomations`), `store` (cteni a zapisy, `recordRun`), `validation` (pocet kroku, nedodelky, druh), `webhook` (token, posledni volani), `runs` (historie po dnech), `seed`, `seedDemo`, `remap` |
|
||||
| `src/data/services.ts` | fasada nad `src/data/services/` |
|
||||
| `src/data/services/index.ts` | katalog za behu: `findService`, `actionsFor`, `setScriptActions`, `setMcpOperations`, `withRuntimeOptions`, `serviceCatalog` |
|
||||
| `src/data/services/catalog/` | staticky zapis po skupinach: `triggers`, `incident`, `ticket`, `crm`, `finance`, `logistics`, `email`, `messaging`, `social`, `office`, `analytics`, `ai`, `mcp`, `tools`, `polstryn`; `index.ts` urcuje poradi v nabidce |
|
||||
| `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/runtime/` | fronta, worker, executor stromu, vestavene kroky, planovac, sandbox skriptu firmy |
|
||||
| `src/runtime/scripts/` | runtime skriptu konektoru: registr, runner, HTTP, napojeni, manifest, kontrola hodnot, `mapping`, `util` (vcetne `ctx.util`) |
|
||||
| `connectors/` | skripty konektoru (obycejny JS) a `_sablona.js`; cesta z `config.scriptsDir`, promenna `SCRIPTS_DIR` |
|
||||
| `src/mcp/` | klient MCP, prihlaseni, dialekty, `errors.ts` se spolecnou chybou prihlaseni |
|
||||
| `tests/` | vitest, stejna cesta jako modul (`tests/data/tickets.test.ts` pro `src/data/tickets/`); `setup.ts` nastavi rezim pameti a umlci `console.info` |
|
||||
|
||||
## Mapa kodu - web
|
||||
|
||||
@@ -81,24 +138,51 @@ image jen `dist`, takze staci jedna slozka.
|
||||
| `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/lib/exampleBody.ts` | vzorove telo spoustece pro ukazku a strom modelu |
|
||||
| `web/src/lib/serviceIcons.ts` | klic ikony ze serveru na komponentu lucide |
|
||||
| `web/src/hooks/useApiQuery.ts` | nacitani dat, cache, spolecny debounce, `refreshing` misto odmontovani |
|
||||
| `web/src/hooks/useSubmit.ts` | odeslani formulare: `busy`, chyba, `issues` na jednom miste |
|
||||
| `web/src/hooks/useUnsavedChanges.ts` | varovani pri odchodu z rozepsaneho formulare |
|
||||
| `web/src/hooks/useLatest.ts` | ref s posledni hodnotou pro callbacky mimo zavislosti effectu |
|
||||
| `web/src/hooks/useSyncFromSource.ts` | prevzeti dat ze zdroje do rozepsaneho stavu pri vykresleni, ne v effectu |
|
||||
| `web/src/hooks/useMediaQuery.ts` | sirka obrazovky pres `useSyncExternalStore` |
|
||||
| `web/src/hooks/usePageMeta.ts` | titulek a popis stranky |
|
||||
| `web/src/types/` | fasada nad `src/shared` (alias `@shared/*`), zadne vlastni typy API |
|
||||
| `web/src/components/ui/` | zakladni prvky, `Chip` |
|
||||
| `web/src/components/ui/` | zakladni prvky: `Badge`, `Button`, `Card`, `Chip`, `Modal`, `Section`, `Spinner`, ... |
|
||||
| `web/src/components/ui/Table.tsx` | `Table`, `TableHead`, `Th`, `TableRow`, `Td`: jedna tabulka seznamu pro `EntityAdmin`, `InvitePanel`, `People`, `AuditView` |
|
||||
| `web/src/components/ui/ServiceIcon.tsx` | ikona sluzby podle klice z katalogu, misto `const Icon = serviceIcon()` v JSX |
|
||||
| `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/EntityAdmin.tsx`, `EntityForm.tsx` | sprava jedne entity: tabulka a formular v modalu |
|
||||
| `web/src/components/dashboard/flow/` | strom akci: `FlowCanvas` a karty `ActionCard`, `ConditionCard`, `ForeachCard`, `StepControls`; k tomu `TriggerConfig`, `SampleBody`, `ModelTree`, `WebhookCalls`, `MappingEditor` |
|
||||
| `web/src/components/dashboard/scripts/` | `TestPanel` (zkusebni spusteni) a `CodeEditor` (uprava kodu) pro stranku Skripty |
|
||||
| `web/src/components/dashboard/settings/` | `FeaturesAdmin` (zalozky a limity), `AuditView`, `types` |
|
||||
| `web/src/components/dashboard/widgets/` | `WidgetCard`, `WidgetPicker`, `CustomWidget`, `EditBar` (lista uprav rozlozeni) |
|
||||
| `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 |
|
||||
|
||||
### Soubory nad 500 radku
|
||||
|
||||
Zasada rika, ze soubor nad 500 radku je signal k rozdeleni. Po rozdeleni
|
||||
zustavaji ctyri, kazdy z duvodu:
|
||||
|
||||
| Soubor | Proc zustava |
|
||||
| ---------------------------------------------- | ---------------------------------------------------------------------- |
|
||||
| `web/src/pages/dashboard/AutomationDetail.tsx` | stranka drzi stav stromu a ukladani; casti bez stavu uz jsou ve `flow/` |
|
||||
| `web/src/pages/dashboard/TicketDetail.tsx` | detail sklada sest komponent, zbytek je stav a odeslani akci |
|
||||
| `web/src/components/dashboard/flow/MappingEditor.tsx` | dva rezimy editoru nad jednim stavem, deleni by stav zdvojilo |
|
||||
| `src/data/services/catalog/ticket.ts` | jedna sluzba s nejvic operacemi; deleni jedne sluzby do dvou souboru by rozbilo "jedna vec v jednom souboru" |
|
||||
|
||||
Dalsi velke soubory (`builtinSteps.ts`, `mcp/client.ts`, `executor.ts`,
|
||||
`routes/connectors.ts`) jsou kandidati na priste, az se do nich bude sahat.
|
||||
|
||||
## Klicova rozhodnuti
|
||||
|
||||
**Jeden container misto dvou.** AppFactory nasazuje jednu aplikaci, proto Express
|
||||
|
||||
@@ -103,7 +103,7 @@ fabrika (`src/routes/crud.ts`):
|
||||
`widgets`, `features`.
|
||||
|
||||
`people` ma stejne cesty a stejne pravo (`people.manage`), ale vlastni
|
||||
handlery v `settings.ts`: zaznam, ktery se meni, je ucet bez firmy
|
||||
handlery v `src/routes/settings/people.ts`: zaznam, ktery se meni, je ucet bez firmy
|
||||
a odpoved je pohled za jednu firmu, coz fabrika neumi. Popis je nize
|
||||
v sekci Lide.
|
||||
|
||||
@@ -458,5 +458,5 @@ zkusit to znovu.
|
||||
|
||||
## Pri pridani endpointu
|
||||
|
||||
Soucasne aktualizovat `src/openapi.ts` a tenhle soubor. Swagger musi odpovidat
|
||||
Soucasne aktualizovat `src/openapi/paths/*.ts` a tenhle soubor. Swagger musi odpovidat
|
||||
skutecnemu chovani aplikace, jinak je horsi nez zadny.
|
||||
|
||||
@@ -148,7 +148,15 @@ callbacky se predavaji podle ID kroku a `collectScopes` je memoizovane -
|
||||
u stromu o padesati krocich byl driv kazdy stisk klavesy v poli prekreslenim
|
||||
vseho.
|
||||
|
||||
Odchod z rozepsaneho stromu hlida `lib/useUnsavedChanges.ts`.
|
||||
Odchod z rozepsaneho stromu hlida `hooks/useUnsavedChanges.ts`.
|
||||
|
||||
Stranka `pages/dashboard/AutomationDetail.tsx` uz jen drzi stav stromu
|
||||
a ukladani. Casti bez vlastniho stavu jsou ve `flow/`: `TriggerConfig.tsx`
|
||||
(nastaveni spoustece, vstupy z `ui/form`), `SampleBody.tsx` (ukazka tela),
|
||||
`ModelTree.tsx` (strom modelu), `WebhookCalls.tsx` (posledni volani
|
||||
webhooku); vzorove telo sklada `lib/exampleBody.ts`. Prevzeti nacteneho
|
||||
stromu do rozepsaneho stavu dela `hooks/useSyncFromSource.ts` uz pri
|
||||
vykresleni, ne v effectu, takze stara verze neproblikne.
|
||||
|
||||
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
|
||||
@@ -205,7 +213,7 @@ je vypise. Rozdelana prace se nikdy nezahazuje.
|
||||
|
||||
## Pridani konektoru
|
||||
|
||||
1. Pridat zaznam do katalogu v `src/data/services.ts` vcetne `triggers`
|
||||
1. Pridat zaznam do katalogu v `src/data/services/catalog/<skupina>.ts` vcetne `triggers`
|
||||
a `actions`. ID operace musi byt v ramci sluzby unikatni,
|
||||
`checkOperationIds()` duplicitu pri nacteni zaloguje - druha by tise
|
||||
prekryla prvni.
|
||||
|
||||
@@ -25,7 +25,7 @@ a **co ktera sluzba vratila**. Kdyz neco nesedi, neni potreba hadat.
|
||||
|
||||
## Datovy model
|
||||
|
||||
`src/data/ticketStore.ts`
|
||||
`src/data/tickets/model.ts` (fasada `src/data/ticketStore.ts`)
|
||||
|
||||
```ts
|
||||
interface Ticket {
|
||||
@@ -415,7 +415,7 @@ automatizace na kanal, smerovani je jedna spolecna nad vsemi tickety.
|
||||
|
||||
## Vzorove automatizace
|
||||
|
||||
V `automationStore.ts` jsou nasazene presne v tomhle rozdeleni:
|
||||
V `src/data/automations/seed.ts` (ukazkove v `seedDemo.ts`) jsou nasazene presne v tomhle rozdeleni:
|
||||
|
||||
| Automatizace | Co ukazuje |
|
||||
| ----------------------------- | --------------------------------------------------- |
|
||||
@@ -459,7 +459,7 @@ Katalog je proto deklaruje v `providedFields` u operace. Chovaji se pak takhle:
|
||||
|
||||
- builder je ukazuje **jen ke cteni**, pridat ani prejmenovat nejdou,
|
||||
- server je pri ulozeni stromu **vzdy dosadi z katalogu** a to, co poslal klient,
|
||||
zahodi (`normalizeTriggerFields` v `src/routes/dashboard.ts`),
|
||||
zahodi (`normalizeTriggerFields` v `src/routes/dashboard/automations.ts`),
|
||||
- dosazeni probiha **pred validaci**, jinak by podminky odkazujici na katalogova
|
||||
ID vypadaly jako rozbite.
|
||||
|
||||
|
||||
@@ -219,14 +219,14 @@ a drzi se vsude, kde se neco zaklada:
|
||||
|
||||
| Co | Kdo smi | Kde se to kontroluje |
|
||||
| -------------------------- | ------------------------------------------------------------ | ---------------------------------------- |
|
||||
| firma | jen spravce platformy (`platformOnly` u CRUD firem) | `src/routes/settings.ts` |
|
||||
| firma | jen spravce platformy (`platformOnly` u CRUD firem) | `src/routes/settings/tenants.ts` |
|
||||
| firma z registru ARES | jen spravce platformy | `src/routes/ares.ts` |
|
||||
| uzivatel | spravce platformy, nebo `user.manage` jen ve sve firme | `src/routes/settings.ts` |
|
||||
| resitel (clen firmy, Lide) | `people.manage` jen ve sve firme, zaklada ucet s clenstvim | `src/routes/settings.ts` |
|
||||
| uzivatel | spravce platformy, nebo `user.manage` jen ve sve firme | `src/routes/settings/users.ts` |
|
||||
| resitel (clen firmy, Lide) | `people.manage` jen ve sve firme, zaklada ucet s clenstvim | `src/routes/settings/people.ts` |
|
||||
| pozvanka | `user.manage`, role jen z te firmy | `src/routes/invites.ts` |
|
||||
| konektor | `connector.manage` | `src/routes/connectors.ts`, `dashboard.ts` |
|
||||
| automatizace | `automation.edit` za firmu automatizace | `src/routes/dashboard.ts` |
|
||||
| stav incidentu | `incident.manage` za firmu incidentu, platformni jen spravce platformy | `src/routes/dashboard.ts` |
|
||||
| konektor | `connector.manage` | `src/routes/connectors.ts`, `dashboard/misc.ts` |
|
||||
| automatizace | `automation.edit` za firmu automatizace | `src/routes/dashboard/automations.ts` |
|
||||
| stav incidentu | `incident.manage` za firmu incidentu, platformni jen spravce platformy | `src/routes/dashboard/incidents.ts` |
|
||||
| akce nad ticketem | pravo akce za firmu ticketu a strop viditelnosti | `src/routes/ticketActions.ts` |
|
||||
|
||||
Spravce firmy s `user.manage` ma **jen svou firmu**: nenastavi `platformAdmin`,
|
||||
|
||||
@@ -99,6 +99,16 @@ Neulozit je tady spravne. Klient by dostal zpatky neco, co neumi vykreslit.
|
||||
Widget, ktery mezitim z katalogu zmizel, se v prehledu ukaze jako cervena karta
|
||||
s jeho ID. Nesmi tise vypadnout z rozlozeni.
|
||||
|
||||
## Kde to je na klientovi
|
||||
|
||||
Stranka `pages/dashboard/Overview.tsx` sklada `widgets/WidgetCard.tsx`
|
||||
(vykresleni podle druhu), `widgets/WidgetPicker.tsx` (nabidka z katalogu),
|
||||
`widgets/CustomWidget.tsx` (widgety, jejichz data pocita server)
|
||||
a `widgets/EditBar.tsx` (lista rezimu uprav: ulozit, zahodit, obnovit
|
||||
vychozi). Vstupy v rezimu uprav jsou z `components/ui/form`, stranka si zadny
|
||||
vlastni nekresli. Server: `src/routes/dashboard/layout.ts`,
|
||||
`src/data/widgets.ts`, `src/data/dashboardLayouts.ts`.
|
||||
|
||||
## Jak pridat widget
|
||||
|
||||
1. Zaznam do `widgets` v `src/data/widgets.ts`.
|
||||
|
||||
@@ -1121,15 +1121,15 @@ Seznam mist, ktera navrh meni a je potreba je hlidat.
|
||||
| `accessFor(user)` -> `accessFor(user, tenantId)` | vsechny routy dashboardu, prava jsou az uvnitr firmy |
|
||||
| `Membership.role` -> `roleIds` | `types.ts`, `users.ts`, `access.ts`, `middleware/auth.ts` |
|
||||
| `requireRole` -> `requirePermission` | `src/middleware/auth.ts` a vsechna jeho pouziti |
|
||||
| `Ticket` dostane `typeId` a `fields` | `ticketStore.ts`, `openapi.ts`, `web/src/types/dashboard.ts`, seznam, detail, simulace |
|
||||
| `Ticket` dostane `typeId` a `fields` | `src/data/tickets/`, `src/openapi/paths/tickets.ts`, `src/shared/tickets.ts`, seznam, detail, simulace |
|
||||
| Katalog konektoru prestane byt spolecny | `connectors.ts`, `GET /connectors`, `Connectors.tsx` - vraci se za firmu |
|
||||
| `ConnectorStatus` se prestane cist z katalogu | pocita se z napojeni, dnes je to pevne pole |
|
||||
| `FlowStep` dostane `connectionId` | `automationStore.ts`, `flow.ts`, validace stromu, builder |
|
||||
| `FlowStep` dostane `connectionId` | `src/data/automations/`, `flow.ts`, validace stromu, builder |
|
||||
| Zalozky ze serveru | `web/src/components/dashboard/DashboardLayout.tsx`, dnes konstanta |
|
||||
| `WidgetKind` -> `render` plus `source` | `widgets.ts`, `WidgetCard.tsx`, ulozena rozlozeni potrebuji prevod ID |
|
||||
| Novy druh kroku `wait` a `call` | `flow.ts`, `flowScope.ts`, `FlowCanvas.tsx`, validace |
|
||||
| `visibleWhen` potrebuje AND vice podminek | model podminek dnes umi jedno porovnani, viz `conditions.ts` |
|
||||
| Log ticketu potrebuje redakci tajemstvi | `ticketStore.ts`, zapis `response` do trace |
|
||||
| Log ticketu potrebuje redakci tajemstvi | `src/data/tickets/trace.ts`, zapis `response` do trace |
|
||||
| Data z pameti do Postgresu | cele `src/data/`, routy zustavaji |
|
||||
|
||||
Dve veci k modelu podminek. `visibleWhen` u akce potrebuje spojit vic porovnani,
|
||||
@@ -1138,5 +1138,5 @@ s AND na obou stranach (`src/data/conditions.ts` i `web/src/lib/flow.ts`, vzdy
|
||||
obe), nebo AND drzet jen u akci a nemichat to do stromu. Druha varianta je
|
||||
levnejsi, prvni upravnejsi.
|
||||
|
||||
A pri kazdem novem endpointu soucasne `src/openapi.ts` a tuhle dokumentaci.
|
||||
A pri kazdem novem endpointu soucasne `src/openapi/paths/*.ts` a tuhle dokumentaci.
|
||||
Swagger, ktery neodpovida chovani, je horsi nez zadny.
|
||||
|
||||
@@ -17,22 +17,32 @@ zeptat na jeho vystupy.
|
||||
## Kde to je
|
||||
|
||||
```
|
||||
scripts/ soubory skriptu, obycejny JavaScript
|
||||
_sablona.js sablona ke zkopirovani (podtrzitko = nenacita se)
|
||||
connectors/ soubory skriptu, obycejny JavaScript
|
||||
_sablona.js sablona ke zkopirovani (podtrzitko = nenacita se)
|
||||
idoklad.get-issued-invoice.js
|
||||
...
|
||||
src/scripts/types.ts co je skript, zod schema manifestu
|
||||
src/scripts/values.ts kontrola vstupu a vystupu
|
||||
src/scripts/util.ts pomocne funkce pro skripty, redakce tajemstvi
|
||||
src/scripts/connections.ts kam se vola a cim se to autorizuje (podle konektoru)
|
||||
src/scripts/http.ts HTTP klient predany skriptu
|
||||
src/scripts/manifest.ts overeni manifestu, prevod na operaci katalogu
|
||||
src/scripts/registry.ts nacitani ze souboru, hot reload, ukladani
|
||||
src/scripts/runner.ts spusteni jednoho skriptu
|
||||
src/routes/scripts.ts API
|
||||
web/src/pages/dashboard/Scripts.tsx stranka /dashboard/skripty
|
||||
src/runtime/scripts/types.ts co je skript, zod schema manifestu
|
||||
src/runtime/scripts/values.ts kontrola vstupu a vystupu
|
||||
src/runtime/scripts/util.ts pomocne funkce pro skripty (`ctx.util`), redakce tajemstvi
|
||||
src/runtime/scripts/connections.ts kam se vola a cim se to autorizuje (podle konektoru)
|
||||
src/runtime/scripts/http.ts HTTP klient predany skriptu
|
||||
src/runtime/scripts/manifest.ts overeni manifestu, prevod na operaci katalogu
|
||||
src/runtime/scripts/registry.ts nacitani ze souboru, hot reload, ukladani
|
||||
src/runtime/scripts/runner.ts spusteni jednoho skriptu
|
||||
src/runtime/scripts/lookup.ts ktery skript obsluhuje operaci katalogu
|
||||
src/runtime/scripts/mapping.ts engine transformaci, viz 13-transformace-dat.md
|
||||
src/routes/scripts.ts API
|
||||
web/src/pages/dashboard/Scripts.tsx stranka /dashboard/skripty
|
||||
web/src/components/dashboard/scripts/ TestPanel (zkusebni spusteni), CodeEditor (uprava kodu)
|
||||
```
|
||||
|
||||
Slozka se skriptu se jmenuje `connectors/`, protoze `scripts/` je podle zasad
|
||||
misto pro pomocne skripty vyvoje, ne pro kod, ktery aplikace nacita za behu.
|
||||
Cestu urcuje `config.scriptsDir` (promenna `SCRIPTS_DIR`, vychozi
|
||||
`./connectors`), Dockerfile slozku kopiruje do image. Lint (`eslint.config.js`)
|
||||
ji kontroluje jako obycejny JS **bez globalu**, takze `Buffer` nebo `process`
|
||||
ve skriptu neprojde.
|
||||
|
||||
## Nic se neotaci
|
||||
|
||||
Soubory jsou zamerne **obycejny JavaScript, ne TypeScript**. TypeScript by se
|
||||
@@ -58,13 +68,13 @@ Nesoulad je chyba, ne varovani - jinak by se skript ulozil pod jednim jmenem
|
||||
a nacetl pod druhym.
|
||||
|
||||
```
|
||||
scripts/idoklad.get-issued-invoice.js
|
||||
connectors/idoklad.get-issued-invoice.js
|
||||
\_____/ \________________/
|
||||
sluzba operace
|
||||
```
|
||||
|
||||
Z ID se dopocita, do ktere sluzby operace patri, takze se to nepise dvakrat.
|
||||
Sluzba **musi existovat** v `src/data/services.ts`, jinak se skript ohlasi
|
||||
Sluzba **musi existovat** v katalogu (`src/data/services/catalog/`), jinak se skript ohlasi
|
||||
jako problem.
|
||||
|
||||
## Manifest
|
||||
@@ -120,8 +130,8 @@ druhem (`output`).
|
||||
|
||||
## Co skript ma a co nema
|
||||
|
||||
Skript ma jen `ctx`. Zadny import, zadny pristup na sit mimo `ctx.http`
|
||||
a **zadne pristupove udaje**.
|
||||
Skript ma jen `ctx`. Zadny import, zadny global Node (`Buffer`, `process`),
|
||||
zadny pristup na sit mimo `ctx.http` a **zadne pristupove udaje**.
|
||||
|
||||
```js
|
||||
export async function run(inputs, ctx) { /* ... */ }
|
||||
@@ -179,12 +189,15 @@ z nich by to resil spatne.
|
||||
| `list(body, ...names)` | seznam z odpovedi: pole primo, nebo pod danym klicem, `data`, `content`, `items`, `results`. Jinak `null` |
|
||||
| `addresses(value)` | adresy z pole "Prijemci" oddelene carkou nebo strednikem, bez prazdnych |
|
||||
| `quote(value)` | hodnota v jednoduchych uvozovkach pro filtr OData nebo SQL, apostrof zdvojeny |
|
||||
| `base64(value)` | text do Base64. Skript nema `Buffer` ani `btoa`, kodovani mu da runtime |
|
||||
|
||||
Ctyri posledni pribyly v zari 2026, kdyz se ukazalo, ze osm skriptu ma kazdy
|
||||
svou verzi. Sablona `scripts/_sablona.js` je vsechny vypisuje, aby se nehledaly
|
||||
v kodu serveru.
|
||||
Ctyri z nich (`day`, `list`, `addresses`, `quote`) pribyly v zari 2026, kdyz
|
||||
se ukazalo, ze osm skriptu ma kazdy svou verzi. `base64` pribyl pri prevodu
|
||||
na zasady: `google.send-email` skladal zpravu pres `Buffer`, tedy pres global
|
||||
Node, ktery skript mit nema. Sablona `connectors/_sablona.js` vsechny funkce
|
||||
vypisuje, aby se nehledaly v kodu serveru.
|
||||
|
||||
`ctx.config` je slozene z `scriptConfig` v `src/scripts/connections.ts`:
|
||||
`ctx.config` je slozene z `scriptConfig` v `src/runtime/scripts/connections.ts`:
|
||||
z nastaveni napojeni vynecha kazde pole, jehoz hodnota je mezi tajnymi. Skript
|
||||
tedy heslo SMTP ani tajemstvi OAuth nedostane ani omylem, i kdyz je runtime
|
||||
(SMTP, MCP) potrebuje - ty si je berou z `serviceConfig`, ke kteremu skript
|
||||
@@ -222,13 +235,13 @@ nastaveni:
|
||||
| --------------------------- | ------------------------------------------------------ |
|
||||
| `SERVICES_BASE_URL` | zaklad adres, vychozi `https://services.csbot.cz/apps` |
|
||||
| `<SLUZBA>_BASE_URL` | presmerovani jedne sluzby, napr. `OPENAI_BASE_URL` |
|
||||
| `SCRIPTS_DIR` | jina slozka se skripty |
|
||||
| `SCRIPTS_DIR` | jina slozka se skripty, vychozi `./connectors` |
|
||||
| `SCRIPT_TIMEOUT_MS` | vychozi strop na beh, 15000 |
|
||||
| `SCRIPT_MAX_RESPONSE_BYTES` | strop na velikost odpovedi, 1000000 |
|
||||
| `SCRIPT_MAX_UPLOAD_BYTES` | strop na odeslany soubor, 10000000 |
|
||||
| `ALLOW_PRIVATE_TARGETS` | povoli volani na localhost, **jen pro lokalni vyvoj** |
|
||||
|
||||
Co ktera sluzba vyzaduje, je v `credentials` u sluzby v `src/data/services.ts`.
|
||||
Co ktera sluzba vyzaduje, je v `credentials` u sluzby v `src/data/services/catalog/`.
|
||||
Hodnoty patri konektoru a zadavaji se v portalu.
|
||||
|
||||
## Redakce tajemstvi
|
||||
@@ -244,7 +257,7 @@ Redaktor (`createRedactor`) maskuje tajemstvi ve **ctyrech tvarech**:
|
||||
prijaty token v chybe i uvnitr adresy nebo v zaescapovanem JSONu, a tam by
|
||||
hola hodnota nesedela.
|
||||
|
||||
Zkracovani ma jednu konstantu, `DETAIL_BYTES` v `src/scripts/util.ts`
|
||||
Zkracovani ma jednu konstantu, `DETAIL_BYTES` v `src/runtime/scripts/util.ts`
|
||||
(`SCRIPT_ERROR_DETAIL_BYTES`, vychozi 8 kB). Detail chyby MCP mel driv vlastnich
|
||||
600 znaku a prave u nej byla cela odpoved potreba nejvic.
|
||||
|
||||
@@ -290,7 +303,7 @@ Skript se domeri do katalogu sluzeb jako akce s `implementation: 'script'`
|
||||
a `scriptId`. Kdyz nese ID operace, ktera uz v katalogu je, **skript vyhrava** -
|
||||
staticky zapis je popis toho, co umime, skript je to, co se opravdu stane.
|
||||
|
||||
Prekryv drzi `src/data/services.ts` (`setScriptActions`, `actionsFor`).
|
||||
Prekryv drzi `src/data/services/index.ts` (`setScriptActions`, `actionsFor`).
|
||||
Je to zamerne tam, protoze vsechno ostatni se uz pta pres `findOperation`.
|
||||
Tim se skripty naraz objevi ve validaci stromu, ve vypoctu toho, co je v kterem
|
||||
kroku videt, i v sablonach - bez toho, aby se to psalo trikrat.
|
||||
@@ -359,11 +372,11 @@ cele je.
|
||||
|
||||
## Jak pridat skript
|
||||
|
||||
1. Zkopirovat `scripts/_sablona.js` na `<sluzba>.<operace>.js`.
|
||||
1. Zkopirovat `connectors/_sablona.js` na `<sluzba>.<operace>.js`.
|
||||
2. Srovnat `manifest.id` s nazvem souboru.
|
||||
3. Vyplnit `inputs` a `outputs`.
|
||||
4. Napsat `run`.
|
||||
5. Kdyz sluzba jeste neni v `src/data/services.ts`, pridat ji.
|
||||
5. Kdyz sluzba jeste neni v katalogu (`src/data/services/catalog/<skupina>.ts`), pridat ji.
|
||||
6. Kdyz potrebuje pristupove udaje, popsat je v `credentials` u te sluzby.
|
||||
Hodnoty pak zada firma v konektoru.
|
||||
|
||||
|
||||
@@ -327,11 +327,11 @@ Cte se zvlast pres `/connectors/:id/checks`.
|
||||
|
||||
## Jak pridat sluzbu
|
||||
|
||||
1. Zaznam do `services` v `src/data/services.ts`: kategorie, ikona, `general`,
|
||||
1. Zaznam do skupiny v `src/data/services/catalog/<skupina>.ts` (fasada `src/data/services.ts`): kategorie, ikona, `general`,
|
||||
`appId` (nebo `baseUrl` u cizi sluzby), `visibility`, `credentials`,
|
||||
pripadne `verifyPath`.
|
||||
2. Pokud pouziva novou ikonu, doplnit klic do `web/src/lib/serviceIcons.ts`.
|
||||
3. Skripty operaci do `scripts/<sluzba>.<operace>.js`, viz
|
||||
3. Skripty operaci do `connectors/<sluzba>.<operace>.js`, viz
|
||||
[11-skripty-konektoru.md](11-skripty-konektoru.md).
|
||||
|
||||
Katalog, builder, stranka Sluzby i zakladani konektoru si ji vezmou samy.
|
||||
@@ -342,7 +342,7 @@ Kdo se v kodu orientoval podle stareho pojmenovani:
|
||||
|
||||
| Driv | Ted |
|
||||
| --------------------------------- | ----------------------------- |
|
||||
| `src/data/connectors.ts` | `src/data/services.ts` |
|
||||
| `src/data/connectors.ts` | `src/data/services/` (fasada `services.ts`) |
|
||||
| `Connector`, `ConnectorOperation` | `Service`, `ServiceOperation` |
|
||||
| `connectorCategories` | `serviceCategories` |
|
||||
| `findConnector` | `findService` |
|
||||
|
||||
@@ -72,7 +72,7 @@ nemuze se v nem udelat preklep v zavorce.
|
||||
|
||||
## Dva rezimy
|
||||
|
||||
Obe moznosti stoji na tom samem enginu v `src/scripts/mapping.ts`.
|
||||
Obe moznosti stoji na tom samem enginu v `src/runtime/scripts/mapping.ts`.
|
||||
Volba je o tom, cehoz je vic:
|
||||
|
||||
| Rezim | Kdy | Skript |
|
||||
@@ -271,10 +271,10 @@ mluvi o jejich schematu, ne o nasich datech.
|
||||
## Kde to je
|
||||
|
||||
```
|
||||
src/scripts/mapping.ts engine: cesty, prevody, pravidla, sablona
|
||||
scripts/transform.map-fields.js rezim 1
|
||||
scripts/transform.to-json.js rezim 2
|
||||
scripts/idoklad.create-invoice-from-object.js druha polovina prikladu
|
||||
src/runtime/scripts/mapping.ts engine: cesty, prevody, pravidla, sablona
|
||||
connectors/transform.map-fields.js rezim 1
|
||||
connectors/transform.to-json.js rezim 2
|
||||
connectors/idoklad.create-invoice-from-object.js druha polovina prikladu
|
||||
web/src/components/dashboard/flow/MappingEditor.tsx klikaci editor pravidel
|
||||
web/src/components/dashboard/flow/StepInputs.tsx pole typu mapping, json a object
|
||||
```
|
||||
|
||||
@@ -114,7 +114,9 @@ v `src/data/refresh.ts`). `listByTenant(tenantIds, sortBy)` je jeden filtr
|
||||
a razeni misto sedmi kopii v modulech.
|
||||
|
||||
**`withMirror`** pro provozni data: meni se v pameti, po zmene se zapise cely
|
||||
zaznam. Zapisy tehoz ID jsou **serazene za sebou** retezem promise. Bez toho
|
||||
zaznam. U ticketu a automatizaci je zapis a nacteni pri startu v modulu
|
||||
`persist.ts` jejich slozky (`src/data/tickets/`, `src/data/automations/`);
|
||||
`ticketStore.ts` a `automationStore.ts` jsou uz jen fasady. Zapisy tehoz ID jsou **serazene za sebou** retezem promise. Bez toho
|
||||
mohl Postgres potvrdit dva `put` tehoz ticketu v opacnem poradi, nez prisly,
|
||||
a v tabulce zustala starsi verze - v pameti to nebylo videt, po restartu ano.
|
||||
Tickety navic slucuji vic zmen v jednom tiku do jednoho zapisu
|
||||
|
||||
@@ -62,13 +62,48 @@ Volající nikdy nezjišťuje, jestli běží Postgres, soubor, nebo pamět.
|
||||
| `personName(id)` | `src/data/people.ts` | Jméno účtu bez ohledu na firmu, pro popisky u záznamů, které už prošly filtrem na firmu. |
|
||||
| `personIdFor(user, tenantId)` | `src/data/people.ts` | ID řešitele, kterým je uživatel ve firmě: ID účtu při členství, jinak `null`. Neptat se `user.id` přímo. |
|
||||
| `findPersonByExternalId(value, tenantIds)` | `src/data/people.ts` | Řešitel podle ID z cizí aplikace, například voicebotId. Externí ID visí na členství. |
|
||||
| `migratePeople()` | `src/data/migratePeople.ts` | Jednorázový převod starých záznamů řešitelů (`ppl_`) na účty při startu. Přepisuje odkazy přes `remapPersonIds` v `ticketStore.ts` a `automationStore.ts`. |
|
||||
| `migratePeople()` | `src/data/migratePeople.ts` | Jednorázový převod starých záznamů řešitelů (`ppl_`) na účty při startu. Přepisuje odkazy přes `remapPersonIds` v `tickets/remap.ts` a `automations/remap.ts`. |
|
||||
| `notify(input)` | `src/data/notifications.ts` | Upozorní člověka. Nečeká se a nevyhazuje chyby, stejně jako audit. |
|
||||
| `runFlow(steps, context, options)` | `src/runtime/executor.ts` | Vykoná strom kroků. Nikdy nevyhodí výjimku, chyba je výsledek. Používá to akce na ticketu i webhook, aby se strom choval všude stejně. |
|
||||
| `widgetCatalog(tenantIds, userId)` | `src/data/widgets.ts` | Jediná definice toho, co jde položit na dashboard. Používá ji nabídka i kontrola ukládaného rozložení. |
|
||||
| `intakeEvent(input)` | `src/data/ticketStore.ts` | Přijme událost zvenku: podle externího ID buď založí ticket, nebo ji navěsí na existující. Jediná cesta, kterou se událost stává ticketem. Hodnoty z `input.apply` zapíše v obou případech, prázdné nemaže. |
|
||||
| `getAgentStats(...)` | `src/data/ticketStore.ts` | Výkon řešitelů: odbavené, mediány časů, vrácené, fronta. Používá to widget i detail osoby, aby čísla seděla. |
|
||||
| `findByExternalId(...)` | `src/data/ticketStore.ts` | Ticket firmy podle externího ID. Klíč je dvojice firma a ID. |
|
||||
| `intakeEvent(input)` | `src/data/tickets/intake.ts` | Přijme událost zvenku: podle externího ID buď založí ticket, nebo ji navěsí na existující. Jediná cesta, kterou se událost stává ticketem. Hodnoty z `input.apply` zapíše v obou případech, prázdné nemaže. |
|
||||
| `getAgentStats(...)` | `src/data/tickets/stats.ts` | Výkon řešitelů: odbavené, mediány časů, vrácené, fronta. Používá to widget i detail osoby, aby čísla seděla. |
|
||||
| `findByExternalId(...)` | `src/data/tickets/queries.ts` | Ticket firmy podle externího ID. Klíč je dvojice firma a ID. |
|
||||
| `createApp()` | `src/app.ts` | Sestavi Express aplikaci: middleware, routery, health, Swagger, statika, SPA. Bez `listen` a bez nacteni dat, takze jde postavit v testu (supertest). `index.ts` ji jen spusti. |
|
||||
| `config.serviceBaseUrlOverride(variable)` | `src/config.ts` | Jedine cteni `process.env` s dynamickym nazvem (`<SLUZBA>_BASE_URL`). Vraci normalizovanou adresu nebo `null`. Nikde jinde se `process.env` necte. |
|
||||
| `buildOpenApiDocument()` | `src/openapi/index.ts` | Sklada OpenAPI z `components.ts` a `paths/*.ts`. Novy endpoint se popisuje v souboru sveho routeru, `crudPaths` v `helpers.ts` popise CRUD petici jednim radkem. |
|
||||
| `pageFrom(query)`, `paginate(items, page)` | `src/routes/dashboard/shared.ts` | Strankovani seznamu ticketu a fronty behu: `limit`, `offset`, strop `MAX_PAGE_LIMIT`. Nepsat vlastni `slice` v route. |
|
||||
| `memberOf(user, tenantId)` | `src/routes/settings/shared.ts` | Je ucet clenem firmy? Sdili sprava uctu a resitelu. |
|
||||
|
||||
### Moduly dat po rozdeleni
|
||||
|
||||
Puvodni soubory zustavaji jako fasady (`ticketStore.ts`, `automationStore.ts`,
|
||||
`services.ts`), importy se nemeni. Kdo hleda, kde co je:
|
||||
|
||||
| Modul | Co drzi |
|
||||
| ---------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| `tickets/index.ts` | verejne API slozky, seed a `initTickets` v poradi, ve kterem se maji volat |
|
||||
| `tickets/model.ts` | `StoredTicket`, `defaultStatuses`, `channelLabels`, `toTicket` (doplneni vychozich hodnot) |
|
||||
| `tickets/state.ts` | pole ticketu, indexy podle ID a externiho ID, log, udalosti, citace ID |
|
||||
| `tickets/persist.ts` | `persist`, `touch` (`updatedAt` a zapis v jednom), `initTickets` |
|
||||
| `tickets/queries.ts` | `listTickets` s `TicketFilter`, `getTicket`, `findTicket`, `findByExternalId`, `ticketWithinVisibility` |
|
||||
| `tickets/store.ts` | zapisy: `createTicket`, `updateTicketStatus`, `assignTicket`, `setTicketType`, `setTicketTags`, `assignTicketGroup`, `claimTicket`, `addComment` |
|
||||
| `tickets/intake.ts` | `intakeEvent`: udalost zvenku se stane ticketem nebo se navesi |
|
||||
| `tickets/trace.ts` | `appendTrace`, `flattenTrace`, `lastTraceId`, `describePayload`: log prubehu |
|
||||
| `tickets/stats.ts` | `getWorkload`, `getAgentStats` |
|
||||
| `tickets/seed.ts`, `remap.ts` | ukazkova data (`SEED_DEMO=1`), preznaceni resitelu pri migraci |
|
||||
| `automations/index.ts` | verejne API slozky, seed a `initAutomations` |
|
||||
| `automations/model.ts` | `StoredAutomation`, `rulesOf`, `matchOf` (cteni podminky ve stare i nove podobe) |
|
||||
| `automations/state.ts` | `Map` automatizaci, `nextId`, `findWritable` |
|
||||
| `automations/persist.ts` | `save`, `initAutomations`, `mirror` |
|
||||
| `automations/store.ts` | `listAutomations`, `getAutomation`, `createAutomation`, `updateAutomation`, `regenerateWebhookToken`, `findByWebhookToken`, `recordRun`, `deleteAutomation` |
|
||||
| `automations/validation.ts` | `countSteps`, `collectFlowIssues`, `deriveKind`, `withDerived`: ciste funkce nad stromem |
|
||||
| `automations/webhook.ts` | `generateWebhookToken`, `withWebhookToken`, `recordWebhookCall`, `recentWebhookCalls`, `bodyForCall` |
|
||||
| `automations/runs.ts` | historie behu po dnech, `KEEP_DAYS`, `statsOf` |
|
||||
| `automations/seed.ts`, `seedDemo.ts`, `remap.ts` | skutecne automatizace (vzdy), ukazkove (`SEED_DEMO=1`), preznaceni resitelu |
|
||||
| `services/index.ts` | katalog za behu: `findService`, `findOperation`, `actionsFor`, `serviceCatalog`, `setScriptActions`, `setMcpOperations`, `withRuntimeOptions`, `visibleServices` |
|
||||
| `services/catalog/index.ts` | `services` a `serviceCategories` slozene ze skupin; poradi tady je poradi v nabidce |
|
||||
| `services/catalog/<skupina>.ts` | staticky zapis sluzeb jedne skupiny: `triggers`, `incident`, `ticket`, `crm`, `finance`, `logistics`, `email`, `messaging`, `social`, `office`, `analytics`, `ai`, `mcp`, `tools`, `polstryn` |
|
||||
| `findByIntakeToken(token)` | `src/data/tenants.ts` | Firma podle tokenu příjmu. Určuje i to, v jakém rozsahu je externí ID unikátní. |
|
||||
| `refreshCaches()`, `refreshEntity(kind)` | `src/data/bootstrap.ts` | Obnoví všechny kopie v paměti, nebo jen jednu entitu. Route nastavení volá `bootstrapDataRefresh(route)` v `src/data/refresh.ts`, která vybere tu jednu. |
|
||||
| `bootstrapData({databaseReady})` | `src/data/bootstrap.ts` | Seznam všech entit a provozních dat. **Nová entita se přidává tady**, ne rozesetě po modulech. |
|
||||
@@ -79,25 +114,25 @@ Viz [11-skripty-konektoru.md](11-skripty-konektoru.md).
|
||||
|
||||
| Co | Kde | K čemu |
|
||||
| ------------------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `runScript(id, inputs, ctx)` | `src/scripts/runner.ts` | Spustí skript. **Nikdy nevyhodí výjimku**, chybu vrací jako výsledek s celým hlášením. |
|
||||
| `validateValues(...)` | `src/scripts/values.ts` | Jedna kontrola pro vstupy i výstupy skriptu podle manifestu. |
|
||||
| `scriptUtil` | `src/scripts/util.ts` | Nádobíčko pro skripty: `pick`, `first`, `num`, `date`, `day`, `list`, `addresses`, `quote`, `need`, `get`, `applyRules`, `fillJson`. Skript nemá sahat na nic jiného. |
|
||||
| `pick`, `pickText`, `jwtExpiry`, `parseBool`, `parseNumber` | `src/scripts/util.ts` | Totéž pro server: pole bez ohledu na velikost písmen, `exp` z JWT, převody. Než napíšeš `Number(x)` s kontrolou `NaN`, je to tady. |
|
||||
| `DETAIL_BYTES`, `truncate(value)` | `src/scripts/util.ts` | Jeden limit na zkracování detailu chyby pro všechny vrstvy. Žádné vlastní `slice(0, 600)`. |
|
||||
| `createRedactor(...)` | `src/scripts/util.ts` | Vyškrtá tajemství z textu **před** logováním, i v URL-encoded a JSON-escaped tvaru. Používá se u všeho, co jde do logu. |
|
||||
| `scriptConfig(target)` | `src/scripts/connections.ts` | Nastavení napojení bez tajných polí. Jediné, co skript dostane jako `ctx.config`. |
|
||||
| `applyRules`, `fillJson` | `src/scripts/mapping.ts` | Transformace dat: pole na pole s převody, nebo objekt na objekt. Viz [13-transformace-dat.md](13-transformace-dat.md). |
|
||||
| `getPath(obj, path)` | `src/scripts/mapping.ts` | Čtení `zakaznik.adresa.mesto` z neznámého objektu. |
|
||||
| `resolveTarget(...)` | `src/scripts/connections.ts` | Z konektoru poskládá adresu a hlavičky. Přístupové údaje nikam jinam nevedou. |
|
||||
| `serviceBaseUrl(service)` | `src/scripts/connections.ts` | Adresa služby: naše aplikace ze `SERVICES_BASE_URL`, cizí (OpenAI) z jejího `baseUrl`. Přebít jde přes `<SLUZBA>_BASE_URL`. |
|
||||
| `targetSecrets(target)` | `src/scripts/connections.ts` | Co se musí vyškrtat z logu. Vrací i holý klíč bez předpony `Bearer `, protože v něm ho cizí služby vracejí v chybách. |
|
||||
| `createHttp(...)` | `src/scripts/http.ts` | HTTP se timeoutem, limitem odpovědi a rozlišením "zkusit znovu" a "marné". |
|
||||
| `isPrivateHost(host)` | `src/scripts/http.ts` | Míří jméno do vnitřní sítě? Jedno pravidlo pro HTTP i pro SMTP server z konektoru. |
|
||||
| `runScript(id, inputs, ctx)` | `src/runtime/scripts/runner.ts` | Spustí skript. **Nikdy nevyhodí výjimku**, chybu vrací jako výsledek s celým hlášením. |
|
||||
| `validateValues(...)` | `src/runtime/scripts/values.ts` | Jedna kontrola pro vstupy i výstupy skriptu podle manifestu. |
|
||||
| `scriptUtil` | `src/runtime/scripts/util.ts` | Nádobíčko pro skripty: `pick`, `first`, `num`, `date`, `day`, `list`, `addresses`, `quote`, `need`, `get`, `applyRules`, `fillJson`. Skript nemá sahat na nic jiného. |
|
||||
| `pick`, `pickText`, `jwtExpiry`, `parseBool`, `parseNumber` | `src/runtime/scripts/util.ts` | Totéž pro server: pole bez ohledu na velikost písmen, `exp` z JWT, převody. Než napíšeš `Number(x)` s kontrolou `NaN`, je to tady. |
|
||||
| `DETAIL_BYTES`, `truncate(value)` | `src/runtime/scripts/util.ts` | Jeden limit na zkracování detailu chyby pro všechny vrstvy. Žádné vlastní `slice(0, 600)`. |
|
||||
| `createRedactor(...)` | `src/runtime/scripts/util.ts` | Vyškrtá tajemství z textu **před** logováním, i v URL-encoded a JSON-escaped tvaru. Používá se u všeho, co jde do logu. |
|
||||
| `scriptConfig(target)` | `src/runtime/scripts/connections.ts` | Nastavení napojení bez tajných polí. Jediné, co skript dostane jako `ctx.config`. |
|
||||
| `applyRules`, `fillJson` | `src/runtime/scripts/mapping.ts` | Transformace dat: pole na pole s převody, nebo objekt na objekt. Viz [13-transformace-dat.md](13-transformace-dat.md). |
|
||||
| `getPath(obj, path)` | `src/runtime/scripts/mapping.ts` | Čtení `zakaznik.adresa.mesto` z neznámého objektu. |
|
||||
| `resolveTarget(...)` | `src/runtime/scripts/connections.ts` | Z konektoru poskládá adresu a hlavičky. Přístupové údaje nikam jinam nevedou. |
|
||||
| `serviceBaseUrl(service)` | `src/runtime/scripts/connections.ts` | Adresa služby: naše aplikace ze `SERVICES_BASE_URL`, cizí (OpenAI) z jejího `baseUrl`. Přebít jde přes `<SLUZBA>_BASE_URL`. |
|
||||
| `targetSecrets(target)` | `src/runtime/scripts/connections.ts` | Co se musí vyškrtat z logu. Vrací i holý klíč bez předpony `Bearer `, protože v něm ho cizí služby vracejí v chybách. |
|
||||
| `createHttp(...)` | `src/runtime/scripts/http.ts` | HTTP se timeoutem, limitem odpovědi a rozlišením "zkusit znovu" a "marné". |
|
||||
| `isPrivateHost(host)` | `src/runtime/scripts/http.ts` | Míří jméno do vnitřní sítě? Jedno pravidlo pro HTTP i pro SMTP server z konektoru. |
|
||||
| `sendMail(target, message)` | `src/mail/smtp.ts` | Odešle e-mail přes SMTP z konektoru. Nikdy nevyhodí výjimku, vrací i to, jestli má smysl zkusit znovu. |
|
||||
| `verifySmtp(target)` | `src/mail/smtp.ts` | Přihlásí se na server bez odeslání zprávy. Tím se ověřuje konektor e-mailu. |
|
||||
| `escapeHtml(value)` | `src/data/templates.ts` | Escapuje **dosazenou hodnotu** v HTML šabloně. Značky autora šablony zůstávají, ostré závorky od zákazníka ne. |
|
||||
| `ctx.http.postForm(...)` | `src/scripts/http.ts` | Odeslání souboru (`multipart/form-data`). Obsah přichází jako Base64, hranici dopisuje runtime. |
|
||||
| `scriptIdFor(serviceId, operationId)` | `src/scripts/lookup.ts` | Který skript obsluhuje operaci z katalogu. |
|
||||
| `ctx.http.postForm(...)` | `src/runtime/scripts/http.ts` | Odeslání souboru (`multipart/form-data`). Obsah přichází jako Base64, hranici dopisuje runtime. |
|
||||
| `scriptIdFor(serviceId, operationId)` | `src/runtime/scripts/lookup.ts` | Který skript obsluhuje operaci z katalogu. |
|
||||
|
||||
## Klient
|
||||
|
||||
@@ -115,28 +150,33 @@ Viz [11-skripty-konektoru.md](11-skripty-konektoru.md).
|
||||
| `MappingEditor` | `components/dashboard/flow/MappingEditor.tsx` | Editor transformací v obou režimech (pole na pole, JSON). |
|
||||
| `DataState` | `components/dashboard/DataState.tsx` | Načítání, chyba, prázdno. Ať to každá stránka nekreslí po svém. |
|
||||
| `apiFetch<T>` | `lib/api.ts` | Jediná cesta na API: base path, token, `ApiError` s celým hlášením ze serveru. |
|
||||
| `useApiQuery<T>` | `lib/useApiQuery.ts` | Načtení dat do stránky včetně `reload`, `refreshing` a `total`. S `body` pošle POST, s `enabled: false` se neptá, `patchOn` opraví data z události bez dotazu. |
|
||||
| `useApiQuery<T>` | `hooks/useApiQuery.ts` | Načtení dat do stránky včetně `reload`, `refreshing` a `total`. S `body` pošle POST, s `enabled: false` se neptá, `patchOn` opraví data z události bez dotazu. |
|
||||
| `useCollection(key)`, `useAccess()`, `useCollectionSelector` | `lib/collections.tsx` | Číselníky za firmu (lidé, skupiny, typy, služby, konektory, přístup) ze sdíleného skladu, opravované z událostí. Ne `apiFetch` na číselník ze stránky. |
|
||||
| `patchTicketList(...)` | `lib/ticketEvents.ts` | Oprava seznamu ticketů z `payload.ticket` v události. Použít jako `patchOn`. |
|
||||
| `apiFetchWithMeta<T>` | `lib/api.ts` | Jako `apiFetch`, ale vrací i `X-Total-Count`. Pro stránkované seznamy. |
|
||||
| `useSubmit(fn)` | `lib/useSubmit.ts` | Odeslání formuláře: `saving`, chyba, reset. Dvanáct řádků, které si dřív psal každý formulář zvlášť. |
|
||||
| `useUnsavedChanges(dirty)` | `lib/useUnsavedChanges.ts` | Varování při odchodu z rozepsaného formuláře nebo stromu. |
|
||||
| `useSubmit(fn)` | `hooks/useSubmit.ts` | Odeslání formuláře: `saving`, chyba, reset. Dvanáct řádků, které si dřív psal každý formulář zvlášť. |
|
||||
| `useUnsavedChanges(dirty)` | `hooks/useUnsavedChanges.ts` | Varování při odchodu z rozepsaného formuláře nebo stromu. |
|
||||
| `priorities`, `priorityLabel` | `lib/options.ts` | Pevné číselníky. Stavy a kanály se berou ze serveru (`/widget-data/options`). |
|
||||
| `plural(count, forms)` | `lib/format.ts` | Skloňování počtu (1 ticket, 2 tickety, 5 ticketů). |
|
||||
| `Field`, `Input`, `Select`, `Textarea` | `components/ui/form/` | Formulářové prvky s jednou sadou tříd (`controlClass`). Vlastní `inputClass` ve stránce je chyba. |
|
||||
| `Chip` | `components/ui/Chip.tsx` | Štítek. |
|
||||
| `Table`, `TableHead`, `Th`, `TableRow`, `Td` | `components/ui/Table.tsx` | Tabulka seznamu v portalu (hlavicka verzalkami, radky s linkou). Ctyri stranky ji kreslily kazda jinak. Huste tabulky ticketu a vykonu zustavaji zvlast, jsou to jine tabulky. |
|
||||
| `ServiceIcon` | `components/ui/ServiceIcon.tsx` | Ikona sluzby podle klice z katalogu. Misto `const Icon = serviceIcon(key)` v JSX, ktere lint hlasi jako komponentu vytvorenou pri vykresleni. |
|
||||
| `EntityForm` | `components/dashboard/EntityForm.tsx` | Formular jedne entity v modalu, pouziva ho `EntityAdmin`. Pole z popisu sloupcu, hodnoty a chyby v propsech. |
|
||||
| `useLatest(value)` | `hooks/useLatest.ts` | Ref s posledni hodnotou pro callbacky, ktere nemaji byt v zavislostech effectu. Zapis v layout effectu, aby vykresleni zustalo ciste. |
|
||||
| `useSyncFromSource(source, apply)` | `hooks/useSyncFromSource.ts` | Prevzeti dat ze zdroje do rozepsaneho stavu uz pri vykresleni, ne v `useEffect`. Stara kopie neproblikne a stranka se nekresli dvakrat. |
|
||||
| `TicketCard` | `components/dashboard/TicketCard.tsx` | Karta ticketu pro dlaždice a mobil, varianta `compact` pro widgety. |
|
||||
| `useMediaQuery(query)` | `lib/useMediaQuery.ts` | Tabulka nebo karty podle šířky. `TicketTable` podle toho kreslí obojí, druhá komponenta není. |
|
||||
| `useMediaQuery(query)`, `MD_UP` | `hooks/useMediaQuery.ts` | Tabulka nebo karty podle šířky pres `useSyncExternalStore`, prohlizec je zdroj pravdy. `TicketTable` podle toho kreslí obojí, druhá komponenta není. |
|
||||
| `cn(...)` | `lib/cn.ts` | Skládání tříd. Podmíněné třídy nikdy ručně přes šablonu. |
|
||||
| `format*` | `lib/format.ts` | Čísla, procenta, datum, relativní čas, trvání. Formátování se nepíše v komponentě. |
|
||||
| `serviceIcon(key)` | `lib/serviceIcons.ts` | Klíč ikony ze serveru na komponentu. Server neposílá komponenty. |
|
||||
| `usePageMeta` | `lib/usePageMeta.ts` | Titulek stránky. |
|
||||
| `usePageMeta` | `hooks/usePageMeta.ts` | Titulek stránky. |
|
||||
| `Badge`, `Button`, `Modal`, `Card`, ... | `components/ui/` | Základní prvky. Nový vzhled tlačítka patří sem, ne do stránky. |
|
||||
|
||||
## Pravidla, která z toho plynou
|
||||
|
||||
1. **Nová entita v nastavení**: `defineStore` v modulu entity, řádek v
|
||||
`bootstrap.ts`, `crudRouter` v `settings.ts`, popis v `Settings.tsx`.
|
||||
`bootstrap.ts`, `crudRouter` v `src/routes/settings/<entita>.ts` a mount v `settings/index.ts`, popis v `Settings.tsx`.
|
||||
Nic jiného se psát nemusí.
|
||||
2. **Data, která se mění za provozu**, jdou přes `withMirror`. Data, která se
|
||||
čtou při každém requestu a mění zřídka, přes `withCache`. Obojí nikdy.
|
||||
|
||||
@@ -43,7 +43,7 @@ i vyúčtovaná částka.
|
||||
|
||||
Co k tomu je potřeba:
|
||||
|
||||
1. **Cena u operace.** Do katalogu (`src/data/services.ts`) přidat
|
||||
1. **Cena u operace.** Do katalogu (`src/data/services/catalog/`) přidat
|
||||
`priceCzk` k `ServiceOperation`. Chybějící cena znamená 0, ne chybu -
|
||||
nová operace nesmí rozbít odhad.
|
||||
2. **Očekávaný počet běhů.** Jedno číslo u automatizace, které zadá uživatel
|
||||
|
||||
@@ -21,7 +21,7 @@ Proto tři vrstvy, každá napsaná jednou:
|
||||
| Klient | `components/dashboard/EntityAdmin.tsx` | Tabulka, modál, validace, mazání. |
|
||||
|
||||
Nová entita v nastavení pak znamená: `defineStore` v modulu entity, jeden řádek
|
||||
v `bootstrap.ts`, jeden `crudRouter` v `settings.ts`, jeden popis v
|
||||
v `bootstrap.ts`, jeden `crudRouter` v `src/routes/settings/<entita>.ts` a mount v `settings/index.ts`, jeden popis v
|
||||
`Settings.tsx`. Nic víc.
|
||||
|
||||
`crudRouter` navic s volbou `event` publikuje `<druh>.created`, `.updated`
|
||||
|
||||
@@ -103,7 +103,7 @@ Medián, ne průměr: jeden ticket zapomenutý přes dovolenou by průměr úpln
|
||||
rozhodil. Fronta se počítá vždycky celá, bez ohledu na období - leží tam bez
|
||||
ohledu na to, na co se zrovna díváme.
|
||||
|
||||
Čísla počítá `getAgentStats` v `src/data/ticketStore.ts` a používá je widget
|
||||
Čísla počítá `getAgentStats` v `src/data/tickets/stats.ts` a používá je widget
|
||||
i detail osoby. Kdyby si je stránka počítala sama, na dvou místech by vyšlo
|
||||
něco jiného.
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ v návrhu, ne v provozu:
|
||||
| Služba odpoví dvakrát jinak | Klíč proti dvojímu provedení u kroku, aby se nevystavila druhá faktura. |
|
||||
| Služba je pomalá jen pro jednu firmu | Fronta po firmách, aby jedna firma nezablokovala ostatní. |
|
||||
|
||||
Timeout a rozlišení "zkusit znovu" a "marné" už v `scripts/http.ts` je,
|
||||
Timeout a rozlišení "zkusit znovu" a "marné" už v `src/runtime/scripts/http.ts` je,
|
||||
klíč proti dvojímu provedení taky. Chybí to, co je nad tím: fronta, opakování
|
||||
a vypínání služby po sérii chyb.
|
||||
|
||||
|
||||
@@ -113,6 +113,13 @@ behu poznat, co spustil clovek a co cas.
|
||||
Pak beh skonci jako `failed` a zustane k nahlednuti. Nemaze se: bez zaznamu
|
||||
by nikdo nezjistil, ze se neco nestalo.
|
||||
|
||||
Prodlevy jsou pole `BACKOFF_MS` v `src/runtime/queue.ts` a index do nej je
|
||||
`attempts - 1`. Po neuspechu je `attempts` aspon 1, takze index sedi; kdyby
|
||||
ale prisla nula, `BACKOFF_MS[-1]` je `undefined` a `new Date(NaN)` by beh
|
||||
naplanoval na nikdy. `noUncheckedIndexedAccess` to odhalil, cteni ma proto
|
||||
zalohu `MAX_BACKOFF_MS`. Podobna chyba byla v `rateLimit`: pri `max: 0` bylo
|
||||
`Retry-After` `NaN`, ted je aspon 1 sekunda.
|
||||
|
||||
**Opakuje se jen to, co samo rekne `retryable`.** Vychozi je "ne". Pravidlo
|
||||
je stejne ve vsech vrstvach a je napsane v komentari nad `StepResult`
|
||||
v `executor.ts`:
|
||||
@@ -302,6 +309,19 @@ k 7. 9. 2026.
|
||||
|
||||
Stara podoba (`fieldId` primo na kroku) se dal cte, prevadi ji `rulesOf`.
|
||||
|
||||
Prvni testy executoru (`tests/runtime/executor.test.ts`, zari 2026) nasly
|
||||
v podminkach dve skutecne chyby, obe jsou opravene:
|
||||
|
||||
- **Prazdna hodnota se porovnavala jako nula.** `ordered()` delal
|
||||
`Number('')`, a to je `0`, takze `castka <= 1000` platilo i pro castku,
|
||||
ktera nikdy nedorazila. Ted prazdna strana znamena "neda se porovnat"
|
||||
a `gt`, `gte`, `lt`, `lte` jsou nepravda. Pro "nedorazilo" plati dal
|
||||
pravidlo vyse: ptat se `isNotEmpty`.
|
||||
- **Hole jmeno vystupu vyhravalo nad `krok.jmeno`.** `conditionValue()`
|
||||
hledal nejdriv hole jmeno, a to drzi vystup **prvniho** kroku, ktery ho
|
||||
zapsal. Podminka nad druhym krokem se stejnym nazvem vystupu tak cetla
|
||||
hodnotu z prvniho. Poradi je ted `fieldId`, `krok.jmeno`, hole jmeno.
|
||||
|
||||
Radek podminky v logu proto nese i to, s cim se porovnavalo, a rozlisuje
|
||||
`nedorazilo` od `prázdné`:
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Seznam bezicich aplikaci je na `https://services.csbot.cz/apps`. Kazda ma
|
||||
`/docs` se Swaggerem a `/openapi.json` (u .NET aplikaci `/docs/v1/swagger.json`)
|
||||
se strojove citelnym popisem.
|
||||
|
||||
Katalog v `src/data/services.ts` z toho vychazi. **Neni to totez**: jedna
|
||||
Katalog v `src/data/services/catalog/` z toho vychazi. **Neni to totez**: jedna
|
||||
aplikace muze nest vic sluzeb katalogu a nektere sluzby katalogu zatim zadnou
|
||||
aplikaci nemaji.
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@ a krok to rekne misto toho, aby predstiral selhani.
|
||||
| Tokeny EasyWebu | `src/mcp/easyweb/session.ts` |
|
||||
| Prevod schemat | `src/mcp/schema.ts` |
|
||||
| Nastroje v katalogu | `src/data/mcpTools.ts` |
|
||||
| Obe sluzby | `src/data/services.ts` |
|
||||
| Obe sluzby | `src/data/services/catalog/mcp.ts` |
|
||||
| Nacteni nastroju | `src/routes/connectors.ts` |
|
||||
| Vykonna cast kroku | `src/runtime/builtinSteps.ts`, `runMcpTool` |
|
||||
| Ulozeni u konektoru | `src/data/connectors/*`, migrace `004` |
|
||||
|
||||
@@ -180,7 +180,7 @@ coz je cil, to sedi.
|
||||
| Navrh | Kde to je |
|
||||
| ------------------------------- | ---------------------------------------------------------------- |
|
||||
| `Field`, `Input`, `Select`, `Textarea` | `components/ui/form/`, tridy v `controlClass.ts` |
|
||||
| `useSubmit` | `lib/useSubmit.ts` |
|
||||
| `useSubmit` | `hooks/useSubmit.ts` |
|
||||
| ciselniky ven | `lib/options.ts` (priority), stavy a kanaly z `/widget-data/options` |
|
||||
| kompaktni karta ticketu | `components/dashboard/TicketCard.tsx`, varianta `compact` |
|
||||
| stitek | `components/ui/Chip.tsx` |
|
||||
@@ -264,6 +264,13 @@ jsou velke a s widgety nesouvisi. Prevest to, ceho se dotykame (ticket, helpdesk
|
||||
plus verejne stranky, kde je drift videt nejvic, a zbytek nechat doputovat, jak
|
||||
se k nemu bude sahat.
|
||||
|
||||
Stav v zari 2026: doputovalo to. Vstupy jsou z `components/ui/form` vsude
|
||||
vcetne `Overview` a `TriggerConfig`, a tabulky seznamu (`EntityAdmin`,
|
||||
`InvitePanel`, `People`, `AuditView`) kresli jedna `components/ui/Table.tsx`.
|
||||
Sprava entit je rozdelena na `EntityAdmin` (tabulka, mazani) a `EntityForm`
|
||||
(formular v modalu); nastaveni ma `settings/FeaturesAdmin` a `settings/AuditView`
|
||||
jako vlastni komponenty, `Settings.tsx` je jen sklada.
|
||||
|
||||
---
|
||||
|
||||
## 3 - Hledani jako modal s kriterii
|
||||
@@ -409,7 +416,7 @@ members: Array<{ personId: string; seesAll: boolean }>
|
||||
```
|
||||
|
||||
Doporuceni je **b**. `personIds` se cte na sesti mistech (`people.ts`,
|
||||
`dashboard.ts`, `settings.ts`, `builtinSteps.ts`, `People.tsx`, seed), takze je to
|
||||
`routes/dashboard/`, `routes/settings/`, `builtinSteps.ts`, `People.tsx`, seed), takze je to
|
||||
hodina prace a ne migrace, ktere by se clovek bal. U varianty a) vznikne za mesic
|
||||
skupina, kde nekdo "vidi vse" a pritom v ni neni.
|
||||
|
||||
|
||||
@@ -2,6 +2,119 @@
|
||||
|
||||
Nejnovejsi nahore.
|
||||
|
||||
## 2026-09-09 - Struktura podle zasad: rozdeleni souboru, lint, testy
|
||||
|
||||
`D:\GitHubRepository\CLAUDE.md` dostal zasady pro vsechny projekty (struktura
|
||||
Node a React, jedno cteni `process.env`, lint a format v repu, testy
|
||||
v `tests/`, soubor nad 500 radku je signal k rozdeleni). Projekt se od nich
|
||||
lisil na nekolika mistech naraz: `index.ts` skladal aplikaci i poslouchal,
|
||||
`routes/dashboard.ts` mel pres tisic radku a `openapi.ts` skoro tri tisice,
|
||||
katalog sluzeb byl jeden soubor, lint ani testy neexistovaly a `process.env`
|
||||
se cetl na sesti mistech. Tahle zmena to srovnava; nic z toho nemeni chovani
|
||||
aplikace, az na dve skryte chyby nize a dve chyby, ktere nasly prvni testy.
|
||||
|
||||
### Co se presunulo
|
||||
|
||||
| Driv | Ted | Proc |
|
||||
| --------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| `scripts/*.js` | `connectors/*.js` | `scripts/` je podle zasad pro pomocne skripty vyvoje, ne pro kod nacitany za behu |
|
||||
| `src/scripts/` | `src/runtime/scripts/` | je to runtime, ktery skripty spousti, patri k fronte a executoru |
|
||||
| `src/index.ts` | `src/index.ts` (jen start) a `src/app.ts` (`createApp()`) | aplikace jde postavit v testu bez portu (supertest) |
|
||||
| `src/routes/dashboard.ts` | `src/routes/dashboard/` (10 souboru po domenach a `shared.ts`) | jeden router = jedna domena, mount v `index.ts` |
|
||||
| `src/routes/settings.ts` | `src/routes/settings/` (jedna entita = jeden soubor) | totez |
|
||||
| `src/openapi.ts` | `src/openapi/{index,helpers,components}.ts` a `paths/*.ts` | popis endpointu lezi u sveho routeru; slozeny dokument ma stejnych 98 cest |
|
||||
| `src/data/ticketStore.ts` | `src/data/tickets/` (model, state, persist, queries, store, intake, trace, stats, seed, remap) | fasada zustava, importy se nemeni |
|
||||
| `src/data/automationStore.ts` | `src/data/automations/` (model, state, persist, store, validation, webhook, runs, seed, seedDemo, remap) | totez |
|
||||
| `src/data/services.ts` | `src/data/services/index.ts` a `catalog/<skupina>.ts` | jeden soubor na skupinu sluzeb, `catalog/index.ts` drzi poradi |
|
||||
| `web/src/lib/use*.ts` | `web/src/hooks/` | hooky maji vlastni slozku, `lib/` jsou ciste funkce |
|
||||
|
||||
`config.scriptsDir` ma vychozi `./connectors`, Dockerfile slozku kopiruje,
|
||||
promenna `SCRIPTS_DIR` se nemeni. `process.env` se ted cte **jen**
|
||||
v `src/config.ts`; pro `<SLUZBA>_BASE_URL` pribylo
|
||||
`config.serviceBaseUrlOverride(variable)`, protoze nazev promenne sklada
|
||||
katalog a vypisovat kazdou sluzbu do konfigurace by znamenalo dve mista.
|
||||
Skripty konektoru dostaly `ctx.util.base64`, `google.send-email` uz nesaha na
|
||||
`Buffer`.
|
||||
|
||||
### Web
|
||||
|
||||
Sdilene prvky: `components/ui/Table.tsx` (ctyri seznamy kreslily tabulku
|
||||
kazdy jinak: `EntityAdmin`, `InvitePanel`, `People`, `AuditView`),
|
||||
`components/ui/ServiceIcon.tsx`, vstupy v `Overview` a `TriggerConfig` z
|
||||
`ui/form` misto vlastnich `<input>`. Rozdelene soubory:
|
||||
`components/dashboard/scripts/{TestPanel,CodeEditor}`,
|
||||
`dashboard/settings/{FeaturesAdmin,AuditView,types}`, `flow/{SampleBody,ModelTree,WebhookCalls}`,
|
||||
`lib/exampleBody.ts`, `components/dashboard/EntityForm.tsx`, `widgets/EditBar.tsx`.
|
||||
Nad 500 radku zustavaji `AutomationDetail`, `TicketDetail`, `MappingEditor`
|
||||
a na serveru `data/services/catalog/ticket.ts`; duvody jsou
|
||||
v [03-architektura-a-mapa-kodu.md](03-architektura-a-mapa-kodu.md).
|
||||
|
||||
Magicka cisla na obou stranach dostala pojmenovane konstanty s komentarem
|
||||
(`JSON_BODY_LIMIT`, `STATIC_MAX_AGE_SEC`, `MAX_PAGE_LIMIT`, `KEEP_DAYS`,
|
||||
`WEBHOOK_TOKEN_BYTES`, `MD_UP`, ...), hodnoty se nezmenily.
|
||||
|
||||
### Nastroje
|
||||
|
||||
`eslint.config.js` (typescript-eslint, `react-hooks` v7 pro web, `connectors/`
|
||||
jako obycejny JS bez globalu, zadne `any`, zadny prazdny `catch`),
|
||||
`.prettierrc`, `.prettierignore`, `.editorconfig`, `.nvmrc` (20),
|
||||
`.env.example` se vsemi promennymi a komentarem, `vitest.config.ts`. Skripty
|
||||
`npm run lint`, `format`, `format:check`, `test`, `test:watch` vedle
|
||||
`typecheck`.
|
||||
|
||||
**Lint je cisty na celem repu bez jedineho `eslint-disable`.** Pravidla hooku
|
||||
Reactu v7 hlasi zapis do refu pri vykresleni, `setState` v effectu
|
||||
a komponentu vytvorenou pri vykresleni. Reseni je vzdy zmena navrhu, ne
|
||||
vyjimka: `hooks/useLatest.ts` (ref s posledni hodnotou, zapis v layout
|
||||
effectu), `hooks/useSyncFromSource.ts` (prevzeti dat ze zdroje pri vykresleni
|
||||
misto `useEffect`), odvozeny stav misto kopie ve stavu, dialogy jako vlastni
|
||||
komponenty, ktere se pri zavreni odmontuji (stav se resetuje sam),
|
||||
`useMediaQuery` pres `useSyncExternalStore`, `ServiceIcon` pres
|
||||
`createElement`.
|
||||
|
||||
### Prisnejsi TypeScript
|
||||
|
||||
Oba `tsconfig` maji `noUncheckedIndexedAccess`. Opraveno 55 mist na serveru
|
||||
a 29 na webu, vzdy osetrenim `undefined`, nikde `!`. Dve z nich byly skutecne
|
||||
chyby:
|
||||
|
||||
- `BACKOFF_MS[attempts - 1]` v `src/runtime/queue.ts` je pri `attempts = 0`
|
||||
`undefined` a `new Date(NaN)` by beh naplanoval na nikdy; cteni ma zalohu
|
||||
`MAX_BACKOFF_MS`.
|
||||
- `rateLimit` s `max: 0` posilal `Retry-After: NaN`; ted aspon 1 sekunda.
|
||||
|
||||
### Testy
|
||||
|
||||
`tests/` zrcadli `src/`: 8 souboru, 105 testu, vsechny prochazi.
|
||||
`tests/setup.ts` nastavi rezim pameti (`DATA_DIR=''`, `DATABASE_URL=''`,
|
||||
pevny `SECRETS_KEY` a `JWT_SECRET`, `SEED_DEMO=0`) a umlci `console.info`
|
||||
a `console.warn`; test migrace si bere docasny `DATA_DIR`.
|
||||
|
||||
| Soubor | Co hlida |
|
||||
| ----------------------------------- | ------------------------------------------------------------------------ |
|
||||
| `data/access.test.ts` | `accessFor`, `visibilityFor`, `resolveScope`: pohledy, strop viditelnosti, cizi firma je 404 |
|
||||
| `data/permissions.test.ts` | `permissionsOf` za firmu, `syncSystemRoles` |
|
||||
| `data/tickets.test.ts` | `intakeEvent` (externi ID za firmu), `listTickets` s povinnym filtrem, `updateTicketStatus` |
|
||||
| `data/migratePeople.test.ts` | prevod `ppl_` na ucty vcetne ticketu, skupin a stromu; zapis na disk |
|
||||
| `net/guard.test.ts` | `urlProblem` (privatni rozsahy), `readBodyLimited`, `readJsonLimited` |
|
||||
| `routes/health.test.ts` | `createApp()` pres supertest: health, 404 jako JSON, 401, prihlaseni, `/access` za firmu |
|
||||
| `runtime/executor.test.ts` | podminky (retezce, cisla, data, seznamy, `all`/`any`), stara podoba, stropy `MAX_STEPS`, `MAX_ACTIONS`, `MAX_LOOP_ITEMS`, vystupy, `retryable` |
|
||||
| `runtime/scripts/util.test.ts` | `createRedactor` ve ctyrech tvarech, `parseBool`, `parseNumber`, `pick`, `truncate` |
|
||||
|
||||
Prvni testy executoru nasly dve chyby v podminkach, obe opravene: prazdna
|
||||
hodnota se pri `gt`/`lt` porovnavala jako nula (`Number('')` je `0`) a hole
|
||||
jmeno vystupu melo prednost pred `krok.jmeno`, takze podminka nad druhym
|
||||
krokem se stejnym vystupem cetla hodnotu z prvniho. Podrobne
|
||||
v [20-fronta-a-runtime.md](20-fronta-a-runtime.md).
|
||||
|
||||
### Znamy stav proti zasadam
|
||||
|
||||
Jeden `package.json` pro server i web (workspaces az bude mit kazda strana
|
||||
vlastni build), logovani `console.*` s prefixem modulu misto strukturovaneho
|
||||
loggeru, zadny soubor CI. Prettier prosel celym kodem (`npm run format`,
|
||||
se svolenim); markdown je z formatovani vyjmuty (`.prettierignore`), protoze
|
||||
dokumentace ma vlastni styl tabulek. Zapsano v [01-prehled-a-stav.md](01-prehled-a-stav.md).
|
||||
|
||||
## 2026-09-09 - Incident jde otevrit a posunout do dalsiho stavu
|
||||
|
||||
Seznam incidentu ukazoval jen titulek, sluzbu a casy. Server pritom uz posilal
|
||||
|
||||
Reference in New Issue
Block a user