evo360-types 1.3.503 → 1.3.507
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps/evo-integrations/zod-schemas.d.ts +10 -10
- package/dist/apps/evo-med/calendar/zod-schemas.d.ts +6 -6
- package/dist/apps/evo-task/zod-schemas.d.ts +52 -52
- package/dist/apps/evo-task/zod-schemas.js +3 -0
- package/dist/apps/evo-task/zod-schemas.ts +3 -0
- package/dist/apps/hub-automation/zod-schemas.d.ts +292 -292
- package/dist/types/evo-integrations/index.d.ts +1 -0
- package/dist/types/evo-integrations/index.js +1 -0
- package/dist/types/evo-integrations/index.ts +1 -0
- package/dist/types/evo-integrations/test-suite.d.ts +211 -0
- package/dist/types/evo-integrations/test-suite.js +101 -0
- package/dist/types/evo-integrations/test-suite.ts +376 -0
- package/dist/types/evo-task/index.d.ts +1 -0
- package/dist/types/evo-task/index.js +6 -0
- package/dist/types/evo-task/index.ts +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
// ======================================================
|
|
2
|
+
// evo-integrations — bateria de regressão de adapters (feat-123)
|
|
3
|
+
//
|
|
4
|
+
// Porte do script `_regressao-adapters.cjs` para ferramenta de produto no Nexus.
|
|
5
|
+
//
|
|
6
|
+
// A ferramenta é APARTADA: roda por fora, chamando as APIs (`integrations_actions`,
|
|
7
|
+
// `integrations_admin`, `integrations_sync_monitor`) exatamente como o script faz.
|
|
8
|
+
// Quem orquestra a sequência é o FE; quem persiste o resultado é o BE.
|
|
9
|
+
//
|
|
10
|
+
// Este módulo é o contrato COMPARTILHADO entre os dois lados:
|
|
11
|
+
// · o FE monta a seleção a partir do catálogo de passos;
|
|
12
|
+
// · o BE valida a seleção contra o MESMO catálogo e calcula o veredito.
|
|
13
|
+
//
|
|
14
|
+
// O catálogo de defeitos CONHECIDOS não mora aqui — mora no backend do Nexus,
|
|
15
|
+
// porque só ele calcula veredito (o FE apenas renderiza o que recebe).
|
|
16
|
+
// ======================================================
|
|
17
|
+
|
|
18
|
+
import type { IFireDoc } from "../shared";
|
|
19
|
+
|
|
20
|
+
// Path: /platform/evo-integrations/test-runs/{run_id}
|
|
21
|
+
export const TEST_RUNS_COLLECTION = "test-runs";
|
|
22
|
+
// Path: /platform/evo-integrations/test-runs/{run_id}/steps/{step_id}
|
|
23
|
+
export const TEST_RUN_STEPS_COLLECTION = "steps";
|
|
24
|
+
|
|
25
|
+
// ======================================================
|
|
26
|
+
// Suítes
|
|
27
|
+
// ======================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* O agrupamento é derivado da DEPENDÊNCIA REAL DE ESTADO, não de estética:
|
|
31
|
+
* o `external_id` devolvido pelo create alimenta get/update/confirm/revert/cancel,
|
|
32
|
+
* e o do patient.create alimenta o round-trip e o delete.
|
|
33
|
+
*/
|
|
34
|
+
export type TestSuiteId =
|
|
35
|
+
| "reading" // S1 — dicionários e leitura; independentes, zero efeito colateral
|
|
36
|
+
| "appointment" // S2 — ciclo de vida; ordem estrita
|
|
37
|
+
| "sync" // S3 — depende do cancel da S2
|
|
38
|
+
| "patient" // S4 — ordem estrita; opcional
|
|
39
|
+
| "cleanup"; // Z — limpeza; selecionável (D11)
|
|
40
|
+
|
|
41
|
+
export interface ITestSuiteMeta {
|
|
42
|
+
id: TestSuiteId;
|
|
43
|
+
label: string;
|
|
44
|
+
/** Ordem estrita = o passo N depende do estado produzido pelo N-1. */
|
|
45
|
+
ordered: boolean;
|
|
46
|
+
description: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const TEST_SUITES: readonly ITestSuiteMeta[] = [
|
|
50
|
+
{
|
|
51
|
+
id: "reading",
|
|
52
|
+
label: "Dicionários e leitura",
|
|
53
|
+
ordered: false,
|
|
54
|
+
description:
|
|
55
|
+
"Capabilities de consulta. Nenhuma escreve — pode rodar sozinha com efeito colateral zero.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "appointment",
|
|
59
|
+
label: "Ciclo de vida do agendamento",
|
|
60
|
+
ordered: true,
|
|
61
|
+
description:
|
|
62
|
+
"create → get → update → confirm → revert_confirm → cancel. Cada passo depende do external_id do create.",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: "sync",
|
|
66
|
+
label: "Sync não ressuscita",
|
|
67
|
+
ordered: true,
|
|
68
|
+
description:
|
|
69
|
+
"Força o sync de 1 dia e confere que o agendamento cancelado NÃO volta. Exige o cancel da suíte anterior.",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "patient",
|
|
73
|
+
label: "Paciente",
|
|
74
|
+
ordered: true,
|
|
75
|
+
description:
|
|
76
|
+
"create → round-trip (get+update) → delete. O create nunca foi exercitado por nenhuma rodada do script.",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "cleanup",
|
|
80
|
+
label: "Varredura de resíduo",
|
|
81
|
+
ordered: false,
|
|
82
|
+
description:
|
|
83
|
+
"Lê a agenda EXTERNA e cancela o que tiver o marcador. Selecionável — quem roda é o dev de integrações, que responde pelo que escolhe.",
|
|
84
|
+
},
|
|
85
|
+
] as const;
|
|
86
|
+
|
|
87
|
+
// ======================================================
|
|
88
|
+
// Passos
|
|
89
|
+
// ======================================================
|
|
90
|
+
|
|
91
|
+
export type TestStepId =
|
|
92
|
+
// S1
|
|
93
|
+
| "caps.list"
|
|
94
|
+
| "ui.config"
|
|
95
|
+
| "procedure.list"
|
|
96
|
+
| "status.list"
|
|
97
|
+
| "dicts.extra"
|
|
98
|
+
| "patient.list"
|
|
99
|
+
| "patient.get"
|
|
100
|
+
| "appointment.list"
|
|
101
|
+
// S2
|
|
102
|
+
| "appointment.create"
|
|
103
|
+
| "appointment.get"
|
|
104
|
+
| "appointment.update"
|
|
105
|
+
| "appointment.confirm"
|
|
106
|
+
| "appointment.revert_confirm"
|
|
107
|
+
| "appointment.cancel"
|
|
108
|
+
// S3
|
|
109
|
+
| "sync.force"
|
|
110
|
+
// S4
|
|
111
|
+
| "patient.create"
|
|
112
|
+
| "patient.roundtrip"
|
|
113
|
+
| "patient.delete"
|
|
114
|
+
// Z
|
|
115
|
+
| "residue.sweep";
|
|
116
|
+
|
|
117
|
+
export interface ITestStepMeta {
|
|
118
|
+
id: TestStepId;
|
|
119
|
+
suite: TestSuiteId;
|
|
120
|
+
label: string;
|
|
121
|
+
/**
|
|
122
|
+
* `true` = o passo ESCREVE no PMS de produção.
|
|
123
|
+
*
|
|
124
|
+
* Usado em dois lugares: para o modo somente-leitura e para classificar o custo
|
|
125
|
+
* de REPETIR um passo — repetir leitura é livre, repetir escrita duplica efeito.
|
|
126
|
+
*/
|
|
127
|
+
writes: boolean;
|
|
128
|
+
/** Passos que precisam ter passado antes. Vazio = pode rodar sozinho. */
|
|
129
|
+
dependsOn: readonly TestStepId[];
|
|
130
|
+
/** Capability invocada, quando houver. Nem todo passo tem uma. */
|
|
131
|
+
capability?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Ordem do array = ordem de execução. Não é 1:1 com capability:
|
|
136
|
+
* · `residue.sweep` não invoca capability nenhuma (varre a agenda externa);
|
|
137
|
+
* · `sync.force` chama `integrations_sync_monitor`, não uma capability;
|
|
138
|
+
* · `appointment.list` aparece em dois passos (leitura e varredura);
|
|
139
|
+
* · `patient.roundtrip` combina `patient.get` + `patient.update`.
|
|
140
|
+
*/
|
|
141
|
+
export const TEST_STEPS: readonly ITestStepMeta[] = [
|
|
142
|
+
// ── S1 — leitura ────────────────────────────────────────────────────────────
|
|
143
|
+
{ id: "caps.list", suite: "reading", label: "capabilities", writes: false, dependsOn: [] },
|
|
144
|
+
{ id: "ui.config", suite: "reading", label: "ui-config", writes: false, dependsOn: [] },
|
|
145
|
+
{ id: "procedure.list", suite: "reading", label: "procedure.list", writes: false, dependsOn: [], capability: "appointment.procedure.list" },
|
|
146
|
+
{ id: "status.list", suite: "reading", label: "status.list", writes: false, dependsOn: [], capability: "appointment.status.list" },
|
|
147
|
+
{ id: "dicts.extra", suite: "reading", label: "dicionários extra", writes: false, dependsOn: [] },
|
|
148
|
+
{ id: "patient.list", suite: "reading", label: "patient.list", writes: false, dependsOn: [], capability: "patient.list" },
|
|
149
|
+
{ id: "patient.get", suite: "reading", label: "patient.get", writes: false, dependsOn: [], capability: "patient.get" },
|
|
150
|
+
{ id: "appointment.list", suite: "reading", label: "appointment.list", writes: false, dependsOn: [], capability: "appointment.list" },
|
|
151
|
+
|
|
152
|
+
// ── S2 — ciclo de vida ──────────────────────────────────────────────────────
|
|
153
|
+
{ id: "appointment.create", suite: "appointment", label: "create", writes: true, dependsOn: [], capability: "appointment.create" },
|
|
154
|
+
{ id: "appointment.get", suite: "appointment", label: "get", writes: false, dependsOn: ["appointment.create"], capability: "appointment.get" },
|
|
155
|
+
{ id: "appointment.update", suite: "appointment", label: "update", writes: true, dependsOn: ["appointment.create"], capability: "appointment.update" },
|
|
156
|
+
{ id: "appointment.confirm", suite: "appointment", label: "confirm", writes: true, dependsOn: ["appointment.create"], capability: "appointment.confirm" },
|
|
157
|
+
{ id: "appointment.revert_confirm", suite: "appointment", label: "revert_confirm", writes: true, dependsOn: ["appointment.confirm"], capability: "appointment.revert_confirm" },
|
|
158
|
+
{ id: "appointment.cancel", suite: "appointment", label: "cancel", writes: true, dependsOn: ["appointment.create"], capability: "appointment.cancel" },
|
|
159
|
+
|
|
160
|
+
// ── S3 — sync ───────────────────────────────────────────────────────────────
|
|
161
|
+
{ id: "sync.force", suite: "sync", label: "sync (1 dia)", writes: true, dependsOn: ["appointment.cancel"] },
|
|
162
|
+
|
|
163
|
+
// ── S4 — paciente ───────────────────────────────────────────────────────────
|
|
164
|
+
{ id: "patient.create", suite: "patient", label: "patient.create", writes: true, dependsOn: [], capability: "patient.create" },
|
|
165
|
+
{ id: "patient.roundtrip", suite: "patient", label: "round-trip (get+update)", writes: true, dependsOn: [], capability: "patient.update" },
|
|
166
|
+
{ id: "patient.delete", suite: "patient", label: "patient.delete", writes: true, dependsOn: ["patient.create"], capability: "patient.delete" },
|
|
167
|
+
|
|
168
|
+
// ── Z — limpeza ─────────────────────────────────────────────────────────────
|
|
169
|
+
{ id: "residue.sweep", suite: "cleanup", label: "varredura de resíduo", writes: true, dependsOn: [] },
|
|
170
|
+
] as const;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Suíte padrão (D10) — a LINHA DE BASE COMPARÁVEL: todos os passos.
|
|
174
|
+
*
|
|
175
|
+
* Só uma corrida com exatamente esta seleção é comparável com a anterior. Sem isso
|
|
176
|
+
* o output principal da ferramenta ("nenhum defeito novo") seria infalsificável:
|
|
177
|
+
* bastaria desmarcar o passo que falha.
|
|
178
|
+
*
|
|
179
|
+
* Atenção: a seleção não basta. `comparable` também exige `target.create_patient`
|
|
180
|
+
* ligado — senão `patient.create`/`patient.delete` são pulados e a cobertura real
|
|
181
|
+
* fica menor que a nominal. Quem decide isso é o backend, em `computeComparable`.
|
|
182
|
+
*/
|
|
183
|
+
export const STANDARD_SUITE_STEP_IDS: readonly TestStepId[] = TEST_STEPS.map(
|
|
184
|
+
(s) => s.id,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
export const READ_ONLY_STEP_IDS: readonly TestStepId[] = TEST_STEPS.filter(
|
|
188
|
+
(s) => !s.writes,
|
|
189
|
+
).map((s) => s.id);
|
|
190
|
+
|
|
191
|
+
// ======================================================
|
|
192
|
+
// Checks
|
|
193
|
+
// ======================================================
|
|
194
|
+
|
|
195
|
+
export type TestCheckStatus = "pass" | "fail" | "skipped";
|
|
196
|
+
|
|
197
|
+
export interface ITestCheck {
|
|
198
|
+
/**
|
|
199
|
+
* Id ESTÁVEL no formato `<step_id>:<slug>` — ex. `appointment.update:sem_divergencia`.
|
|
200
|
+
*
|
|
201
|
+
* É a chave que o catálogo de conhecidos referencia. O script antigo casava por
|
|
202
|
+
* REGEX no texto do label, o que quebrava nos dois sentidos: mudar a redação
|
|
203
|
+
* descatalogava um defeito em silêncio, e um regex largo engolia defeito novo de
|
|
204
|
+
* outra causa. Por isso o id vem antes do texto — o label pode ser reescrito à
|
|
205
|
+
* vontade.
|
|
206
|
+
*/
|
|
207
|
+
id: string;
|
|
208
|
+
label: string;
|
|
209
|
+
status: TestCheckStatus;
|
|
210
|
+
detail?: string;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ======================================================
|
|
214
|
+
// Passo executado
|
|
215
|
+
// ======================================================
|
|
216
|
+
|
|
217
|
+
export type TestStepStatus =
|
|
218
|
+
| "pending"
|
|
219
|
+
| "running"
|
|
220
|
+
| "pass"
|
|
221
|
+
| "known" // falhou, mas casa com defeito catalogado — não reprova a corrida
|
|
222
|
+
| "fail" // defeito NOVO
|
|
223
|
+
| "skipped"
|
|
224
|
+
| "error";
|
|
225
|
+
|
|
226
|
+
export interface ITestSchemaValidation {
|
|
227
|
+
ok: boolean;
|
|
228
|
+
errors?: Array<{ path: (string | number)[]; message: string; code?: string }>;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* O wire — o que o BACKEND mandou para o n8n, lido de
|
|
233
|
+
* `integrations_sync_monitor GET /calls?run_id=`.
|
|
234
|
+
*
|
|
235
|
+
* É a camada que interessa a quem mantém os workflows: a resposta da action mostra
|
|
236
|
+
* o que a UI mandou, não o que saiu na linha. `DocumentReference` vivo no payload
|
|
237
|
+
* (a classe de bug que derrubou produção no revert_confirm) só aparece aqui.
|
|
238
|
+
*/
|
|
239
|
+
export interface ITestStepWire {
|
|
240
|
+
request_json?: string;
|
|
241
|
+
response_json?: string;
|
|
242
|
+
n8n_execution_id?: string | null;
|
|
243
|
+
n8n_workflow_id?: string | null;
|
|
244
|
+
workflow_url?: string;
|
|
245
|
+
http_status?: number | null;
|
|
246
|
+
timed_out?: boolean | null;
|
|
247
|
+
error_message?: string | null;
|
|
248
|
+
request_truncated?: boolean | null;
|
|
249
|
+
response_truncated?: boolean | null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface ITestRunStep extends IFireDoc {
|
|
253
|
+
step_id: TestStepId;
|
|
254
|
+
suite: TestSuiteId;
|
|
255
|
+
order: number;
|
|
256
|
+
status: TestStepStatus;
|
|
257
|
+
started_at?: unknown;
|
|
258
|
+
finished_at?: unknown;
|
|
259
|
+
duration_ms?: number;
|
|
260
|
+
|
|
261
|
+
/** Camada 1 — o que a UI mandou para `integrations_actions` e o que voltou. */
|
|
262
|
+
layer1?: { request?: unknown; response?: unknown };
|
|
263
|
+
|
|
264
|
+
/** Correlação com o wire: `transport_metadata.run_id` da resposta da action. */
|
|
265
|
+
n8n_run_id?: string | null;
|
|
266
|
+
|
|
267
|
+
/** Camada 2 — o que o BE mandou para o n8n. */
|
|
268
|
+
wire?: ITestStepWire | null;
|
|
269
|
+
|
|
270
|
+
schema_validation?: {
|
|
271
|
+
request?: ITestSchemaValidation;
|
|
272
|
+
response?: ITestSchemaValidation;
|
|
273
|
+
} | null;
|
|
274
|
+
|
|
275
|
+
checks: ITestCheck[];
|
|
276
|
+
|
|
277
|
+
/** Preenchido quando `status === 'known'`: qual defeito catalogado casou. */
|
|
278
|
+
known_defects?: Array<{ check_id: string; description: string; ref: string }>;
|
|
279
|
+
|
|
280
|
+
error?: string | null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ======================================================
|
|
284
|
+
// Corrida
|
|
285
|
+
// ======================================================
|
|
286
|
+
|
|
287
|
+
export type TestRunStatus = "running" | "finished" | "abandoned";
|
|
288
|
+
|
|
289
|
+
/** Dados do paciente novo, quando o usuário liga a criação (D3). */
|
|
290
|
+
export interface ITestNewPatient {
|
|
291
|
+
first_name: string;
|
|
292
|
+
last_name?: string;
|
|
293
|
+
mobile_phone?: string;
|
|
294
|
+
email?: string;
|
|
295
|
+
social_id?: string;
|
|
296
|
+
birth_date?: string;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export interface ITestRunTarget {
|
|
300
|
+
/** Paciente de teste JÁ EXISTENTE, usado na leitura e no agendamento. */
|
|
301
|
+
patient_id: string;
|
|
302
|
+
/** Só quando `create_patient` está ligado. */
|
|
303
|
+
new_patient?: ITestNewPatient | null;
|
|
304
|
+
create_patient: boolean;
|
|
305
|
+
/** `YYYY-MM-DD`. Recomendado no passado — é aviso, não trava (D2). */
|
|
306
|
+
slot_date: string;
|
|
307
|
+
/** `HH:MM`. */
|
|
308
|
+
slot_time: string;
|
|
309
|
+
/** Dia povoado para o `appointment.list`; sem isso usa `slot_date`. */
|
|
310
|
+
list_date?: string | null;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Diagnóstico de segurança — AVISO, não trava (D2).
|
|
315
|
+
*
|
|
316
|
+
* Os dois avisos têm gravidade diferente e a UI precisa refletir isso: data futura
|
|
317
|
+
* só ativa as varreduras D-2/D-0, que dependem de janela; gatilho de evento ligado
|
|
318
|
+
* dispara na hora do create.
|
|
319
|
+
*/
|
|
320
|
+
export interface ITestRunPreflight {
|
|
321
|
+
slot_in_past: boolean;
|
|
322
|
+
/** Quais dos gatilhos de evento estão ligados na agenda-alvo. */
|
|
323
|
+
triggers_enabled: string[];
|
|
324
|
+
/**
|
|
325
|
+
* `notification_config.configs` vazio.
|
|
326
|
+
*
|
|
327
|
+
* Distinguir de "desligado" importa: nada dispara nos dois casos, mas aqui é por
|
|
328
|
+
* AUSÊNCIA DE CONFIGURAÇÃO, não por decisão de alguém.
|
|
329
|
+
*/
|
|
330
|
+
notification_config_empty: boolean;
|
|
331
|
+
evaluated_at?: unknown;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** O que a corrida criou no PMS — permite enumerar resíduo quando o `Z` é desmarcado (D11). */
|
|
335
|
+
export interface ITestRunInventory {
|
|
336
|
+
appointment_external_ids: string[];
|
|
337
|
+
patient_external_id?: string | null;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export interface ITestRunVerdict {
|
|
341
|
+
ok: number;
|
|
342
|
+
known: number;
|
|
343
|
+
new_defects: number;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export interface ITestRun extends IFireDoc {
|
|
347
|
+
adapter_id: string;
|
|
348
|
+
tenant: string;
|
|
349
|
+
calendar_id: string;
|
|
350
|
+
|
|
351
|
+
target: ITestRunTarget;
|
|
352
|
+
|
|
353
|
+
selection: {
|
|
354
|
+
preset: "standard" | "read-only" | "custom";
|
|
355
|
+
step_ids: TestStepId[];
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
/** Quantos passos da suíte padrão esta corrida cobriu. */
|
|
359
|
+
coverage: { ran: number; total: number };
|
|
360
|
+
/** `true` só quando a seleção é exatamente a suíte padrão (D10). */
|
|
361
|
+
comparable: boolean;
|
|
362
|
+
|
|
363
|
+
preflight: ITestRunPreflight;
|
|
364
|
+
inventory: ITestRunInventory;
|
|
365
|
+
verdict: ITestRunVerdict;
|
|
366
|
+
|
|
367
|
+
status: TestRunStatus;
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Dono da corrida. Quem orquestra é o FE, então duas abas conduzindo a mesma
|
|
371
|
+
* corrida escreveriam na mesma agenda de produção em paralelo — outro usuário
|
|
372
|
+
* abre em modo leitura até assumir explicitamente.
|
|
373
|
+
*/
|
|
374
|
+
created_by: string;
|
|
375
|
+
finished_at?: unknown;
|
|
376
|
+
}
|
|
@@ -58,6 +58,7 @@ export declare const TaskAutoHandlerEnum: {
|
|
|
58
58
|
readonly AppointmentConfirmation: "appointment_confirmation";
|
|
59
59
|
readonly AppointmentPostConsultation: "appointment_post_consultation";
|
|
60
60
|
readonly IntegrationsSyncRun: "evo-integrations.sync-run";
|
|
61
|
+
readonly LeadFormCapture: "lead_form_capture";
|
|
61
62
|
readonly CampaignMaterialize: "campaign.materialize";
|
|
62
63
|
readonly CampaignDispatchBatch: "campaign.dispatch_batch";
|
|
63
64
|
};
|
|
@@ -117,6 +117,12 @@ exports.TaskAutoHandlerEnum = {
|
|
|
117
117
|
// types/evo-integrations). Permite que o `/force` roteie pelo task-runner e
|
|
118
118
|
// herde retry/backoff/DLQ, em vez de montar a mensagem PubSub na mão.
|
|
119
119
|
IntegrationsSyncRun: "evo-integrations.sync-run",
|
|
120
|
+
// feat-121: captação de lead por FORMULÁRIO (site/landing). Resolve ou cria o lead
|
|
121
|
+
// pelo telefone, aplica o pipe que vier no payload (origem/qualificação/tags/campanha)
|
|
122
|
+
// e inicia a conversa no WhatsApp conforme o `mode` (`contato` | `agenda_demo`).
|
|
123
|
+
// Tópico do executor: `lead_form_capture.execute_requests` (functions-notifications).
|
|
124
|
+
// Espelhado à mão em `zTaskAutoHandlerSchema` — sem lá, o POST /tasks estoura ZodError.
|
|
125
|
+
LeadFormCapture: "lead_form_capture",
|
|
120
126
|
// feat-081 F2: handlers do modulo de campanhas (padrao pontilhado da feat-078 —
|
|
121
127
|
// `resolveHandlerTopic` monta `campaign.materialize.execute_requests`, topico que
|
|
122
128
|
// a CF `campaign_materialize` ja escuta desde a F1, e
|
|
@@ -128,6 +128,12 @@ export const TaskAutoHandlerEnum = {
|
|
|
128
128
|
// types/evo-integrations). Permite que o `/force` roteie pelo task-runner e
|
|
129
129
|
// herde retry/backoff/DLQ, em vez de montar a mensagem PubSub na mão.
|
|
130
130
|
IntegrationsSyncRun: "evo-integrations.sync-run",
|
|
131
|
+
// feat-121: captação de lead por FORMULÁRIO (site/landing). Resolve ou cria o lead
|
|
132
|
+
// pelo telefone, aplica o pipe que vier no payload (origem/qualificação/tags/campanha)
|
|
133
|
+
// e inicia a conversa no WhatsApp conforme o `mode` (`contato` | `agenda_demo`).
|
|
134
|
+
// Tópico do executor: `lead_form_capture.execute_requests` (functions-notifications).
|
|
135
|
+
// Espelhado à mão em `zTaskAutoHandlerSchema` — sem lá, o POST /tasks estoura ZodError.
|
|
136
|
+
LeadFormCapture: "lead_form_capture",
|
|
131
137
|
// feat-081 F2: handlers do modulo de campanhas (padrao pontilhado da feat-078 —
|
|
132
138
|
// `resolveHandlerTopic` monta `campaign.materialize.execute_requests`, topico que
|
|
133
139
|
// a CF `campaign_materialize` ja escuta desde a F1, e
|