Fronta a worker: webhook odpovi hned, praci udelaji workeri
Webhook uz nic nevykonava v requestu. Zapise udalost do fronty a odpovi 202 do jednotek milisekund; strom vykona worker na pozadi. Za konektory nerucime, takze cekat na cizi sluzbu v requestu znamena ztracet udalosti pri timeoutu. Fronta ma opakovani s rostouci prodlevou (30 s, 2 min, 10 min, hodina), spravedlive poradi po firmach (jedna firma s tisicem udalosti nezablokuje ostatni), navrat zaseknutych behu po restartu a uklid hotovych. Marna chyba se neopakuje - chybejici skript za minutu existovat nezacne. Tri druhy spoustecu: push (webhook), vnitrni udalost (vznik a zmena ticketu) a pull, tedy pravidelne dotazovani u sluzeb bez webhooku (posta, zpravy). Planovac jen rekne "je cas", samotny dotaz je prvni krok stromu, takze ma zaznam v logu a opakuje se pri chybe jako cokoliv jineho. Kontrakt tela webhooku: kazdy parametr ma cestu (data.order.id, errors.0.message), takze jde napojit i odesilatel s vnorenym modelem. U adresy je metoda, ukazka tela a kopiruje se cela adresa vcetne domeny. Vnitrni kroky, ktere sahaji do naseho uloziste: ticket/upsert (zaloz nebo dopln podle externiho ID), assign-least-busy, assign-by-external, set-type, set-stage, add-tags, set-status, incident/create, flow/pause a flow/log. Faze ticketu jako treti osa vedle stavu a stitku. Stav je zivotni cyklus a pocitaji se z nej statistiky, faze je workflow daneho typu a muze byt jen jedna, takze se na ni da spolehnout v podmince. ID z cizich aplikaci u resitele: voicebot posle voicebotId a ticket skonci u toho, komu patri. Vazba je na jednom miste, ne v kazde automatizaci. Kazda chyba zaklada incident se dvema urovnemi: impact cte klient a je srozumitelny, detail cte admin a je v nem cely beh, ktery krok selhal, cele hlaseni a data na vstupu. Detail vidi jen spravce platformy. Ochrana proti smycce: automatizace navazana na zmenu ticketu ticket meni, cimz se spousti znovu - pri vyvoji to server polozilo. Resi to oznaceni behu pres AsyncLocalStorage a strop peti behu na jeden ticket za minutu. Upozorneni pri prideleni prace vcetne cisla u zalozky Tickety. Zivy dashboard: dlazdice nad nasimi daty na udalost, data z konektoru podle ttlSec s moznosti vynutit nacteni znovu. Opraveno: path a intervalSec u spoustece se pri ulozeni zahazovaly; nad seznamem neslo pouzit contains, takze na stitky neslo postavit podminku; novejsi vystup kroku ted prekryje starsi misto hlaseni konfliktu. Overeno dvema scenari proti bezicimu serveru, 34 kontrol: firma se skladem, expedici a IT, a hovory z voicebota (callSid do externiho ID, status do faze, prirazeni podle voicebotId, tri zpravy = jeden ticket se tremi udalostmi). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5d186dcd2e
commit
a57eca123e
+172
@@ -1968,6 +1968,178 @@ export function buildOpenApiDocument() {
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/dashboard/notifications': {
|
||||
get: {
|
||||
tags: ['Dashboard'],
|
||||
summary: 'Upozorneni prihlaseneho',
|
||||
description:
|
||||
'Cislo u zalozky Tickety a hlasky o pridelene praci. Upozorneni jsou ulozena, ' +
|
||||
'takze je najde i ten, kdo mel portal zavreny.',
|
||||
security: [{ bearerAuth: [] }],
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Upozorneni',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
items: { type: 'array', items: { type: 'object' } },
|
||||
unread: { type: 'integer' },
|
||||
mine: { type: 'integer', description: 'Kolik ticketu ma volajici u sebe.' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/dashboard/notifications/read': {
|
||||
post: {
|
||||
tags: ['Dashboard'],
|
||||
summary: 'Oznacit upozorneni jako prectena',
|
||||
security: [{ bearerAuth: [] }],
|
||||
requestBody: {
|
||||
required: false,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
description: 'Bez seznamu se oznaci vsechna.',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: { '200': { description: 'Oznaceno' } },
|
||||
},
|
||||
},
|
||||
'/api/dashboard/runs': {
|
||||
get: {
|
||||
tags: ['Automatizace'],
|
||||
summary: 'Stav fronty behu',
|
||||
description:
|
||||
'Kdyz neco nefunguje, tohle je prvni misto, kam se clovek podiva: ceka fronta, ' +
|
||||
'nebo uz to nekolikrat selhalo? U kazdeho behu je cele chybove hlaseni.',
|
||||
security: [{ bearerAuth: [] }],
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Fronta a posledni behy',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
stats: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
pending: { type: 'integer' },
|
||||
running: { type: 'integer' },
|
||||
done: { type: 'integer' },
|
||||
failed: { type: 'integer' },
|
||||
oldestPendingAt: { type: 'string', nullable: true },
|
||||
},
|
||||
},
|
||||
items: { type: 'array', items: { type: 'object' } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'/webhook/ticket/{token}': {
|
||||
post: {
|
||||
tags: ['Webhook'],
|
||||
summary: 'Prijem udalosti do ticketu',
|
||||
description:
|
||||
'VEREJNY endpoint, autorizuje token firmy v adrese. Se stejnym externalId se ' +
|
||||
'udalost navesi na existujici ticket, jinak vznikne novy. externalId je ' +
|
||||
'unikatni v ramci firmy.',
|
||||
parameters: [{ name: 'token', in: 'path', required: true, schema: { type: 'string' } }],
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
externalId: { oneOf: [{ type: 'string' }, { type: 'number' }] },
|
||||
source: { type: 'string', example: 'eshop' },
|
||||
event: { type: 'string', example: 'order.created' },
|
||||
subject: { type: 'string' },
|
||||
typeId: { type: 'string' },
|
||||
tags: { type: 'array', items: { type: 'string' } },
|
||||
fields: { type: 'object', additionalProperties: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
'201': { description: 'Ticket vznikl' },
|
||||
'200': { description: 'Udalost se navesila na existujici ticket' },
|
||||
'400': { description: 'Neplatna data' },
|
||||
'404': { description: 'Neznamy token' },
|
||||
},
|
||||
},
|
||||
},
|
||||
'/webhook/{token}': {
|
||||
post: {
|
||||
tags: ['Webhook'],
|
||||
summary: 'Prijem dat do automatizace',
|
||||
description:
|
||||
'VEREJNY endpoint. **Odpovi hned** (202) a strom vykona worker na pozadi - ' +
|
||||
'cizi sluzba muze odpovidat pomalu a odesilateli by vyprsel timeout. ' +
|
||||
'Telo se kontroluje proti kontraktu spoustece, vcetne vnorenych cest.',
|
||||
parameters: [{ name: 'token', in: 'path', required: true, schema: { type: 'string' } }],
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { type: 'object', additionalProperties: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
'202': {
|
||||
description: 'Prijato, zpracuje se na pozadi',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
accepted: { type: 'boolean' },
|
||||
automationId: { type: 'string' },
|
||||
runId: { type: 'string', nullable: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'400': { description: 'Telo neodpovida kontraktu spoustece' },
|
||||
'404': { description: 'Neznamy token' },
|
||||
'409': { description: 'Automatizace je pozastavena' },
|
||||
},
|
||||
},
|
||||
get: {
|
||||
tags: ['Webhook'],
|
||||
summary: 'Napoveda: co se v tele ceka',
|
||||
description: 'Vraci metodu, seznam parametru vcetne cest a ukazku tela.',
|
||||
parameters: [{ name: 'token', in: 'path', required: true, schema: { type: 'string' } }],
|
||||
responses: {
|
||||
'200': { description: 'Kontrakt' },
|
||||
'404': { description: 'Neznamy token' },
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/contact': {
|
||||
post: {
|
||||
tags: ['Kontakt'],
|
||||
|
||||
Reference in New Issue
Block a user