evo360-types 1.3.326 → 1.3.329

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.
@@ -4,6 +4,7 @@ exports.zMedCalendarSchema = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const zod_schemas_1 = require("../../shared/zod-schemas");
6
6
  const zod_schemas_2 = require("../people/zod-schemas");
7
+ const zod_schemas_3 = require("../../evo-integrations/zod-schemas");
7
8
  exports.zMedCalendarSchema = zod_schemas_1.zFireDocSchema
8
9
  .extend({
9
10
  calendarId: zod_1.z.string().min(1).max(30),
@@ -42,5 +43,6 @@ exports.zMedCalendarSchema = zod_schemas_1.zFireDocSchema
42
43
  .default([1, 2, 3, 4, 5])
43
44
  .optional(),
44
45
  available_for_hubia: zod_1.z.boolean().default(false).optional(),
46
+ integration: zod_schemas_3.zMedCalendarIntegrationSchema.optional(),
45
47
  })
46
48
  .passthrough();
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { zFireDocSchema, zTagSchema } from "../../shared/zod-schemas";
3
3
  import { zAppointmentCountersSchema } from "../people/zod-schemas";
4
+ import { zMedCalendarIntegrationSchema } from "../../evo-integrations/zod-schemas";
4
5
 
5
6
  export const zMedCalendarSchema = zFireDocSchema
6
7
  .extend({
@@ -40,5 +41,6 @@ export const zMedCalendarSchema = zFireDocSchema
40
41
  .default([1, 2, 3, 4, 5])
41
42
  .optional(),
42
43
  available_for_hubia: z.boolean().default(false).optional(),
44
+ integration: zMedCalendarIntegrationSchema.optional(),
43
45
  })
44
46
  .passthrough();
