@voyantjs/crm 0.26.2 → 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.
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/routes/customer-signals.d.ts +281 -0
- package/dist/routes/customer-signals.d.ts.map +1 -0
- package/dist/routes/customer-signals.js +45 -0
- package/dist/routes/index.d.ts +450 -0
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +4 -0
- package/dist/routes/person-relationships.d.ts +189 -0
- package/dist/routes/person-relationships.d.ts.map +1 -0
- package/dist/routes/person-relationships.js +36 -0
- package/dist/schema-accounts.d.ts +237 -0
- package/dist/schema-accounts.d.ts.map +1 -1
- package/dist/schema-accounts.js +64 -1
- package/dist/schema-signals.d.ts +324 -0
- package/dist/schema-signals.d.ts.map +1 -0
- package/dist/schema-signals.js +80 -0
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +1 -0
- package/dist/service/customer-signals.d.ts +733 -0
- package/dist/service/customer-signals.d.ts.map +1 -0
- package/dist/service/customer-signals.js +112 -0
- package/dist/service/index.d.ts +1187 -0
- package/dist/service/index.d.ts.map +1 -1
- package/dist/service/index.js +6 -0
- package/dist/service/person-relationships.d.ts +502 -0
- package/dist/service/person-relationships.d.ts.map +1 -0
- package/dist/service/person-relationships.js +121 -0
- package/dist/validation.d.ts +246 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +98 -0
- package/package.json +6 -6
|
@@ -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
package/dist/schema.d.ts.map
CHANGED
|
@@ -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