# 04 - API Interaktivni dokumentace je na `/apps//docs`. Tenhle soubor popisuje to, co ze Swaggeru neni videt. ## Endpointy Verejne: | Metoda | Cesta | Popis | | ------ | ------------------- | --------------------------------------- | | GET | `/health` | health check | | GET | `/docs` | Swagger UI | | GET | `/openapi.json` | OpenAPI definice | | POST | `/api/auth/login` | prihlaseni, vraci JWT | | POST | `/api/contact` | poptavka z webu | | POST | `/webhook/:token` | prijem dat do automatizace | Vyzaduji `Authorization: Bearer `: | Metoda | Cesta | | ------ | --------------------------------------------------- | | GET | `/api/auth/me` | | POST | `/api/auth/logout` | | GET | `/api/dashboard/summary` | | GET | `/api/dashboard/people` | | GET | `/api/dashboard/tickets` | | GET | `/api/dashboard/tickets/workload` | | GET | `/api/dashboard/tickets/:id` | | POST | `/api/dashboard/tickets/:id/assign` | | POST | `/api/dashboard/tickets/:id/status` | | POST | `/api/dashboard/tickets/:id/comment` | | GET | `/api/dashboard/incidents` | | GET | `/api/dashboard/connectors` | | GET | `/api/dashboard/stream` | | GET | `/api/dashboard/automations` | | POST | `/api/dashboard/automations` | | GET | `/api/dashboard/automations/:id` | | PUT | `/api/dashboard/automations/:id` | | DELETE | `/api/dashboard/automations/:id` | | POST | `/api/dashboard/automations/:id/webhook/regenerate` | | POST | `/api/simulate` | ## Format chyb Jednotny pro cele API: ```json { "error": "validation_error", "message": "Zadejte platny e-mail." } ``` | HTTP | `error` | Kdy | | ---- | --------------------- | --------------------------------------- | | 400 | `validation_error` | vstup neprosel schematem | | 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 | | 409 | ruzne | operace nedava v danem stavu smysl | | 500 | `internal_error` | neodchycena chyba, detail jen mimo produkci | `message` je vzdy cesky a je urcena k zobrazeni uzivateli. ## Autentizace Hesla se hashuji bcryptem, plaintext se nikde neuklada. Login vraci JWT podepsany `JWT_SECRET` s platnosti `JWT_EXPIRES_IN`. Spatne heslo i neexistujici e-mail vraci stejnou odpoved, aby se neprozradilo, ktere ucty existuji. Pokus se loguje bez hesla. Token si drzi klient v `localStorage`. Pro produkci je cilovy stav `httpOnly` cookie se `Secure` a `SameSite` plus CSRF token. ## Zivy stream `GET /api/dashboard/stream` je Server-Sent Events. Po pripojeni posle potvrzeni a poslednich par udalosti, pak uz jen nove. Kazdych 25 sekund jde komentarovy radek, aby spojeni neuspalo proxy. Typy udalosti: `ticket.created`, `ticket.updated`, `ticket.assigned`, `ticket.resolved`, `incident.started`, `incident.updated`, `incident.resolved`, `automation.created`, `automation.updated`, `automation.deleted`, `automation.run`, `webhook.received`. 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). ## Webhook Verejny endpoint bez prihlaseni. Autorizuje neuhodnutelny token v adrese, 32 znaku z `randomBytes(24)` v base64url. Token generuje **vyhradne server**. Hodnota `webhookToken` poslana klientem se ignoruje, jinak by si sel nastavit predvidatelnou adresu. | Situace | Odpoved | | ----------------------------------- | ------- | | vse v poradku | 202 | | neznamy token | 404 | | automatizace je pozastavena | 409 | | chybi povinny parametr, spatny typ | 400 | Parametry navic se neodmitaji, jen loguji. Odesilatele bezne posilaji i vlastni data a odmitat je by rozbijelo integrace. ```bash curl -X POST https://services.csbot.cz/apps//webhook/ \ -H "Content-Type: application/json" \ -d '{"customer":"Nordis","score":18}' ``` Prototyp pozadavek prijme, zvaliduje a zapocita do metrik, ale strom akci nevykona - runtime neexistuje. ## Tickety Popis modelu je v [06-tickety.md](06-tickety.md), tady jen to, co se tyka API. `GET /api/dashboard/tickets` bere filtry v query: `assignee`, `status`, `channel`. U `assignee` jsou dve zvlastni hodnoty: `me` znamena resitele odpovidajiciho prihlasenemu uzivateli, `unassigned` frontu bez resitele. Neznama hodnota filtru se zaloguje a ignoruje - je lepsi ukazat vic ticketu nez prazdny seznam bez vysvetleni. Odpoved nese vedle `items` jeste `meId`. Klient podle nej pozna, ktere tickety jsou jeho, a jestli ma vubec smysl nabizet filtr "moje". 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. `GET /api/dashboard/tickets/:id` vraci navic `trace`, tedy log prubehu vcetne toho, co ktera volana sluzba vratila. `POST /api/dashboard/tickets/:id/assign` s telem `{"assigneeId": null}` vrati ticket do fronty. Neznamy resitel vraci 404, ne tiche odpojeni. ## Simulace `POST /api/simulate` vyvola provozni udalost pro nahled ziveho dashboardu. Zamerne meni skutecna data, ne jen posila falesnou notifikaci. Akce: `ticket.created`, `ticket.resolved`, `incident.started`, `incident.resolved`, `automation.run`. U `ticket.created` urcuje `channel` (whatsapp, facebook, instagram, email, voice, form, portal), odkud pozadavek prisel, a podle toho se poskladá i log ticketu. `knownCustomer: false` znamena, ze CRM firmu nedohleda - ticket zustane bez zakaznika i bez resitele a v logu je videt proc. Nevyplnena pole server doplni ukazkovou hodnotou. U akci s "resolved" se bez zadaneho id pouzije prvni nevyrizeny zaznam. ## Pri pridani endpointu Soucasne aktualizovat `src/openapi.ts` a tenhle soubor. Swagger musi odpovidat skutecnemu chovani aplikace, jinak je horsi nez zadny.