@voyantjs/crm 0.26.3 → 0.26.4

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 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAYjE,KAAK,GAAG,GAAG;IACT,SAAS,EAAE;QACT,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AAED,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAQU,CAAA;AAEhC,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAajE,KAAK,GAAG,GAAG;IACT,SAAS,EAAE;QACT,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AAED,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBASU,CAAA;AAEhC,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAA"}
@@ -2,6 +2,7 @@ import { Hono } from "hono";
2
2
  import { accountRoutes } from "./accounts.js";
3
3
  import { activityRoutes } from "./activities.js";
4
4
  import { customFieldRoutes } from "./custom-fields.js";
5
+ import { customerSignalRoutes } from "./customer-signals.js";
5
6
  import { opportunityRoutes } from "./opportunities.js";
6
7
  import { personDocumentRoutes } from "./person-documents.js";
7
8
  import { personRelationshipRoutes } from "./person-relationships.js";
@@ -11,6 +12,7 @@ export const crmRoutes = new Hono()
11
12
  .route("/", accountRoutes)
12
13
  .route("/", personDocumentRoutes)
13
14
  .route("/", personRelationshipRoutes)
15
+ .route("/", customerSignalRoutes)
14
16
  .route("/", pipelineRoutes)
15
17
  .route("/", opportunityRoutes)
