@voyantjs/products 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/schema.js ADDED
@@ -0,0 +1,655 @@
1
+ import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
2
+ import { relations } from "drizzle-orm";
3
+ import { boolean, date, doublePrecision, index, integer, jsonb, pgEnum, pgTable, primaryKey, text, timestamp, uniqueIndex, } from "drizzle-orm/pg-core";
4
+ export const productStatusEnum = pgEnum("product_status", ["draft", "active", "archived"]);
5
+ export const productOptionStatusEnum = pgEnum("product_option_status", [
6
+ "draft",
7
+ "active",
8
+ "archived",
9
+ ]);
10
+ export const optionUnitTypeEnum = pgEnum("option_unit_type", [
11
+ "person",
12
+ "group",
13
+ "room",
14
+ "vehicle",
15
+ "service",
16
+ "other",
17
+ ]);
18
+ export const productBookingModeEnum = pgEnum("product_booking_mode", [
19
+ "date",
20
+ "date_time",
21
+ "open",
22
+ "stay",
23
+ "transfer",
24
+ "itinerary",
25
+ "other",
26
+ ]);
27
+ export const productCapacityModeEnum = pgEnum("product_capacity_mode", [
28
+ "free_sale",
29
+ "limited",
30
+ "on_request",
31
+ ]);
32
+ export const productVisibilityEnum = pgEnum("product_visibility", ["public", "private", "hidden"]);
33
+ export const productActivationModeEnum = pgEnum("product_activation_mode", [
34
+ "manual",
35
+ "scheduled",
36
+ "channel_controlled",
37
+ ]);
38
+ export const productTicketFulfillmentEnum = pgEnum("product_ticket_fulfillment", [
39
+ "none",
40
+ "per_booking",
41
+ "per_participant",
42
+ "per_item",
43
+ ]);
44
+ export const productDeliveryFormatEnum = pgEnum("product_delivery_format", [
45
+ "voucher",
46
+ "ticket",
47
+ "pdf",
48
+ "qr_code",
49
+ "barcode",
50
+ "email",
51
+ "mobile",
52
+ "none",
53
+ ]);
54
+ export const productCapabilityEnum = pgEnum("product_capability", [
55
+ "instant_confirmation",
56
+ "on_request",
57
+ "pickup_available",
58
+ "dropoff_available",
59
+ "guided",
60
+ "private",
61
+ "shared",
62
+ "digital_ticket",
63
+ "voucher_required",
64
+ "external_inventory",
65
+ "multi_day",
66
+ "accommodation",
67
+ "transport",
68
+ ]);
69
+ export const productFeatureTypeEnum = pgEnum("product_feature_type", [
70
+ "inclusion",
71
+ "exclusion",
72
+ "highlight",
73
+ "important_information",
74
+ "other",
75
+ ]);
76
+ export const productLocationTypeEnum = pgEnum("product_location_type", [
77
+ "start",
78
+ "end",
79
+ "meeting_point",
80
+ "pickup",
81
+ "dropoff",
82
+ "point_of_interest",
83
+ "other",
84
+ ]);
85
+ // Inlined from suppliers to avoid cross-package schema dependency
86
+ export const serviceTypeEnum = pgEnum("service_type", [
87
+ "accommodation",
88
+ "transfer",
89
+ "experience",
90
+ "guide",
91
+ "meal",
92
+ "other",
93
+ ]);
94
+ // ---------- products ----------
95
+ export const products = pgTable("products", {
96
+ id: typeId("products"),
97
+ name: text("name").notNull(),
98
+ status: productStatusEnum("status").notNull().default("draft"),
99
+ description: text("description"),
100
+ bookingMode: productBookingModeEnum("booking_mode").notNull().default("date"),
101
+ capacityMode: productCapacityModeEnum("capacity_mode").notNull().default("limited"),
102
+ timezone: text("timezone"),
103
+ visibility: productVisibilityEnum("visibility").notNull().default("private"),
104
+ activated: boolean("activated").notNull().default(false),
105
+ reservationTimeoutMinutes: integer("reservation_timeout_minutes"),
106
+ // Pricing
107
+ sellCurrency: text("sell_currency").notNull(),
108
+ sellAmountCents: integer("sell_amount_cents"),
109
+ costAmountCents: integer("cost_amount_cents"),
110
+ marginPercent: integer("margin_percent"),
111
+ // Client link — person/organization associations now live in cross-module link tables
112
+ // (see `defineLink(crmModule.linkable.person, productsModule.linkable.product)`).
113
+ facilityId: text("facility_id"),
114
+ // Trip details
115
+ startDate: date("start_date"),
116
+ endDate: date("end_date"),
117
+ pax: integer("pax"),
118
+ // Taxonomy
119
+ productTypeId: text("product_type_id"),
120
+ // Metadata
121
+ tags: jsonb("tags").$type().default([]),
122
+ // Timestamps
123
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
124
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
125
+ }, (table) => [
126
+ index("idx_products_status").on(table.status),
127
+ index("idx_products_facility").on(table.facilityId),
128
+ index("idx_products_product_type").on(table.productTypeId),
129
+ ]);
130
+ // ---------- product_options ----------
131
+ export const productOptions = pgTable("product_options", {
132
+ id: typeId("product_options"),
133
+ productId: typeIdRef("product_id")
134
+ .notNull()
135
+ .references(() => products.id, { onDelete: "cascade" }),
136
+ name: text("name").notNull(),
137
+ code: text("code"),
138
+ description: text("description"),
139
+ status: productOptionStatusEnum("status").notNull().default("draft"),
140
+ isDefault: boolean("is_default").notNull().default(false),
141
+ sortOrder: integer("sort_order").notNull().default(0),
142
+ availableFrom: date("available_from"),
143
+ availableTo: date("available_to"),
144
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
145
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
146
+ }, (table) => [
147
+ index("idx_product_options_product").on(table.productId),
148
+ index("idx_product_options_status").on(table.status),
149
+ index("idx_product_options_default").on(table.isDefault),
150
+ uniqueIndex("uidx_product_options_product_code").on(table.productId, table.code),
151
+ ]);
152
+ // ---------- option_units ----------
153
+ export const optionUnits = pgTable("option_units", {
154
+ id: typeId("option_units"),
155
+ optionId: typeIdRef("option_id")
156
+ .notNull()
157
+ .references(() => productOptions.id, { onDelete: "cascade" }),
158
+ name: text("name").notNull(),
159
+ code: text("code"),
160
+ description: text("description"),
161
+ unitType: optionUnitTypeEnum("unit_type").notNull().default("person"),
162
+ minQuantity: integer("min_quantity"),
163
+ maxQuantity: integer("max_quantity"),
164
+ minAge: integer("min_age"),
165
+ maxAge: integer("max_age"),
166
+ occupancyMin: integer("occupancy_min"),
167
+ occupancyMax: integer("occupancy_max"),
168
+ isRequired: boolean("is_required").notNull().default(false),
169
+ isHidden: boolean("is_hidden").notNull().default(false),
170
+ sortOrder: integer("sort_order").notNull().default(0),
171
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
172
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
173
+ }, (table) => [
174
+ index("idx_option_units_option").on(table.optionId),
175
+ index("idx_option_units_type").on(table.unitType),
176
+ uniqueIndex("uidx_option_units_option_code").on(table.optionId, table.code),
177
+ ]);
178
+ // ---------- product operating configuration ----------
179
+ export const productActivationSettings = pgTable("product_activation_settings", {
180
+ id: typeId("product_activation_settings"),
181
+ productId: typeIdRef("product_id")
182
+ .notNull()
183
+ .references(() => products.id, { onDelete: "cascade" }),
184
+ activationMode: productActivationModeEnum("activation_mode").notNull().default("manual"),
185
+ activateAt: timestamp("activate_at", { withTimezone: true }),
186
+ deactivateAt: timestamp("deactivate_at", { withTimezone: true }),
187
+ sellAt: timestamp("sell_at", { withTimezone: true }),
188
+ stopSellAt: timestamp("stop_sell_at", { withTimezone: true }),
189
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
190
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
191
+ }, (table) => [
192
+ uniqueIndex("uidx_product_activation_settings_product").on(table.productId),
193
+ index("idx_product_activation_settings_mode").on(table.activationMode),
194
+ ]);
195
+ export const productTicketSettings = pgTable("product_ticket_settings", {
196
+ id: typeId("product_ticket_settings"),
197
+ productId: typeIdRef("product_id")
198
+ .notNull()
199
+ .references(() => products.id, { onDelete: "cascade" }),
200
+ fulfillmentMode: productTicketFulfillmentEnum("fulfillment_mode").notNull().default("none"),
201
+ defaultDeliveryFormat: productDeliveryFormatEnum("default_delivery_format")
202
+ .notNull()
203
+ .default("none"),
204
+ ticketPerUnit: boolean("ticket_per_unit").notNull().default(false),
205
+ barcodeFormat: text("barcode_format"),
206
+ voucherMessage: text("voucher_message"),
207
+ ticketMessage: text("ticket_message"),
208
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
209
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
210
+ }, (table) => [uniqueIndex("uidx_product_ticket_settings_product").on(table.productId)]);
211
+ export const productVisibilitySettings = pgTable("product_visibility_settings", {
212
+ id: typeId("product_visibility_settings"),
213
+ productId: typeIdRef("product_id")
214
+ .notNull()
215
+ .references(() => products.id, { onDelete: "cascade" }),
216
+ isSearchable: boolean("is_searchable").notNull().default(false),
217
+ isBookable: boolean("is_bookable").notNull().default(false),
218
+ isFeatured: boolean("is_featured").notNull().default(false),
219
+ requiresAuthentication: boolean("requires_authentication").notNull().default(false),
220
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
221
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
222
+ }, (table) => [uniqueIndex("uidx_product_visibility_settings_product").on(table.productId)]);
223
+ export const productCapabilities = pgTable("product_capabilities", {
224
+ id: typeId("product_capabilities"),
225
+ productId: typeIdRef("product_id")
226
+ .notNull()
227
+ .references(() => products.id, { onDelete: "cascade" }),
228
+ capability: productCapabilityEnum("capability").notNull(),
229
+ enabled: boolean("enabled").notNull().default(true),
230
+ notes: text("notes"),
231
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
232
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
233
+ }, (table) => [
234
+ index("idx_product_capabilities_product").on(table.productId),
235
+ index("idx_product_capabilities_capability").on(table.capability),
236
+ uniqueIndex("uidx_product_capabilities_product_capability").on(table.productId, table.capability),
237
+ ]);
238
+ export const productDeliveryFormats = pgTable("product_delivery_formats", {
239
+ id: typeId("product_delivery_formats"),
240
+ productId: typeIdRef("product_id")
241
+ .notNull()
242
+ .references(() => products.id, { onDelete: "cascade" }),
243
+ format: productDeliveryFormatEnum("format").notNull(),
244
+ isDefault: boolean("is_default").notNull().default(false),
245
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
246
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
247
+ }, (table) => [
248
+ index("idx_product_delivery_formats_product").on(table.productId),
249
+ uniqueIndex("uidx_product_delivery_formats_product_format").on(table.productId, table.format),
250
+ ]);
251
+ // ---------- structured content ----------
252
+ export const productFeatures = pgTable("product_features", {
253
+ id: typeId("product_features"),
254
+ productId: typeIdRef("product_id")
255
+ .notNull()
256
+ .references(() => products.id, { onDelete: "cascade" }),
257
+ featureType: productFeatureTypeEnum("feature_type").notNull().default("highlight"),
258
+ title: text("title").notNull(),
259
+ description: text("description"),
260
+ sortOrder: integer("sort_order").notNull().default(0),
261
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
262
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
263
+ }, (table) => [
264
+ index("idx_product_features_product").on(table.productId),
265
+ index("idx_product_features_type").on(table.featureType),
266
+ ]);
267
+ export const productFaqs = pgTable("product_faqs", {
268
+ id: typeId("product_faqs"),
269
+ productId: typeIdRef("product_id")
270
+ .notNull()
271
+ .references(() => products.id, { onDelete: "cascade" }),
272
+ question: text("question").notNull(),
273
+ answer: text("answer").notNull(),
274
+ sortOrder: integer("sort_order").notNull().default(0),
275
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
276
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
277
+ }, (table) => [index("idx_product_faqs_product").on(table.productId)]);
278
+ export const productLocations = pgTable("product_locations", {
279
+ id: typeId("product_locations"),
280
+ productId: typeIdRef("product_id")
281
+ .notNull()
282
+ .references(() => products.id, { onDelete: "cascade" }),
283
+ locationType: productLocationTypeEnum("location_type").notNull().default("point_of_interest"),
284
+ title: text("title").notNull(),
285
+ address: text("address"),
286
+ city: text("city"),
287
+ countryCode: text("country_code"),
288
+ latitude: doublePrecision("latitude"),
289
+ longitude: doublePrecision("longitude"),
290
+ googlePlaceId: text("google_place_id"),
291
+ applePlaceId: text("apple_place_id"),
292
+ tripadvisorLocationId: text("tripadvisor_location_id"),
293
+ sortOrder: integer("sort_order").notNull().default(0),
294
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
295
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
296
+ }, (table) => [
297
+ index("idx_product_locations_product").on(table.productId),
298
+ index("idx_product_locations_type").on(table.locationType),
299
+ ]);
300
+ // ---------- translations ----------
301
+ export const productTranslations = pgTable("product_translations", {
302
+ id: typeId("product_translations"),
303
+ productId: typeIdRef("product_id")
304
+ .notNull()
305
+ .references(() => products.id, { onDelete: "cascade" }),
306
+ languageTag: text("language_tag").notNull(),
307
+ slug: text("slug"),
308
+ name: text("name").notNull(),
309
+ shortDescription: text("short_description"),
310
+ description: text("description"),
311
+ seoTitle: text("seo_title"),
312
+ seoDescription: text("seo_description"),
313
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
314
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
315
+ }, (table) => [
316
+ index("idx_product_translations_product").on(table.productId),
317
+ index("idx_product_translations_language").on(table.languageTag),
318
+ uniqueIndex("uidx_product_translations_product_language").on(table.productId, table.languageTag),
319
+ ]);
320
+ export const productOptionTranslations = pgTable("product_option_translations", {
321
+ id: typeId("product_option_translations"),
322
+ optionId: typeIdRef("option_id")
323
+ .notNull()
324
+ .references(() => productOptions.id, { onDelete: "cascade" }),
325
+ languageTag: text("language_tag").notNull(),
326
+ name: text("name").notNull(),
327
+ shortDescription: text("short_description"),
328
+ description: text("description"),
329
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
330
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
331
+ }, (table) => [
332
+ index("idx_product_option_translations_option").on(table.optionId),
333
+ index("idx_product_option_translations_language").on(table.languageTag),
334
+ uniqueIndex("uidx_product_option_translations_option_language").on(table.optionId, table.languageTag),
335
+ ]);
336
+ export const optionUnitTranslations = pgTable("option_unit_translations", {
337
+ id: typeId("option_unit_translations"),
338
+ unitId: typeIdRef("unit_id")
339
+ .notNull()
340
+ .references(() => optionUnits.id, { onDelete: "cascade" }),
341
+ languageTag: text("language_tag").notNull(),
342
+ name: text("name").notNull(),
343
+ shortDescription: text("short_description"),
344
+ description: text("description"),
345
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
346
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
347
+ }, (table) => [
348
+ index("idx_option_unit_translations_unit").on(table.unitId),
349
+ index("idx_option_unit_translations_language").on(table.languageTag),
350
+ uniqueIndex("uidx_option_unit_translations_unit_language").on(table.unitId, table.languageTag),
351
+ ]);
352
+ // ---------- product_days ----------
353
+ export const productDays = pgTable("product_days", {
354
+ id: typeId("product_days"),
355
+ productId: typeIdRef("product_id")
356
+ .notNull()
357
+ .references(() => products.id, { onDelete: "cascade" }),
358
+ dayNumber: integer("day_number").notNull(),
359
+ title: text("title"),
360
+ description: text("description"),
361
+ location: text("location"),
362
+ // Timestamps
363
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
364
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
365
+ }, (table) => [index("idx_product_days_product").on(table.productId)]);
366
+ // ---------- product_day_services ----------
367
+ export const productDayServices = pgTable("product_day_services", {
368
+ id: typeId("product_day_services"),
369
+ dayId: typeIdRef("day_id")
370
+ .notNull()
371
+ .references(() => productDays.id, { onDelete: "cascade" }),
372
+ // Supplier link (snapshot)
373
+ supplierServiceId: text("supplier_service_id"),
374
+ serviceType: serviceTypeEnum("service_type").notNull(),
375
+ name: text("name").notNull(),
376
+ description: text("description"),
377
+ // Cost (independent currency per service)
378
+ costCurrency: text("cost_currency").notNull(),
379
+ costAmountCents: integer("cost_amount_cents").notNull(),
380
+ quantity: integer("quantity").notNull().default(1),
381
+ sortOrder: integer("sort_order"),
382
+ notes: text("notes"),
383
+ // Timestamps
384
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
385
+ }, (table) => [
386
+ index("idx_product_day_services_day").on(table.dayId),
387
+ index("idx_product_day_services_supplier_service").on(table.supplierServiceId),
388
+ ]);
389
+ // ---------- product_versions ----------
390
+ export const productVersions = pgTable("product_versions", {
391
+ id: typeId("product_versions"),
392
+ productId: typeIdRef("product_id")
393
+ .notNull()
394
+ .references(() => products.id, { onDelete: "cascade" }),
395
+ versionNumber: integer("version_number").notNull(),
396
+ snapshot: jsonb("snapshot").notNull(),
397
+ authorId: text("author_id").notNull(),
398
+ notes: text("notes"),
399
+ // Timestamps
400
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
401
+ }, (table) => [index("idx_product_versions_product").on(table.productId)]);
402
+ // ---------- product_notes ----------
403
+ export const productNotes = pgTable("product_notes", {
404
+ id: typeId("product_notes"),
405
+ productId: typeIdRef("product_id")
406
+ .notNull()
407
+ .references(() => products.id, { onDelete: "cascade" }),
408
+ authorId: text("author_id").notNull(),
409
+ content: text("content").notNull(),
410
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
411
+ }, (table) => [index("idx_product_notes_product").on(table.productId)]);
412
+ // ---------- product_media ----------
413
+ export const productMediaTypeEnum = pgEnum("product_media_type", ["image", "video", "document"]);
414
+ export const productMedia = pgTable("product_media", {
415
+ id: typeId("product_media"),
416
+ productId: typeIdRef("product_id")
417
+ .notNull()
418
+ .references(() => products.id, { onDelete: "cascade" }),
419
+ dayId: typeIdRef("day_id").references(() => productDays.id, { onDelete: "cascade" }),
420
+ mediaType: productMediaTypeEnum("media_type").notNull(),
421
+ name: text("name").notNull(),
422
+ url: text("url").notNull(),
423
+ storageKey: text("storage_key"),
424
+ mimeType: text("mime_type"),
425
+ fileSize: integer("file_size"),
426
+ altText: text("alt_text"),
427
+ sortOrder: integer("sort_order").notNull().default(0),
428
+ isCover: boolean("is_cover").notNull().default(false),
429
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
430
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
431
+ }, (table) => [
432
+ index("idx_product_media_product").on(table.productId),
433
+ index("idx_product_media_day").on(table.dayId),
434
+ index("idx_product_media_product_day").on(table.productId, table.dayId),
435
+ ]);
436
+ // ---------- product_types ----------
437
+ export const productTypes = pgTable("product_types", {
438
+ id: typeId("product_types"),
439
+ name: text("name").notNull(),
440
+ code: text("code").notNull(),
441
+ description: text("description"),
442
+ sortOrder: integer("sort_order").notNull().default(0),
443
+ active: boolean("active").notNull().default(true),
444
+ metadata: jsonb("metadata").$type(),
445
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
446
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
447
+ }, (table) => [
448
+ uniqueIndex("uidx_product_types_code").on(table.code),
449
+ index("idx_product_types_active").on(table.active),
450
+ ]);
451
+ // ---------- product_categories ----------
452
+ export const productCategories = pgTable("product_categories", {
453
+ id: typeId("product_categories"),
454
+ parentId: text("parent_id"),
455
+ name: text("name").notNull(),
456
+ slug: text("slug").notNull(),
457
+ description: text("description"),
458
+ sortOrder: integer("sort_order").notNull().default(0),
459
+ active: boolean("active").notNull().default(true),
460
+ metadata: jsonb("metadata").$type(),
461
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
462
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
463
+ }, (table) => [
464
+ uniqueIndex("uidx_product_categories_slug").on(table.slug),
465
+ index("idx_product_categories_parent").on(table.parentId),
466
+ index("idx_product_categories_active").on(table.active),
467
+ ]);
468
+ // ---------- product_tags ----------
469
+ export const productTags = pgTable("product_tags", {
470
+ id: typeId("product_tags"),
471
+ name: text("name").notNull(),
472
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
473
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
474
+ }, (table) => [
475
+ uniqueIndex("uidx_product_tags_name").on(table.name),
476
+ ]);
477
+ // ---------- product_category_products (junction) ----------
478
+ export const productCategoryProducts = pgTable("product_category_products", {
479
+ productId: typeIdRef("product_id")
480
+ .notNull()
481
+ .references(() => products.id, { onDelete: "cascade" }),
482
+ categoryId: typeIdRef("category_id")
483
+ .notNull()
484
+ .references(() => productCategories.id, { onDelete: "cascade" }),
485
+ sortOrder: integer("sort_order").notNull().default(0),
486
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
487
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
488
+ }, (table) => [
489
+ primaryKey({ columns: [table.productId, table.categoryId] }),
490
+ index("idx_pcp_category").on(table.categoryId),
491
+ ]);
492
+ // ---------- product_tag_products (junction) ----------
493
+ export const productTagProducts = pgTable("product_tag_products", {
494
+ productId: typeIdRef("product_id")
495
+ .notNull()
496
+ .references(() => products.id, { onDelete: "cascade" }),
497
+ tagId: typeIdRef("tag_id")
498
+ .notNull()
499
+ .references(() => productTags.id, { onDelete: "cascade" }),
500
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
501
+ }, (table) => [
502
+ primaryKey({ columns: [table.productId, table.tagId] }),
503
+ index("idx_ptp_tag").on(table.tagId),
504
+ ]);
505
+ // ---------- relations ----------
506
+ export const productsRelations = relations(products, ({ one, many }) => ({
507
+ productType: one(productTypes, {
508
+ fields: [products.productTypeId],
509
+ references: [productTypes.id],
510
+ }),
511
+ activationSettings: many(productActivationSettings),
512
+ ticketSettings: many(productTicketSettings),
513
+ visibilitySettings: many(productVisibilitySettings),
514
+ capabilities: many(productCapabilities),
515
+ deliveryFormats: many(productDeliveryFormats),
516
+ features: many(productFeatures),
517
+ faqs: many(productFaqs),
518
+ locations: many(productLocations),
519
+ options: many(productOptions),
520
+ translations: many(productTranslations),
521
+ days: many(productDays),
522
+ versions: many(productVersions),
523
+ notes: many(productNotes),
524
+ media: many(productMedia),
525
+ categoryLinks: many(productCategoryProducts),
526
+ tagLinks: many(productTagProducts),
527
+ }));
528
+ export const productOptionsRelations = relations(productOptions, ({ one, many }) => ({
529
+ product: one(products, { fields: [productOptions.productId], references: [products.id] }),
530
+ translations: many(productOptionTranslations),
531
+ units: many(optionUnits),
532
+ }));
533
+ export const optionUnitsRelations = relations(optionUnits, ({ one, many }) => ({
534
+ option: one(productOptions, { fields: [optionUnits.optionId], references: [productOptions.id] }),
535
+ translations: many(optionUnitTranslations),
536
+ }));
537
+ export const productActivationSettingsRelations = relations(productActivationSettings, ({ one }) => ({
538
+ product: one(products, {
539
+ fields: [productActivationSettings.productId],
540
+ references: [products.id],
541
+ }),
542
+ }));
543
+ export const productTicketSettingsRelations = relations(productTicketSettings, ({ one }) => ({
544
+ product: one(products, {
545
+ fields: [productTicketSettings.productId],
546
+ references: [products.id],
547
+ }),
548
+ }));
549
+ export const productVisibilitySettingsRelations = relations(productVisibilitySettings, ({ one }) => ({
550
+ product: one(products, {
551
+ fields: [productVisibilitySettings.productId],
552
+ references: [products.id],
553
+ }),
554
+ }));
555
+ export const productCapabilitiesRelations = relations(productCapabilities, ({ one }) => ({
556
+ product: one(products, {
557
+ fields: [productCapabilities.productId],
558
+ references: [products.id],
559
+ }),
560
+ }));
561
+ export const productDeliveryFormatsRelations = relations(productDeliveryFormats, ({ one }) => ({
562
+ product: one(products, {
563
+ fields: [productDeliveryFormats.productId],
564
+ references: [products.id],
565
+ }),
566
+ }));
567
+ export const productFeaturesRelations = relations(productFeatures, ({ one }) => ({
568
+ product: one(products, {
569
+ fields: [productFeatures.productId],
570
+ references: [products.id],
571
+ }),
572
+ }));
573
+ export const productFaqsRelations = relations(productFaqs, ({ one }) => ({
574
+ product: one(products, {
575
+ fields: [productFaqs.productId],
576
+ references: [products.id],
577
+ }),
578
+ }));
579
+ export const productLocationsRelations = relations(productLocations, ({ one }) => ({
580
+ product: one(products, {
581
+ fields: [productLocations.productId],
582
+ references: [products.id],
583
+ }),
584
+ }));
585
+ export const productTranslationsRelations = relations(productTranslations, ({ one }) => ({
586
+ product: one(products, {
587
+ fields: [productTranslations.productId],
588
+ references: [products.id],
589
+ }),
590
+ }));
591
+ export const productOptionTranslationsRelations = relations(productOptionTranslations, ({ one }) => ({
592
+ option: one(productOptions, {
593
+ fields: [productOptionTranslations.optionId],
594
+ references: [productOptions.id],
595
+ }),
596
+ }));
597
+ export const optionUnitTranslationsRelations = relations(optionUnitTranslations, ({ one }) => ({
598
+ unit: one(optionUnits, {
599
+ fields: [optionUnitTranslations.unitId],
600
+ references: [optionUnits.id],
601
+ }),
602
+ }));
603
+ export const productDaysRelations = relations(productDays, ({ one, many }) => ({
604
+ product: one(products, { fields: [productDays.productId], references: [products.id] }),
605
+ services: many(productDayServices),
606
+ media: many(productMedia),
607
+ }));
608
+ export const productDayServicesRelations = relations(productDayServices, ({ one }) => ({
609
+ day: one(productDays, { fields: [productDayServices.dayId], references: [productDays.id] }),
610
+ }));
611
+ export const productVersionsRelations = relations(productVersions, ({ one }) => ({
612
+ product: one(products, { fields: [productVersions.productId], references: [products.id] }),
613
+ }));
614
+ export const productNotesRelations = relations(productNotes, ({ one }) => ({
615
+ product: one(products, { fields: [productNotes.productId], references: [products.id] }),
616
+ }));
617
+ export const productMediaRelations = relations(productMedia, ({ one }) => ({
618
+ product: one(products, { fields: [productMedia.productId], references: [products.id] }),
619
+ day: one(productDays, { fields: [productMedia.dayId], references: [productDays.id] }),
620
+ }));
621
+ export const productTypesRelations = relations(productTypes, ({ many }) => ({
622
+ products: many(products),
623
+ }));
624
+ export const productCategoriesRelations = relations(productCategories, ({ one, many }) => ({
625
+ parent: one(productCategories, {
626
+ fields: [productCategories.parentId],
627
+ references: [productCategories.id],
628
+ relationName: "parentChild",
629
+ }),
630
+ children: many(productCategories, { relationName: "parentChild" }),
631
+ productLinks: many(productCategoryProducts),
632
+ }));
633
+ export const productTagsRelations = relations(productTags, ({ many }) => ({
634
+ productLinks: many(productTagProducts),
635
+ }));
636
+ export const productCategoryProductsRelations = relations(productCategoryProducts, ({ one }) => ({
637
+ product: one(products, {
638
+ fields: [productCategoryProducts.productId],
639
+ references: [products.id],
640
+ }),
641
+ category: one(productCategories, {
642
+ fields: [productCategoryProducts.categoryId],
643
+ references: [productCategories.id],
644
+ }),
645
+ }));
646
+ export const productTagProductsRelations = relations(productTagProducts, ({ one }) => ({
647
+ product: one(products, {
648
+ fields: [productTagProducts.productId],
649
+ references: [products.id],
650
+ }),
651
+ tag: one(productTags, {
652
+ fields: [productTagProducts.tagId],
653
+ references: [productTags.id],
654
+ }),
655
+ }));