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>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
0c405ea55a
commit
104ae36783
+93
-11
@@ -85,6 +85,9 @@ Vyzaduji `Authorization: Bearer <token>`:
|
||||
| GET | `/api/dashboard/settings/people-overview` |
|
||||
| GET | `/api/dashboard/settings/users-overview` |
|
||||
| PATCH | `/api/dashboard/settings/users/:id/password` |
|
||||
| GET | `/api/dashboard/settings/ares/companies` |
|
||||
| GET | `/api/dashboard/settings/ares/companies/:ico/persons` |
|
||||
| POST | `/api/dashboard/settings/ares/tenants` |
|
||||
| POST | `/api/admin/impersonate` |
|
||||
| POST | `/api/admin/impersonate/stop` |
|
||||
| GET | `/api/admin/impersonate/candidates` |
|
||||
@@ -102,20 +105,35 @@ fabrika (`src/routes/crud.ts`):
|
||||
Jednotny pro cele API:
|
||||
|
||||
```json
|
||||
{ "error": "validation_error", "message": "Zadejte platny e-mail." }
|
||||
{
|
||||
"error": "validation_error",
|
||||
"message": "Zadejte platny e-mail.",
|
||||
"issues": [{ "field": "email", "message": "Zadejte platny e-mail." }]
|
||||
}
|
||||
```
|
||||
|
||||
| HTTP | `error` | Kdy |
|
||||
| ---- | --------------------- | ------------------------------------------- |
|
||||
| 400 | `validation_error` | vstup neprosel schematem |
|
||||
| 400 | `validation_error` | vstup neprosel schematem, `issues` po polich |
|
||||
| 401 | `unauthorized` | chybi nebo neplatny token |
|
||||
| 401 | `invalid_credentials` | spatny e-mail nebo heslo |
|
||||
| 403 | `forbidden` | nedostatecna role |
|
||||
| 404 | `not_found` | zaznam nebo endpoint neexistuje |
|
||||
| 403 | `forbidden` | nedostatecne pravo v dane firme |
|
||||
| 404 | `not_found` | zaznam nebo endpoint neexistuje, nebo je cizi firmy |
|
||||
| 409 | ruzne | operace nedava v danem stavu smysl |
|
||||
| 429 | `too_many_requests` | prekrocen limit requestu, hlavicka `Retry-After` |
|
||||
| 500 | `internal_error` | neodchycena chyba, detail jen mimo produkci |
|
||||
|
||||
`message` je vzdy cesky a je urcena k zobrazeni uzivateli.
|
||||
`message` je vzdy cesky a je urcena k zobrazeni uzivateli. Chybu validace
|
||||
sklada `validationError` v `src/middleware/validation.ts`, aby `issues` mely
|
||||
vsude stejny tvar a formular umel chybu ukazat u pole.
|
||||
|
||||
Limity (`src/middleware/rateLimit.ts`) jsou jen na verejnych endpointech, kde
|
||||
se da hadat: prihlaseni 20 pokusu za 15 minut, kontakt 5 za hodinu, prijeti
|
||||
pozvanky 5 za 15 minut. Pocita se podle adresy klienta, proto ma Express
|
||||
`trust proxy` = 1 - bez toho by vsichni za Caddy sdileli jeden limit.
|
||||
|
||||
Kazdy asynchronni handler je obaleny (`safeRouter` v `src/middleware/asyncHandler.ts`).
|
||||
Odmitnuta promise je 500 s logem, ne pad procesu.
|
||||
|
||||
## Autentizace
|
||||
|
||||
@@ -139,6 +157,21 @@ Typy udalosti: `ticket.created`, `ticket.updated`, `ticket.assigned`,
|
||||
`automation.created`, `automation.updated`, `automation.deleted`,
|
||||
`automation.run`, `webhook.received`.
|
||||
|
||||
K tomu udalosti entit `tenant`, `user`, `role`, `person`, `group`,
|
||||
`ticketType`, `action`, `widget`, `connector`, `feature` s priponou
|
||||
`.created`, `.updated`, `.deleted`. Payload je `{ id, <druh>: zaznam }`,
|
||||
u smazani jen `{ id }`. Publikuje je `crudRouter` (volba `event`), routy
|
||||
konektoru a PUT features. Klient z nich opravuje sklad ciselniku bez dotazu.
|
||||
|
||||
**Kazda udalost nese `tenantId`** (`null` = cela platforma). Stream posila jen
|
||||
udalosti firem, do kterych uzivatel patri, a to i v historii po pripojeni.
|
||||
Udalost s `payload.userId` jde jen tomu cloveku. Spravce platformy vidi vse.
|
||||
Driv videl kazdy prihlaseny udalosti vsech firem - nazev ticketu cizi firmy
|
||||
v bubline je unik dat, i kdyz se na ticket nedostane.
|
||||
|
||||
`ticket.updated`, `ticket.assigned` a `ticket.resolved` nesou
|
||||
v `payload.ticket` cely ticket, aby klient opravil seznam na miste.
|
||||
|
||||
Klient se pripojuje pres fetch s hlavickou `Authorization`, ne pres EventSource.
|
||||
Duvod je v [03-architektura-a-mapa-kodu.md](03-architektura-a-mapa-kodu.md).
|
||||
|
||||
@@ -166,8 +199,9 @@ curl -X POST https://services.csbot.cz/apps/<app-id>/webhook/<token> \
|
||||
-d '{"customer":"Nordis","score":18}'
|
||||
```
|
||||
|
||||
Prototyp pozadavek prijme, zvaliduje a zapocita do metrik, ale strom akci
|
||||
nevykona - runtime neexistuje.
|
||||
Token se porovnava v konstantnim case (`timingSafeEqualString`
|
||||
v `src/lib/secure.ts`), stejne jako token prijmu a kod pozvanky. V logu
|
||||
requestu je z tokenu videt jen prvnich sest znaku.
|
||||
|
||||
## Firmy a pohledy
|
||||
|
||||
@@ -192,6 +226,11 @@ bez vysvetleni.
|
||||
Odpoved nese vedle `items` jeste `meId`. Klient podle nej pozna, ktere tickety
|
||||
jsou jeho, a jestli ma vubec smysl nabizet filtr "moje".
|
||||
|
||||
**Strankovani.** `/tickets` a `/runs` berou `limit` a `offset`, `limit` nejvys
|
||||
500. Celkovy pocet je v hlavicce `X-Total-Count`, u ticketu i v tele jako
|
||||
`total`. Bez `limit` se vraci vse jako driv (u behu poslednich 50), aby se
|
||||
nerozbily stavajici odkazy. Klient cte hlavicku pres `apiFetchWithMeta`.
|
||||
|
||||
Filtrovani dela **server**, ne klient. Seznam a prehled vytizeni tak nikdy
|
||||
neukazuji jina cisla. Vyhledavaci pole v portalu je jina vec - to jen dohledava
|
||||
v uz nactenem seznamu.
|
||||
@@ -246,7 +285,26 @@ selhala**. Selhani akce neni chyba API. V odpovedi je `ok`, `summary`, `detail`
|
||||
s celym chybovym hlasenim a `durationMs`. Cely prubeh se zapise do logu ticketu.
|
||||
|
||||
Vestavene akce (`type`, `tags`, `group`, `assign`, `status`, `comment`) jsou
|
||||
zvlast: meni ticket sam, ne cizi sluzbu, a kazda ma vlastni pravo.
|
||||
zvlast: meni ticket sam, ne cizi sluzbu, a kazda ma vlastni pravo. Vsechny
|
||||
vcetne `claim` jdou pres `builtinAction` v `src/routes/ticketActions.ts`, kde
|
||||
se pravo pta za firmu ticketu a ticket se nejdriv najde pres strop
|
||||
viditelnosti (`visibleTicketOrDeny`). Driv mely `assign`, `status` a `comment`
|
||||
vlastni handlery a kazdy se ptal jinak.
|
||||
|
||||
## Firma z registru ARES
|
||||
|
||||
Jen spravce platformy (`/api/dashboard/settings/ares`). Popis rozhodnuti je
|
||||
v [07-firmy-a-prava.md](07-firmy-a-prava.md).
|
||||
|
||||
| Endpoint | Co vraci |
|
||||
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| `GET ares/companies?query=` | same cislice (1 az 8) hledaji IC presne, jinak nazev, nejvys 10. U firmy, ktera uz v portalu je, `existingTenantId` |
|
||||
| `GET ares/companies/{ico}/persons` | soucasni statutari a prokura z verejneho rejstriku, u kazdeho navrzeny e-mail `IC-poradi@placeholder.cz` |
|
||||
| `POST ares/tenants` | zalozi firmu a ucty vybranych osob, vraci firmu a seznam uctu |
|
||||
|
||||
Chyba registru je `ares_error` s kodem podle toho, co ARES vratil - neni to
|
||||
chyba naseho API a nema se opakovat automaticky. Adresa registru je
|
||||
`ARES_BASE_URL`.
|
||||
|
||||
## Prijem udalosti do ticketu
|
||||
|
||||
@@ -284,9 +342,33 @@ a kdy se to zkusi znovu.
|
||||
## Prava a navigace
|
||||
|
||||
`GET /api/dashboard/access` vraci `permissions` (efektivni prava po slouceni
|
||||
roli), `nav` (zalozky, ktere ma volajici videt) a `platformAdmin`. Klient podle
|
||||
toho kresli, ale **nic si nedovozuje** - kdo co smi, rozhoduje server u kazdeho
|
||||
requestu znovu.
|
||||
roli), `nav` (zalozky, ktere ma volajici videt), `platformAdmin` a `roleNames`
|
||||
(nazvy roli v prepnute firme, pro popisek u uctu). Klient podle toho kresli,
|
||||
ale **nic si nedovozuje** - kdo co smi, rozhoduje server u kazdeho requestu
|
||||
znovu.
|
||||
|
||||
### Kdo co smi, po routach
|
||||
|
||||
Pravo se vzdy pta **za firmu zaznamu**, ne za prepnutou firmu. Cizi firma je
|
||||
404, chybejici pravo 403.
|
||||
|
||||
| Co | Pravo |
|
||||
| ----------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| firmy CRUD, ARES | spravce platformy |
|
||||
| uzivatele CRUD | spravce platformy, nebo `user.manage` jen v ramci sve firmy |
|
||||
| pozvanky | `user.manage`, role jen z te firmy |
|
||||
| konektory create, update, delete, test | `connector.manage` |
|
||||
| automatizace create, update, delete, regenerate | `automation.edit` |
|
||||
| `/services`, `/connectors/services` | clenstvi ve firme |
|
||||
| assign, status, comment, claim na ticketu | prava vestavene akce za firmu ticketu plus strop viditelnosti |
|
||||
| `/api/admin/impersonate*` | `impersonate` |
|
||||
| `/api/admin/audit` | `audit.view` |
|
||||
| `/storage`, `/scripts` s cestami na serveru | cesty jen spravci platformy, ostatni dostanou odpoved bez nich |
|
||||
|
||||
Spravce firmy s `user.manage` **nenastavi `platformAdmin`**, neprida clenstvi
|
||||
v jine firme, nesahne na spravce platformy a nesmaze cloveka, ktery je i
|
||||
v jine firme - ten ucet neni jen jeho. Podrobnosti
|
||||
v [07-firmy-a-prava.md](07-firmy-a-prava.md).
|
||||
|
||||
`GET /api/dashboard/settings/catalog` vraci katalog prav a modulu, aby formular
|
||||
role nemel seznam prav napsany v kodu klienta.
|
||||
|
||||
Reference in New Issue
Block a user