16
18
  .route("/", quoteRoutes)
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Customer signals — lighter than `opportunities` (no deal value or
3
+ * stages), heavier than `segments` (lifecycle + assignment). Records
4
+ * "person X expressed interest in product/departure Y from source Z,
5
+ * status pending". The most common use cases:
6
+ *
7
+ * - Notify-availability ("ping me when this departure opens up")
8
+ * - Wishlist / saved trips
9
+ * - Inquiry captured by an operator (phone call, web form)
10
+ * - Request-offer pre-pipeline that may or may not become a booking
11
+ * - Abandoned-cart recovery
12
+ *
13
+ * Cross-module IDs (`productId`, `optionUnitId`, `resolvedBookingId`)
14
+ * are intentionally plain `text()` columns rather than FK references
15
+ * — voyant's project-wide rule is that cross-module FKs go through
16
+ * link tables or stay loose. The signal is owned by CRM; products
17
+ * and bookings reference its id, not the other way around.
18
+ */
19
+ export declare const customerSignalKindEnum: import("drizzle-orm/pg-core").PgEnum<["wishlist", "notify", "inquiry", "request_offer", "referral"]>;
20
+ export declare const customerSignalSourceEnum: import("drizzle-orm/pg-core").PgEnum<["form", "phone", "admin", "abandoned_cart", "website", "booking"]>;
21
+ export declare const customerSignalStatusEnum: import("drizzle-orm/pg-core").PgEnum<["new", "contacted", "qualified", "converted", "lost", "expired"]>;
22
+ export declare const customerSignals: import("drizzle-orm/pg-core").PgTableWithColumns<{
23
+ name: "customer_signals";
24
+ schema: undefined;
25
+ columns: {
26
+ id: import("drizzle-orm/pg-core").PgColumn<{
27
+ name: string;
28
+ tableName: "customer_signals";
29
+ dataType: "string";
30
+ columnType: "PgText";
31
+ data: string;
32
+ driverParam: string;
33
+ notNull: true;
34
+ hasDefault: true;
35
+ isPrimaryKey: true;
36
+ isAutoincrement: false;
37
+ hasRuntimeDefault: true;
38
+ enumValues: [string, ...string[]];
39
+ baseColumn: never;
40
+ identity: undefined;
41
+ generated: undefined;
42
+ }, {}, {}>;
43
+ personId: import("drizzle-orm/pg-core").PgColumn<{
44
+ name: string;
45
+ tableName: "customer_signals";
46
+ dataType: "string";
47
+ columnType: "PgText";
48
+ data: string;
49
+ driverParam: string;
50
+ notNull: true;
51
+ hasDefault: false;
52
+ isPrimaryKey: false;
53
+ isAutoincrement: false;
54
+ hasRuntimeDefault: false;
55
+ enumValues: [string, ...string[]];
56
+ baseColumn: never;
57
+ identity: undefined;
58
+ generated: undefined;
59
+ }, {}, {}>;
60
+ productId: import("drizzle-orm/pg-core").PgColumn<{
61
+ name: "product_id";
62
+ tableName: "customer_signals";
63
+ dataType: "string";
64
+ columnType: "PgText";
65
+ data: string;
66
+ driverParam: string;
67
+ notNull: false;
68
+ hasDefault: false;
69
+ isPrimaryKey: false;
70
+ isAutoincrement: false;
71
+ hasRuntimeDefault: false;
72
+ enumValues: [string, ...string[]];
73
+ baseColumn: never;
74
+ identity: undefined;
75
+ generated: undefined;
76
+ }, {}, {}>;
77
+ optionUnitId: import("drizzle-orm/pg-core").PgColumn<{
78
+ name: "option_unit_id";
79
+ tableName: "customer_signals";
80
+ dataType: "string";
81
+ columnType: "PgText";
82
+ data: string;
83
+ driverParam: string;
84
+ notNull: false;
85
+ hasDefault: false;
86
+ isPrimaryKey: false;
87
+ isAutoincrement: false;
88
+ hasRuntimeDefault: false;
89
+ enumValues: [string, ...string[]];
90
+ baseColumn: never;
91
+ identity: undefined;
92
+ generated: undefined;
93
+ }, {}, {}>;
94
+ kind: import("drizzle-orm/pg-core").PgColumn<{
95
+ name: "kind";
96
+ tableName: "customer_signals";
97
+ dataType: "string";
98
+ columnType: "PgEnumColumn";
99
+ data: "wishlist" | "notify" | "inquiry" | "request_offer" | "referral";
100
+ driverParam: string;
101
+ notNull: true;
102
+ hasDefault: false;
103
+ isPrimaryKey: false;
104
+ isAutoincrement: false;
105
+ hasRuntimeDefault: false;
106
+ enumValues: ["wishlist", "notify", "inquiry", "request_offer", "referral"];
107
+ baseColumn: never;
108
+ identity: undefined;
109
+ generated: undefined;
110
+ }, {}, {}>;
111
+ source: import("drizzle-orm/pg-core").PgColumn<{
112
+ name: "source";
113
+ tableName: "customer_signals";
114
+ dataType: "string";
115
+ columnType: "PgEnumColumn";
116
+ data: "admin" | "form" | "phone" | "website" | "abandoned_cart" | "booking";
117
+ driverParam: string;
118
+ notNull: true;
119
+ hasDefault: false;
120
+ isPrimaryKey: false;
121
+ isAutoincrement: false;
122
+ hasRuntimeDefault: false;
123
+ enumValues: ["form", "phone", "admin", "abandoned_cart", "website", "booking"];
124
+ baseColumn: never;
125
+ identity: undefined;
126
+ generated: undefined;
127
+ }, {}, {}>;
128
+ status: import("drizzle-orm/pg-core").PgColumn<{
129
+ name: "status";
130
+ tableName: "customer_signals";
131
+ dataType: "string";
132
+ columnType: "PgEnumColumn";
133
+ data: "lost" | "expired" | "new" | "contacted" | "qualified" | "converted";
134
+ driverParam: string;
135
+ notNull: true;
136
+ hasDefault: true;
137
+ isPrimaryKey: false;
138
+ isAutoincrement: false;
139
+ hasRuntimeDefault: false;
140
+ enumValues: ["new", "contacted", "qualified", "converted", "lost", "expired"];
141
+ baseColumn: never;
142
+ identity: undefined;
143
+ generated: undefined;
144
+ }, {}, {}>;
145
+ priority: import("drizzle-orm/pg-core").PgColumn<{
146
+ name: "priority";
147
+ tableName: "customer_signals";
148
+ dataType: "string";
149
+ columnType: "PgText";
150
+ data: string;
151
+ driverParam: string;
152
+ notNull: true;
153
+ hasDefault: true;
154
+ isPrimaryKey: false;
155
+ isAutoincrement: false;
156
+ hasRuntimeDefault: false;
157
+ enumValues: [string, ...string[]];
158
+ baseColumn: never;
159
+ identity: undefined;
160
+ generated: undefined;
161
+ }, {}, {}>;
162
+ notes: import("drizzle-orm/pg-core").PgColumn<{
163
+ name: "notes";
164
+ tableName: "customer_signals";
165
+ dataType: "string";
166
+ columnType: "PgText";
167
+ data: string;
168
+ driverParam: string;
169
+ notNull: false;
170
+ hasDefault: false;
171
+ isPrimaryKey: false;
172
+ isAutoincrement: false;
173
+ hasRuntimeDefault: false;
174
+ enumValues: [string, ...string[]];
175
+ baseColumn: never;
176
+ identity: undefined;
177
+ generated: undefined;
178
+ }, {}, {}>;
179
+ tags: import("drizzle-orm/pg-core").PgColumn<{
180
+ name: "tags";
181
+ tableName: "customer_signals";
182
+ dataType: "json";
183
+ columnType: "PgJsonb";
184
+ data: string[];
185
+ driverParam: unknown;
186
+ notNull: true;
187
+ hasDefault: true;
188
+ isPrimaryKey: false;
189
+ isAutoincrement: false;
190
+ hasRuntimeDefault: false;
191
+ enumValues: undefined;
192
+ baseColumn: never;
193
+ identity: undefined;
194
+ generated: undefined;
195
+ }, {}, {
196
+ $type: string[];
197
+ }>;
198
+ assignedToUserId: import("drizzle-orm/pg-core").PgColumn<{
199
+ name: "assigned_to_user_id";
200
+ tableName: "customer_signals";
201
+ dataType: "string";
202
+ columnType: "PgText";
203
+ data: string;
204
+ driverParam: string;
205
+ notNull: false;
206
+ hasDefault: false;
207
+ isPrimaryKey: false;
208
+ isAutoincrement: false;
209
+ hasRuntimeDefault: false;
210
+ enumValues: [string, ...string[]];
211
+ baseColumn: never;
212
+ identity: undefined;
213
+ generated: undefined;
214
+ }, {}, {}>;
215
+ followUpAt: import("drizzle-orm/pg-core").PgColumn<{
216
+ name: "follow_up_at";
217
+ tableName: "customer_signals";
218
+ dataType: "date";
219
+ columnType: "PgTimestamp";
220
+ data: Date;
221
+ driverParam: string;
222
+ notNull: false;
223
+ hasDefault: false;
224
+ isPrimaryKey: false;
225
+ isAutoincrement: false;
226
+ hasRuntimeDefault: false;
227
+ enumValues: undefined;
228
+ baseColumn: never;
229
+ identity: undefined;
230
+ generated: undefined;
231
+ }, {}, {}>;
232
+ resolvedBookingId: import("drizzle-orm/pg-core").PgColumn<{
233
+ name: "resolved_booking_id";
234
+ tableName: "customer_signals";
235
+ dataType: "string";
236
+ columnType: "PgText";
237
+ data: string;
238
+ driverParam: string;
239
+ notNull: false;
240
+ hasDefault: false;
241
+ isPrimaryKey: false;
242
+ isAutoincrement: false;
243
+ hasRuntimeDefault: false;
244
+ enumValues: [string, ...string[]];
245
+ baseColumn: never;
246
+ identity: undefined;
247
+ generated: undefined;
248
+ }, {}, {}>;
249
+ sourceSubmissionId: import("drizzle-orm/pg-core").PgColumn<{
250
+ name: "source_submission_id";
251
+ tableName: "customer_signals";
252
+ dataType: "string";
253
+ columnType: "PgText";
254
+ data: string;
255
+ driverParam: string;
256
+ notNull: false;
257
+ hasDefault: false;
258
+ isPrimaryKey: false;
259
+ isAutoincrement: false;
260
+ hasRuntimeDefault: false;
261
+ enumValues: [string, ...string[]];
262
+ baseColumn: never;
263
+ identity: undefined;
264
+ generated: undefined;
265
+ }, {}, {}>;
266
+ metadata: import("drizzle-orm/pg-core").PgColumn<{
267
+ name: "metadata";
268
+ tableName: "customer_signals";
269
+ dataType: "json";
270
+ columnType: "PgJsonb";
271
+ data: Record<string, unknown>;
272
+ driverParam: unknown;
273
+ notNull: false;
274
+ hasDefault: false;
275
+ isPrimaryKey: false;
276
+ isAutoincrement: false;
277
+ hasRuntimeDefault: false;
278
+ enumValues: undefined;
279
+ baseColumn: never;
280
+ identity: undefined;
281
+ generated: undefined;
282
+ }, {}, {
283
+ $type: Record<string, unknown>;
284
+ }>;
285
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
286
+ name: "created_at";
287
+ tableName: "customer_signals";
288
+ dataType: "date";
289
+ columnType: "PgTimestamp";
290
+ data: Date;
291
+ driverParam: string;
292
+ notNull: true;
293
+ hasDefault: true;
294
+ isPrimaryKey: false;
295
+ isAutoincrement: false;
296
+ hasRuntimeDefault: false;
297
+ enumValues: undefined;
298
+ baseColumn: never;
299
+ identity: undefined;
300
+ generated: undefined;
301
+ }, {}, {}>;
302
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
303
+ name: "updated_at";
304
+ tableName: "customer_signals";
305
+ dataType: "date";
306
+ columnType: "PgTimestamp";
307
+ data: Date;
308
+ driverParam: string;
309
+ notNull: true;
310
+ hasDefault: true;
311
+ isPrimaryKey: false;
312
+ isAutoincrement: false;
313
+ hasRuntimeDefault: false;
314
+ enumValues: undefined;
315
+ baseColumn: never;
316
+ identity: undefined;
317
+ generated: undefined;
318
+ }, {}, {}>;
319
+ };
320
+ dialect: "pg";
321
+ }>;
322
+ export type CustomerSignal = typeof customerSignals.$inferSelect;
323
+ export type NewCustomerSignal = typeof customerSignals.$inferInsert;
324
+ //# sourceMappingURL=schema-signals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-signals.d.ts","sourceRoot":"","sources":["../src/schema-signals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,eAAO,MAAM,sBAAsB,sGAMjC,CAAA;AAEF,eAAO,MAAM,wBAAwB,0GAOnC,CAAA;AAEF,eAAO,MAAM,wBAAwB,yGAOnC,CAAA;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2C3B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,eAAe,CAAC,YAAY,CAAA;AAChE,MAAM,MAAM,iBAAiB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAA"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Customer signals — lighter than `opportunities` (no deal value or
3
+ * stages), heavier than `segments` (lifecycle + assignment). Records
4
+ * "person X expressed interest in product/departure Y from source Z,
5
+ * status pending". The most common use cases:
6
+ *
7
+ * - Notify-availability ("ping me when this departure opens up")
8
+ * - Wishlist / saved trips
9
+ * - Inquiry captured by an operator (phone call, web form)
10
+ * - Request-offer pre-pipeline that may or may not become a booking
11
+ * - Abandoned-cart recovery
12
+ *
13
+ * Cross-module IDs (`productId`, `optionUnitId`, `resolvedBookingId`)
14
+ * are intentionally plain `text()` columns rather than FK references
15
+ * — voyant's project-wide rule is that cross-module FKs go through
16
+ * link tables or stay loose. The signal is owned by CRM; products
17
+ * and bookings reference its id, not the other way around.
18
+ */
19
+ import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
20
+ import { index, jsonb, pgEnum, pgTable, text, timestamp } from "drizzle-orm/pg-core";
21
+ import { people } from "./schema-accounts.js";
22
+ export const customerSignalKindEnum = pgEnum("customer_signal_kind", [
23
+ "wishlist",
24
+ "notify",
25
+ "inquiry",
26
+ "request_offer",
27
+ "referral",
28
+ ]);
29
+ export const customerSignalSourceEnum = pgEnum("customer_signal_source", [
30
+ "form",
31
+ "phone",
32
+ "admin",
33
+ "abandoned_cart",
34
+ "website",
35
+ "booking",
36
+ ]);
37
+ export const customerSignalStatusEnum = pgEnum("customer_signal_status", [
38
+ "new",
39
+ "contacted",
40
+ "qualified",
41
+ "converted",
42
+ "lost",
43
+ "expired",
44
+ ]);
45
+ export const customerSignals = pgTable("customer_signals", {
46
+ id: typeId("customer_signals"),
47
+ personId: typeIdRef("person_id")
48
+ .notNull()
49
+ .references(() => people.id, { onDelete: "cascade" }),
50
+ /** Optional reference into `@voyantjs/products`. Plain text — no FK. */
51
+ productId: text("product_id"),
52
+ /** Optional reference into a product's `option_units` row (the "departure"-equivalent). Plain text — no FK. */
53
+ optionUnitId: text("option_unit_id"),
54
+ kind: customerSignalKindEnum("kind").notNull(),
55
+ source: customerSignalSourceEnum("source").notNull(),
56
+ status: customerSignalStatusEnum("status").notNull().default("new"),
57
+ /**
58
+ * Free-form priority. The validation layer constrains input to
59
+ * `low | normal | high | urgent`; storing as text keeps room for
60
+ * deployment-specific values without a DB migration.
61
+ */
62
+ priority: text("priority").notNull().default("normal"),
63
+ notes: text("notes"),
64
+ tags: jsonb("tags").$type().notNull().default([]),
65
+ /** User id (Better Auth user) of the staff member assigned to follow up. */
66
+ assignedToUserId: text("assigned_to_user_id"),
67
+ followUpAt: timestamp("follow_up_at", { withTimezone: true }),
68
+ /** Set when the signal was converted into a real booking. Plain text — cross-module FK. */
69
+ resolvedBookingId: text("resolved_booking_id"),
70
+ /** Free-form provenance id (form-submission id, abandoned-cart key, ...). */
71
+ sourceSubmissionId: text("source_submission_id"),
72
+ metadata: jsonb("metadata").$type(),
73
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
74
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
75
+ }, (table) => [
76
+ index("idx_customer_signals_person_status_created").on(table.personId, table.status, table.createdAt),
77
+ index("idx_customer_signals_assignee_status").on(table.assignedToUserId, table.status),
78
+ index("idx_customer_signals_kind").on(table.kind),
79
+ index("idx_customer_signals_resolved_booking").on(table.resolvedBookingId),
80
+ ]);
package/dist/schema.d.ts CHANGED
@@ -4,4 +4,5 @@ export * from "./schema-activities.js";
4
4
  export * from "./schema-relations.js";
5
5
  export * from "./schema-sales.js";
6
6
  export * from "./schema-shared.js";
7
+ export * from "./schema-signals.js";
7
8
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA"}
package/dist/schema.js CHANGED
@@ -4,3 +4,4 @@ export * from "./schema-activities.js";
4
4
  export * from "./schema-relations.js";
5
5
  export * from "./schema-sales.js";
6
6
  export * from "./schema-shared.js";
7
+ export * from "./schema-signals.js";