@@ -13,7 +13,7 @@ export declare const zTenantSchema: z.ZodObject<{
13
13
  } & {
14
14
  name: z.ZodString;
15
15
  url_alias: z.ZodString;
16
- base_tenant: z.ZodOptional<z.ZodString>;
16
+ base_tenant: z.ZodOptional<z.ZodNullable<z.ZodString>>;
17
17
  hidden: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
18
18
  readonly: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
19
19
  date_format: z.ZodOptional<z.ZodString>;
@@ -32,7 +32,7 @@ export declare const zTenantSchema: z.ZodObject<{
32
32
  created_at?: Date | null | undefined;
33
33
  updated_at?: Date | null | undefined;
34
34
  deleted_at?: Date | null | undefined;
35
- base_tenant?: string | undefined;
35
+ base_tenant?: string | null | undefined;
36
36
  hidden?: boolean | undefined;
37
37
  readonly?: boolean | undefined;
38
38
  date_format?: string | undefined;
@@ -50,7 +50,7 @@ export declare const zTenantSchema: z.ZodObject<{
50
50
  created_at?: Date | null | undefined;
51
51
  updated_at?: Date | null | undefined;
52
52
  deleted_at?: Date | null | undefined;
53
- base_tenant?: string | undefined;
53
+ base_tenant?: string | null | undefined;
54
54
  hidden?: boolean | undefined;
55
55
  readonly?: boolean | undefined;
56
56
  date_format?: string | undefined;
@@ -14,7 +14,7 @@ exports.zTenantSchema = zod_schemas_1.zFireDocSchema // Extend from FireDocSchem
14
14
  .extend({
15
15
  name: zod_1.z.string().min(1).max(255),
16
16
  url_alias: zod_1.z.string().min(1).max(255),
17
- base_tenant: zod_1.z.string().optional(),
17
+ base_tenant: zod_1.z.string().nullable().optional(),
18
18
  hidden: zod_1.z.boolean().default(false).optional(),
19
19
  readonly: zod_1.z.boolean().default(false).optional(),
20
20
  date_format: zod_1.z.string().optional(),
@@ -15,7 +15,7 @@ export const zTenantSchema = zFireDocSchema // Extend from FireDocSchema
15
15
  .extend({
16
16
  name: z.string().min(1).max(255),
17
17
  url_alias: z.string().min(1).max(255),
18
- base_tenant: z.string().optional(),
18
+ base_tenant: z.string().nullable().optional(),
19
19
  hidden: z.boolean().default(false).optional(),
20
20
  readonly: z.boolean().default(false).optional(),
21
21
  date_format: z.string().optional(),
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ export * from "./types/evo-finops";
22
22
  export * from "./types/evo-notif-user";
23
23
  export * from "./types/evo-notifications";
24
24
  export * from "./types/evo-task-runner";
25
+ export * from "./types/evo-integrations";
25
26
  export * from "./types/nex-customers";
26
27
  export * from "./apps/shared/zod-schemas";
27
28
  export * from "./apps/evo-core/zod-schemas";
@@ -56,3 +57,4 @@ export * from "./apps/evo-finops/zod-schemas";
56
57
  export * from "./apps/evo-notif-user/zod-schemas";
57
58
  export * from "./apps/evo-notifications/zod-schemas";
58
59
  export * from "./apps/evo-task-runner/zod-schemas";
60
+ export * from "./apps/evo-integrations/zod-schemas";
package/dist/index.js CHANGED
@@ -39,6 +39,7 @@ __exportStar(require("./types/evo-finops"), exports);
39
39
  __exportStar(require("./types/evo-notif-user"), exports);
40
40
  __exportStar(require("./types/evo-notifications"), exports);
41
41
  __exportStar(require("./types/evo-task-runner"), exports);
42
+ __exportStar(require("./types/evo-integrations"), exports);
42
43
  __exportStar(require("./types/nex-customers"), exports);
43
44
  // zod schemas
44
45
  __exportStar(require("./apps/shared/zod-schemas"), exports);
@@ -74,3 +75,4 @@ __exportStar(require("./apps/evo-finops/zod-schemas"), exports);
74
75
  __exportStar(require("./apps/evo-notif-user/zod-schemas"), exports);
75
76
  __exportStar(require("./apps/evo-notifications/zod-schemas"), exports);
76
77
  __exportStar(require("./apps/evo-task-runner/zod-schemas"), exports);
78
+ __exportStar(require("./apps/evo-integrations/zod-schemas"), exports);
package/dist/index.ts CHANGED
@@ -23,6 +23,7 @@ export * from "./types/evo-finops";
23
23
  export * from "./types/evo-notif-user";
24
24
  export * from "./types/evo-notifications";
25
25
  export * from "./types/evo-task-runner";
26
+ export * from "./types/evo-integrations";
26
27
  export * from "./types/nex-customers";
27
28
 
28
29
  // zod schemas
@@ -59,3 +60,4 @@ export * from "./apps/evo-finops/zod-schemas";
59
60
  export * from "./apps/evo-notif-user/zod-schemas";
60
61
  export * from "./apps/evo-notifications/zod-schemas";
61
62
  export * from "./apps/evo-task-runner/zod-schemas";
63
+ export * from "./apps/evo-integrations/zod-schemas";
@@ -0,0 +1,5 @@
1
+ export declare const PLATFORM_COLLECTION = "platform";
2
+ export declare const EVO_INTEGRATIONS_PLATFORM_DOC = "evo-integrations";
3
+ export declare const ADAPTERS_COLLECTION = "adapters";
4
+ export declare const INTEGRATION_CREDENTIALS_COLLECTION = "integration-credentials";
5
+ export declare const SYNC_STATES_COLLECTION = "sync-states";
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SYNC_STATES_COLLECTION = exports.INTEGRATION_CREDENTIALS_COLLECTION = exports.ADAPTERS_COLLECTION = exports.EVO_INTEGRATIONS_PLATFORM_DOC = exports.PLATFORM_COLLECTION = void 0;
4
+ // Platform-level (Nexus-managed, cross-tenant) adapter catalog
5
+ // Path: /platform/evo-integrations/adapters/{adapter_id}
6
+ exports.PLATFORM_COLLECTION = "platform";
7
+ exports.EVO_INTEGRATIONS_PLATFORM_DOC = "evo-integrations";
8
+ exports.ADAPTERS_COLLECTION = "adapters";
9
+ // Tenant-level (under apps/evo-med — integration config lives with the calendar it serves)
10
+ // Path: /tenants/{t}/apps/evo-med/integration-credentials/{cred_id}
11
+ exports.INTEGRATION_CREDENTIALS_COLLECTION = "integration-credentials";
12
+ // Per-calendar sync state (1 doc per calendar).
13
+ // Path: /tenants/{t}/apps/evo-med/sync-states/{calendar_id}
14
+ exports.SYNC_STATES_COLLECTION = "sync-states";
@@ -0,0 +1,13 @@
1
+ // Platform-level (Nexus-managed, cross-tenant) adapter catalog
2
+ // Path: /platform/evo-integrations/adapters/{adapter_id}
3
+ export const PLATFORM_COLLECTION = "platform";
4
+ export const EVO_INTEGRATIONS_PLATFORM_DOC = "evo-integrations";
5
+ export const ADAPTERS_COLLECTION = "adapters";
6
+
7
+ // Tenant-level (under apps/evo-med — integration config lives with the calendar it serves)
8
+ // Path: /tenants/{t}/apps/evo-med/integration-credentials/{cred_id}
9
+ export const INTEGRATION_CREDENTIALS_COLLECTION = "integration-credentials";
10
+
11
+ // Per-calendar sync state (1 doc per calendar).
12
+ // Path: /tenants/{t}/apps/evo-med/sync-states/{calendar_id}
13
+ export const SYNC_STATES_COLLECTION = "sync-states";
@@ -0,0 +1,133 @@
1
+ export * from "./fb_collections";
2
+ import type { IFireDoc } from "../shared";
3
+ export declare const EvoIntegrationsPermissions: {
4
+ readonly List: "evo_integrations_read";
5
+ readonly Get: "evo_integrations_read";
6
+ readonly Create: "evo_integrations_write";
7
+ readonly Update: "evo_integrations_write";
8
+ readonly Delete: "evo_integrations_write";
9
+ readonly InvokeAction: "evo_integrations_action_invoke";
10
+ };
11
+ export type EvoIntegrationsPermissions = (typeof EvoIntegrationsPermissions)[keyof typeof EvoIntegrationsPermissions];
12
+ export declare const SYNC_RUN_PUBSUB_TOPIC = "evo-integrations.sync_runs";
13
+ export declare const SYNC_RUN_HANDLER = "evo-integrations.sync-run";
14
+ export type CapabilityEntity = "appointment" | "patient" | "payment" | "sync";
15
+ export type CapabilityName = "appointment.get" | "appointment.list" | "appointment.create" | "appointment.update" | "appointment.cancel" | "appointment.confirm" | "appointment.reschedule" | "patient.get" | "patient.list" | "patient.create" | "patient.update" | "patient.document.upload" | "payment.update" | "sync.appointments";
16
+ /**
17
+ * Capabilities obrigatórias em qualquer adapter. Sem elas, o adapter
18
+ * não pode ser ativado. `appointment.get` é fundamental pra auto-deleção
19
+ * confiável via get-after-diff.
20
+ */
21
+ export declare const OBLIGATORY_CAPABILITIES: readonly CapabilityName[];
22
+ /**
23
+ * Capabilities internas (não expostas via action dispatcher — apenas
24
+ * via sync engine / task-runner).
25
+ */
26
+ export declare function isInternalCapability(name: CapabilityName): boolean;
27
+ export declare function splitCapabilityName(name: CapabilityName): {
28
+ entity: CapabilityEntity;
29
+ action: string;
30
+ };
31
+ export type AdapterCategory = "clinic-agenda" | "prontuario" | "misc";
32
+ export type AdapterStatus = "active" | "disabled" | "beta";
33
+ /**
34
+ * Doc Firestore global do adapter, gerenciado pela Nexus UI.
35
+ * Path: /platform/evo-integrations/adapters/{adapter_id}
36
+ */
37
+ export interface IIntegrationsAdapterDoc extends IFireDoc {
38
+ name: string;
39
+ description?: string;
40
+ category: AdapterCategory;
41
+ status: AdapterStatus;
42
+ /** Semver string do código do adapter (distinto do `version` numérico do IFireDoc). */
43
+ adapter_version: string;
44
+ /**
45
+ * URLs default dos workflows n8n por capability.
46
+ * Precedência: calendar.integration.workflow_overrides → este doc → adapter code default.
47
+ */
48
+ default_workflow_urls: Partial<Record<CapabilityName, string>>;
49
+ supported_capabilities: readonly CapabilityName[];
50
+ auth_schema_version?: number;
51
+ }
52
+ export type IntegrationCredentialStatus = "active" | "paused" | "revoked";
53
+ export interface IIntegrationsCredential extends IFireDoc {
54
+ adapter_id: string;
55
+ name: string;
56
+ /**
57
+ * Referência ao secret no Google Secret Manager.
58
+ * Formato: projects/hr-evo360/secrets/evo-integrations-{tenant}-{cred_id}
59
+ */
60
+ secret_ref: string;
61
+ /** Config não-secreta (api_base, external_org_id, etc.). */
62
+ config?: Record<string, unknown>;
63
+ status: IntegrationCredentialStatus;
64
+ last_used_at?: Date | null;
65
+ }
66
+ export type SyncWindowType = "hot" | "warm" | "recent_reconcile" | "cold";
67
+ export interface ICoveredWindow {
68
+ start: Date;
69
+ end: Date;
70
+ }
71
+ export interface ISyncedHashes {
72
+ patients: Record<string, string>;
73
+ appointments: Record<string, string>;
74
+ }
75
+ export interface ISyncState extends IFireDoc {
76
+ calendar_id: string;
77
+ last_sync_at?: Date | null;
78
+ last_window_type?: SyncWindowType;
79
+ last_synced_hashes: ISyncedHashes;
80
+ last_coveredWindow?: ICoveredWindow | null;
81
+ }
82
+ export type SyncRunStatus = "success" | "partial" | "error";
83
+ export interface ISyncRunEventError {
84
+ code?: string;
85
+ message: string;
86
+ details?: Record<string, unknown>;
87
+ }
88
+ export interface ISyncRunEvent {
89
+ run_id: string;
90
+ tenant: string;
91
+ calendar_id: string;
92
+ adapter_id: string;
93
+ window_type: SyncWindowType;
94
+ started_at: Date;
95
+ finished_at: Date;
96
+ status: SyncRunStatus;
97
+ patients_upserted: number;
98
+ appointments_upserted: number;
99
+ appointments_skipped: number;
100
+ deletions_detected: number;
101
+ coveredWindow_start?: Date;
102
+ coveredWindow_end?: Date;
103
+ duration_ms: number;
104
+ firestore_reads: number;
105
+ firestore_writes: number;
106
+ n8n_calls: number;
107
+ errors?: ISyncRunEventError[];
108
+ }
109
+ export interface ISyncWindowConfig {
110
+ enabled: boolean;
111
+ /** Cadência em minutos. Ex.: hot=60, warm=360, cold=10080 (semanal). */
112
+ cadence_minutes: number;
113
+ /** Janela absoluta em dias a partir de "hoje". */
114
+ window_days: {
115
+ past: number;
116
+ future: number;
117
+ };
118
+ }
119
+ export interface ISyncConfig {
120
+ hot?: ISyncWindowConfig;
121
+ warm?: ISyncWindowConfig;
122
+ recent_reconcile?: ISyncWindowConfig;
123
+ cold?: ISyncWindowConfig;
124
+ }
125
+ export interface IMedCalendarIntegration {
126
+ adapter_id: string;
127
+ credentials_id: string;
128
+ /** Prefixo opcional pra namespacing de patient_id entre adapters/calendars. Default vazio. */
129
+ patient_prefix?: string;
130
+ sync_config: ISyncConfig;
131
+ /** Override por capability — precedência mais alta no resolver de URL. */
132
+ workflow_overrides?: Partial<Record<CapabilityName, string>>;
133
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.OBLIGATORY_CAPABILITIES = exports.SYNC_RUN_HANDLER = exports.SYNC_RUN_PUBSUB_TOPIC = exports.EvoIntegrationsPermissions = void 0;
18
+ exports.isInternalCapability = isInternalCapability;
19
+ exports.splitCapabilityName = splitCapabilityName;
20
+ __exportStar(require("./fb_collections"), exports);
21
+ // ======================================================
22
+ // evo-integrations
23
+ //
24
+ // Padroniza integração com sistemas externos de agenda/prontuário
25
+ // (iClinic, Feegow, MedX, ...). Feat-004.
26
+ //
27
+ // Arquitetura em 4 pilares:
28
+ // 1. Adapter registry global (Nexus-managed, /platform/evo-integrations/adapters)
29
+ // 2. Credential vault (Google Secret Manager; n8n lê via SA direto)
30
+ // 3. Sync engine (handler do evo-task-runner; janelas hot/warm/recent_reconcile/cold)
31
+ // 4. Action envelope (dispatcher transparente — uma URL fixa pra consumers)
32
+ // ======================================================
33
+ // ----- Permissions
34
+ exports.EvoIntegrationsPermissions = {
35
+ List: "evo_integrations_read",
36
+ Get: "evo_integrations_read",
37
+ Create: "evo_integrations_write",
38
+ Update: "evo_integrations_write",
39
+ Delete: "evo_integrations_write",
40
+ InvokeAction: "evo_integrations_action_invoke",
41
+ };
42
+ // ----- PubSub topics
43
+ // 1 evento por sync run, sink em BigQuery (hr-evo360.evo_log.evo_integrations_sync_runs).
44
+ exports.SYNC_RUN_PUBSUB_TOPIC = "evo-integrations.sync_runs";
45
+ // Handler do evo-task-runner — resolve pro tópico ${handler}.execute_requests.
46
+ exports.SYNC_RUN_HANDLER = "evo-integrations.sync-run";
47
+ /**
48
+ * Capabilities obrigatórias em qualquer adapter. Sem elas, o adapter
49
+ * não pode ser ativado. `appointment.get` é fundamental pra auto-deleção
50
+ * confiável via get-after-diff.
51
+ */
52
+ exports.OBLIGATORY_CAPABILITIES = [
53
+ "appointment.get",
54
+ "appointment.create",
55
+ "appointment.update",
56
+ "appointment.cancel",
57
+ "appointment.confirm",
58
+ "patient.get",
59
+ "sync.appointments",
60
+ ];
61
+ /**
62
+ * Capabilities internas (não expostas via action dispatcher — apenas
63
+ * via sync engine / task-runner).
64
+ */
65
+ function isInternalCapability(name) {
66
+ return name === "sync.appointments";
67
+ }
68
+ function splitCapabilityName(name) {
69
+ const [entity, ...rest] = name.split(".");
70
+ return { entity: entity, action: rest.join(".") };
71
+ }
@@ -0,0 +1,232 @@
1
+ export * from "./fb_collections";
2
+ import type { IFireDoc } from "../shared";
3
+
4
+ // ======================================================
5
+ // evo-integrations
6
+ //
7
+ // Padroniza integração com sistemas externos de agenda/prontuário
8
+ // (iClinic, Feegow, MedX, ...). Feat-004.
9
+ //
10
+ // Arquitetura em 4 pilares:
11
+ // 1. Adapter registry global (Nexus-managed, /platform/evo-integrations/adapters)
12
+ // 2. Credential vault (Google Secret Manager; n8n lê via SA direto)
13
+ // 3. Sync engine (handler do evo-task-runner; janelas hot/warm/recent_reconcile/cold)
14
+ // 4. Action envelope (dispatcher transparente — uma URL fixa pra consumers)
15
+ // ======================================================
16
+
17
+ // ----- Permissions
18
+ export const EvoIntegrationsPermissions = {
19
+ List: "evo_integrations_read",
20
+ Get: "evo_integrations_read",
21
+ Create: "evo_integrations_write",
22
+ Update: "evo_integrations_write",
23
+ Delete: "evo_integrations_write",
24
+ InvokeAction: "evo_integrations_action_invoke",
25
+ } as const;
26
+
27
+ export type EvoIntegrationsPermissions =
28
+ (typeof EvoIntegrationsPermissions)[keyof typeof EvoIntegrationsPermissions];
29
+
30
+ // ----- PubSub topics
31
+ // 1 evento por sync run, sink em BigQuery (hr-evo360.evo_log.evo_integrations_sync_runs).
32
+ export const SYNC_RUN_PUBSUB_TOPIC = "evo-integrations.sync_runs";
33
+
34
+ // Handler do evo-task-runner — resolve pro tópico ${handler}.execute_requests.
35
+ export const SYNC_RUN_HANDLER = "evo-integrations.sync-run";
36
+
37
+ // ======================================================
38
+ // Capabilities — nomenclatura {entity}.{action}
39
+ // ======================================================
40
+
41
+ export type CapabilityEntity = "appointment" | "patient" | "payment" | "sync";
42
+
43
+ export type CapabilityName =
44
+ | "appointment.get"
45
+ | "appointment.list"
46
+ | "appointment.create"
47
+ | "appointment.update"
48
+ | "appointment.cancel"
49
+ | "appointment.confirm"
50
+ | "appointment.reschedule"
51
+ | "patient.get"
52
+ | "patient.list"
53
+ | "patient.create"
54
+ | "patient.update"
55
+ | "patient.document.upload"
56
+ | "payment.update"
57
+ | "sync.appointments";
58
+
59
+ /**
60
+ * Capabilities obrigatórias em qualquer adapter. Sem elas, o adapter
61
+ * não pode ser ativado. `appointment.get` é fundamental pra auto-deleção
62
+ * confiável via get-after-diff.
63
+ */
64
+ export const OBLIGATORY_CAPABILITIES: readonly CapabilityName[] = [
65
+ "appointment.get",
66
+ "appointment.create",
67
+ "appointment.update",
68
+ "appointment.cancel",
69
+ "appointment.confirm",
70
+ "patient.get",
71
+ "sync.appointments",
72
+ ] as const;
73
+
74
+ /**
75
+ * Capabilities internas (não expostas via action dispatcher — apenas
76
+ * via sync engine / task-runner).
77
+ */
78
+ export function isInternalCapability(name: CapabilityName): boolean {
79
+ return name === "sync.appointments";
80
+ }
81
+
82
+ export function splitCapabilityName(name: CapabilityName): {
83
+ entity: CapabilityEntity;
84
+ action: string;
85
+ } {
86
+ const [entity, ...rest] = name.split(".");
87
+ return { entity: entity as CapabilityEntity, action: rest.join(".") };
88
+ }
89
+
90
+ // ======================================================
91
+ // Adapter — contrato declarativo
92
+ // Código do adapter vive em @evo/model/evo-integrations/adapters/{id}.
93
+ // Doc correspondente em Firestore (/platform/evo-integrations/adapters/{id})
94
+ // pode overrider URLs default sem deploy.
95
+ // ======================================================
96
+
97
+ export type AdapterCategory = "clinic-agenda" | "prontuario" | "misc";
98
+ export type AdapterStatus = "active" | "disabled" | "beta";
99
+
100
+ /**
101
+ * Doc Firestore global do adapter, gerenciado pela Nexus UI.
102
+ * Path: /platform/evo-integrations/adapters/{adapter_id}
103
+ */
104
+ export interface IIntegrationsAdapterDoc extends IFireDoc {
105
+ name: string;
106
+ description?: string;
107
+ category: AdapterCategory;
108
+ status: AdapterStatus;
109
+ /** Semver string do código do adapter (distinto do `version` numérico do IFireDoc). */
110
+ adapter_version: string;
111
+ /**
112
+ * URLs default dos workflows n8n por capability.
113
+ * Precedência: calendar.integration.workflow_overrides → este doc → adapter code default.
114
+ */
115
+ default_workflow_urls: Partial<Record<CapabilityName, string>>;
116
+ supported_capabilities: readonly CapabilityName[];
117
+ auth_schema_version?: number;
118
+ }
119
+
120
+ // ======================================================
121
+ // Credential — metadados. Raw creds vivem no Google Secret Manager.
122
+ // Path: /tenants/{t}/apps/evo-med/integration-credentials/{cred_id}
123
+ // ======================================================
124
+
125
+ export type IntegrationCredentialStatus = "active" | "paused" | "revoked";
126
+
127
+ export interface IIntegrationsCredential extends IFireDoc {
128
+ adapter_id: string;
129
+ name: string;
130
+ /**
131
+ * Referência ao secret no Google Secret Manager.
132
+ * Formato: projects/hr-evo360/secrets/evo-integrations-{tenant}-{cred_id}
133
+ */
134
+ secret_ref: string;
135
+ /** Config não-secreta (api_base, external_org_id, etc.). */
136
+ config?: Record<string, unknown>;
137
+ status: IntegrationCredentialStatus;
138
+ last_used_at?: Date | null;
139
+ }
140
+
141
+ // ======================================================
142
+ // Sync state — 1 doc por calendar, mutável.
143
+ // Path: /tenants/{t}/apps/evo-med/sync-states/{calendar_id}
144
+ // ======================================================
145
+
146
+ export type SyncWindowType = "hot" | "warm" | "recent_reconcile" | "cold";
147
+
148
+ export interface ICoveredWindow {
149
+ start: Date;
150
+ end: Date;
151
+ }
152
+
153
+ export interface ISyncedHashes {
154
+ patients: Record<string, string>;
155
+ appointments: Record<string, string>;
156
+ }
157
+
158
+ export interface ISyncState extends IFireDoc {
159
+ calendar_id: string;
160
+ last_sync_at?: Date | null;
161
+ last_window_type?: SyncWindowType;
162
+ last_synced_hashes: ISyncedHashes;
163
+ last_coveredWindow?: ICoveredWindow | null;
164
+ }
165
+
166
+ // ======================================================
167
+ // Sync run event — publicado no SYNC_RUN_PUBSUB_TOPIC ao final de cada run.
168
+ // Schema espelha a tabela BigQuery (hr-evo360.evo_log.evo_integrations_sync_runs).
169
+ // ======================================================
170
+
171
+ export type SyncRunStatus = "success" | "partial" | "error";
172
+
173
+ export interface ISyncRunEventError {
174
+ code?: string;
175
+ message: string;
176
+ details?: Record<string, unknown>;
177
+ }
178
+
179
+ export interface ISyncRunEvent {
180
+ run_id: string;
181
+ tenant: string;
182
+ calendar_id: string;
183
+ adapter_id: string;
184
+ window_type: SyncWindowType;
185
+ started_at: Date;
186
+ finished_at: Date;
187
+ status: SyncRunStatus;
188
+ patients_upserted: number;
189
+ appointments_upserted: number;
190
+ appointments_skipped: number;
191
+ deletions_detected: number;
192
+ coveredWindow_start?: Date;
193
+ coveredWindow_end?: Date;
194
+ duration_ms: number;
195
+ firestore_reads: number;
196
+ firestore_writes: number;
197
+ n8n_calls: number;
198
+ errors?: ISyncRunEventError[];
199
+ }
200
+
201
+ // ======================================================
202
+ // Calendar integration config — vive inline no calendar doc.
203
+ // Ver IMedCalendar em evo-types/src/types/evo-med/calendar.
204
+ // ======================================================
205
+
206
+ export interface ISyncWindowConfig {
207
+ enabled: boolean;
208
+ /** Cadência em minutos. Ex.: hot=60, warm=360, cold=10080 (semanal). */
209
+ cadence_minutes: number;
210
+ /** Janela absoluta em dias a partir de "hoje". */
211
+ window_days: {
212
+ past: number;
213
+ future: number;
214
+ };
215
+ }
216
+
217
+ export interface ISyncConfig {
218
+ hot?: ISyncWindowConfig;
219
+ warm?: ISyncWindowConfig;
220
+ recent_reconcile?: ISyncWindowConfig;
221
+ cold?: ISyncWindowConfig;
222
+ }
223
+
224
+ export interface IMedCalendarIntegration {
225
+ adapter_id: string;
226
+ credentials_id: string;
227
+ /** Prefixo opcional pra namespacing de patient_id entre adapters/calendars. Default vazio. */
228
+ patient_prefix?: string;
229
+ sync_config: ISyncConfig;
230
+ /** Override por capability — precedência mais alta no resolver de URL. */
231
+ workflow_overrides?: Partial<Record<CapabilityName, string>>;
232
+ }
@@ -1,6 +1,7 @@
1
1
  export * from "../../evo-people/fb_collections";
2
2
  import type { FirestoreDocumentReference, IFireDoc, ITag } from "../../shared";
3
3
  import type { IAppointmentCounters } from "../people";
4
+ import type { IMedCalendarIntegration } from "../../evo-integrations";
4
5
  export declare const EvoMedCalendarPermissions: {
5
6
  readonly List: "evo_med_calendar_read";
6
7
  readonly Get: "evo_med_calendar_read";
@@ -35,5 +36,6 @@ export interface IMedCalendar extends IFireDoc {
35
36
  appointmentCounters?: IAppointmentCounters | null;
36
37
  available_weekdays?: number[];
37
38
  available_for_hubia?: boolean;
39
+ integration?: IMedCalendarIntegration;
38
40
  [key: string]: unknown;
39
41
  }
@@ -1,6 +1,7 @@
1
1
  export * from "../../evo-people/fb_collections";
2
2
  import type { FirestoreDocumentReference, IFireDoc, ITag } from "../../shared";
3
3
  import type { IAppointmentCounters } from "../people";
4
+ import type { IMedCalendarIntegration } from "../../evo-integrations";
4
5
 
5
6
  // Permissões para o calendário
6
7
  export const EvoMedCalendarPermissions = {
@@ -44,5 +45,7 @@ export interface IMedCalendar extends IFireDoc {
44
45
  available_weekdays?: number[];
45
46
  // Se true, a agenda é elegível para oferecer horários via HubIA
46
47
  available_for_hubia?: boolean;
48
+ // Config de integração (feat-004 evo-integrations). Opcional — calendars legados mantêm n8n_wf/url/ext_urls.
49
+ integration?: IMedCalendarIntegration;
47
50
  [key: string]: unknown; // index signature
48
51
  }
@@ -35,7 +35,7 @@ export declare enum ITenantStatus {
35
35
  }
36
36
  export interface ITenant extends IFireDoc {
37
37
  name: string;
38
- base_tenant?: string;
38
+ base_tenant?: string | null;
39
39
  hidden?: boolean;
40
40
  readonly?: boolean;
41
41
  url_alias: string;
@@ -48,7 +48,7 @@ export enum ITenantStatus {
48
48
 
49
49
  export interface ITenant extends IFireDoc {
50
50
  name: string;
51
- base_tenant?: string;
51
+ base_tenant?: string | null;
52
52
  hidden?: boolean;
53
53
  readonly?: boolean;
54
54
  url_alias: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evo360-types",
3
- "version": "1.3.326",
3
+ "version": "1.3.329",
4
4
  "description": "HREVO360 Shared Types",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",