@axova/shared 1.0.1 → 1.0.2

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.
Files changed (31) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.js +0 -2
  3. package/dist/middleware/storeOwnership.js +3 -22
  4. package/dist/middleware/storeValidationMiddleware.js +39 -16
  5. package/dist/schemas/admin/admin-schema.d.ts +2 -2
  6. package/dist/schemas/ai-moderation/ai-moderation-schema.d.ts +2 -2
  7. package/dist/schemas/index.d.ts +0 -28
  8. package/dist/schemas/index.js +3 -125
  9. package/dist/utils/subdomain.d.ts +1 -1
  10. package/dist/utils/subdomain.js +15 -10
  11. package/package.json +1 -1
  12. package/src/index.ts +0 -3
  13. package/src/middleware/storeOwnership.ts +3 -21
  14. package/src/middleware/storeValidationMiddleware.ts +50 -17
  15. package/src/schemas/index.ts +5 -194
  16. package/src/utils/subdomain.ts +15 -11
  17. package/src/schemas/compliance/compliance-schema.ts +0 -927
  18. package/src/schemas/compliance/kyc-schema.ts +0 -649
  19. package/src/schemas/customer/customer-schema.ts +0 -576
  20. package/src/schemas/inventory/inventory-tables.ts +0 -1927
  21. package/src/schemas/inventory/lot-tables.ts +0 -799
  22. package/src/schemas/order/order-schema.ts +0 -1400
  23. package/src/schemas/product/discount-relations.ts +0 -44
  24. package/src/schemas/product/discount-schema.ts +0 -464
  25. package/src/schemas/product/product-relations.ts +0 -187
  26. package/src/schemas/product/product-schema.ts +0 -955
  27. package/src/schemas/store/ethiopian_business_api.md.resolved +0 -212
  28. package/src/schemas/store/store-audit-schema.ts +0 -1257
  29. package/src/schemas/store/store-schema.ts +0 -661
  30. package/src/schemas/store/store-settings-schema.ts +0 -231
  31. package/src/schemas/store/storefront-config-schema.ts +0 -604
