evo360-types 1.3.409 → 1.3.413
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-campaigns/zod-schemas.d.ts +17367 -0
- package/dist/apps/evo-campaigns/zod-schemas.js +354 -0
- package/dist/apps/evo-campaigns/zod-schemas.ts +389 -0
- package/dist/apps/evo-finops/zod-schemas.d.ts +96 -96
- package/dist/apps/evo-integrations/zod-schemas.d.ts +66 -66
- package/dist/apps/evo-med/calendar/zod-schemas.d.ts +72 -72
- package/dist/apps/evo-med/dic/zod-schemas.d.ts +6 -6
- package/dist/apps/evo-med/people/zod-schemas.d.ts +16 -16
- package/dist/apps/evo-notifications/quick-reply-action/zod-schemas.d.ts +33 -6
- package/dist/apps/evo-notifications/quick-reply-action/zod-schemas.js +12 -2
- package/dist/apps/evo-notifications/quick-reply-action/zod-schemas.ts +13 -2
- package/dist/apps/hub-automation/zod-schemas.d.ts +312 -0
- package/dist/apps/hub-automation/zod-schemas.js +12 -0
- package/dist/apps/hub-automation/zod-schemas.ts +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.ts +2 -0
- package/dist/types/evo-campaigns/index.d.ts +355 -0
- package/dist/types/evo-campaigns/index.js +34 -0
- package/dist/types/evo-campaigns/index.ts +495 -0
- package/dist/types/evo-crm/lead/index.d.ts +16 -2
- package/dist/types/evo-crm/lead/index.ts +20 -1
- package/dist/types/hub-automation/index.d.ts +18 -1
- package/dist/types/hub-automation/index.js +8 -1
- package/dist/types/hub-automation/index.ts +49 -3
- package/package.json +1 -1
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import type { FirestoreDocumentReference, IFireDoc } from "../shared";
|
|
2
|
+
import type { QualificationFunnelLevel } from "../evo-crm/dic";
|
|
3
|
+
|
|
4
|
+
// ======================================================
|
|
5
|
+
// evo-campaigns (feat-081 — Hub Omni Campaigns)
|
|
6
|
+
//
|
|
7
|
+
// Campaign orchestrator: aggregate entity over audience enumeration,
|
|
8
|
+
// multi-bucket dedup, pacing, ticket auto-close, conversion attribution
|
|
9
|
+
// and exportable reporting. Firestore holds mutable state ONLY; business
|
|
10
|
+
// events flow to BigQuery via evo_campaigns.events.
|
|
11
|
+
//
|
|
12
|
+
// Firestore (per tenant):
|
|
13
|
+
// - App root: /tenants/{t}/apps/evo-campaigns
|
|
14
|
+
// - Campaigns: /tenants/{t}/apps/evo-campaigns/campaigns/{campaignId}
|
|
15
|
+
// - Buckets: .../campaigns/{campaignId}/buckets/{bucketId}
|
|
16
|
+
// - Recipients: .../campaigns/{campaignId}/recipients/{recipientId}
|
|
17
|
+
// - Conversions: .../campaigns/{campaignId}/conversions/{leadId}
|
|
18
|
+
// - Lead history: /tenants/{t}/apps/evo-crm/leads/{leadId}/campaign-history/{campaignId}
|
|
19
|
+
// ======================================================
|
|
20
|
+
|
|
21
|
+
// ----- App + Firestore collections
|
|
22
|
+
export const EVO_CAMPAIGNS_APP = "evo-campaigns";
|
|
23
|
+
export const CAMPAIGNS_COLLECTION = "campaigns";
|
|
24
|
+
export const CAMPAIGN_BUCKETS_COLLECTION = "buckets";
|
|
25
|
+
export const CAMPAIGN_RECIPIENTS_COLLECTION = "recipients";
|
|
26
|
+
export const CAMPAIGN_CONVERSIONS_COLLECTION = "conversions";
|
|
27
|
+
/** Subcollection on the lead doc (evo-crm) — history + frequency + attribution. */
|
|
28
|
+
export const LEAD_CAMPAIGN_HISTORY_COLLECTION = "campaign-history";
|
|
29
|
+
|
|
30
|
+
// ----- Permissions (Q13)
|
|
31
|
+
export const EvoCampaignsPermissions = {
|
|
32
|
+
Read: "evo_campaigns_read",
|
|
33
|
+
Manage: "evo_campaigns_manage",
|
|
34
|
+
Export: "evo_campaigns_export",
|
|
35
|
+
CostsView: "evo_campaigns_costs_view",
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
export type EvoCampaignsPermissions =
|
|
39
|
+
(typeof EvoCampaignsPermissions)[keyof typeof EvoCampaignsPermissions];
|
|
40
|
+
|
|
41
|
+
// ----- Shared value objects -------------------------------------------------
|
|
42
|
+
|
|
43
|
+
/** Dictionary reference snapshot ({code,name}) — purpose, objective, close status... */
|
|
44
|
+
export interface ICampaignCodeName {
|
|
45
|
+
code: string;
|
|
46
|
+
name: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Campaign FSM (§1.3). */
|
|
50
|
+
export type CampaignStatus =
|
|
51
|
+
| "draft"
|
|
52
|
+
| "scheduled"
|
|
53
|
+
| "running"
|
|
54
|
+
| "paused"
|
|
55
|
+
| "finished"
|
|
56
|
+
| "canceled"
|
|
57
|
+
| "finished_error";
|
|
58
|
+
|
|
59
|
+
/** Business classification of the campaign. */
|
|
60
|
+
export type CampaignType =
|
|
61
|
+
| "conversion"
|
|
62
|
+
| "informative"
|
|
63
|
+
| "relationship"
|
|
64
|
+
| "operational"
|
|
65
|
+
| "promotional";
|
|
66
|
+
|
|
67
|
+
/** Delivery channel of a campaign. */
|
|
68
|
+
export type CampaignChannel = "whatsapp" | "email";
|
|
69
|
+
|
|
70
|
+
// ----- Variable mapping + CTAs ----------------------------------------------
|
|
71
|
+
|
|
72
|
+
/** Where a template variable gets its value from at send time. */
|
|
73
|
+
export type CampaignVariableSource =
|
|
74
|
+
| "placeholder" // resolved by the placeholder engine (feat-055) via `token`
|
|
75
|
+
| "fixed" // literal `value`
|
|
76
|
+
| "csv_column" // pulled from the recipient's csv_variables by `column`
|
|
77
|
+
| "qr_link"; // a quick-reply /qr link for `cta_id`
|
|
78
|
+
|
|
79
|
+
export interface ICampaignVariableMapping {
|
|
80
|
+
/** Template variable name/index this mapping fills. */
|
|
81
|
+
variable: string;
|
|
82
|
+
source: CampaignVariableSource;
|
|
83
|
+
/** source='placeholder': placeholder token (e.g. 'patient.first_name'). */
|
|
84
|
+
token?: string;
|
|
85
|
+
/** source='fixed': literal value. */
|
|
86
|
+
value?: string;
|
|
87
|
+
/** source='csv_column': column name in the uploaded CSV. */
|
|
88
|
+
column?: string;
|
|
89
|
+
/** source='qr_link': the CTA whose /qr link is injected. */
|
|
90
|
+
cta_id?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface ICampaignCta {
|
|
94
|
+
cta_id: string;
|
|
95
|
+
label: string;
|
|
96
|
+
/** WhatsApp template button position (0,1,2...). */
|
|
97
|
+
button_index?: number;
|
|
98
|
+
/** Final destination for the /qr redirect. */
|
|
99
|
+
target_url?: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ----- Pacing + ticket policy -----------------------------------------------
|
|
103
|
+
|
|
104
|
+
export interface ICampaignPacingWindow {
|
|
105
|
+
/** 'HH:mm' local (tenant timezone). */
|
|
106
|
+
start: string;
|
|
107
|
+
/** 'HH:mm' local (tenant timezone). */
|
|
108
|
+
end: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface ICampaignPacing {
|
|
112
|
+
batch_size: number;
|
|
113
|
+
batch_interval_minutes: number;
|
|
114
|
+
daily_limit: number;
|
|
115
|
+
allowed_window: ICampaignPacingWindow;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface ICampaignTicketPolicy {
|
|
119
|
+
/** 'close' auto-closes the ticket after send (default, Q7); 'keep_open' leaves it. */
|
|
120
|
+
mode: "close" | "keep_open";
|
|
121
|
+
/** Status from the ticket-closes dic applied when mode='close'. */
|
|
122
|
+
close_status?: ICampaignCodeName;
|
|
123
|
+
/** Optional note stamped on the closed ticket. */
|
|
124
|
+
note?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface ICampaignMedia {
|
|
128
|
+
/** 'image' | 'video' | 'document' — WhatsApp header media type. */
|
|
129
|
+
type: string;
|
|
130
|
+
gcs_path?: string;
|
|
131
|
+
url?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ----- Channel config -------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
/** Per-channel configuration (whatsapp/email) of a campaign. */
|
|
137
|
+
export interface ICampaignChannelConfig {
|
|
138
|
+
/** evo-chat channel id (WABA channel or email channel). */
|
|
139
|
+
channel_id: string;
|
|
140
|
+
/** HSM/email template id. */
|
|
141
|
+
template_id: string;
|
|
142
|
+
/** WhatsApp: template language code (e.g. 'pt_BR'). */
|
|
143
|
+
template_language?: string;
|
|
144
|
+
/** WhatsApp: template category from introspection (MARKETING/UTILITY/AUTHENTICATION). */
|
|
145
|
+
template_category?: string;
|
|
146
|
+
variable_mappings: ICampaignVariableMapping[];
|
|
147
|
+
/** WhatsApp header media (when the template requires it). */
|
|
148
|
+
media?: ICampaignMedia;
|
|
149
|
+
ctas: ICampaignCta[];
|
|
150
|
+
/** Outbound department for the resulting ticket. */
|
|
151
|
+
department_id?: string;
|
|
152
|
+
ticket_policy: ICampaignTicketPolicy;
|
|
153
|
+
pacing: ICampaignPacing;
|
|
154
|
+
/** Email: overrides the template subject when set (F5). */
|
|
155
|
+
subject_override?: string;
|
|
156
|
+
/** Email: preheader text. */
|
|
157
|
+
preheader?: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ----- Attribution / new-lead / frequency / schedule ------------------------
|
|
161
|
+
|
|
162
|
+
export interface ICampaignAttribution {
|
|
163
|
+
/** Conversion window in days (default 30). */
|
|
164
|
+
window_days: number;
|
|
165
|
+
/** Conversion event key (default 'appointment_scheduled'). */
|
|
166
|
+
conversion_event: string;
|
|
167
|
+
/** statusBase values that count as a conversion (Q10 default). */
|
|
168
|
+
appointment_status_base_in: string[];
|
|
169
|
+
/** Minimum interaction required to attribute a conversion. */
|
|
170
|
+
requires: "delivery" | "click" | "reply";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface ICampaignNewLeadConfig {
|
|
174
|
+
dist_channel: ICampaignCodeName;
|
|
175
|
+
/** Optional (Q8) — no default; only stamped when explicitly selected. */
|
|
176
|
+
qualification?: {
|
|
177
|
+
code: string;
|
|
178
|
+
name: string;
|
|
179
|
+
funnelLevel: QualificationFunnelLevel;
|
|
180
|
+
} | null;
|
|
181
|
+
tags?: string[];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface ICampaignFrequency {
|
|
185
|
+
/** Minimum days since the last marketing touch (Q4, default 15). */
|
|
186
|
+
min_days: number;
|
|
187
|
+
/** Bypass the frequency check (requires evo_campaigns_manage, Q13). */
|
|
188
|
+
override: boolean;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface ICampaignSchedule {
|
|
192
|
+
mode: "immediate" | "scheduled";
|
|
193
|
+
scheduled_at?: Date | null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ----- Dispatch state / snapshots / counters --------------------------------
|
|
197
|
+
|
|
198
|
+
export interface ICampaignSentToday {
|
|
199
|
+
/** 'yyyy-MM-dd' in tenant timezone. */
|
|
200
|
+
date: string;
|
|
201
|
+
per_channel: {
|
|
202
|
+
whatsapp?: number;
|
|
203
|
+
email?: number;
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface ICampaignDispatchState {
|
|
208
|
+
cursor_doc_id?: string | null;
|
|
209
|
+
next_dispatch_task_id?: string | null;
|
|
210
|
+
sent_today?: ICampaignSentToday;
|
|
211
|
+
batches_dispatched?: number;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export type CampaignPrevalidationStatus = "approved" | "warnings" | "blocked";
|
|
215
|
+
|
|
216
|
+
export interface ICampaignPrevalidation {
|
|
217
|
+
status: CampaignPrevalidationStatus;
|
|
218
|
+
errors: string[];
|
|
219
|
+
warnings: string[];
|
|
220
|
+
ran_at?: Date | null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface ICampaignCostEstimate {
|
|
224
|
+
per_channel: Record<string, unknown>;
|
|
225
|
+
total?: number;
|
|
226
|
+
currency?: string;
|
|
227
|
+
tariff_version?: string;
|
|
228
|
+
estimated_at?: Date | null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Per-channel delivery/engagement counters (increment/CAS). */
|
|
232
|
+
export interface ICampaignChannelCounters {
|
|
233
|
+
pending?: number;
|
|
234
|
+
sent?: number;
|
|
235
|
+
delivered?: number;
|
|
236
|
+
read?: number;
|
|
237
|
+
failed?: number;
|
|
238
|
+
clicked?: number;
|
|
239
|
+
replied?: number;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export interface ICampaignCounters {
|
|
243
|
+
raw?: number;
|
|
244
|
+
unique?: number;
|
|
245
|
+
eligible?: number;
|
|
246
|
+
excluded_optout?: number;
|
|
247
|
+
excluded_frequency?: number;
|
|
248
|
+
excluded_invalid?: number;
|
|
249
|
+
excluded_no_channel?: number;
|
|
250
|
+
excluded_duplicate?: number;
|
|
251
|
+
per_channel?: {
|
|
252
|
+
whatsapp?: ICampaignChannelCounters;
|
|
253
|
+
email?: ICampaignChannelCounters;
|
|
254
|
+
};
|
|
255
|
+
converted?: number;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ----- Campaign aggregate doc -----------------------------------------------
|
|
259
|
+
|
|
260
|
+
export interface ICampaign extends IFireDoc {
|
|
261
|
+
name: string;
|
|
262
|
+
description?: string | null;
|
|
263
|
+
purpose: ICampaignCodeName;
|
|
264
|
+
objective: ICampaignCodeName;
|
|
265
|
+
campaign_type: CampaignType;
|
|
266
|
+
tags?: string[];
|
|
267
|
+
|
|
268
|
+
status: CampaignStatus;
|
|
269
|
+
/** true until the post-finished attribution window closes. */
|
|
270
|
+
attribution_open: boolean;
|
|
271
|
+
/** now + window_days, set when the campaign finishes. */
|
|
272
|
+
attribution_deadline?: Date | null;
|
|
273
|
+
|
|
274
|
+
attribution: ICampaignAttribution;
|
|
275
|
+
|
|
276
|
+
channels: {
|
|
277
|
+
whatsapp?: ICampaignChannelConfig;
|
|
278
|
+
email?: ICampaignChannelConfig;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
new_lead_config?: ICampaignNewLeadConfig;
|
|
282
|
+
frequency: ICampaignFrequency;
|
|
283
|
+
schedule: ICampaignSchedule;
|
|
284
|
+
|
|
285
|
+
dispatch_state?: ICampaignDispatchState;
|
|
286
|
+
prevalidation?: ICampaignPrevalidation;
|
|
287
|
+
cost_estimate?: ICampaignCostEstimate;
|
|
288
|
+
counters?: ICampaignCounters;
|
|
289
|
+
|
|
290
|
+
// Audit (who/when per FSM transition)
|
|
291
|
+
created_by?: FirestoreDocumentReference;
|
|
292
|
+
updated_by?: FirestoreDocumentReference;
|
|
293
|
+
scheduled_by?: FirestoreDocumentReference;
|
|
294
|
+
started_by?: FirestoreDocumentReference;
|
|
295
|
+
paused_by?: FirestoreDocumentReference;
|
|
296
|
+
resumed_by?: FirestoreDocumentReference;
|
|
297
|
+
canceled_by?: FirestoreDocumentReference;
|
|
298
|
+
scheduled_at?: Date | null;
|
|
299
|
+
started_at?: Date | null;
|
|
300
|
+
paused_at?: Date | null;
|
|
301
|
+
resumed_at?: Date | null;
|
|
302
|
+
canceled_at?: Date | null;
|
|
303
|
+
finished_at?: Date | null;
|
|
304
|
+
cancel_reason?: string | null;
|
|
305
|
+
error_reason?: string | null;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ----- Bucket ---------------------------------------------------------------
|
|
309
|
+
|
|
310
|
+
export type CampaignBucketSourceType =
|
|
311
|
+
| "leads"
|
|
312
|
+
| "patients"
|
|
313
|
+
| "appointments"
|
|
314
|
+
| "csv";
|
|
315
|
+
|
|
316
|
+
export interface ICampaignBucketCsvFile {
|
|
317
|
+
gcs_path: string;
|
|
318
|
+
original_name: string;
|
|
319
|
+
headers: string[];
|
|
320
|
+
row_count: number;
|
|
321
|
+
/** Invalid rows with reason, capped at 200 in the doc (full report in GCS). */
|
|
322
|
+
invalid_rows?: Array<{ row: number; reason: string; [key: string]: unknown }>;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export interface ICampaignBucketCounts {
|
|
326
|
+
raw?: number;
|
|
327
|
+
unique_contribution?: number;
|
|
328
|
+
eligible?: number;
|
|
329
|
+
invalid?: number;
|
|
330
|
+
opt_out?: number;
|
|
331
|
+
frequency_excluded?: number;
|
|
332
|
+
no_channel?: number;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export interface ICampaignBucket extends IFireDoc {
|
|
336
|
+
source_type: CampaignBucketSourceType;
|
|
337
|
+
label: string;
|
|
338
|
+
/** Shape depends on source_type (Algolia filters or CSV mapping). */
|
|
339
|
+
filters?: Record<string, unknown>;
|
|
340
|
+
csv_file?: ICampaignBucketCsvFile;
|
|
341
|
+
counts?: ICampaignBucketCounts;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// ----- Recipient ------------------------------------------------------------
|
|
345
|
+
|
|
346
|
+
/** Flat field driving the batch queue (indexed). */
|
|
347
|
+
export type RecipientDispatchState =
|
|
348
|
+
| "pending"
|
|
349
|
+
| "dispatched"
|
|
350
|
+
| "done"
|
|
351
|
+
| "excluded";
|
|
352
|
+
|
|
353
|
+
/** Per-channel delivery status of a recipient (monotonic). */
|
|
354
|
+
export type RecipientChannelStatus =
|
|
355
|
+
| "pending"
|
|
356
|
+
| "scheduled"
|
|
357
|
+
| "sent"
|
|
358
|
+
| "delivered"
|
|
359
|
+
| "read"
|
|
360
|
+
| "failed"
|
|
361
|
+
| "clicked"
|
|
362
|
+
| "replied";
|
|
363
|
+
|
|
364
|
+
/** Aggregated, monotonic recipient status (Portuguese labels — FE display). */
|
|
365
|
+
export type RecipientInteractionStatus =
|
|
366
|
+
| "pendente"
|
|
367
|
+
| "inelegivel"
|
|
368
|
+
| "agendado"
|
|
369
|
+
| "enviado"
|
|
370
|
+
| "entregue"
|
|
371
|
+
| "lido"
|
|
372
|
+
| "clicou"
|
|
373
|
+
| "respondeu"
|
|
374
|
+
| "convertido"
|
|
375
|
+
| "falhou"
|
|
376
|
+
| "optout"
|
|
377
|
+
| "cancelado";
|
|
378
|
+
|
|
379
|
+
export interface ICampaignRecipientContact {
|
|
380
|
+
display_name?: string;
|
|
381
|
+
mobile?: string;
|
|
382
|
+
email?: string;
|
|
383
|
+
external_id?: string;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export interface ICampaignRecipientChannelState {
|
|
387
|
+
status: RecipientChannelStatus;
|
|
388
|
+
task_id?: string;
|
|
389
|
+
qr_action_ids?: string[];
|
|
390
|
+
sent_at?: Date | null;
|
|
391
|
+
delivered_at?: Date | null;
|
|
392
|
+
read_at?: Date | null;
|
|
393
|
+
clicked_at?: Date | null;
|
|
394
|
+
replied_at?: Date | null;
|
|
395
|
+
error?: string | null;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export interface ICampaignRecipientEligibility {
|
|
399
|
+
per_channel: {
|
|
400
|
+
whatsapp?: "eligible" | "excluded";
|
|
401
|
+
email?: "eligible" | "excluded";
|
|
402
|
+
};
|
|
403
|
+
/** channel -> exclusion reason. */
|
|
404
|
+
exclusion_reasons?: Record<string, string>;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export interface ICampaignRecipient extends IFireDoc {
|
|
408
|
+
lead_id?: string;
|
|
409
|
+
patient_id?: string;
|
|
410
|
+
is_new_lead: boolean;
|
|
411
|
+
contact: ICampaignRecipientContact;
|
|
412
|
+
bucket_ids: string[];
|
|
413
|
+
primary_bucket_id: string;
|
|
414
|
+
csv_variables?: Record<string, string>;
|
|
415
|
+
/** FLAT field for the batch queue (indexed). */
|
|
416
|
+
dispatch_state: RecipientDispatchState;
|
|
417
|
+
eligibility: ICampaignRecipientEligibility;
|
|
418
|
+
channels: {
|
|
419
|
+
whatsapp?: ICampaignRecipientChannelState;
|
|
420
|
+
email?: ICampaignRecipientChannelState;
|
|
421
|
+
};
|
|
422
|
+
interaction_status: RecipientInteractionStatus;
|
|
423
|
+
converted_at?: Date | null;
|
|
424
|
+
conversion_id?: string | null;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ----- Conversion (docId = leadId) ------------------------------------------
|
|
428
|
+
|
|
429
|
+
export type CampaignConversionSourceEntity =
|
|
430
|
+
| "appointment"
|
|
431
|
+
| "qr_action"
|
|
432
|
+
| "ticket"
|
|
433
|
+
| "message";
|
|
434
|
+
|
|
435
|
+
export interface ICampaignConversion extends IFireDoc {
|
|
436
|
+
lead_id: string;
|
|
437
|
+
recipient_id: string;
|
|
438
|
+
conversion_event: string;
|
|
439
|
+
source_entity_type: CampaignConversionSourceEntity;
|
|
440
|
+
source_entity_id: string;
|
|
441
|
+
channel?: CampaignChannel;
|
|
442
|
+
cta_id?: string;
|
|
443
|
+
attributed_at: Date;
|
|
444
|
+
attribution_model: "last_campaign_in_window";
|
|
445
|
+
window_days: number;
|
|
446
|
+
metadata?: Record<string, unknown>;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// ----- Lead campaign-history entry ------------------------------------------
|
|
450
|
+
// Path: /tenants/{t}/apps/evo-crm/leads/{leadId}/campaign-history/{campaignId}
|
|
451
|
+
// Serves three consumers: lead history, 15d frequency check, attribution.
|
|
452
|
+
|
|
453
|
+
export interface ILeadCampaignHistoryEntry extends IFireDoc {
|
|
454
|
+
campaign_id: string;
|
|
455
|
+
campaign_name: string;
|
|
456
|
+
/** e.g. 'marketing' — filters the frequency query (Q4). */
|
|
457
|
+
classification_level: string;
|
|
458
|
+
channels_sent: CampaignChannel[];
|
|
459
|
+
template_ids?: Record<string, string>;
|
|
460
|
+
bucket_ids?: string[];
|
|
461
|
+
first_sent_at?: Date | null;
|
|
462
|
+
last_sent_at?: Date | null;
|
|
463
|
+
delivered_at?: Date | null;
|
|
464
|
+
read_at?: Date | null;
|
|
465
|
+
clicked_at?: Date | null;
|
|
466
|
+
replied_at?: Date | null;
|
|
467
|
+
converted_at?: Date | null;
|
|
468
|
+
interaction_status: RecipientInteractionStatus;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// ----- Tariff dic item (Q6/Q12 — generic financial infra) -------------------
|
|
472
|
+
// Path: /{base}/apps/evo-crm/dics/tariffs/{itemId}
|
|
473
|
+
|
|
474
|
+
export interface ITariffItem {
|
|
475
|
+
code: string;
|
|
476
|
+
name: string;
|
|
477
|
+
description?: string;
|
|
478
|
+
/** 'messaging' | 'fees' | ... */
|
|
479
|
+
context: string;
|
|
480
|
+
channel?: string;
|
|
481
|
+
provider?: string;
|
|
482
|
+
/** ISO country code, e.g. 'BR'. */
|
|
483
|
+
country?: string;
|
|
484
|
+
/** 'marketing' | 'utility' | 'authentication'. */
|
|
485
|
+
category?: string;
|
|
486
|
+
currency: string;
|
|
487
|
+
calc_type: "fixed" | "percentage";
|
|
488
|
+
value: number;
|
|
489
|
+
/** For percentage: what the percent is applied over. */
|
|
490
|
+
percent_base?: string;
|
|
491
|
+
valid_from: Date;
|
|
492
|
+
valid_to?: Date | null;
|
|
493
|
+
active: boolean;
|
|
494
|
+
metadata?: Record<string, unknown>;
|
|
495
|
+
}
|
|
@@ -32,7 +32,7 @@ export interface ILeadDistChannel {
|
|
|
32
32
|
/** Origem de aquisição do lead (feat-038) — base expansível p/ múltiplas
|
|
33
33
|
* plataformas. v1 implementa só `type:'ctwa'` (Click-to-WhatsApp da Meta);
|
|
34
34
|
* Google Ads / Instagram Direct / TikTok / site ficam para fast-follow. */
|
|
35
|
-
export type LeadReferralType = "ctwa" | "instagram_direct" | "google_ads" | "tiktok" | "site" | "meta_organic" | "referral" | "other";
|
|
35
|
+
export type LeadReferralType = "ctwa" | "instagram_direct" | "google_ads" | "tiktok" | "site" | "meta_organic" | "referral" | "campaign" | "other";
|
|
36
36
|
export interface ILeadReferralBase {
|
|
37
37
|
type: LeadReferralType;
|
|
38
38
|
captured_at?: Date | string | null;
|
|
@@ -61,7 +61,21 @@ export interface ILeadReferralGeneric extends ILeadReferralBase {
|
|
|
61
61
|
type: "google_ads" | "tiktok" | "site" | "instagram_direct" | "meta_organic" | "referral" | "other";
|
|
62
62
|
headline?: string | null;
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
/** Origem via campanha do Hub Omni (feat-081) — carimbada em `acquisition_sources`
|
|
65
|
+
* quando o lead é criado/vinculado no provisionamento de destinatários da campanha. */
|
|
66
|
+
export interface ILeadReferralCampaign extends ILeadReferralBase {
|
|
67
|
+
type: "campaign";
|
|
68
|
+
campaignId: string;
|
|
69
|
+
campaignName: string;
|
|
70
|
+
campaignType: string;
|
|
71
|
+
campaignObjective: string;
|
|
72
|
+
channel: string;
|
|
73
|
+
bucketId: string;
|
|
74
|
+
createdAt: Date | string | null;
|
|
75
|
+
importedFrom?: string | null;
|
|
76
|
+
initialCtaId?: string | null;
|
|
77
|
+
}
|
|
78
|
+
export type ILeadReferral = ILeadReferralCTWA | ILeadReferralGeneric | ILeadReferralCampaign;
|
|
65
79
|
/** Estado da régua de reativação de lead (feat-037).
|
|
66
80
|
* Mantido pelo subscriber `ticket_closed` (streak) e pela task
|
|
67
81
|
* `lead_reactivation` (último disparo). Semântica do streak alinhada ao
|
|
@@ -55,6 +55,7 @@ export type LeadReferralType =
|
|
|
55
55
|
| "site"
|
|
56
56
|
| "meta_organic" // menção/URL orgânica de FB/IG (não-pago, sem referral) ← feat-039
|
|
57
57
|
| "referral" // indicação ("me indicaram", "amigo falou") ← feat-039
|
|
58
|
+
| "campaign" // origem via campanha do Hub Omni (feat-081) ← feat-081
|
|
58
59
|
| "other"; // ← futuro
|
|
59
60
|
|
|
60
61
|
export interface ILeadReferralBase {
|
|
@@ -95,7 +96,25 @@ export interface ILeadReferralGeneric extends ILeadReferralBase {
|
|
|
95
96
|
headline?: string | null; // paridade com CTWA p/ o FE existente
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
/** Origem via campanha do Hub Omni (feat-081) — carimbada em `acquisition_sources`
|
|
100
|
+
* quando o lead é criado/vinculado no provisionamento de destinatários da campanha. */
|
|
101
|
+
export interface ILeadReferralCampaign extends ILeadReferralBase {
|
|
102
|
+
type: "campaign";
|
|
103
|
+
campaignId: string;
|
|
104
|
+
campaignName: string;
|
|
105
|
+
campaignType: string; // CampaignType da campanha (conversion/informative/...)
|
|
106
|
+
campaignObjective: string; // code do objetivo (dic)
|
|
107
|
+
channel: string; // 'whatsapp' | 'email' — canal que originou o toque
|
|
108
|
+
bucketId: string; // bucket primário do destinatário
|
|
109
|
+
createdAt: Date | string | null;
|
|
110
|
+
importedFrom?: string | null; // 'csv' | 'leads' | 'patients' | 'appointments'
|
|
111
|
+
initialCtaId?: string | null; // CTA inicial associado, quando houver
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export type ILeadReferral =
|
|
115
|
+
| ILeadReferralCTWA
|
|
116
|
+
| ILeadReferralGeneric
|
|
117
|
+
| ILeadReferralCampaign;
|
|
99
118
|
|
|
100
119
|
/** Estado da régua de reativação de lead (feat-037).
|
|
101
120
|
* Mantido pelo subscriber `ticket_closed` (streak) e pela task
|
|
@@ -29,10 +29,24 @@ export interface IAutomationAppointmentSelection {
|
|
|
29
29
|
status_in?: string[];
|
|
30
30
|
status_base_in?: string[];
|
|
31
31
|
appointment_type_not_in?: string[];
|
|
32
|
+
professional_names?: string[];
|
|
33
|
+
procedure_names?: string[];
|
|
34
|
+
insurance_names?: string[];
|
|
35
|
+
address_names?: string[];
|
|
36
|
+
payment_status_in?: string[];
|
|
32
37
|
};
|
|
33
38
|
}
|
|
34
39
|
export type IAutomationSelection = IAutomationAppointmentSelection;
|
|
35
|
-
export
|
|
40
|
+
export interface IAutomationFilterValues {
|
|
41
|
+
professionals: string[];
|
|
42
|
+
procedures: string[];
|
|
43
|
+
insurances: string[];
|
|
44
|
+
addresses: string[];
|
|
45
|
+
statuses: string[];
|
|
46
|
+
status_bases: string[];
|
|
47
|
+
appointment_types: string[];
|
|
48
|
+
}
|
|
49
|
+
export declare const AUTOMATION_APPOINTMENT_FACTS: readonly ["appointment.status", "appointment.status_base", "appointment.appointment_type", "appointment.appointment_base_type", "appointment.appointment_mode", "appointment.professional_id", "appointment.procedure_ids", "appointment.professional_name", "appointment.procedure_names", "appointment.insurance_name", "appointment.address_name", "appointment.payment_status", "appointment.calendar_id"];
|
|
36
50
|
export type AutomationAppointmentFact = (typeof AUTOMATION_APPOINTMENT_FACTS)[number];
|
|
37
51
|
export type AutomationFact = AutomationAppointmentFact;
|
|
38
52
|
export declare const AutomationOperatorEnum: {
|
|
@@ -67,6 +81,9 @@ export type IAutomationExecuteAt = {
|
|
|
67
81
|
rule: "send_at_local";
|
|
68
82
|
time: string;
|
|
69
83
|
base: "target_date" | "run_date";
|
|
84
|
+
} | {
|
|
85
|
+
rule: "relative_to_appointment";
|
|
86
|
+
offset_minutes: number;
|
|
70
87
|
};
|
|
71
88
|
export interface IAutomationAutoTaskOutput {
|
|
72
89
|
type: "auto_task";
|
|
@@ -47,9 +47,16 @@ exports.AUTOMATION_APPOINTMENT_FACTS = [
|
|
|
47
47
|
"appointment.appointment_base_type",
|
|
48
48
|
// 'telemedicine' | 'in_person'
|
|
49
49
|
"appointment.appointment_mode",
|
|
50
|
-
// Derived from professional.professionalRef.id
|
|
50
|
+
// Derived from professional.professionalRef.id. On external calendars the
|
|
51
|
+
// reliable value is the name (Q21) — professional_id kept for internal.
|
|
51
52
|
"appointment.professional_id",
|
|
52
53
|
"appointment.procedure_ids",
|
|
54
|
+
// Embed-sourced names (Q20-C passthrough); reliable across adapters.
|
|
55
|
+
"appointment.professional_name",
|
|
56
|
+
// string[] — matches if ANY procedure name matches.
|
|
57
|
+
"appointment.procedure_names",
|
|
58
|
+
"appointment.insurance_name",
|
|
59
|
+
"appointment.address_name",
|
|
53
60
|
"appointment.payment_status",
|
|
54
61
|
"appointment.calendar_id",
|
|
55
62
|
];
|