evo360-types 1.3.602 → 1.3.606

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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.zContactSchema = exports.zAddressSchema = exports.zTagSchema = exports.zFireDocSchema = exports.zFirestoreDateSchema = exports.zEvoAppSchema = void 0;
3
+ exports.zCaptureDataMapSchema = exports.zCaptureDataValueSchema = exports.zCaptureDataFieldSchema = exports.zCaptureDataFieldOptionSchema = exports.zCaptureDataFieldTypeSchema = exports.zContactSchema = exports.zAddressSchema = exports.zTagSchema = exports.zFireDocSchema = exports.zFirestoreDateSchema = exports.zEvoAppSchema = void 0;
4
4
  const zod_1 = require("zod");
5
5
  // Enum for activity read status
6
6
  exports.zEvoAppSchema = zod_1.z.enum([
@@ -92,3 +92,41 @@ exports.zContactSchema = zod_1.z.object({
92
92
  // WhatsApp BSUID (Business-Scoped User ID) — contato que a Meta entrega sem telefone
93
93
  bsuid: zod_1.z.string().nullable().optional(),
94
94
  }).passthrough();
95
+ // ----- Campos complementares (capture-data) — feat-196
96
+ exports.zCaptureDataFieldTypeSchema = zod_1.z.enum([
97
+ "text",
98
+ "number",
99
+ "date",
100
+ "select",
101
+ "boolean",
102
+ ]);
103
+ exports.zCaptureDataFieldOptionSchema = zod_1.z
104
+ .object({
105
+ value: zod_1.z.string().min(1).max(255),
106
+ label: zod_1.z.string().min(1).max(255),
107
+ })
108
+ .passthrough();
109
+ /**
110
+ * Campo do dicionário (qualquer entidade). O `code` aceita o legado (1–64);
111
+ * o slug `^[a-z][a-z0-9_]{0,63}$` é regra de CRIAÇÃO, aplicada no backend.
112
+ */
113
+ exports.zCaptureDataFieldSchema = exports.zFireDocSchema
114
+ .extend({
115
+ code: zod_1.z.string().min(1).max(64),
116
+ name: zod_1.z.string().min(1).max(255),
117
+ type: exports.zCaptureDataFieldTypeSchema.optional(),
118
+ options: zod_1.z.array(exports.zCaptureDataFieldOptionSchema).nullable().optional(),
119
+ required: zod_1.z.boolean().optional(),
120
+ order: zod_1.z.number().int().nullable().optional(),
121
+ searchable: zod_1.z.boolean().optional(),
122
+ mcp_description: zod_1.z.string().max(2000).nullable().optional(),
123
+ mcp_enabled: zod_1.z.boolean().optional(),
124
+ })
125
+ .passthrough();
126
+ exports.zCaptureDataValueSchema = zod_1.z.union([
127
+ zod_1.z.string(),
128
+ zod_1.z.number(),
129
+ zod_1.z.boolean(),
130
+ ]);
131
+ /** Mapa `capture_data` gravado na entidade. */
132
+ exports.zCaptureDataMapSchema = zod_1.z.record(exports.zCaptureDataValueSchema);
@@ -107,3 +107,47 @@ export const zContactSchema = z.object({
107
107
  // WhatsApp BSUID (Business-Scoped User ID) — contato que a Meta entrega sem telefone
108
108
  bsuid: z.string().nullable().optional(),
109
109
  }).passthrough();
110
+
111
+ // ----- Campos complementares (capture-data) — feat-196
112
+
113
+ export const zCaptureDataFieldTypeSchema = z.enum([
114
+ "text",
115
+ "number",
116
+ "date",
117
+ "select",
118
+ "boolean",
119
+ ]);
120
+
121
+ export const zCaptureDataFieldOptionSchema = z
122
+ .object({
123
+ value: z.string().min(1).max(255),
124
+ label: z.string().min(1).max(255),
125
+ })
126
+ .passthrough();
127
+
128
+ /**
129
+ * Campo do dicionário (qualquer entidade). O `code` aceita o legado (1–64);
130
+ * o slug `^[a-z][a-z0-9_]{0,63}$` é regra de CRIAÇÃO, aplicada no backend.
131
+ */
132
+ export const zCaptureDataFieldSchema = zFireDocSchema
133
+ .extend({
134
+ code: z.string().min(1).max(64),
135
+ name: z.string().min(1).max(255),
136
+ type: zCaptureDataFieldTypeSchema.optional(),
137
+ options: z.array(zCaptureDataFieldOptionSchema).nullable().optional(),
138
+ required: z.boolean().optional(),
139
+ order: z.number().int().nullable().optional(),
140
+ searchable: z.boolean().optional(),
141
+ mcp_description: z.string().max(2000).nullable().optional(),
142
+ mcp_enabled: z.boolean().optional(),
143
+ })
144
+ .passthrough();
145
+
146
+ export const zCaptureDataValueSchema = z.union([
147
+ z.string(),
148
+ z.number(),
149
+ z.boolean(),
150
+ ]);
151
+
152
+ /** Mapa `capture_data` gravado na entidade. */
153
+ export const zCaptureDataMapSchema = z.record(zCaptureDataValueSchema);
@@ -1,5 +1,5 @@
1
1
  export * from "../fb_collections";
2
- import { FirestoreDocumentReference, IAddress, IContact, IExternalLink, ITag } from "../../shared";
2
+ import { CaptureDataMap, FirestoreDocumentReference, IAddress, IContact, IExternalLink, ITag } from "../../shared";
3
3
  import { IProfile } from "../../evo-people";
4
4
  import { QualificationFunnelLevel } from "../dic";
5
5
  export declare const EvoCrmLeadPermissions: {
@@ -112,6 +112,8 @@ export interface ILead extends IProfile {
112
112
  /** Derivado de `externalLinks` (`"type:id"`) pelo model — habilita `array-contains`. */
113
113
  externalLinkKeys?: string[];
114
114
  tags?: ITag[] | null;
115
+ /** Campos complementares (code → valor), validados contra o dicionário `dics/leads/capture-data` (feat-196). */
116
+ capture_data?: CaptureDataMap | null;
115
117
  userRef?: FirestoreDocumentReference;
116
118
  ctwa_clid?: string | null;
117
119
  /**
@@ -1,6 +1,7 @@
1
1
  export * from "../fb_collections";
2
2
 
3
3
  import {
4
+ CaptureDataMap,
4
5
  FirestoreDocumentReference,
5
6
  IAddress,
6
7
  IContact,
@@ -154,6 +155,8 @@ export interface ILead extends IProfile {
154
155
  /** Derivado de `externalLinks` (`"type:id"`) pelo model — habilita `array-contains`. */
155
156
  externalLinkKeys?: string[];
156
157
  tags?: ITag[] | null;
158
+ /** Campos complementares (code → valor), validados contra o dicionário `dics/leads/capture-data` (feat-196). */
159
+ capture_data?: CaptureDataMap | null;
157
160
  userRef?: FirestoreDocumentReference;
158
161
  // CTWA attribution (feat-034) — capturado do referral do 1º inbound vindo de anúncio Click-to-WhatsApp.
159
162
  ctwa_clid?: string | null;
@@ -9,7 +9,11 @@ export * from "./fb_collections";
9
9
  * da rubrica (profissional de saude no canal, nome completo so com agendamento, agenda so pelo
10
10
  * codigo, urgencia = encaixe, soma de familia, responsavel x paciente). Serve para separar as
11
11
  * series antes/depois na analise. */
12
- export declare const CSQ_RUBRIC_VERSION = "v1.2";
12
+ /** v1.3 (2026-09-24, auditoria dos laudos "encaminhar a supervisao"): mesmos pilares/criterios;
13
+ * muda o TEXTO (hierarquia de precedencia: autorizacao da profissional > roteiro do tenant >
14
+ * regra generica; familia em horarios vizinhos e esperada; `retorno_apos_vou_verificar` e
15
+ * `nomes_corretos` com ponderacao) e a SAIDA do juiz ganha `revalidations` e `resolved_alerts`. */
16
+ export declare const CSQ_RUBRIC_VERSION = "v1.3";
13
17
  /** Modo do CSQ por departamento (gravado no binding da HubIA).
14
18
  * - `off` : nao avalia (default quando ausente).
15
19
  * - `shadow` : avalia e grava o laudo, sem notificar supervisores.
@@ -29,6 +33,14 @@ export type CsqAlertScope = "ticket" | "journey";
29
33
  /** Ciclo de vida do alerta. Um alerta da jornada fica `open` no laudo corrente
30
34
  * ate uma avaliacao posterior constatar a correcao; entao vira `resolved`. */
31
35
  export type CsqAlertLifecycle = "open" | "resolved";
36
+ /** Por que um alerta virou `resolved` (feat-154 lote 9). Ausente em laudos anteriores.
37
+ * - `fact` : o recomputo/fato da avaliacao seguinte o encerrou.
38
+ * - `judge_resolved` : o juiz declarou corrigido/insustentavel (alerta `llm`).
39
+ * - `judge_dismissed` : o juiz revalidou um achado automatico e o descartou.
40
+ * - `code_guard` : guarda deterministica aplicada a alerta herdado.
41
+ * - `recheck_ok` : a rechecagem da agenda passou a bater.
42
+ * - `supervisor_false_positive` : marcado como falso positivo na revisao do supervisor. */
43
+ export type CsqAlertResolvedReason = "fact" | "judge_resolved" | "judge_dismissed" | "code_guard" | "recheck_ok" | "supervisor_false_positive";
32
44
  /** Estado da rechecagem agendada de agenda (adendo §B). Alertas de agenda
33
45
  * nascem `pending` (sem auto-fail nem notificacao) e sao reavaliados em
34
46
  * `closed_at + CSQ_DEFAULTS.recheck_delay_min`.
@@ -145,6 +157,10 @@ export interface ICsqAlert {
145
157
  recheck_after?: Date;
146
158
  /** Ticket em que o alerta foi constatado como resolvido. */
147
159
  resolved_in_ticket?: string;
160
+ /** Motivo da resolucao (lote 9). */
161
+ resolved_reason?: CsqAlertResolvedReason;
162
+ /** Texto do motivo, quando houver (ex.: justificativa do juiz). */
163
+ resolved_note?: string;
148
164
  /** So em alertas de agenda: agendamento com que o claim foi cruzado, para o
149
165
  * Nexus linkar `/{tenant}/evo-med/calendar/{calendar_id}/appointment/{appointment_id}`. */
150
166
  appointment_id?: string;
@@ -442,6 +458,18 @@ export interface ICsqLlmUsage {
442
458
  /** Tentativas gastas. Contrato: <= 2 (1 retry por falha de schema). */
443
459
  rounds?: number;
444
460
  }
461
+ /** Veredito do juiz sobre um achado automatico revalidavel (lote 9). O codigo
462
+ * so aplica `dismiss` a codigos da allowlist de revalidacao. */
463
+ export interface ICsqJudgeRevalidation {
464
+ fingerprint: string;
465
+ verdict: "confirm" | "dismiss";
466
+ reason: string;
467
+ }
468
+ /** Alerta anterior (fonte `llm`) que o juiz declarou resolvido, com o motivo. */
469
+ export interface ICsqJudgeResolvedAlert {
470
+ fingerprint: string;
471
+ reason: string;
472
+ }
445
473
  /** Saida estruturada da tool `submit_csq_evaluation`. O juiz NAO recebe tools
446
474
  * de leitura e nao decide o score final: so pontua, extrai e cita evidencia. */
447
475
  export interface ICsqJudgeOutput {
@@ -454,6 +482,11 @@ export interface ICsqJudgeOutput {
454
482
  /** Fingerprints de alertas anteriores que este atendimento resolveu.
455
483
  * So resolve alertas de fonte `llm` (adendo §G). */
456
484
  resolved_alert_ids: string[];
485
+ /** Lote 9: os mesmos resolvidos, com o motivo. Os fingerprints entram tambem em
486
+ * `resolved_alert_ids` na normalizacao. */
487
+ resolved_alerts?: ICsqJudgeResolvedAlert[];
488
+ /** Lote 9: veredito sobre os "achados automaticos a revalidar" do prompt. */
489
+ revalidations?: ICsqJudgeRevalidation[];
457
490
  highlights: string[];
458
491
  improvements: string[];
459
492
  confidence: number;
@@ -472,12 +505,35 @@ export interface ICsqAppointmentFact {
472
505
  modality?: string;
473
506
  created_at?: Date;
474
507
  }
475
- /** Sobreposicao detectada entre agendamentos do mesmo profissional. */
508
+ /** Agendamento envolvido numa sobreposicao (lote 9). */
509
+ export interface ICsqOverlapAppointmentFact {
510
+ id: string;
511
+ patient_id?: string;
512
+ patient_name?: string;
513
+ start_at: Date;
514
+ end_at?: Date;
515
+ professional_name?: string;
516
+ /** O agendamento e de paciente vinculado ao lead avaliado. */
517
+ is_lead: boolean;
518
+ }
519
+ /** Pistas de agendamento de familia numa sobreposicao (lote 9). */
520
+ export interface ICsqOverlapFamilyHints {
521
+ /** Os pacientes envolvidos (ou o lead) compartilham o sobrenome. */
522
+ same_surname: boolean;
523
+ /** O outro paciente tem o mesmo telefone do lead. */
524
+ same_contact: boolean;
525
+ /** Todos os pacientes envolvidos estao vinculados ao mesmo lead. */
526
+ same_lead: boolean;
527
+ }
528
+ /** Sobreposicao detectada entre agendamentos do mesmo profissional. Desde o
529
+ * lote 9 so envolve agendamentos em que pelo menos um e do lead. */
476
530
  export interface ICsqOverlapFact {
477
531
  professional_name?: string;
478
532
  appointment_ids: string[];
479
533
  start_at: Date;
480
534
  end_at: Date;
535
+ appointments?: ICsqOverlapAppointmentFact[];
536
+ family_hints?: ICsqOverlapFamilyHints;
481
537
  }
482
538
  /** Ticket anterior da jornada (motivo, quem fechou). */
483
539
  export interface ICsqPreviousTicketFact {
@@ -633,6 +689,9 @@ export interface ICsqLeadReport extends IFireDoc {
633
689
  data_quality?: ICsqDataQuality;
634
690
  /** Veredito humano (adendo §D). */
635
691
  review?: ICsqReview;
692
+ /** Fingerprints marcados como falso positivo pelo supervisor em laudos anteriores
693
+ * (acumulado, lote 9). Alerta com fingerprint aqui fica `resolved` e nao reabre. */
694
+ suppressed_alert_fingerprints?: string[];
636
695
  /** Exclusao (soft delete) pelo supervisor: `deleted_at` vem do IFireDoc. O laudo
637
696
  * some da fila e do historico do lead; a proxima avaliacao do lead comeca do zero.
638
697
  * Transcricao e prompt ficam em `artifacts/` para auditoria. */
@@ -34,7 +34,11 @@ __exportStar(require("./fb_collections"), exports);
34
34
  * da rubrica (profissional de saude no canal, nome completo so com agendamento, agenda so pelo
35
35
  * codigo, urgencia = encaixe, soma de familia, responsavel x paciente). Serve para separar as
36
36
  * series antes/depois na analise. */
37
- exports.CSQ_RUBRIC_VERSION = "v1.2";
37
+ /** v1.3 (2026-09-24, auditoria dos laudos "encaminhar a supervisao"): mesmos pilares/criterios;
38
+ * muda o TEXTO (hierarquia de precedencia: autorizacao da profissional > roteiro do tenant >
39
+ * regra generica; familia em horarios vizinhos e esperada; `retorno_apos_vou_verificar` e
40
+ * `nomes_corretos` com ponderacao) e a SAIDA do juiz ganha `revalidations` e `resolved_alerts`. */
41
+ exports.CSQ_RUBRIC_VERSION = "v1.3";
38
42
  // ───────── Catalogo de alertas (report-spec §6) ─────────
39
43
  /** Codigos de alerta v1. Os subtipos de `POLITICA_VIOLADA` e
40
44
  * `FLUXO_VENDA_NAO_SEGUIDO` vivem em `ICsqAlert.subtype`, nao como codigos. */
@@ -22,7 +22,11 @@ export * from "./fb_collections";
22
22
  * da rubrica (profissional de saude no canal, nome completo so com agendamento, agenda so pelo
23
23
  * codigo, urgencia = encaixe, soma de familia, responsavel x paciente). Serve para separar as
24
24
  * series antes/depois na analise. */
25
- export const CSQ_RUBRIC_VERSION = "v1.2";
25
+ /** v1.3 (2026-09-24, auditoria dos laudos "encaminhar a supervisao"): mesmos pilares/criterios;
26
+ * muda o TEXTO (hierarquia de precedencia: autorizacao da profissional > roteiro do tenant >
27
+ * regra generica; familia em horarios vizinhos e esperada; `retorno_apos_vou_verificar` e
28
+ * `nomes_corretos` com ponderacao) e a SAIDA do juiz ganha `revalidations` e `resolved_alerts`. */
29
+ export const CSQ_RUBRIC_VERSION = "v1.3";
26
30
 
27
31
  // ───────── Enums / Literals ─────────
28
32
 
@@ -57,6 +61,21 @@ export type CsqAlertScope = "ticket" | "journey";
57
61
  * ate uma avaliacao posterior constatar a correcao; entao vira `resolved`. */
58
62
  export type CsqAlertLifecycle = "open" | "resolved";
59
63
 
64
+ /** Por que um alerta virou `resolved` (feat-154 lote 9). Ausente em laudos anteriores.
65
+ * - `fact` : o recomputo/fato da avaliacao seguinte o encerrou.
66
+ * - `judge_resolved` : o juiz declarou corrigido/insustentavel (alerta `llm`).
67
+ * - `judge_dismissed` : o juiz revalidou um achado automatico e o descartou.
68
+ * - `code_guard` : guarda deterministica aplicada a alerta herdado.
69
+ * - `recheck_ok` : a rechecagem da agenda passou a bater.
70
+ * - `supervisor_false_positive` : marcado como falso positivo na revisao do supervisor. */
71
+ export type CsqAlertResolvedReason =
72
+ | "fact"
73
+ | "judge_resolved"
74
+ | "judge_dismissed"
75
+ | "code_guard"
76
+ | "recheck_ok"
77
+ | "supervisor_false_positive";
78
+
60
79
  /** Estado da rechecagem agendada de agenda (adendo §B). Alertas de agenda
61
80
  * nascem `pending` (sem auto-fail nem notificacao) e sao reavaliados em
62
81
  * `closed_at + CSQ_DEFAULTS.recheck_delay_min`.
@@ -337,6 +356,10 @@ export interface ICsqAlert {
337
356
  recheck_after?: Date;
338
357
  /** Ticket em que o alerta foi constatado como resolvido. */
339
358
  resolved_in_ticket?: string;
359
+ /** Motivo da resolucao (lote 9). */
360
+ resolved_reason?: CsqAlertResolvedReason;
361
+ /** Texto do motivo, quando houver (ex.: justificativa do juiz). */
362
+ resolved_note?: string;
340
363
  /** So em alertas de agenda: agendamento com que o claim foi cruzado, para o
341
364
  * Nexus linkar `/{tenant}/evo-med/calendar/{calendar_id}/appointment/{appointment_id}`. */
342
365
  appointment_id?: string;
@@ -691,6 +714,20 @@ export interface ICsqLlmUsage {
691
714
  rounds?: number;
692
715
  }
693
716
 
717
+ /** Veredito do juiz sobre um achado automatico revalidavel (lote 9). O codigo
718
+ * so aplica `dismiss` a codigos da allowlist de revalidacao. */
719
+ export interface ICsqJudgeRevalidation {
720
+ fingerprint: string;
721
+ verdict: "confirm" | "dismiss";
722
+ reason: string;
723
+ }
724
+
725
+ /** Alerta anterior (fonte `llm`) que o juiz declarou resolvido, com o motivo. */
726
+ export interface ICsqJudgeResolvedAlert {
727
+ fingerprint: string;
728
+ reason: string;
729
+ }
730
+
694
731
  /** Saida estruturada da tool `submit_csq_evaluation`. O juiz NAO recebe tools
695
732
  * de leitura e nao decide o score final: so pontua, extrai e cita evidencia. */
696
733
  export interface ICsqJudgeOutput {
@@ -703,6 +740,11 @@ export interface ICsqJudgeOutput {
703
740
  /** Fingerprints de alertas anteriores que este atendimento resolveu.
704
741
  * So resolve alertas de fonte `llm` (adendo §G). */
705
742
  resolved_alert_ids: string[];
743
+ /** Lote 9: os mesmos resolvidos, com o motivo. Os fingerprints entram tambem em
744
+ * `resolved_alert_ids` na normalizacao. */
745
+ resolved_alerts?: ICsqJudgeResolvedAlert[];
746
+ /** Lote 9: veredito sobre os "achados automaticos a revalidar" do prompt. */
747
+ revalidations?: ICsqJudgeRevalidation[];
706
748
  highlights: string[];
707
749
  improvements: string[];
708
750
  confidence: number;
@@ -725,12 +767,37 @@ export interface ICsqAppointmentFact {
725
767
  created_at?: Date;
726
768
  }
727
769
 
728
- /** Sobreposicao detectada entre agendamentos do mesmo profissional. */
770
+ /** Agendamento envolvido numa sobreposicao (lote 9). */
771
+ export interface ICsqOverlapAppointmentFact {
772
+ id: string;
773
+ patient_id?: string;
774
+ patient_name?: string;
775
+ start_at: Date;
776
+ end_at?: Date;
777
+ professional_name?: string;
778
+ /** O agendamento e de paciente vinculado ao lead avaliado. */
779
+ is_lead: boolean;
780
+ }
781
+
782
+ /** Pistas de agendamento de familia numa sobreposicao (lote 9). */
783
+ export interface ICsqOverlapFamilyHints {
784
+ /** Os pacientes envolvidos (ou o lead) compartilham o sobrenome. */
785
+ same_surname: boolean;
786
+ /** O outro paciente tem o mesmo telefone do lead. */
787
+ same_contact: boolean;
788
+ /** Todos os pacientes envolvidos estao vinculados ao mesmo lead. */
789
+ same_lead: boolean;
790
+ }
791
+
792
+ /** Sobreposicao detectada entre agendamentos do mesmo profissional. Desde o
793
+ * lote 9 so envolve agendamentos em que pelo menos um e do lead. */
729
794
  export interface ICsqOverlapFact {
730
795
  professional_name?: string;
731
796
  appointment_ids: string[];
732
797
  start_at: Date;
733
798
  end_at: Date;
799
+ appointments?: ICsqOverlapAppointmentFact[];
800
+ family_hints?: ICsqOverlapFamilyHints;
734
801
  }
735
802
 
736
803
  /** Ticket anterior da jornada (motivo, quem fechou). */
@@ -905,6 +972,9 @@ export interface ICsqLeadReport extends IFireDoc {
905
972
  data_quality?: ICsqDataQuality;
906
973
  /** Veredito humano (adendo §D). */
907
974
  review?: ICsqReview;
975
+ /** Fingerprints marcados como falso positivo pelo supervisor em laudos anteriores
976
+ * (acumulado, lote 9). Alerta com fingerprint aqui fica `resolved` e nao reabre. */
977
+ suppressed_alert_fingerprints?: string[];
908
978
  /** Exclusao (soft delete) pelo supervisor: `deleted_at` vem do IFireDoc. O laudo
909
979
  * some da fila e do historico do lead; a proxima avaliacao do lead comeca do zero.
910
980
  * Transcricao e prompt ficam em `artifacts/` para auditoria. */
@@ -1,6 +1,6 @@
1
1
  export * from "../fb_collections";
2
2
  import { IProfile } from "../../evo-people";
3
- import type { FirestoreDocumentReference, IAddress, IContact, IExternalLink, ITag } from "../../shared";
3
+ import type { CaptureDataMap, FirestoreDocumentReference, IAddress, IContact, IExternalLink, ITag } from "../../shared";
4
4
  import { IMedication, PatientAttachmentBaseCategory } from "../dic";
5
5
  export declare const EvoMedProfessionalPermissions: {
6
6
  readonly List: "evo_med_people_professional_read";
@@ -184,6 +184,8 @@ export interface IPatient extends IProfile {
184
184
  attachments?: IPatientAttachment[] | null;
185
185
  attachmentExternalLinkKeys?: string[] | null;
186
186
  tags?: ITag[] | null;
187
+ /** Campos complementares (code → valor), validados contra o dicionário `dics/patients/capture-data` (feat-196). */
188
+ capture_data?: CaptureDataMap | null;
187
189
  userRef?: FirestoreDocumentReference;
188
190
  [key: string]: unknown;
189
191
  }
@@ -1,6 +1,7 @@
1
1
  export * from "../fb_collections";
2
2
  import { IProfile } from "../../evo-people";
3
3
  import type {
4
+ CaptureDataMap,
4
5
  FirestoreDocumentReference,
5
6
  IAddress,
6
7
  IContact,
@@ -249,6 +250,8 @@ export interface IPatient extends IProfile {
249
250
  attachments?: IPatientAttachment[] | null;
250
251
  attachmentExternalLinkKeys?: string[] | null;
251
252
  tags?: ITag[] | null;
253
+ /** Campos complementares (code → valor), validados contra o dicionário `dics/patients/capture-data` (feat-196). */
254
+ capture_data?: CaptureDataMap | null;
252
255
  userRef?: FirestoreDocumentReference;
253
256
  [key: string]: unknown; // index signature
254
257
  }
@@ -0,0 +1,49 @@
1
+ import type { IFireDoc } from "./index";
2
+ /** Nome da subcoleção do dicionário, sob `dics/{entidade}/`. */
3
+ export declare const CAPTURE_DATA_COLLECTION = "capture-data";
4
+ /** Entidades que têm dicionário de campos complementares (= segmento do path em `dics/`). */
5
+ export type CaptureDataEntity = "leads" | "patients";
6
+ export declare const CAPTURE_DATA_FIELD_TYPES: readonly ["text", "number", "date", "select", "boolean"];
7
+ /** Tipo do campo. Ausente no doc = `text` (campos legados de lead). */
8
+ export type CaptureDataFieldType = (typeof CAPTURE_DATA_FIELD_TYPES)[number];
9
+ /**
10
+ * Valor gravado no mapa `capture_data`. `date` é string `YYYY-MM-DD`;
11
+ * `select` grava o `value` da opção.
12
+ */
13
+ export type CaptureDataValue = string | number | boolean;
14
+ /** Mapa gravado na entidade (`lead.capture_data`, `patient.capture_data`). */
15
+ export type CaptureDataMap = Record<string, CaptureDataValue>;
16
+ /**
17
+ * Regra de CRIAÇÃO do `code` (aplicada no backend). Codes legados fora desse
18
+ * padrão (ex.: `Convênio`, `nome-paciente`) continuam válidos para leitura.
19
+ */
20
+ export declare const CAPTURE_DATA_CODE_PATTERN = "^[a-z][a-z0-9_]{0,63}$";
21
+ /** Limite de caracteres de um valor `text`. */
22
+ export declare const CAPTURE_DATA_TEXT_MAX_LENGTH = 2000;
23
+ export interface ICaptureDataFieldOption {
24
+ /** O que vai gravado no mapa. */
25
+ value: string;
26
+ /** O que a UI mostra. */
27
+ label: string;
28
+ }
29
+ export interface ICaptureDataField extends IFireDoc {
30
+ /** Chave no mapa `capture_data`. Imutável depois de criado. */
31
+ code: string;
32
+ name: string;
33
+ /** Ausente = `text` (legado). Imutável depois de definido. */
34
+ type?: CaptureDataFieldType;
35
+ /** Só para `select`. */
36
+ options?: ICaptureDataFieldOption[] | null;
37
+ required?: boolean;
38
+ order?: number | null;
39
+ /** Envia o valor ao índice de busca (Algolia, região US). Default false (D2). */
40
+ searchable?: boolean;
41
+ /** Instrução para a IA preencher o campo. */
42
+ mcp_description?: string | null;
43
+ /** Default true. */
44
+ mcp_enabled?: boolean;
45
+ }
46
+ /** Compatibilidade: o dicionário de lead é o genérico. */
47
+ export type ILeadCaptureDataField = ICaptureDataField;
48
+ /** Dicionário de campos complementares de paciente. */
49
+ export type IPatientCaptureDataField = ICaptureDataField;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CAPTURE_DATA_TEXT_MAX_LENGTH = exports.CAPTURE_DATA_CODE_PATTERN = exports.CAPTURE_DATA_FIELD_TYPES = exports.CAPTURE_DATA_COLLECTION = void 0;
4
+ // ----- Campos complementares (capture-data) — feat-196
5
+ //
6
+ // Dicionário genérico por entidade: cada tenant define campos próprios que são
7
+ // gravados em `{entidade}.capture_data` (mapa code → valor).
8
+ // leads → tenants/{t}/apps/evo-crm/dics/leads/capture-data/{id}
9
+ // patients → tenants/{t}/apps/evo-med/dics/patients/capture-data/{id}
10
+ // Herda do `base_tenant` (o tenant atual vence o base, deduplicado por `code`).
11
+ /** Nome da subcoleção do dicionário, sob `dics/{entidade}/`. */
12
+ exports.CAPTURE_DATA_COLLECTION = "capture-data";
13
+ exports.CAPTURE_DATA_FIELD_TYPES = [
14
+ "text",
15
+ "number",
16
+ "date",
17
+ "select",
18
+ "boolean",
19
+ ];
20
+ /**
21
+ * Regra de CRIAÇÃO do `code` (aplicada no backend). Codes legados fora desse
22
+ * padrão (ex.: `Convênio`, `nome-paciente`) continuam válidos para leitura.
23
+ */
24
+ exports.CAPTURE_DATA_CODE_PATTERN = "^[a-z][a-z0-9_]{0,63}$";
25
+ /** Limite de caracteres de um valor `text`. */
26
+ exports.CAPTURE_DATA_TEXT_MAX_LENGTH = 2000;
@@ -0,0 +1,74 @@
1
+ import type { IFireDoc } from "./index";
2
+
3
+ // ----- Campos complementares (capture-data) — feat-196
4
+ //
5
+ // Dicionário genérico por entidade: cada tenant define campos próprios que são
6
+ // gravados em `{entidade}.capture_data` (mapa code → valor).
7
+ // leads → tenants/{t}/apps/evo-crm/dics/leads/capture-data/{id}
8
+ // patients → tenants/{t}/apps/evo-med/dics/patients/capture-data/{id}
9
+ // Herda do `base_tenant` (o tenant atual vence o base, deduplicado por `code`).
10
+
11
+ /** Nome da subcoleção do dicionário, sob `dics/{entidade}/`. */
12
+ export const CAPTURE_DATA_COLLECTION = "capture-data";
13
+
14
+ /** Entidades que têm dicionário de campos complementares (= segmento do path em `dics/`). */
15
+ export type CaptureDataEntity = "leads" | "patients";
16
+
17
+ export const CAPTURE_DATA_FIELD_TYPES = [
18
+ "text",
19
+ "number",
20
+ "date",
21
+ "select",
22
+ "boolean",
23
+ ] as const;
24
+
25
+ /** Tipo do campo. Ausente no doc = `text` (campos legados de lead). */
26
+ export type CaptureDataFieldType = (typeof CAPTURE_DATA_FIELD_TYPES)[number];
27
+
28
+ /**
29
+ * Valor gravado no mapa `capture_data`. `date` é string `YYYY-MM-DD`;
30
+ * `select` grava o `value` da opção.
31
+ */
32
+ export type CaptureDataValue = string | number | boolean;
33
+
34
+ /** Mapa gravado na entidade (`lead.capture_data`, `patient.capture_data`). */
35
+ export type CaptureDataMap = Record<string, CaptureDataValue>;
36
+
37
+ /**
38
+ * Regra de CRIAÇÃO do `code` (aplicada no backend). Codes legados fora desse
39
+ * padrão (ex.: `Convênio`, `nome-paciente`) continuam válidos para leitura.
40
+ */
41
+ export const CAPTURE_DATA_CODE_PATTERN = "^[a-z][a-z0-9_]{0,63}$";
42
+
43
+ /** Limite de caracteres de um valor `text`. */
44
+ export const CAPTURE_DATA_TEXT_MAX_LENGTH = 2000;
45
+
46
+ export interface ICaptureDataFieldOption {
47
+ /** O que vai gravado no mapa. */
48
+ value: string;
49
+ /** O que a UI mostra. */
50
+ label: string;
51
+ }
52
+
53
+ export interface ICaptureDataField extends IFireDoc {
54
+ /** Chave no mapa `capture_data`. Imutável depois de criado. */
55
+ code: string;
56
+ name: string;
57
+ /** Ausente = `text` (legado). Imutável depois de definido. */
58
+ type?: CaptureDataFieldType;
59
+ /** Só para `select`. */
60
+ options?: ICaptureDataFieldOption[] | null;
61
+ required?: boolean;
62
+ order?: number | null;
63
+ /** Envia o valor ao índice de busca (Algolia, região US). Default false (D2). */
64
+ searchable?: boolean;
65
+ /** Instrução para a IA preencher o campo. */
66
+ mcp_description?: string | null;
67
+ /** Default true. */
68
+ mcp_enabled?: boolean;
69
+ }
70
+
71
+ /** Compatibilidade: o dicionário de lead é o genérico. */
72
+ export type ILeadCaptureDataField = ICaptureDataField;
73
+ /** Dicionário de campos complementares de paciente. */
74
+ export type IPatientCaptureDataField = ICaptureDataField;
@@ -1,5 +1,6 @@
1
1
  export * from "./fb_collections";
2
2
  export * from "./external-links";
3
+ export * from "./capture-data";
3
4
  export interface FirestoreDocumentReference {
4
5
  id: string;
5
6
  path: string;
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.IEvoApp = void 0;
18
18
  __exportStar(require("./fb_collections"), exports);
19
19
  __exportStar(require("./external-links"), exports);
20
+ __exportStar(require("./capture-data"), exports);
20
21
  var IEvoApp;
21
22
  (function (IEvoApp) {
22
23
  IEvoApp["EvoActivity"] = "evo-activity";
@@ -1,5 +1,6 @@
1
1
  export * from "./fb_collections";
2
2
  export * from "./external-links";
3
+ export * from "./capture-data";
3
4
 
4
5
  // ----- FirestoreTypes
5
6
  // Definir o tipo unificado para DocumentReference
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evo360-types",
3
- "version": "1.3.602",
3
+ "version": "1.3.606",
4
4
  "description": "HREVO360 Shared Types",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",