@@ -1,661 +0,0 @@
1
- import { createId } from "@paralleldrive/cuid2";
2
- import { relations } from "drizzle-orm";
3
- import {
4
- boolean,
5
- index,
6
- integer,
7
- jsonb,
8
- pgTable,
9
- text,
10
- timestamp,
11
- unique,
12
- varchar,
13
- numeric,
14
- } from "drizzle-orm/pg-core";
15
-
16
- // Core Store Table - Enhanced with performance optimizations
17
- export const stores = pgTable(
18
- "stores",
19
- {
20
- id: text("id")
21
- .primaryKey()
22
- .$defaultFn(() => createId()),
23
- userId: text("user_id").notNull(),
24
- organizationId: text("organization_id"), // Organization ID from Fastify Better Auth
25
- storeName: varchar("store_name", { length: 255 }).notNull(),
26
- subdomain: varchar("subdomain", { length: 63 }).notNull(),
27
- storeUrl: varchar("store_url", { length: 255 }),
28
-
29
- // Core Settings
30
- timezone: varchar("timezone", { length: 50 }).notNull().default("UTC"),
31
- currency: varchar("currency", { length: 3 }).notNull().default("USD"),
32
- languages: jsonb("languages").$type<string[]>().notNull().default(["en"]),
33
-
34
- // Store Configuration
35
- storeType: varchar("store_type", { length: 50 })
36
- .notNull()
37
- .default("STANDARD")
38
- .$type<"STANDARD" | "PREMIUM" | "ENTERPRISE">(),
39
-
40
- plan: varchar("plan", { length: 50 })
41
- .notNull()
42
- .default("FREE")
43
- .$type<"FREE" | "BASIC" | "PRO" | "ENTERPRISE">(),
44
-
45
- // Ethiopian Business Registration
46
- tinNumber: varchar("tin_number", { length: 50 }),
47
- businessType: varchar("business_type", { length: 20 })
48
- .$type<"starter" | "business_owner">()
49
- .default("starter"),
50
- region: varchar("region", { length: 100 }),
51
- subcity: varchar("subcity", { length: 100 }),
52
- woreda: varchar("woreda", { length: 100 }),
53
- houseNumber: varchar("house_number", { length: 50 }),
54
- tradeNames: jsonb("trade_names").$type<string[]>().default([]),
55
-
56
- // Store Additional Details
57
- attributes: jsonb("attributes")
58
- .$type<Record<string, unknown>>()
59
- .default({}),
60
- settings: jsonb("settings")
61
- .$type<{
62
- enablePublicListing?: boolean;
63
- enableReviews?: boolean;
64
- enableInventoryTracking?: boolean;
65
- enableMultiCurrency?: boolean;
66
- maintenanceMode?: boolean;
67
- customCss?: string;
68
- logoUrl?: string;
69
- faviconUrl?: string;
70
- themeColor?: string;
71
- }>()
72
- .default({}),
73
-
74
- // Performance metrics
75
- monthlyVisitors: integer("monthly_visitors").default(0),
76
- totalOrders: integer("total_orders").default(0),
77
- totalRevenue: integer("total_revenue").default(0), // in cents
78
-
79
- // Status and lifecycle
80
- isActive: boolean("is_active").notNull().default(true),
81
- isPublished: boolean("is_published").notNull().default(false),
82
- launchedAt: timestamp("launched_at", { withTimezone: true }),
83
-
84
- // Audit fields
85
- createdAt: timestamp("created_at", { withTimezone: true })
86
- .defaultNow()
87
- .notNull(),
88
- updatedAt: timestamp("updated_at", { withTimezone: true })
89
- .defaultNow()
90
- .notNull(),
91
- deletedAt: timestamp("deleted_at", { withTimezone: true }),
92
- },
93
- (table) => ({
94
- // Primary indexes for performance
95
- subdomainUnique: unique("idx_stores_subdomain_unique").on(table.subdomain),
96
- storeNameIndex: index("idx_stores_name").on(table.storeName),
97
- userIdIndex: index("idx_stores_user_id").on(table.userId),
98
- organizationIdIndex: index("idx_stores_organization_id").on(
99
- table.organizationId,
100
- ),
101
-
102
- // Composite indexes for common queries
103
- userActiveStoresIndex: index("idx_stores_user_active").on(
104
- table.userId,
105
- table.isActive,
106
- ),
107
- activePublishedIndex: index("idx_stores_active_published").on(
108
- table.isActive,
109
- table.isPublished,
110
- ),
111
- planTypeIndex: index("idx_stores_plan_type").on(
112
- table.plan,
113
- table.storeType,
114
- ),
115
-
116
- // Performance tracking indexes
117
- visitorsIndex: index("idx_stores_monthly_visitors").on(
118
- table.monthlyVisitors,
119
- ),
120
- revenueIndex: index("idx_stores_total_revenue").on(table.totalRevenue),
121
-
122
- // Temporal indexes
123
- createdAtIndex: index("idx_stores_created_at").on(table.createdAt),
124
- launchedAtIndex: index("idx_stores_launched_at").on(table.launchedAt),
125
-
126
- // Ethiopian business indexes
127
- tinNumberIndex: index("idx_stores_tin_number").on(table.tinNumber),
128
- businessTypeIndex: index("idx_stores_business_type").on(table.businessType),
129
- locationIndex: index("idx_stores_location").on(
130
- table.region,
131
- table.subcity,
132
- table.woreda,
133
- ),
134
- }),
135
- );
136
-
137
- // Store Business Details Table - Enhanced
138
- export const storeBusinessDetails = pgTable(
139
- "store_business_details",
140
- {
141
- id: text("id")
142
- .primaryKey()
143
- .$defaultFn(() => createId()),
144
- storeId: text("store_id")
145
- .notNull()
146
- .references(() => stores.id, { onDelete: "cascade" }),
147
-
148
- // Business Type and Legal Structure
149
- businessType: varchar("business_type", { length: 20 })
150
- .notNull()
151
- .$type<"INDIVIDUAL" | "BUSINESS" | "NON_PROFIT" | "GOVERNMENT">()
152
- .default("INDIVIDUAL"),
153
-
154
- legalStructure: varchar("legal_structure", { length: 30 }).$type<
155
- | "SOLE_PROPRIETORSHIP"
156
- | "PARTNERSHIP"
157
- | "LLC"
158
- | "CORPORATION"
159
- | "S_CORP"
160
- | "NON_PROFIT"
161
- >(),
162
-
163
- // Ethiopian Registration Details
164
- legalBusinessNameAmh: varchar("legal_business_name_amh", { length: 255 }),
165
- registrationDate: timestamp("registration_date", { withTimezone: true }),
166
- paidUpCapital: numeric("paid_up_capital", { precision: 15, scale: 2 }),
167
- licenseDetails: jsonb("license_details").$type<any[]>().default([]),
168
- associateInfo: jsonb("associate_info").$type<any[]>().default([]),
169
- tradeNames: jsonb("trade_names").$type<string[]>().default([]),
170
-
171
- // Business Details
172
- businessName: varchar("business_name", { length: 255 }),
173
- dbaName: varchar("dba_name", { length: 255 }), // "Doing Business As"
174
- businessRegistrationNumber: varchar("business_registration_number", {
175
- length: 100,
176
- }),
177
- taxIdentificationNumber: varchar("tax_identification_number", {
178
- length: 100,
179
- }),
180
- vatNumber: varchar("vat_number", { length: 50 }),
181
-
182
- // Address Information
183
- businessAddress: jsonb("business_address").$type<{
184
- street: string;
185
- street2?: string;
186
- city: string;
187
- state: string;
188
- postalCode: string;
189
- country: string;
190
- }>(),
191
-
192
- mailingAddress: jsonb("mailing_address").$type<{
193
- street: string;
194
- street2?: string;
195
- city: string;
196
- state: string;
197
- postalCode: string;
198
- country: string;
199
- sameAsBusiness?: boolean;
200
- }>(),
201
-
202
- // Industry and Size
203
- industry: varchar("industry", { length: 100 }),
204
- subIndustry: varchar("sub_industry", { length: 100 }),
205
- employeeCount: varchar("employee_count", { length: 20 }).$type<
206
- "1" | "2-10" | "11-50" | "51-200" | "201-500" | "500+"
207
- >(),
208
-
209
- // Financial Information
210
- annualRevenue: varchar("annual_revenue", { length: 30 }).$type<
211
- | "<10K"
212
- | "10K-50K"
213
- | "50K-100K"
214
- | "100K-500K"
215
- | "500K-1M"
216
- | "1M-10M"
217
- | "10M+"
218
- >(),
219
-
220
- // Verification Status
221
- isVerified: boolean("is_verified").notNull().default(false),
222
- verificationStatus: varchar("verification_status", { length: 30 })
223
- .notNull()
224
- .default("PENDING")
225
- .$type<
226
- "PENDING" | "IN_PROGRESS" | "VERIFIED" | "REJECTED" | "REQUIRES_UPDATE"
227
- >(),
228
-
229
- verificationDocuments: jsonb("verification_documents").$type<{
230
- businessLicense?: string;
231
- taxCertificate?: string;
232
- bankStatement?: string;
233
- proofOfAddress?: string;
234
- other?: string[];
235
- }>(),
236
-
237
- verifiedAt: timestamp("verified_at", { withTimezone: true }),
238
- verifiedBy: text("verified_by"),
239
-
240
- createdAt: timestamp("created_at", { withTimezone: true })
241
- .defaultNow()
242
- .notNull(),
243
- updatedAt: timestamp("updated_at", { withTimezone: true })
244
- .defaultNow()
245
- .notNull(),
246
- },
247
- (table) => ({
248
- storeIdIndex: index("idx_business_details_store_id").on(table.storeId),
249
- businessTypeIndex: index("idx_business_details_type").on(
250
- table.businessType,
251
- ),
252
- verificationStatusIndex: index("idx_business_details_verification").on(
253
- table.verificationStatus,
254
- ),
255
- industryIndex: index("idx_business_details_industry").on(table.industry),
256
-
257
- // Composite indexes for verification workflows
258
- verificationWorkflowIndex: index("idx_business_verification_workflow").on(
259
- table.verificationStatus,
260
- table.businessType,
261
- ),
262
-
263
- // Ethiopian indexes
264
- tinIndex: index("idx_business_details_tin").on(table.taxIdentificationNumber),
265
- registrationDateIndex: index("idx_business_details_registration_date").on(table.registrationDate),
266
- }),
267
- );
268
-
269
- // Store Contacts Table - Enhanced
270
- export const storeContacts = pgTable(
271
- "store_contacts",
272
- {
273
- id: text("id")
274
- .primaryKey()
275
- .$defaultFn(() => createId()),
276
- storeId: text("store_id")
277
- .notNull()
278
- .references(() => stores.id, { onDelete: "cascade" }),
279
-
280
- // Primary Contact Information
281
- contactEmail: varchar("contact_email", { length: 255 }).notNull(),
282
- contactName: varchar("contact_name", { length: 255 }),
283
- contactTitle: varchar("contact_title", { length: 100 }),
284
-
285
- // Departmental Emails
286
- supportEmail: varchar("support_email", { length: 255 }),
287
- salesEmail: varchar("sales_email", { length: 255 }),
288
- technicalEmail: varchar("technical_email", { length: 255 }),
289
- billingEmail: varchar("billing_email", { length: 255 }),
290
- marketingEmail: varchar("marketing_email", { length: 255 }),
291
- legalEmail: varchar("legal_email", { length: 255 }),
292
-
293
- // Phone Numbers with international support
294
- primaryPhone: varchar("primary_phone", { length: 20 }),
295
- supportPhone: varchar("support_phone", { length: 20 }),
296
- whatsappNumber: varchar("whatsapp_number", { length: 20 }),
297
- faxNumber: varchar("fax_number", { length: 20 }),
298
-
299
- // Business Hours
300
- businessHours: jsonb("business_hours").$type<{
301
- timezone: string;
302
- monday?: { open: string; close: string; closed?: boolean };
303
- tuesday?: { open: string; close: string; closed?: boolean };
304
- wednesday?: { open: string; close: string; closed?: boolean };
305
- thursday?: { open: string; close: string; closed?: boolean };
306
- friday?: { open: string; close: string; closed?: boolean };
307
- saturday?: { open: string; close: string; closed?: boolean };
308
- sunday?: { open: string; close: string; closed?: boolean };
309
- holidays?: Array<{ date: string; name: string }>;
310
- }>(),
311
-
312
- // Emergency and After-hours Contact
313
- emergencyContact: jsonb("emergency_contact").$type<{
314
- name: string;
315
- position: string;
316
- phone: string;
317
- email: string;
318
- available24x7: boolean;
319
- escalationProcess?: string;
320
- }>(),
321
-
322
- // Communication Preferences
323
- preferredContactMethod: varchar("preferred_contact_method", { length: 20 })
324
- .$type<"EMAIL" | "PHONE" | "SMS" | "WHATSAPP">()
325
- .default("EMAIL"),
326
-
327
- // Social Media and Other Channels
328
- communicationChannels: jsonb("communication_channels").$type<{
329
- slack?: string;
330
- discord?: string;
331
- telegram?: string;
332
- skype?: string;
333
- zoom?: string;
334
- teams?: string;
335
- }>(),
336
-
337
- createdAt: timestamp("created_at", { withTimezone: true })
338
- .defaultNow()
339
- .notNull(),
340
- updatedAt: timestamp("updated_at", { withTimezone: true })
341
- .defaultNow()
342
- .notNull(),
343
- },
344
- (table) => ({
345
- storeIdIndex: index("idx_contacts_store_id").on(table.storeId),
346
- contactEmailIndex: index("idx_contacts_email").on(table.contactEmail),
347
- preferredMethodIndex: index("idx_contacts_preferred_method").on(
348
- table.preferredContactMethod,
349
- ),
350
- }),
351
- );
352
-
353
- // Store Social Profiles Table - Enhanced
354
- export const storeSocialProfiles = pgTable(
355
- "store_social_profiles",
356
- {
357
- id: text("id")
358
- .primaryKey()
359
- .$defaultFn(() => createId()),
360
- storeId: text("store_id")
361
- .notNull()
362
- .references(() => stores.id, { onDelete: "cascade" }),
363
-
364
- // Major Social Platforms
365
- facebookUrl: varchar("facebook_url", { length: 500 }),
366
- facebookEnabled: boolean("facebook_enabled").notNull().default(false),
367
- facebookPageId: varchar("facebook_page_id", { length: 100 }),
368
-
369
- instagramUrl: varchar("instagram_url", { length: 500 }),
370
- instagramEnabled: boolean("instagram_enabled").notNull().default(false),
371
- instagramHandle: varchar("instagram_handle", { length: 100 }),
372
-
373
- twitterUrl: varchar("twitter_url", { length: 500 }),
374
- twitterEnabled: boolean("twitter_enabled").notNull().default(false),
375
- twitterHandle: varchar("twitter_handle", { length: 100 }),
376
-
377
- linkedinUrl: varchar("linkedin_url", { length: 500 }),
378
- linkedinEnabled: boolean("linkedin_enabled").notNull().default(false),
379
- linkedinPageId: varchar("linkedin_page_id", { length: 100 }),
380
-
381
- youtubeUrl: varchar("youtube_url", { length: 500 }),
382
- youtubeEnabled: boolean("youtube_enabled").notNull().default(false),
383
- youtubeChannelId: varchar("youtube_channel_id", { length: 100 }),
384
-
385
- tiktokUrl: varchar("tiktok_url", { length: 500 }),
386
- tiktokEnabled: boolean("tiktok_enabled").notNull().default(false),
387
- tiktokHandle: varchar("tiktok_handle", { length: 100 }),
388
-
389
- pinterestUrl: varchar("pinterest_url", { length: 500 }),
390
- pinterestEnabled: boolean("pinterest_enabled").notNull().default(false),
391
- pinterestHandle: varchar("pinterest_handle", { length: 100 }),
392
-
393
- // Professional and Niche Platforms
394
- githubUrl: varchar("github_url", { length: 500 }),
395
- githubEnabled: boolean("github_enabled").notNull().default(false),
396
-
397
- snapchatUrl: varchar("snapchat_url", { length: 500 }),
398
- snapchatEnabled: boolean("snapchat_enabled").notNull().default(false),
399
-
400
- redditUrl: varchar("reddit_url", { length: 500 }),
401
- redditEnabled: boolean("reddit_enabled").notNull().default(false),
402
-
403
- // Messaging Platforms
404
- discordUrl: varchar("discord_url", { length: 500 }),
405
- discordEnabled: boolean("discord_enabled").notNull().default(false),
406
-
407
- telegramUrl: varchar("telegram_url", { length: 500 }),
408
- telegramEnabled: boolean("telegram_enabled").notNull().default(false),
409
-
410
- whatsappUrl: varchar("whatsapp_url", { length: 500 }),
411
- whatsappEnabled: boolean("whatsapp_enabled").notNull().default(false),
412
-
413
- // Custom and Regional Platforms
414
- customPlatforms: jsonb("custom_platforms")
415
- .$type<
416
- Array<{
417
- name: string;
418
- url: string;
419
- enabled: boolean;
420
- icon?: string;
421
- displayOrder?: number;
422
- }>
423
- >()
424
- .default([]),
425
-
426
- // Social Media Strategy
427
- socialMediaStrategy: jsonb("social_media_strategy").$type<{
428
- primaryPlatforms: string[];
429
- postingSchedule?: Record<string, string[]>; // platform -> days/times
430
- contentThemes?: string[];
431
- hashtagStrategy?: Record<string, string[]>; // platform -> hashtags
432
- engagementGoals?: Record<string, number>;
433
- }>(),
434
-
435
- // Analytics and Tracking
436
- socialAnalytics: jsonb("social_analytics")
437
- .$type<{
438
- trackingEnabled: boolean;
439
- utmSource?: string;
440
- utmMedium?: string;
441
- utmCampaign?: string;
442
- conversionTracking?: boolean;
443
- }>()
444
- .default({ trackingEnabled: false }),
445
-
446
- createdAt: timestamp("created_at", { withTimezone: true })
447
- .defaultNow()
448
- .notNull(),
449
- updatedAt: timestamp("updated_at", { withTimezone: true })
450
- .defaultNow()
451
- .notNull(),
452
- },
453
- (table) => ({
454
- storeIdIndex: index("idx_social_store_id").on(table.storeId),
455
- // Index for enabled platforms for quick filtering
456
- enabledPlatformsIndex: index("idx_social_enabled_facebook").on(
457
- table.storeId,
458
- table.facebookEnabled,
459
- ),
460
- enabledInstagramIndex: index("idx_social_enabled_instagram").on(
461
- table.storeId,
462
- table.instagramEnabled,
463
- ),
464
- enabledTwitterIndex: index("idx_social_enabled_twitter").on(
465
- table.storeId,
466
- table.twitterEnabled,
467
- ),
468
- }),
469
- );
470
-
471
- // Store Blogs Table - Enhanced
472
- export const storeBlogs = pgTable(
473
- "store_blogs",
474
- {
475
- id: text("id")
476
- .primaryKey()
477
- .$defaultFn(() => createId()),
478
- storeId: text("store_id")
479
- .notNull()
480
- .references(() => stores.id, { onDelete: "cascade" }),
481
-
482
- // Content
483
- title: varchar("title", { length: 255 }).notNull(),
484
- slug: varchar("slug", { length: 255 }).notNull(),
485
- excerpt: text("excerpt"),
486
- content: text("content").notNull(),
487
-
488
- // Media
489
- featuredImage: varchar("featured_image", { length: 500 }),
490
- gallery: jsonb("gallery").$type<string[]>().default([]),
491
- media: jsonb("media")
492
- .$type<
493
- Array<{
494
- type:
495
- | "video"
496
- | "audio"
497
- | "podcast"
498
- | "youtube"
499
- | "vimeo"
500
- | "spotify"
501
- | "soundcloud"
502
- | "other";
503
- url: string;
504
- title?: string;
505
- description?: string;
506
- thumbnail?: string;
507
- duration?: number; // Duration in seconds
508
- size?: number; // File size in bytes
509
- }>
510
- >()
511
- .default([]),
512
-
513
- // SEO and Metadata
514
- metaTitle: varchar("meta_title", { length: 255 }),
515
- metaDescription: text("meta_description"),
516
- metaKeywords: jsonb("meta_keywords").$type<string[]>().default([]),
517
- canonicalUrl: varchar("canonical_url", { length: 500 }),
518
-
519
- // Content Organization
520
- categoryId: text("category_id"),
521
- tags: jsonb("tags").$type<string[]>().notNull().default([]),
522
- topics: jsonb("topics").$type<string[]>().default([]),
523
-
524
- // Publishing
525
- status: varchar("status", { length: 20 })
526
- .notNull()
527
- .default("draft")
528
- .$type<"draft" | "pending" | "published" | "archived" | "deleted">(),
529
-
530
- publishedAt: timestamp("published_at", { withTimezone: true }),
531
- scheduledFor: timestamp("scheduled_for", { withTimezone: true }),
532
-
533
- // Authoring
534
- authors: jsonb("authors")
535
- .$type<
536
- Array<{
537
- id: string;
538
- name: string;
539
- role?: string;
540
- bio?: string;
541
- avatar?: string;
542
- }>
543
- >()
544
- .notNull()
545
- .default([]),
546
-
547
- // Engagement and Analytics
548
- viewCount: integer("view_count").default(0),
549
- likeCount: integer("like_count").default(0),
550
- shareCount: integer("share_count").default(0),
551
- commentCount: integer("comment_count").default(0),
552
-
553
- // Content Settings
554
- allowComments: boolean("allow_comments").notNull().default(true),
555
- allowSharing: boolean("allow_sharing").notNull().default(true),
556
- allowRating: boolean("allow_rating").notNull().default(false),
557
-
558
- // Features
559
- isFeatured: boolean("is_featured").notNull().default(false),
560
- isSticky: boolean("is_sticky").notNull().default(false),
561
- isPremium: boolean("is_premium").notNull().default(false),
562
-
563
- // Reading Experience
564
- estimatedReadTime: integer("estimated_read_time"), // in minutes
565
- difficulty: varchar("difficulty", { length: 20 }).$type<
566
- "beginner" | "intermediate" | "advanced"
567
- >(),
568
-
569
- // Language and Localization
570
- language: varchar("language", { length: 10 }).default("en"),
571
- translations: jsonb("translations")
572
- .$type<Record<string, string>>()
573
- .default({}),
574
-
575
- createdAt: timestamp("created_at", { withTimezone: true })
576
- .defaultNow()
577
- .notNull(),
578
- updatedAt: timestamp("updated_at", { withTimezone: true })
579
- .defaultNow()
580
- .notNull(),
581
- },
582
- (table) => ({
583
- storeIdIndex: index("idx_blog_store_id").on(table.storeId),
584
- slugUniqueIndex: unique("idx_blog_slug_unique").on(
585
- table.storeId,
586
- table.slug,
587
- ),
588
- statusIndex: index("idx_blog_status").on(table.status),
589
- publishedAtIndex: index("idx_blog_published_at").on(table.publishedAt),
590
-
591
- // Content discovery indexes
592
- featuredIndex: index("idx_blog_featured").on(
593
- table.isFeatured,
594
- table.status,
595
- ),
596
- categoryIndex: index("idx_blog_category").on(
597
- table.categoryId,
598
- table.status,
599
- ),
600
-
601
- // Performance indexes
602
- viewCountIndex: index("idx_blog_view_count").on(table.viewCount),
603
-
604
- // Publishing workflow indexes
605
- publishingWorkflowIndex: index("idx_blog_publishing_workflow").on(
606
- table.status,
607
- table.scheduledFor,
608
- ),
609
- }),
610
- );
611
-
612
- // Relations
613
- export const storesRelations = relations(stores, ({ one, many }) => ({
614
- businessDetails: one(storeBusinessDetails, {
615
- fields: [stores.id],
616
- references: [storeBusinessDetails.storeId],
617
- }),
618
- contacts: one(storeContacts, {
619
- fields: [stores.id],
620
- references: [storeContacts.storeId],
621
- }),
622
- socialProfiles: one(storeSocialProfiles, {
623
- fields: [stores.id],
624
- references: [storeSocialProfiles.storeId],
625
- }),
626
- blogs: many(storeBlogs),
627
- }));
628
-
629
- export const storeBusinessDetailsRelations = relations(
630
- storeBusinessDetails,
631
- ({ one }) => ({
632
- store: one(stores, {
633
- fields: [storeBusinessDetails.storeId],
634
- references: [stores.id],
635
- }),
636
- }),
637
- );
638
-
639
- export const storeContactsRelations = relations(storeContacts, ({ one }) => ({
640
- store: one(stores, {
641
- fields: [storeContacts.storeId],
642
- references: [stores.id],
643
- }),
644
- }));
645
-
646
- export const storeSocialProfilesRelations = relations(
647
- storeSocialProfiles,
648
- ({ one }) => ({
649
- store: one(stores, {
650
- fields: [storeSocialProfiles.storeId],
651
- references: [stores.id],
652
- }),
653
- }),
654
- );
655
-
656
- export const storeBlogsRelations = relations(storeBlogs, ({ one }) => ({
657
- store: one(stores, {
658
- fields: [storeBlogs.storeId],
659
- references: [stores.id],
660
- }),
661
- }));