@bash-app/bash-common 30.225.0 → 30.226.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.
Files changed (109) hide show
  1. package/dist/__tests__/agePolicy.test.d.ts +2 -0
  2. package/dist/__tests__/agePolicy.test.d.ts.map +1 -0
  3. package/dist/__tests__/agePolicy.test.js +203 -0
  4. package/dist/__tests__/agePolicy.test.js.map +1 -0
  5. package/dist/__tests__/getDisplayGender.test.d.ts +2 -0
  6. package/dist/__tests__/getDisplayGender.test.d.ts.map +1 -0
  7. package/dist/__tests__/getDisplayGender.test.js +34 -0
  8. package/dist/__tests__/getDisplayGender.test.js.map +1 -0
  9. package/dist/__tests__/statusEnums.test.d.ts +2 -0
  10. package/dist/__tests__/statusEnums.test.d.ts.map +1 -0
  11. package/dist/__tests__/statusEnums.test.js +24 -0
  12. package/dist/__tests__/statusEnums.test.js.map +1 -0
  13. package/dist/aiApproval.d.ts +64 -0
  14. package/dist/aiApproval.d.ts.map +1 -0
  15. package/dist/aiApproval.js +54 -0
  16. package/dist/aiApproval.js.map +1 -0
  17. package/dist/definitions.d.ts +44 -2
  18. package/dist/definitions.d.ts.map +1 -1
  19. package/dist/definitions.js +106 -2
  20. package/dist/definitions.js.map +1 -1
  21. package/dist/extendedSchemas.d.ts +237 -104
  22. package/dist/extendedSchemas.d.ts.map +1 -1
  23. package/dist/extendedSchemas.js +12 -2
  24. package/dist/extendedSchemas.js.map +1 -1
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +1 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/legalTemplates.d.ts +1 -1
  30. package/dist/legalTemplates.js +1 -1
  31. package/dist/utils/__tests__/badgeUtils.test.d.ts +2 -0
  32. package/dist/utils/__tests__/badgeUtils.test.d.ts.map +1 -0
  33. package/dist/utils/__tests__/badgeUtils.test.js +157 -0
  34. package/dist/utils/__tests__/badgeUtils.test.js.map +1 -0
  35. package/dist/utils/__tests__/bashPointsPaymentUtils.test.d.ts +2 -0
  36. package/dist/utils/__tests__/bashPointsPaymentUtils.test.d.ts.map +1 -0
  37. package/dist/utils/__tests__/bashPointsPaymentUtils.test.js +114 -0
  38. package/dist/utils/__tests__/bashPointsPaymentUtils.test.js.map +1 -0
  39. package/dist/utils/__tests__/contentFilterUtils.test.d.ts +2 -0
  40. package/dist/utils/__tests__/contentFilterUtils.test.d.ts.map +1 -0
  41. package/dist/utils/__tests__/contentFilterUtils.test.js +443 -0
  42. package/dist/utils/__tests__/contentFilterUtils.test.js.map +1 -0
  43. package/dist/utils/__tests__/displayDateUtils.test.d.ts +2 -0
  44. package/dist/utils/__tests__/displayDateUtils.test.d.ts.map +1 -0
  45. package/dist/utils/__tests__/displayDateUtils.test.js +105 -0
  46. package/dist/utils/__tests__/displayDateUtils.test.js.map +1 -0
  47. package/dist/utils/__tests__/getBackendHost.test.d.ts +2 -0
  48. package/dist/utils/__tests__/getBackendHost.test.d.ts.map +1 -0
  49. package/dist/utils/__tests__/getBackendHost.test.js +104 -0
  50. package/dist/utils/__tests__/getBackendHost.test.js.map +1 -0
  51. package/dist/utils/__tests__/getFrontendHost.test.d.ts +2 -0
  52. package/dist/utils/__tests__/getFrontendHost.test.d.ts.map +1 -0
  53. package/dist/utils/__tests__/getFrontendHost.test.js +207 -0
  54. package/dist/utils/__tests__/getFrontendHost.test.js.map +1 -0
  55. package/dist/utils/__tests__/promoCodesUtils.test.d.ts +2 -0
  56. package/dist/utils/__tests__/promoCodesUtils.test.d.ts.map +1 -0
  57. package/dist/utils/__tests__/promoCodesUtils.test.js +183 -0
  58. package/dist/utils/__tests__/promoCodesUtils.test.js.map +1 -0
  59. package/dist/utils/__tests__/qrCodeUtils.test.d.ts +2 -0
  60. package/dist/utils/__tests__/qrCodeUtils.test.d.ts.map +1 -0
  61. package/dist/utils/__tests__/qrCodeUtils.test.js +99 -0
  62. package/dist/utils/__tests__/qrCodeUtils.test.js.map +1 -0
  63. package/dist/utils/__tests__/stripeAccountUtils.test.d.ts +2 -0
  64. package/dist/utils/__tests__/stripeAccountUtils.test.d.ts.map +1 -0
  65. package/dist/utils/__tests__/stripeAccountUtils.test.js +75 -0
  66. package/dist/utils/__tests__/stripeAccountUtils.test.js.map +1 -0
  67. package/dist/utils/blog/__tests__/getRelatedBlogPosts.test.d.ts +2 -0
  68. package/dist/utils/blog/__tests__/getRelatedBlogPosts.test.d.ts.map +1 -0
  69. package/dist/utils/blog/__tests__/getRelatedBlogPosts.test.js +233 -0
  70. package/dist/utils/blog/__tests__/getRelatedBlogPosts.test.js.map +1 -0
  71. package/dist/utils/blog/blogCommentDbUtils.d.ts +161 -0
  72. package/dist/utils/blog/blogCommentDbUtils.d.ts.map +1 -0
  73. package/dist/utils/blog/blogCommentDbUtils.js +111 -0
  74. package/dist/utils/blog/blogCommentDbUtils.js.map +1 -0
  75. package/dist/utils/blog/blogDbUtils.d.ts +10 -0
  76. package/dist/utils/blog/blogDbUtils.d.ts.map +1 -1
  77. package/dist/utils/blog/blogDbUtils.js +71 -0
  78. package/dist/utils/blog/blogDbUtils.js.map +1 -1
  79. package/dist/utils/urlUtils.d.ts +10 -0
  80. package/dist/utils/urlUtils.d.ts.map +1 -1
  81. package/dist/utils/urlUtils.js +24 -5
  82. package/dist/utils/urlUtils.js.map +1 -1
  83. package/dist/utils/userUtils.d.ts +32 -0
  84. package/dist/utils/userUtils.d.ts.map +1 -1
  85. package/dist/utils/userUtils.js +27 -0
  86. package/dist/utils/userUtils.js.map +1 -1
  87. package/package.json +1 -1
  88. package/prisma/schema.prisma +927 -845
  89. package/src/__tests__/agePolicy.test.ts +257 -0
  90. package/src/__tests__/getDisplayGender.test.ts +50 -0
  91. package/src/__tests__/statusEnums.test.ts +36 -0
  92. package/src/definitions.ts +138 -1
  93. package/src/extendedSchemas.ts +41 -2
  94. package/src/index.ts +1 -0
  95. package/src/legalTemplates.ts +1 -1
  96. package/src/utils/__tests__/badgeUtils.test.ts +191 -0
  97. package/src/utils/__tests__/bashPointsPaymentUtils.test.ts +153 -0
  98. package/src/utils/__tests__/contentFilterUtils.test.ts +547 -0
  99. package/src/utils/__tests__/displayDateUtils.test.ts +113 -0
  100. package/src/utils/__tests__/getBackendHost.test.ts +128 -0
  101. package/src/utils/__tests__/getFrontendHost.test.ts +232 -0
  102. package/src/utils/__tests__/promoCodesUtils.test.ts +237 -0
  103. package/src/utils/__tests__/qrCodeUtils.test.ts +143 -0
  104. package/src/utils/__tests__/stripeAccountUtils.test.ts +93 -0
  105. package/src/utils/blog/__tests__/getRelatedBlogPosts.test.ts +271 -0
  106. package/src/utils/blog/blogCommentDbUtils.ts +161 -0
  107. package/src/utils/blog/blogDbUtils.ts +95 -1
  108. package/src/utils/urlUtils.ts +27 -5
  109. package/src/utils/userUtils.ts +40 -0
@@ -55,38 +55,38 @@ model BashComment {
55
55
 
56
56
  // BashFeed Models - Event-Centric Social Discovery Feed
57
57
  model BashFeedPost {
58
- id String @id @default(cuid())
59
- userId String
60
- bashId String?
61
- serviceId String?
62
- bashAssociationType BashAssociationType? // How user is associated with the bash (for post display)
63
- content String? @db.Text
64
- mediaIds String[] // Array of Media IDs
65
- mentionedUserIds String[] // Array of User IDs mentioned in post
66
- isAnonymous Boolean @default(false) // User can choose to post anonymously
67
- viewCount Int @default(0) // Analytics only, not shown publicly
68
- isFeatured Boolean @default(false) // Post is promoted/featured
69
- featuredAt DateTime? // When post was featured
70
- featuredBoost Float @default(0) // Current boost score (time-decayed)
71
- featuredUntil DateTime? // When the feature boost expires
72
- createdAt DateTime @default(now())
73
- updatedAt DateTime @updatedAt
74
- editedAt DateTime?
58
+ id String @id @default(cuid())
59
+ userId String
60
+ bashId String?
61
+ serviceId String?
62
+ bashAssociationType BashAssociationType? // How user is associated with the bash (for post display)
63
+ content String? @db.Text
64
+ mediaIds String[] // Array of Media IDs
65
+ mentionedUserIds String[] // Array of User IDs mentioned in post
66
+ isAnonymous Boolean @default(false) // User can choose to post anonymously
67
+ viewCount Int @default(0) // Analytics only, not shown publicly
68
+ isFeatured Boolean @default(false) // Post is promoted/featured
69
+ featuredAt DateTime? // When post was featured
70
+ featuredBoost Float @default(0) // Current boost score (time-decayed)
71
+ featuredUntil DateTime? // When the feature boost expires
72
+ createdAt DateTime @default(now())
73
+ updatedAt DateTime @updatedAt
74
+ editedAt DateTime?
75
75
  /// When set, this row is a feed "repost shell": `user` is the reposter; content lives on `repostOf`.
76
- repostOfPostId String?
77
- repostOf BashFeedPost? @relation("BashFeedPostRepost", fields: [repostOfPostId], references: [id], onDelete: Cascade)
78
- repostShells BashFeedPost[] @relation("BashFeedPostRepost")
76
+ repostOfPostId String?
77
+ repostOf BashFeedPost? @relation("BashFeedPostRepost", fields: [repostOfPostId], references: [id], onDelete: Cascade)
78
+ repostShells BashFeedPost[] @relation("BashFeedPostRepost")
79
79
 
80
80
  // Relationships
81
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
82
- bash BashEvent? @relation(fields: [bashId], references: [id], onDelete: Cascade)
83
- service Service? @relation(fields: [serviceId], references: [id], onDelete: Cascade)
84
- likes BashFeedLike[]
85
- comments BashFeedComment[]
86
- ratings BashFeedRating[]
87
- reports BashFeedReport[]
88
- saves BashFeedSave[]
89
- reposts BashFeedRepost[]
81
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
82
+ bash BashEvent? @relation(fields: [bashId], references: [id], onDelete: Cascade)
83
+ service Service? @relation(fields: [serviceId], references: [id], onDelete: Cascade)
84
+ likes BashFeedLike[]
85
+ comments BashFeedComment[]
86
+ ratings BashFeedRating[]
87
+ reports BashFeedReport[]
88
+ saves BashFeedSave[]
89
+ reposts BashFeedRepost[]
90
90
  helpfulVotes ReviewHelpfulVote[]
91
91
 
92
92
  @@unique([userId, repostOfPostId])
@@ -236,18 +236,18 @@ model Competition {
236
236
  bracketData Json? // Store bracket structure/metadata
237
237
  bracketVisible Boolean @default(true)
238
238
 
239
- createdAt DateTime @default(now())
240
- updatedAt DateTime @updatedAt
241
- bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
242
- owner User @relation(fields: [userId], references: [id], onDelete: Cascade)
243
- sponsor CompetitionSponsor[]
244
- prizes Prize[]
245
- participants CompetitionParticipant[]
246
- votes CompetitionVote[]
247
- matches CompetitionMatch[]
248
- judgeAssignments CompetitionJudgeAssignment[]
249
- judgeScores CompetitionJudgeScore[]
250
- notifications Notification[]
239
+ createdAt DateTime @default(now())
240
+ updatedAt DateTime @updatedAt
241
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
242
+ owner User @relation(fields: [userId], references: [id], onDelete: Cascade)
243
+ sponsor CompetitionSponsor[]
244
+ prizes Prize[]
245
+ participants CompetitionParticipant[]
246
+ votes CompetitionVote[]
247
+ matches CompetitionMatch[]
248
+ judgeAssignments CompetitionJudgeAssignment[]
249
+ judgeScores CompetitionJudgeScore[]
250
+ notifications Notification[]
251
251
 
252
252
  @@index([bashEventId])
253
253
  @@index([competitionType])
@@ -318,9 +318,9 @@ model CompetitionParticipant {
318
318
  votes CompetitionVote[]
319
319
 
320
320
  // Tournament bracket relations
321
- matchesAsParticipant1 CompetitionMatch[] @relation("MatchParticipant1")
322
- matchesAsParticipant2 CompetitionMatch[] @relation("MatchParticipant2")
323
- matchesWon CompetitionMatch[] @relation("MatchWinner")
321
+ matchesAsParticipant1 CompetitionMatch[] @relation("MatchParticipant1")
322
+ matchesAsParticipant2 CompetitionMatch[] @relation("MatchParticipant2")
323
+ matchesWon CompetitionMatch[] @relation("MatchWinner")
324
324
  judgeScores CompetitionJudgeScore[]
325
325
 
326
326
  @@index([competitionId])
@@ -376,7 +376,7 @@ model CompetitionVote {
376
376
  }
377
377
 
378
378
  model EventTask {
379
- id String @id @default(cuid())
379
+ id String @id @default(cuid())
380
380
  creatorId String
381
381
  bashEventId String
382
382
  title String
@@ -385,15 +385,15 @@ model EventTask {
385
385
  status TaskStatus?
386
386
  neededCount Int? // Number of volunteers needed
387
387
  estimatedDuration Int? // Estimated duration in minutes
388
- createdAt DateTime? @default(now())
388
+ createdAt DateTime? @default(now())
389
389
  organizationId String? // Organization association
390
- assignedTo User? @relation("TasksAssignedToMe", fields: [assignedToId], references: [id], onDelete: Cascade)
391
- bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
392
- creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
390
+ assignedTo User? @relation("TasksAssignedToMe", fields: [assignedToId], references: [id], onDelete: Cascade)
391
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
392
+ creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
393
393
  notificationsReferencingMe Notification[]
394
394
  comments TaskComment[]
395
395
  invitations TaskInvitation[]
396
- potluckItem PotluckItem? @relation("PotluckItemTask")
396
+ potluckItem PotluckItem? @relation("PotluckItemTask")
397
397
  bashEventSuggestion BashEventSuggestion? @relation("SuggestionTask")
398
398
  }
399
399
 
@@ -462,20 +462,20 @@ model SentReminder {
462
462
  }
463
463
 
464
464
  model BashEventPromoCode {
465
- id String @id @default(cuid())
466
- code String
467
- ticketTierId String
468
- stripeCouponId String?
469
- discountAmountInCents Int?
470
- discountAmountPercentage Int?
471
- maxRedemptions Int?
472
- redeemBy DateTime?
473
- promoterId String?
474
- meta String?
475
- bashPointsRewardPerTicket Int? // Host-defined BashPoints per ticket for promoter rewards
476
- promoter Promoter? @relation(fields: [promoterId], references: [id])
477
- ticketTier TicketTier @relation(fields: [ticketTierId], references: [id])
478
- usedBy User[] @relation("BashEventPromoCodeToUser")
465
+ id String @id @default(cuid())
466
+ code String
467
+ ticketTierId String
468
+ stripeCouponId String?
469
+ discountAmountInCents Int?
470
+ discountAmountPercentage Int?
471
+ maxRedemptions Int?
472
+ redeemBy DateTime?
473
+ promoterId String?
474
+ meta String?
475
+ bashPointsRewardPerTicket Int? // Host-defined BashPoints per ticket for promoter rewards
476
+ promoter Promoter? @relation(fields: [promoterId], references: [id])
477
+ ticketTier TicketTier @relation(fields: [ticketTierId], references: [id])
478
+ usedBy User[] @relation("BashEventPromoCodeToUser")
479
479
 
480
480
  @@unique([ticketTierId, code])
481
481
  }
@@ -588,6 +588,7 @@ model Invitation {
588
588
  rejectedDate DateTime?
589
589
  maybeDate DateTime?
590
590
  isFreeGuest Boolean @default(false)
591
+ sentCount Int @default(1) // Number of times this invitation email has been sent (1 on initial send; incremented on each host-confirmed re-invite for the same email + bash)
591
592
  associatedBash AssociatedBash?
592
593
  bashEvent BashEvent? @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
593
594
  creator User @relation("InvitationsCreatedByMe", fields: [creatorId], references: [id], onDelete: Cascade)
@@ -600,124 +601,135 @@ model Invitation {
600
601
  }
601
602
 
602
603
  model BashEvent {
603
- id String @id @default(cuid())
604
- source BashEventSource @default(Bash)
605
- sourcePartnerId String? // When source=Partner, e.g. 'jamwith', 'mixlog'
606
- title String
607
- slug String? @unique
608
- creatorId String
609
- createdAt DateTime? @default(now())
610
- isApproved Boolean? @default(false)
611
- description String?
612
- eventType String @default("Other")
613
- timezone String?
614
- startDateTime DateTime?
615
- endDateTime DateTime?
616
- waiverUrl String?
617
- waiverRequired Boolean @default(false)
618
- waiverDisplayType String? @default("inline")
604
+ id String @id @default(cuid())
605
+ source BashEventSource @default(Bash)
606
+ sourcePartnerId String? // When source=Partner, e.g. 'jamwith', 'mixlog'
607
+ title String
608
+ slug String? @unique
609
+ creatorId String
610
+ createdAt DateTime? @default(now())
611
+ isApproved Boolean? @default(false)
612
+ description String?
613
+ eventType String @default("Other")
614
+ timezone String?
615
+ startDateTime DateTime?
616
+ endDateTime DateTime?
617
+ waiverUrl String?
618
+ waiverRequired Boolean @default(false)
619
+ waiverDisplayType String? @default("inline")
619
620
  /// Host opt-in: show photo/video consent at checkout; null photoReleaseText = platform default template
620
- photoReleaseEnabled Boolean @default(false)
621
- photoReleaseRequired Boolean @default(true)
622
- photoReleaseText String? @db.Text
623
- targetAudienceId String? @unique
624
- amountOfGuestsId String? @unique
625
- vibe String?
626
- occasion String?
627
- dress String?
628
- allowed String?
629
- notAllowed String?
630
- eventFormat EventFormat? // Derived from location and videoLink: In-Person, Virtual, or Hybrid
631
- nonProfit Boolean?
632
- nonProfitId String?
633
- privacy Privacy @default(Public)
634
- capacity Int?
635
- location String?
636
- street String?
637
- city String?
638
- state String?
639
- zipCode String?
640
- country String?
641
- status BashStatus @default(Draft)
642
- tags String[]
643
- coverPhoto String?
644
- clubId String?
645
- dateTimePublished DateTime?
646
- includedItems String[]
647
- videoLink String?
648
- subtitle String?
649
- isFeatured Boolean?
650
- featuredUntil DateTime? // When paid feature expires (null = no expiry / super-user pinned)
651
- isTrending Boolean?
652
- venueId String?
653
- averageRating Float? @default(0)
654
- totalRatings Int? @default(0) // Total count of all ratings (Review + BashFeedRating)
655
- totalReviews Int? @default(0) // Count of Review records (anonymous quick ratings)
656
- totalFeedRatings Int? @default(0) // Count of BashFeedRating records (from posts)
657
- allowDonations Boolean? @default(true)
658
- suggestedDonationAmount Int?
659
- donationDetails String?
660
- absorbDonationFees Boolean @default(false)
661
- absorbTicketFees Boolean @default(false)
621
+ photoReleaseEnabled Boolean @default(false)
622
+ photoReleaseRequired Boolean @default(true)
623
+ photoReleaseText String? @db.Text
624
+ /// Host-required IDs for ticket checkout
625
+ requireGovernmentId Boolean @default(false)
626
+ requireStudentId Boolean @default(false)
627
+ /// Minimum-age policy surfaced on the BashCard and used as a discover filter.
628
+ /// When set to EighteenPlus / TwentyOnePlus the wizard auto-toggles requireGovernmentId
629
+ /// so we can verify age via the user's stored ID at checkout.
630
+ agePolicy AgePolicy @default(AllAges)
631
+ targetAudienceId String? @unique
632
+ amountOfGuestsId String? @unique
633
+ vibe String?
634
+ occasion String?
635
+ dress String?
636
+ allowed String?
637
+ notAllowed String?
638
+ eventFormat EventFormat? // Derived from location and videoLink: In-Person, Virtual, or Hybrid
639
+ nonProfit Boolean?
640
+ nonProfitId String?
641
+ privacy Privacy @default(Public)
642
+ capacity Int?
643
+ location String?
644
+ street String?
645
+ city String?
646
+ state String?
647
+ zipCode String?
648
+ country String?
649
+ status BashStatus @default(Draft)
650
+ tags String[]
651
+ coverPhoto String?
652
+ clubId String?
653
+ dateTimePublished DateTime?
654
+ includedItems String[]
655
+ videoLink String?
656
+ subtitle String?
657
+ isFeatured Boolean?
658
+ featuredUntil DateTime? // When paid feature expires (null = no expiry / super-user pinned)
659
+ isTrending Boolean?
660
+ venueId String?
661
+ averageRating Float? @default(0)
662
+ totalRatings Int? @default(0) // Total count of all ratings (Review + BashFeedRating)
663
+ totalReviews Int? @default(0) // Count of Review records (anonymous quick ratings)
664
+ totalFeedRatings Int? @default(0) // Count of BashFeedRating records (from posts)
665
+ allowDonations Boolean? @default(false)
666
+ suggestedDonationAmount Int?
667
+ donationDetails String?
668
+ absorbDonationFees Boolean @default(false)
669
+ absorbTicketFees Boolean @default(false)
662
670
  /// When true, attendees may request a refund from the app/email (host approves in Tickets → Refunds). When false, self-serve refund CTAs are hidden.
663
- allowAttendeeRefundRequests Boolean @default(true)
671
+ allowAttendeeRefundRequests Boolean @default(true)
664
672
  // GuestPays / Split: Stripe processing + Bash platform fee presentation (see platformFeeEnabled).
665
- feeHandling String @default("HostAbsorbs") // "GuestPays" | "HostAbsorbs" | "Split"
673
+ feeHandling String @default("HostAbsorbs") // "GuestPays" | "HostAbsorbs" | "Split"
666
674
  /// When true, Bash charges platformFeeRate on ticket gross (e.g. 3%) in addition to Stripe processing pass-through.
667
- platformFeeEnabled Boolean @default(false)
675
+ platformFeeEnabled Boolean @default(false)
668
676
  /// Bash platform take rate on ticket gross (e.g. 0.03 = 3%). Ignored when platformFeeEnabled is false.
669
- platformFeeRate Float @default(0.03)
677
+ platformFeeRate Float @default(0.03)
670
678
  /// Optional: attendees can tag which act they came to see; drives attribution reports and future payouts.
671
- artistAttributionEnabled Boolean @default(false)
679
+ artistAttributionEnabled Boolean @default(false)
672
680
  /// "percentage" | "flat" — how artistPayoutRate is interpreted for suggested splits (display/export).
673
- artistPayoutMode String?
681
+ artistPayoutMode String?
674
682
  /// Percentage of door (0–100) or flat cents per ticket depending on artistPayoutMode.
675
- artistPayoutRate Float?
676
- topPromoterPrize String? // Optional prize label: "Free table for your crew"
677
- promoterLeaderboardIsPublic Boolean @default(false) // Host opts in to public leaderboard
678
- showAttendees Boolean @default(true)
679
- /// Host opt-in: show soft "public interest" controls on the event page (signed-in viewers). Not a guest list; invite RSVP stays separate.
680
- allowPublicInterestRsvp Boolean @default(false)
681
- attendeeDisplayMode String @default("All") // "All" | "NetworkOnly" | "Hidden"
682
- servicePreferences Json? // New tiered status: { "Entertainment": "need", "Sponsors": "booked_closed", ... }
683
- bookedServices Json? // Booked service details: { "Entertainment": { serviceId: "...", providerId: "...", bookedAt: "..." }, ... }
684
- serviceVisibility Json? // DEPRECATED: Use servicePreferences instead. Kept for backward compatibility during migration.
685
- originalCreatorId String?
686
- transferredAt DateTime?
687
- transferredFromId String?
688
- transferCount Int @default(0)
689
- payoutUserId String? // When set, payouts go to this user's Stripe instead of owner's (for transfer-with-retained-payouts)
690
- startTimeLocked Boolean @default(false)
691
- p2pPaymentMethod String?
692
- venmoUsername String?
693
- venmoQRCodeUrl String?
694
- zelleEmail String?
695
- zellePhone String?
696
- zelleQRCodeUrl String?
697
- externalTicketUrl String? // URL to external ticket purchase page (for imported events)
698
- externalPriceMin Int? // Minimum ticket price in cents (for imported events)
683
+ artistPayoutRate Float?
684
+ topPromoterPrize String? // Optional prize label: "Free table for your crew"
685
+ promoterLeaderboardIsPublic Boolean @default(false) // Host opts in to public leaderboard
686
+ showAttendees Boolean @default(true)
687
+ /// Host opt-in: show soft "public interest" controls on the bash detail page (signed-in viewers). Not a guest list; invite RSVP stays separate.
688
+ allowPublicInterestRsvp Boolean @default(false)
689
+ /// When true, guests can join a waitlist (activated automatically when amountOfGuests.allowWaitlistAtMax is set and max capacity is reached)
690
+ waitlistEnabled Boolean @default(false)
691
+ attendeeDisplayMode String @default("All") // "All" | "NetworkOnly" | "Hidden"
692
+ showOrganizerTitles Boolean @default(false)
693
+ servicePreferences Json? // New tiered status: { "Entertainment": "need", "Sponsors": "booked_closed", ... }
694
+ bookedServices Json? // Booked service details: { "Entertainment": { serviceId: "...", providerId: "...", bookedAt: "..." }, ... }
695
+ serviceVisibility Json? // DEPRECATED: Use servicePreferences instead. Kept for backward compatibility during migration.
696
+ plannedServiceIds String[] @default([]) // Service IDs the host has flagged as "plan to book" in the wizard
697
+ originalCreatorId String?
698
+ transferredAt DateTime?
699
+ transferredFromId String?
700
+ transferCount Int @default(0)
701
+ payoutUserId String? // When set, payouts go to this user's Stripe instead of owner's (for transfer-with-retained-payouts)
702
+ startTimeLocked Boolean @default(false)
703
+ p2pPaymentMethod String?
704
+ venmoUsername String?
705
+ venmoQRCodeUrl String?
706
+ zelleEmail String?
707
+ zellePhone String?
708
+ zelleQRCodeUrl String?
709
+ externalTicketUrl String? // URL to external ticket purchase page (for imported events)
710
+ externalPriceMin Int? // Minimum ticket price in cents (for imported events)
699
711
  /// Structured potluck / BYOB (MVP: flags + free-text notes on detail + wizard)
700
- potluckEnabled Boolean @default(false)
701
- byobEnabled Boolean @default(false)
702
- potluckNotes String? @db.Text
712
+ potluckEnabled Boolean @default(false)
713
+ byobEnabled Boolean @default(false)
714
+ potluckNotes String? @db.Text
703
715
  /// When false, included/allowed/not-allowed chips are read-only (no upvotes or suggestions)
704
- collaborationEnabled Boolean @default(true)
705
- /// Host opt-in: show icebreaker prompts on the event page for guests
706
- icebreakerEnabled Boolean @default(false)
716
+ collaborationEnabled Boolean @default(true)
717
+ /// Host opt-in: show icebreaker prompts on the bash detail page for guests
718
+ icebreakerEnabled Boolean @default(false)
707
719
  /// Host-curated merch catalog for this event (informational; not a checkout line item for MVP)
708
- merchandiseItems Json?
709
- externalPriceMax Int? // Maximum ticket price in cents (for imported events)
710
- externalPriceSummary String? // Human-readable price summary e.g., "$50 - $150" or "$75"
711
- customTermsAndConditions String?
712
- itinerary Json? // Array of { id: string, title: string, startTime: string, endTime: string, description?: string }
713
- backgroundImage String? // Custom or curated background image URL for the event page
714
- themeColor String? // Dominant hex color extracted from the event flyer (e.g. "#7c3aed")
720
+ merchandiseItems Json?
721
+ externalPriceMax Int? // Maximum ticket price in cents (for imported events)
722
+ externalPriceSummary String? // Human-readable price summary e.g., "$50 - $150" or "$75"
723
+ customTermsAndConditions String?
724
+ itinerary Json? // Array of { id: string, title: string, startTime: string, endTime: string, description?: string }
725
+ backgroundImage String? // Custom or curated background image URL for the bash detail page
726
+ themeColor String? // Dominant hex color extracted from the event flyer (e.g. "#7c3aed")
715
727
 
716
728
  // Host broadcast fields
717
- postEventMessageSent Boolean @default(false)
718
- postEventMessageSentAt DateTime?
719
- broadcastCount Int @default(0)
720
- lastBroadcastAt DateTime?
729
+ postEventMessageSent Boolean @default(false)
730
+ postEventMessageSentAt DateTime?
731
+ broadcastCount Int @default(0)
732
+ lastBroadcastAt DateTime?
721
733
 
722
734
  // Idea-specific fields (only used when status = 'Idea')
723
735
  ideaExpiresAt DateTime?
@@ -801,7 +813,9 @@ model BashEvent {
801
813
  interests IdeaInterest[]
802
814
  configurations IdeaConfiguration[]
803
815
 
804
- /** Logged-in users: soft RSVP (Going / Maybe / NotGoing) for public published events — not org EventRSVP */
816
+ /**
817
+ * Logged-in users: soft RSVP (Going / Maybe / NotGoing) for public published events — not org EventRSVP
818
+ */
805
819
  publicBashRsvps PublicBashRsvp[]
806
820
 
807
821
  // Claiming Relations
@@ -828,8 +842,8 @@ model BashEvent {
828
842
  rsvps EventRSVP[] @relation("EventRSVPs")
829
843
 
830
844
  // Groups & page views (Phases 0–4)
831
- pageViews BashEventPageView[]
832
- eventGroups EventGroup[]
845
+ pageViews BashEventPageView[]
846
+ eventGroups EventGroup[]
833
847
  groupUnlockOffers GroupUnlockOffer[]
834
848
 
835
849
  bashEventArtists BashEventArtist[]
@@ -870,16 +884,16 @@ enum BashCreativeStatus {
870
884
  model BashCreativeSubmission {
871
885
  id String @id @default(cuid())
872
886
  serviceId String
873
- service Service @relation(fields: [serviceId], references: [id], onDelete: Cascade)
887
+ service Service @relation(fields: [serviceId], references: [id], onDelete: Cascade)
874
888
  submittedById String?
875
- submittedBy User? @relation(fields: [submittedById], references: [id], onDelete: SetNull)
876
- status BashCreativeStatus @default(Pending)
877
- scriptNotes String? @db.Text
889
+ submittedBy User? @relation(fields: [submittedById], references: [id], onDelete: SetNull)
890
+ status BashCreativeStatus @default(Pending)
891
+ scriptNotes String? @db.Text
878
892
  footageUrl String?
879
893
  deliverableUrl String?
880
- requestedAt DateTime @default(now())
894
+ requestedAt DateTime @default(now())
881
895
  deliveredAt DateTime?
882
- updatedAt DateTime @updatedAt
896
+ updatedAt DateTime @updatedAt
883
897
 
884
898
  @@index([serviceId])
885
899
  @@index([status])
@@ -1045,15 +1059,15 @@ model PublicBashRsvp {
1045
1059
 
1046
1060
  // Per-event referral rewards: host defines tiers (e.g. 3 referrals = free drink)
1047
1061
  model EventReferralReward {
1048
- id String @id @default(cuid())
1049
- bashEventId String
1050
- referralCount Int // How many referrals needed for this reward
1051
- rewardType String // BashPoints, FreeTicket, FreeDrink, Custom
1052
- rewardLabel String // e.g. "Free drink at the bar"
1053
- bashPointsAmount Int? // When rewardType=BashPoints
1054
- sortOrder Int @default(0)
1055
- createdAt DateTime @default(now())
1056
- updatedAt DateTime @updatedAt
1062
+ id String @id @default(cuid())
1063
+ bashEventId String
1064
+ referralCount Int // How many referrals needed for this reward
1065
+ rewardType String // BashPoints, FreeTicket, FreeDrink, Custom
1066
+ rewardLabel String // e.g. "Free drink at the bar"
1067
+ bashPointsAmount Int? // When rewardType=BashPoints
1068
+ sortOrder Int @default(0)
1069
+ createdAt DateTime @default(now())
1070
+ updatedAt DateTime @updatedAt
1057
1071
 
1058
1072
  bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1059
1073
 
@@ -1062,12 +1076,12 @@ model EventReferralReward {
1062
1076
 
1063
1077
  // Tracks referrals: attendee A referred person B who bought a ticket
1064
1078
  model EventReferral {
1065
- id String @id @default(cuid())
1066
- bashEventId String
1067
- referrerId String // Attendee who shared their link
1068
- referredUserId String // Person who bought via the link
1069
- ticketId String? @unique // Ticket purchased (optional, 1:1 with Ticket)
1070
- createdAt DateTime @default(now())
1079
+ id String @id @default(cuid())
1080
+ bashEventId String
1081
+ referrerId String // Attendee who shared their link
1082
+ referredUserId String // Person who bought via the link
1083
+ ticketId String? @unique // Ticket purchased (optional, 1:1 with Ticket)
1084
+ createdAt DateTime @default(now())
1071
1085
 
1072
1086
  bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1073
1087
  referrer User @relation("EventReferralsMade", fields: [referrerId], references: [id], onDelete: Cascade)
@@ -1081,16 +1095,16 @@ model EventReferral {
1081
1095
 
1082
1096
  // Curated event lists for discovery (super-user editorial tool)
1083
1097
  model BashList {
1084
- id String @id @default(cuid())
1085
- title String // e.g. "Best Friday Night in Ogden"
1086
- slug String @unique // URL-friendly identifier
1087
- description String? @db.Text
1088
- filterConfig Json // { dateRange?, city?, state?, eventType?, maxPrice?, ... }
1089
- isFeatured Boolean @default(false)
1090
- sortOrder Int @default(0)
1091
- createdById String
1092
- createdAt DateTime @default(now())
1093
- updatedAt DateTime @updatedAt
1098
+ id String @id @default(cuid())
1099
+ title String // e.g. "Best Friday Night in Ogden"
1100
+ slug String @unique // URL-friendly identifier
1101
+ description String? @db.Text
1102
+ filterConfig Json // { dateRange?, city?, state?, eventType?, maxPrice?, ... }
1103
+ isFeatured Boolean @default(false)
1104
+ sortOrder Int @default(0)
1105
+ createdById String
1106
+ createdAt DateTime @default(now())
1107
+ updatedAt DateTime @updatedAt
1094
1108
 
1095
1109
  createdBy User @relation(fields: [createdById], references: [id], onDelete: Cascade)
1096
1110
 
@@ -1103,11 +1117,11 @@ model UserItinerary {
1103
1117
  id String @id @default(cuid())
1104
1118
  userId String
1105
1119
  date DateTime @db.Date // The night (e.g. 2026-03-15)
1106
- title String? // e.g. "Friday night out"
1120
+ title String? // e.g. "Friday night out"
1107
1121
  createdAt DateTime @default(now())
1108
1122
  updatedAt DateTime @updatedAt
1109
1123
 
1110
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1124
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1111
1125
  items UserItineraryItem[]
1112
1126
 
1113
1127
  @@unique([userId, date])
@@ -1138,15 +1152,15 @@ model Coordinates {
1138
1152
  }
1139
1153
 
1140
1154
  model Checkout {
1141
- id String @id @default(cuid())
1155
+ id String @id @default(cuid())
1142
1156
  ownerId String
1143
1157
  bashEventId String
1144
- checkoutDateTime DateTime? @default(now())
1145
- stripeCheckoutSessionId String? @unique
1146
- stripePaymentIntentId String? @unique
1158
+ checkoutDateTime DateTime? @default(now())
1159
+ stripeCheckoutSessionId String? @unique
1160
+ stripePaymentIntentId String? @unique
1147
1161
  refundedAt DateTime?
1148
- bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1149
- owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
1162
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1163
+ owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
1150
1164
  tickets Ticket[]
1151
1165
  appliedDiscounts AppliedDiscount[] // NEW - Discounts applied to this checkout
1152
1166
  waiverAcceptances WaiverAcceptance[]
@@ -1184,13 +1198,13 @@ model BashCreditTransaction {
1184
1198
  status CreditTransactionStatus @default(Pending)
1185
1199
 
1186
1200
  // Source Tracking (Legacy fields - keeping for backwards compatibility)
1187
- source String // Legacy source field
1188
- referralCode String?
1189
- referredUserId String?
1190
- referredUser User? @relation("ReferredUser", fields: [referredUserId], references: [id])
1191
- membershipTier MembershipTier?
1192
- description String?
1193
- metadata String? // JSON string for additional context
1201
+ source String // Legacy source field
1202
+ referralCode String?
1203
+ referredUserId String?
1204
+ referredUser User? @relation("ReferredUser", fields: [referredUserId], references: [id])
1205
+ membershipTier MembershipTier?
1206
+ description String?
1207
+ metadata String? // JSON string for additional context
1194
1208
 
1195
1209
  // New Source Tracking
1196
1210
  sourceType CreditSourceType?
@@ -1226,19 +1240,19 @@ model BashCreditTransaction {
1226
1240
  }
1227
1241
 
1228
1242
  model PendingBashPointsGift {
1229
- id String @id @default(cuid())
1230
- senderId String
1231
- sender User @relation("SentPendingGifts", fields: [senderId], references: [id], onDelete: Cascade)
1232
- recipientEmail String
1233
- amount Int
1234
- message String?
1235
- status PendingGiftStatus @default(Pending)
1236
- claimedAt DateTime?
1243
+ id String @id @default(cuid())
1244
+ senderId String
1245
+ sender User @relation("SentPendingGifts", fields: [senderId], references: [id], onDelete: Cascade)
1246
+ recipientEmail String
1247
+ amount Int
1248
+ message String?
1249
+ status PendingGiftStatus @default(Pending)
1250
+ claimedAt DateTime?
1237
1251
  claimedByUserId String?
1238
- claimedBy User? @relation("ClaimedPendingGifts", fields: [claimedByUserId], references: [id], onDelete: SetNull)
1239
- returnedAt DateTime?
1240
- expiresAt DateTime
1241
- createdAt DateTime @default(now())
1252
+ claimedBy User? @relation("ClaimedPendingGifts", fields: [claimedByUserId], references: [id], onDelete: SetNull)
1253
+ returnedAt DateTime?
1254
+ expiresAt DateTime
1255
+ createdAt DateTime @default(now())
1242
1256
 
1243
1257
  @@index([recipientEmail, status])
1244
1258
  @@index([senderId])
@@ -1369,23 +1383,23 @@ model TicketTier {
1369
1383
  // Availability rules
1370
1384
  availabilityType String @default("Immediate") // "Immediate" | "OnDate" | "EngagedUsersOnly" | "UnlockWhenInterestReached" | "UnlockWhenTicketsSold"
1371
1385
  availableAt DateTime? // OnDate: when tier unlocks
1372
- availableWhenInterestReached Int? // UnlockWhenInterestReached: min IdeaInterest count
1373
- unlockWhenTicketsSold Int? // UnlockWhenTicketsSold: min tickets sold across event to unlock this tier
1374
- maxTicketsPerUser Int? // Optional per-user purchase cap
1386
+ availableWhenInterestReached Int? // UnlockWhenInterestReached: min IdeaInterest count
1387
+ unlockWhenTicketsSold Int? // UnlockWhenTicketsSold: min tickets sold across event to unlock this tier
1388
+ maxTicketsPerUser Int? // Optional per-user purchase cap
1375
1389
 
1376
1390
  // Privacy: "Public" | "LinkOnly" | "InviteOnly"
1377
- tierPrivacy String @default("Public")
1391
+ tierPrivacy String @default("Public")
1378
1392
 
1379
1393
  // Checkout timer: host-configurable per-tier timeout (minutes). null = no timer.
1380
- checkoutTimeoutMinutes Int?
1394
+ checkoutTimeoutMinutes Int?
1381
1395
 
1382
1396
  /// When true, BashPass subscribers may redeem this tier (subject to caps).
1383
- bashPassEligible Boolean @default(false)
1397
+ bashPassEligible Boolean @default(false)
1384
1398
  /// Max BashPass redemptions for this tier (null = unlimited within tier capacity).
1385
- bashPassMaxRedemptions Int?
1399
+ bashPassMaxRedemptions Int?
1400
+ ticketGiftGrants TicketGiftGrant[]
1386
1401
 
1387
1402
  @@unique([bashEventId, title])
1388
- ticketGiftGrants TicketGiftGrant[]
1389
1403
  }
1390
1404
 
1391
1405
  enum TicketGiftGrantStatus {
@@ -1442,7 +1456,9 @@ model Ticket {
1442
1456
  waitlistJoinedAt DateTime?
1443
1457
  waitlistNotifiedAt DateTime?
1444
1458
  waitlistExpiresAt DateTime?
1445
- /** Set when we send the "your waitlist window expires soon" reminder (once per ticket). */
1459
+ /**
1460
+ * Set when we send the "your waitlist window expires soon" reminder (once per ticket).
1461
+ */
1446
1462
  waitlistReminderSentAt DateTime?
1447
1463
  refundRequestedAt DateTime? // Set when RefundPending; cleared once refund processes
1448
1464
  checkInLocation String?
@@ -1472,20 +1488,20 @@ model Ticket {
1472
1488
  utmMedium String?
1473
1489
  utmCampaign String?
1474
1490
 
1475
- bashEvent BashEvent @relation(fields: [bashEventId], references: [id])
1491
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id])
1476
1492
  attributedArtistId String?
1477
- attributedArtist BashEventArtist? @relation(fields: [attributedArtistId], references: [id], onDelete: SetNull)
1478
- checkout Checkout? @relation(fields: [checkoutId], references: [id])
1479
- forUser User? @relation("TicketsISent", fields: [forUserId], references: [id])
1480
- invitation Invitation? @relation("TicketsForInvitation", fields: [invitationId], references: [id])
1481
- owner User @relation("TicketsIOwn", fields: [ownerId], references: [id])
1482
- ticketTier TicketTier? @relation(fields: [ticketTierId], references: [id])
1483
- waitlistUser User? @relation("TicketsOnWaitlist", fields: [waitlistUserId], references: [id])
1484
- metadata TicketMetadata[]
1485
- transfers TicketTransfer[]
1486
- transferInvite TicketTransferInvite?
1487
- appliedDiscounts AppliedDiscount[] // NEW - Discounts applied to this ticket
1488
- eventReferral EventReferral? // When this ticket was purchased via a referral link
1493
+ attributedArtist BashEventArtist? @relation(fields: [attributedArtistId], references: [id], onDelete: SetNull)
1494
+ checkout Checkout? @relation(fields: [checkoutId], references: [id])
1495
+ forUser User? @relation("TicketsISent", fields: [forUserId], references: [id])
1496
+ invitation Invitation? @relation("TicketsForInvitation", fields: [invitationId], references: [id])
1497
+ owner User @relation("TicketsIOwn", fields: [ownerId], references: [id])
1498
+ ticketTier TicketTier? @relation(fields: [ticketTierId], references: [id])
1499
+ waitlistUser User? @relation("TicketsOnWaitlist", fields: [waitlistUserId], references: [id])
1500
+ metadata TicketMetadata[]
1501
+ transfers TicketTransfer[]
1502
+ transferInvite TicketTransferInvite?
1503
+ appliedDiscounts AppliedDiscount[] // NEW - Discounts applied to this ticket
1504
+ eventReferral EventReferral? // When this ticket was purchased via a referral link
1489
1505
 
1490
1506
  @@index([bashEventId])
1491
1507
  @@index([waitlistUserId])
@@ -1526,9 +1542,9 @@ model TicketTransferInvite {
1526
1542
  expiresAt DateTime
1527
1543
  createdAt DateTime @default(now())
1528
1544
 
1529
- ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
1530
- fromUser User @relation("TicketTransferInviteFrom", fields: [fromUserId], references: [id])
1531
- invitedUser User? @relation("TicketTransferInviteToUser", fields: [toUserId], references: [id])
1545
+ ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
1546
+ fromUser User @relation("TicketTransferInviteFrom", fields: [fromUserId], references: [id])
1547
+ invitedUser User? @relation("TicketTransferInviteToUser", fields: [toUserId], references: [id])
1532
1548
 
1533
1549
  @@index([token])
1534
1550
  @@index([fromUserId])
@@ -1593,20 +1609,20 @@ model Recurrence {
1593
1609
 
1594
1610
  // Recurring event series: template that spawns many BashEvent instances (e.g. "Every Tuesday 7pm for 14 weeks")
1595
1611
  model EventSeries {
1596
- id String @id @default(cuid())
1612
+ id String @id @default(cuid())
1597
1613
  organizationId String?
1598
1614
  creatorId String
1599
1615
  name String
1600
- description String? @db.Text
1616
+ description String? @db.Text
1601
1617
  frequency RecurringFrequency
1602
- interval Int @default(1)
1618
+ interval Int @default(1)
1603
1619
  repeatOnDays DayOfWeek[]
1604
1620
  seriesStart DateTime
1605
1621
  seriesEnd DateTime
1606
- exceptions Json? // Array of ISO date strings to skip
1607
- templateConfig Json? // Event defaults: title pattern, ticketTiers, etc.
1608
- createdAt DateTime @default(now())
1609
- updatedAt DateTime @updatedAt
1622
+ exceptions Json? // Array of ISO date strings to skip
1623
+ templateConfig Json? // Event defaults: title pattern, ticketTiers, etc.
1624
+ createdAt DateTime @default(now())
1625
+ updatedAt DateTime @updatedAt
1610
1626
 
1611
1627
  organization Organization? @relation("OrganizationEventSeries", fields: [organizationId], references: [id], onDelete: SetNull)
1612
1628
  creator User @relation("EventSeriesCreator", fields: [creatorId], references: [id], onDelete: Restrict)
@@ -1655,21 +1671,28 @@ model BashEventTemplate {
1655
1671
 
1656
1672
  // Used by BashEvent (amountOfGuests) and by Services (crowdSizeId/crowdSize); same model, different relation names.
1657
1673
  model AmountOfGuests {
1658
- id String @id @default(cuid())
1659
- minimum Int? @default(10)
1660
- ideal Int? @default(35)
1661
- expected Int? @default(25)
1662
- showMinimumGuests Boolean @default(true)
1663
- showIdealGuests Boolean @default(true)
1664
- showExpectedGuests Boolean @default(true)
1665
- venueId String?
1666
- organizationId String?
1667
- bashEvent BashEvent?
1668
- entertainmentService EntertainmentService?
1669
- eventService EventService?
1670
- exhibitor Exhibitor?
1671
- sponsor Sponsor?
1672
- vendor Vendor?
1674
+ id String @id @default(cuid())
1675
+ minimum Int? @default(10)
1676
+ ideal Int? @default(35)
1677
+ expected Int? @default(25)
1678
+ showMinimumGuests Boolean @default(true)
1679
+ showIdealGuests Boolean @default(true)
1680
+ showExpectedGuests Boolean @default(true)
1681
+ maximum Int?
1682
+ showMaximumGuests Boolean @default(false)
1683
+ autoCancelIfMinNotMet Boolean @default(false)
1684
+ autoPublicWhenMinMet Boolean @default(false)
1685
+ makePrivateAtMax Boolean @default(false)
1686
+ allowWaitlistAtMax Boolean @default(false)
1687
+ aimingForMaxCapacity Boolean @default(false)
1688
+ venueId String?
1689
+ organizationId String?
1690
+ bashEvent BashEvent?
1691
+ entertainmentService EntertainmentService?
1692
+ eventService EventService?
1693
+ exhibitor Exhibitor?
1694
+ sponsor Sponsor?
1695
+ vendor Vendor?
1673
1696
  }
1674
1697
 
1675
1698
  model TargetAudience {
@@ -1795,19 +1818,19 @@ model Prize {
1795
1818
  }
1796
1819
 
1797
1820
  model Review {
1798
- id String @id @default(cuid())
1799
- rating Int
1800
- creatorId String
1801
- bashEventId String
1802
- createdAt DateTime @default(now())
1803
- updatedAt DateTime @updatedAt
1821
+ id String @id @default(cuid())
1822
+ rating Int
1823
+ creatorId String
1824
+ bashEventId String
1825
+ createdAt DateTime @default(now())
1826
+ updatedAt DateTime @updatedAt
1804
1827
  /// Public reply from the event host (service provider) to the reviewer.
1805
- hostReplyText String? @db.Text
1828
+ hostReplyText String? @db.Text
1806
1829
  hostReplyAt DateTime?
1807
- comments BashComment[]
1808
- bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1809
- creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
1810
- helpfulVotes ReviewHelpfulVote[]
1830
+ comments BashComment[]
1831
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1832
+ creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
1833
+ helpfulVotes ReviewHelpfulVote[]
1811
1834
 
1812
1835
  @@unique([creatorId, bashEventId])
1813
1836
  }
@@ -1891,7 +1914,7 @@ model User {
1891
1914
  isSuperUser Boolean @default(false)
1892
1915
  isSuspended Boolean @default(false)
1893
1916
  intent UserIntent?
1894
- signupSource String? // e.g. 'jamwith', 'mixlog', 'organic' for attribution
1917
+ signupSource String? // e.g. 'jamwith', 'mixlog', 'organic' for attribution
1895
1918
  googleCalendarAccess String?
1896
1919
 
1897
1920
  // Google OAuth tokens for API access (Contacts, Calendar, etc.)
@@ -1900,123 +1923,148 @@ model User {
1900
1923
  googleTokenExpiry DateTime?
1901
1924
 
1902
1925
  // LinkedIn OAuth tokens for UGC posting (w_member_social scope)
1903
- linkedinAccessToken String?
1904
- linkedinTokenExpiry DateTime?
1905
- linkedinPersonId String? // LinkedIn `sub` / person URN
1906
- linkedinVanityUrl String? // e.g. "stevegoodrick" → linkedin.com/in/stevegoodrick
1907
- linkedinHeadline String? // e.g. "Founder at The Bash App"
1908
-
1909
- givenName String?
1910
- familyName String?
1911
- nameChangeCount Int @default(0)
1912
- hash String?
1913
- previousPasswordHashes String[] @default([]) // Last 5 bcrypt hashes (oldest first) for password-reuse prevention
1914
- emailVerified DateTime?
1915
- image String?
1916
- imageUpdatedAt DateTime? // When Google/OAuth image was last updated
1917
- uploadedImage String?
1918
- uploadedImageUpdatedAt DateTime? // When manually uploaded image was last updated
1919
- dob DateTime?
1920
- showBirthdayOnProfile Boolean @default(false) // If true, show month/day on public profile
1926
+ linkedinAccessToken String?
1927
+ linkedinTokenExpiry DateTime?
1928
+ linkedinPersonId String? // LinkedIn `sub` / person URN
1929
+ linkedinVanityUrl String? // e.g. "stevegoodrick" → linkedin.com/in/stevegoodrick
1930
+ linkedinHeadline String? // e.g. "Founder at The Bash App"
1931
+
1932
+ givenName String?
1933
+ familyName String?
1934
+ nameChangeCount Int @default(0)
1935
+ hash String?
1936
+ previousPasswordHashes String[] @default([]) // Last 5 bcrypt hashes (oldest first) for password-reuse prevention
1937
+ emailVerified DateTime?
1938
+ image String?
1939
+ imageUpdatedAt DateTime? // When Google/OAuth image was last updated
1940
+ uploadedImage String?
1941
+ uploadedImageUpdatedAt DateTime? // When manually uploaded image was last updated
1942
+ dob DateTime?
1943
+ showBirthdayOnProfile Boolean @default(false) // If true, show month/day on public profile
1921
1944
  // Part B: Birthday Rewards full product
1922
- birthdayRewardsOptIn Boolean @default(false)
1923
- birthdayRewardsOptInAt DateTime?
1924
- birthdayLocationId String? // FK UserLocation (birthday home base)
1925
- birthdayMaxDistanceMiles Int @default(25)
1926
- birthdayNoPurchaseOnly Boolean @default(false)
1945
+ birthdayRewardsOptIn Boolean @default(false)
1946
+ birthdayRewardsOptInAt DateTime?
1947
+ birthdayLocationId String? // FK UserLocation (birthday home base)
1948
+ birthdayMaxDistanceMiles Int @default(25)
1949
+ birthdayNoPurchaseOnly Boolean @default(false)
1927
1950
  /// Email reminder N days before birthday (birthday rewards plan nudge)
1928
- birthdayReminderEnabled Boolean @default(true)
1929
- birthdayReminderDaysAdvance Int @default(7)
1930
- birthdayCategories String[] @default([]) // e.g. restaurant, coffee, dessert
1951
+ birthdayReminderEnabled Boolean @default(true)
1952
+ birthdayReminderDaysAdvance Int @default(7)
1953
+ birthdayCategories String[] @default([]) // e.g. restaurant, coffee, dessert
1931
1954
  /// Calendar year when we last sent the "your birthday month freebies" reminder (cron on 1st of month).
1932
- birthdayMonthReminderSentYear Int?
1933
- idDocumentUrl String? // Optional: secure ID upload for verification
1934
- gender Gender?
1935
- sex Sex?
1936
- organization String?
1937
- jobTitle String?
1938
- roles UserRole[] @default([User])
1939
- aboutMe String?
1940
- levelBadge String?
1941
- temporaryBadges String[] @default([])
1942
- status UserStatus
1943
- hostRating Float?
1944
- totalRatings Int?
1945
- totalEventsHosted Int? @default(0) // Total published/completed events hosted
1946
- totalAttendeesHosted Int? @default(0) // Total checked-in attendees across all events
1947
- totalBookingsAccepted Int? @default(0) // Service provider stat
1948
- totalBookingsCompleted Int? @default(0) // Service provider stat
1949
- magicLink String?
1950
- magicLinkExpiration DateTime?
1951
- hostNumber Int?
1952
- foundingHostBadgeAwarded Boolean @default(false)
1953
- firstBashWithAttendeesDate DateTime?
1954
- bashesCreatedCount Int @default(0)
1955
- bashesPublishedCount Int @default(0)
1956
- bashesApprovedCount Int @default(0)
1957
- bashesCompletedCount Int @default(0)
1958
- magicLinkUsed DateTime?
1959
- idVerified DateTime?
1960
- street String?
1961
- city String?
1962
- state String?
1963
- zipCode String?
1964
- country String? @default("US")
1965
- phone String?
1966
- documentIDId String? @unique
1967
- accepted Boolean? @default(false)
1968
- boughtTicket Boolean? @default(false)
1969
- noPay Boolean? @default(false)
1970
- supportedEvent Boolean? @default(false)
1971
- suspendedUntil DateTime?
1972
- suspendedById String?
1973
- isLightweightAccount Boolean @default(false)
1974
- notifyForTrendingBashes Boolean @default(false)
1975
- trendingBashThreshold Int @default(10)
1976
- artistsToSee String[] @default([])
1977
- googleCalendarSyncSettings String?
1978
- membershipTier MembershipTier @default(Basic)
1979
- membershipExpiresAt DateTime?
1980
- membershipAutoRenew Boolean @default(false)
1981
- membershipBillingInterval String?
1982
- membershipLastBilledAt DateTime?
1983
- membershipFeaturedEventsUsed Int @default(0)
1984
- membershipStripeSubscriptionId String? @unique
1955
+ birthdayMonthReminderSentYear Int?
1956
+ idDocumentUrl String? // Optional: secure ID upload for verification
1957
+ gender Gender?
1958
+ /// Free-text self-described gender. Takes precedence over `gender` when present.
1959
+ genderIdentity String?
1960
+ sex Sex?
1961
+ /// Public-profile visibility flags for self-reported demographics
1962
+ showAgeOnProfile Boolean @default(true)
1963
+ showGenderOnProfile Boolean @default(true)
1964
+ /// Master visibility toggle for ID/Payment/Host/Student trust badges
1965
+ showVerifiedBadgesOnProfile Boolean @default(true)
1966
+ organization String?
1967
+ jobTitle String?
1968
+ roles UserRole[] @default([User])
1969
+ aboutMe String?
1970
+ levelBadge String?
1971
+ temporaryBadges String[] @default([])
1972
+ status UserStatus
1973
+ hostRating Float?
1974
+ totalRatings Int?
1975
+ totalEventsHosted Int? @default(0) // Total published/completed events hosted
1976
+ totalAttendeesHosted Int? @default(0) // Total checked-in attendees across all events
1977
+ totalBookingsAccepted Int? @default(0) // Service provider stat
1978
+ totalBookingsCompleted Int? @default(0) // Service provider stat
1979
+ magicLink String?
1980
+ magicLinkExpiration DateTime?
1981
+ hostNumber Int?
1982
+ foundingHostBadgeAwarded Boolean @default(false)
1983
+ firstBashWithAttendeesDate DateTime?
1984
+ bashesCreatedCount Int @default(0)
1985
+ bashesPublishedCount Int @default(0)
1986
+ bashesApprovedCount Int @default(0)
1987
+ bashesCompletedCount Int @default(0)
1988
+ magicLinkUsed DateTime?
1989
+ idVerified DateTime?
1990
+ street String?
1991
+ city String?
1992
+ state String?
1993
+ zipCode String?
1994
+ country String? @default("US")
1995
+ phone String?
1996
+ documentIDId String? @unique
1997
+ /// Encrypted-S3 key for the user's stored government-ID image (deleted per retention policy / on ID expiration)
1998
+ govIdImageS3Key String?
1999
+ /// When the gov-ID image becomes deletable (null = "indefinite, until I remove it").
2000
+ /// Indexed via a Postgres PARTIAL index for the expireIdImages cron — see
2001
+ /// migrations/20260418061500_index_gov_id_image_expires_at. Prisma does
2002
+ /// not support partial indexes declaratively, so the index is SQL-only.
2003
+ govIdImageExpiresAt DateTime?
2004
+ /// Retention policy for the stored gov-ID image (drives expireIdImages cron)
2005
+ govIdRetentionPolicy GovIdRetentionPolicy?
2006
+ /// GDPR Art. 7 audit trail for retention-policy consent
2007
+ govIdRetentionConsentedAt DateTime?
2008
+ /// Encrypted-S3 key for the user's stored student-ID image (no OCR; school inferred via vision model)
2009
+ studentIdImageS3Key String?
2010
+ studentIdUploadedAt DateTime?
2011
+ /// School/university name extracted from student-ID by vision model; user-editable.
2012
+ schoolName String?
2013
+ /// Whether `schoolName` came from the AI vision model or was edited by the user
2014
+ schoolNameSource SchoolNameSource?
2015
+ accepted Boolean? @default(false)
2016
+ boughtTicket Boolean? @default(false)
2017
+ noPay Boolean? @default(false)
2018
+ supportedEvent Boolean? @default(false)
2019
+ suspendedUntil DateTime?
2020
+ suspendedById String?
2021
+ isLightweightAccount Boolean @default(false)
2022
+ notifyForTrendingBashes Boolean @default(false)
2023
+ trendingBashThreshold Int @default(10)
2024
+ artistsToSee String[] @default([])
2025
+ googleCalendarSyncSettings String?
2026
+ membershipTier MembershipTier @default(Basic)
2027
+ membershipExpiresAt DateTime?
2028
+ membershipAutoRenew Boolean @default(false)
2029
+ membershipBillingInterval String?
2030
+ membershipLastBilledAt DateTime?
2031
+ membershipFeaturedEventsUsed Int @default(0)
2032
+ membershipStripeSubscriptionId String? @unique
1985
2033
  /// Optional consumer BashPass subscription (waives guest platform fee on tickets; monthly BashPoints).
1986
- bashPassStripeSubscriptionId String? @unique
1987
- bashPassCurrentPeriodEnd DateTime?
2034
+ bashPassStripeSubscriptionId String? @unique
2035
+ bashPassCurrentPeriodEnd DateTime?
1988
2036
  /// Stripe price tier for standalone BashPass; effective tier may also come from membership bundle.
1989
- bashPassTier BashPassTier?
1990
- bashPassEventsUsedThisMonth Int @default(0)
1991
- bashPassMonthlyCapResetAt DateTime?
1992
- isVerified Boolean @default(false)
1993
- verificationMethod String?
1994
- verifiedAt DateTime?
1995
- verificationScore Int @default(0)
2037
+ bashPassTier BashPassTier?
2038
+ bashPassEventsUsedThisMonth Int @default(0)
2039
+ bashPassMonthlyCapResetAt DateTime?
2040
+ isVerified Boolean @default(false)
2041
+ verificationMethod String?
2042
+ verifiedAt DateTime?
2043
+ verificationScore Int @default(0)
1996
2044
  /// $1 card verification (Stripe) — distinct from Stripe Identity / isVerified
1997
- paymentVerified Boolean @default(false)
1998
- paymentVerifiedAt DateTime?
2045
+ paymentVerified Boolean @default(false)
2046
+ paymentVerifiedAt DateTime?
1999
2047
  /// One-time BashPoints bonus after $1 verification payment succeeded
2000
- paymentVerificationBonusAwarded Boolean @default(false)
2001
- biometricFingerprint String?
2002
- venmoUsername String?
2003
- venmoQRCodeUrl String?
2004
- zelleEmail String?
2048
+ paymentVerificationBonusAwarded Boolean @default(false)
2049
+ biometricFingerprint String?
2050
+ venmoUsername String?
2051
+ venmoQRCodeUrl String?
2052
+ zelleEmail String?
2005
2053
  /// Optional Venmo / Zelle / CashApp handle shown to hosts (promo requests, code assignment). Bash does not move money.
2006
- paymentHandle String?
2007
- zellePhone String?
2008
- zelleQRCodeUrl String?
2009
- isAmbashador Boolean @default(false)
2010
- ambashadorAwardedAt DateTime?
2011
- isBashInsider Boolean @default(false)
2012
- insiderAwardedAt DateTime?
2013
- scoutTier ScoutTier @default(None)
2014
- scoutAwardedAt DateTime?
2015
- agentAwardedAt DateTime?
2016
- totalServiceReferrals Int @default(0)
2017
- isFirstInCity Boolean @default(false)
2018
- firstInCityAt DateTime?
2019
- fcmTokens String[] @default([]) // Firebase Cloud Messaging tokens for push notifications
2054
+ paymentHandle String?
2055
+ zellePhone String?
2056
+ zelleQRCodeUrl String?
2057
+ isAmbashador Boolean @default(false)
2058
+ ambashadorAwardedAt DateTime?
2059
+ isBashInsider Boolean @default(false)
2060
+ insiderAwardedAt DateTime?
2061
+ scoutTier ScoutTier @default(None)
2062
+ scoutAwardedAt DateTime?
2063
+ agentAwardedAt DateTime?
2064
+ totalServiceReferrals Int @default(0)
2065
+ isFirstInCity Boolean @default(false)
2066
+ firstInCityAt DateTime?
2067
+ fcmTokens String[] @default([]) // Firebase Cloud Messaging tokens for push notifications
2020
2068
 
2021
2069
  // BashPoints System Fields
2022
2070
  bashPointsBalance Int @default(0)
@@ -2027,48 +2075,48 @@ model User {
2027
2075
  referralPurchaseCredited Boolean @default(false)
2028
2076
 
2029
2077
  // Security Fields
2030
- accountLockedUntil DateTime? // Account lockout timestamp for failed login protection
2031
- revokedTokens RevokedToken[] @relation("RevokedTokens") // Revoked JWT tokens
2032
- auditLogs AuditLog[] @relation("UserAuditLogs")
2033
- auditLogsPerformed AuditLog[] @relation("PerformedByUser")
2034
- consents UserConsent[]
2035
- birthdayOfferOptIns UserBirthdayOfferOptIn[]
2036
- birthdayOfferDeliveries BirthdayOfferDelivery[]
2037
- birthdayBoostGrants BirthdayBoostGrant[]
2038
- birthdayRewardRedemptions BirthdayRewardRedemption[]
2039
- birthdayRewardFavorites BirthdayRewardFavorite[]
2040
- birthdayDealSuggestions BirthdayDealSuggestion[]
2078
+ accountLockedUntil DateTime? // Account lockout timestamp for failed login protection
2079
+ revokedTokens RevokedToken[] @relation("RevokedTokens") // Revoked JWT tokens
2080
+ auditLogs AuditLog[] @relation("UserAuditLogs")
2081
+ auditLogsPerformed AuditLog[] @relation("PerformedByUser")
2082
+ consents UserConsent[]
2083
+ birthdayOfferOptIns UserBirthdayOfferOptIn[]
2084
+ birthdayOfferDeliveries BirthdayOfferDelivery[]
2085
+ birthdayBoostGrants BirthdayBoostGrant[]
2086
+ birthdayRewardRedemptions BirthdayRewardRedemption[]
2087
+ birthdayRewardFavorites BirthdayRewardFavorite[]
2088
+ birthdayDealSuggestions BirthdayDealSuggestion[]
2041
2089
  birthdayCityResourceSuggestions BirthdayCityResourceSuggestion[]
2042
- rewardReports RewardReport[]
2043
- birthdayFreebieVotes BirthdayFreebieVote[]
2044
- rewardReportsReviewed RewardReport[] @relation("RewardReportReviewedBy")
2045
- nationalChainReports NationalChainReport[]
2046
- nationalChainReportsReviewed NationalChainReport[] @relation("NationalChainReportReviewedBy")
2047
- userLocations UserLocation[]
2048
- birthdayLocation UserLocation? @relation("UserBirthdayLocation", fields: [birthdayLocationId], references: [id], onDelete: SetNull)
2049
- offerClaims OfferClaim[]
2050
- birthdayPlans BirthdayPlan[]
2051
- birthdayFreebiesSavedPlan BirthdayFreebiesSavedPlan?
2090
+ rewardReports RewardReport[]
2091
+ birthdayFreebieVotes BirthdayFreebieVote[]
2092
+ rewardReportsReviewed RewardReport[] @relation("RewardReportReviewedBy")
2093
+ nationalChainReports NationalChainReport[]
2094
+ nationalChainReportsReviewed NationalChainReport[] @relation("NationalChainReportReviewedBy")
2095
+ userLocations UserLocation[]
2096
+ birthdayLocation UserLocation? @relation("UserBirthdayLocation", fields: [birthdayLocationId], references: [id], onDelete: SetNull)
2097
+ offerClaims OfferClaim[]
2098
+ birthdayPlans BirthdayPlan[]
2099
+ birthdayFreebiesSavedPlan BirthdayFreebiesSavedPlan?
2052
2100
 
2053
2101
  associatedBashes AssociatedBash[]
2054
2102
  associatedServices AssociatedService[]
2055
2103
  comment BashComment[]
2056
- referredTransactions BashCreditTransaction[] @relation("ReferredUser")
2104
+ referredTransactions BashCreditTransaction[] @relation("ReferredUser")
2057
2105
  creditTransactions BashCreditTransaction[]
2058
- createdEvents BashEvent[] @relation("CreatedEvent")
2059
- bashEventsTransferredFrom BashEvent[] @relation("TransferredFrom")
2060
- bashEventsPayoutRecipient BashEvent[] @relation("BashEventsPayoutRecipient")
2061
- bashEventMessagesSent BashEventMessage[] @relation("BashMessageSender")
2062
- bashEventMessagesRead BashEventMessageRead[] @relation("BashMessageReader")
2063
- transferRequestsFrom BashEventTransferRequest[] @relation("TransferRequestsFrom")
2064
- transferRequestsTo BashEventTransferRequest[] @relation("TransferRequestsTo")
2065
- sentPendingGifts PendingBashPointsGift[] @relation("SentPendingGifts")
2066
- claimedPendingGifts PendingBashPointsGift[] @relation("ClaimedPendingGifts")
2106
+ createdEvents BashEvent[] @relation("CreatedEvent")
2107
+ bashEventsTransferredFrom BashEvent[] @relation("TransferredFrom")
2108
+ bashEventsPayoutRecipient BashEvent[] @relation("BashEventsPayoutRecipient")
2109
+ bashEventMessagesSent BashEventMessage[] @relation("BashMessageSender")
2110
+ bashEventMessagesRead BashEventMessageRead[] @relation("BashMessageReader")
2111
+ transferRequestsFrom BashEventTransferRequest[] @relation("TransferRequestsFrom")
2112
+ transferRequestsTo BashEventTransferRequest[] @relation("TransferRequestsTo")
2113
+ sentPendingGifts PendingBashPointsGift[] @relation("SentPendingGifts")
2114
+ claimedPendingGifts PendingBashPointsGift[] @relation("ClaimedPendingGifts")
2067
2115
  biometricCredentials BiometricCredential[]
2068
- blocksReceived BlockedUser[] @relation("UserBlocksReceived")
2069
- blocksCreated BlockedUser[] @relation("UserBlocksMade")
2070
- blogComments BlogComment[] @relation("BlogCommentAuthor")
2071
- blogPosts BlogPost[] @relation("BlogAuthor")
2116
+ blocksReceived BlockedUser[] @relation("UserBlocksReceived")
2117
+ blocksCreated BlockedUser[] @relation("UserBlocksMade")
2118
+ blogComments BlogComment[] @relation("BlogCommentAuthor")
2119
+ blogPosts BlogPost[] @relation("BlogAuthor")
2072
2120
  checkouts Checkout[]
2073
2121
  waiverAcceptances WaiverAcceptance[]
2074
2122
  clubAdmins ClubAdmin[]
@@ -2077,90 +2125,90 @@ model User {
2077
2125
  competitionSponsorships CompetitionSponsor[]
2078
2126
  competitionParticipations CompetitionParticipant[]
2079
2127
  competitionVotes CompetitionVote[]
2080
- competitionJudgeAssignments CompetitionJudgeAssignment[] @relation("CompetitionJudgeAssignments")
2081
- competitionJudgeScoresAuthored CompetitionJudgeScore[] @relation("CompetitionJudgeScoresAuthored")
2128
+ competitionJudgeAssignments CompetitionJudgeAssignment[] @relation("CompetitionJudgeAssignments")
2129
+ competitionJudgeScoresAuthored CompetitionJudgeScore[] @relation("CompetitionJudgeScoresAuthored")
2082
2130
  contacts Contact[]
2083
- contactLists ContactList[] @relation("UserContactLists")
2131
+ contactLists ContactList[] @relation("UserContactLists")
2084
2132
  contactlist ContactList[]
2085
- expungedDemerits Demerit[] @relation("ExpungedDemerits")
2086
- issuedDemerits Demerit[] @relation("IssuedDemerits")
2087
- demerits Demerit[] @relation("UserDemerits")
2133
+ expungedDemerits Demerit[] @relation("ExpungedDemerits")
2134
+ issuedDemerits Demerit[] @relation("IssuedDemerits")
2135
+ demerits Demerit[] @relation("UserDemerits")
2088
2136
  documentID DocumentID?
2089
- eventTasksAssignedToMe EventTask[] @relation("TasksAssignedToMe")
2137
+ eventTasksAssignedToMe EventTask[] @relation("TasksAssignedToMe")
2090
2138
  eventTasks EventTask[]
2091
- potluckItemsClaimed PotluckItem[] @relation("PotluckItemsClaimedBy")
2092
- bashEventSuggestionsCreated BashEventSuggestion[] @relation("BashEventSuggestionsCreated")
2093
- bashSuggestionUpvotes SuggestionUpvote[] @relation("BashSuggestionUpvotes")
2094
- itemUpvotesGiven ItemUpvote[] @relation("ItemUpvotesGiven")
2095
- taskCommentsAuthored TaskComment[] @relation("TaskCommentsAuthored")
2096
- taskInvitationsSent TaskInvitation[] @relation("TaskInvitationsSent")
2097
- taskInvitationsAccepted TaskInvitation[] @relation("TaskInvitationsAccepted")
2098
- exhibitorBookingRequestsAsHost ExhibitorBookingRequest[] @relation("ExhibitorBookingHost")
2139
+ potluckItemsClaimed PotluckItem[] @relation("PotluckItemsClaimedBy")
2140
+ bashEventSuggestionsCreated BashEventSuggestion[] @relation("BashEventSuggestionsCreated")
2141
+ bashSuggestionUpvotes SuggestionUpvote[] @relation("BashSuggestionUpvotes")
2142
+ itemUpvotesGiven ItemUpvote[] @relation("ItemUpvotesGiven")
2143
+ taskCommentsAuthored TaskComment[] @relation("TaskCommentsAuthored")
2144
+ taskInvitationsSent TaskInvitation[] @relation("TaskInvitationsSent")
2145
+ taskInvitationsAccepted TaskInvitation[] @relation("TaskInvitationsAccepted")
2146
+ exhibitorBookingRequestsAsHost ExhibitorBookingRequest[] @relation("ExhibitorBookingHost")
2099
2147
  investments Investment[]
2100
- invitationsCreatedByMe Invitation[] @relation("InvitationsCreatedByMe")
2101
- invitationsSentToMe Invitation[] @relation("InvitationsSentToMe")
2102
- notificationsCreatedByMe Notification[] @relation("NotificationsCreatedByMe")
2103
- notification Notification[] @relation("NotificationsReceivedByMe")
2148
+ invitationsCreatedByMe Invitation[] @relation("InvitationsCreatedByMe")
2149
+ invitationsSentToMe Invitation[] @relation("InvitationsSentToMe")
2150
+ notificationsCreatedByMe Notification[] @relation("NotificationsCreatedByMe")
2151
+ notification Notification[] @relation("NotificationsReceivedByMe")
2104
2152
  competitionPrizes Prize[]
2105
2153
  promoter Promoter[]
2106
2154
  promoterStats PromoterStats?
2107
- remindersCreatedByMe Reminder[] @relation("RemindersCreatedByMe")
2108
- remindersAssignedToMe Reminder[] @relation("RemindersAssignedToMe")
2155
+ remindersCreatedByMe Reminder[] @relation("RemindersCreatedByMe")
2156
+ remindersAssignedToMe Reminder[] @relation("RemindersAssignedToMe")
2109
2157
  sentReminders SentReminder[]
2110
2158
  reviews Review[]
2111
2159
  firstFreeListingId String?
2112
- createdServices Service[] @relation("CreatedService")
2113
- ownedServices Service[] @relation("OwnedService")
2114
- serviceBlocksReceived ServiceBlock[] @relation("ServiceBlocksReceived")
2115
- serviceBlocksMade ServiceBlock[] @relation("ServiceBlocksMade")
2116
- serviceBookingForCreator ServiceBooking[] @relation("BookingCreator")
2117
- serviceBookingForUser ServiceBooking[] @relation("BookingForUser")
2160
+ createdServices Service[] @relation("CreatedService")
2161
+ ownedServices Service[] @relation("OwnedService")
2162
+ serviceBlocksReceived ServiceBlock[] @relation("ServiceBlocksReceived")
2163
+ serviceBlocksMade ServiceBlock[] @relation("ServiceBlocksMade")
2164
+ serviceBookingForCreator ServiceBooking[] @relation("BookingCreator")
2165
+ serviceBookingForUser ServiceBooking[] @relation("BookingForUser")
2118
2166
  serviceBookingCheckout ServiceBookingCheckout[]
2119
- serviceBookingMessages ServiceBookingMessage[] @relation("ServiceMessageSender")
2167
+ serviceBookingMessages ServiceBookingMessage[] @relation("ServiceMessageSender")
2120
2168
  sessions Session[]
2121
2169
  socialMediaProfiles SocialMediaProfile[]
2122
- sponsorBookingRequestsAsHost SponsorBookingRequest[] @relation("SponsorBookingHost")
2170
+ sponsorBookingRequestsAsHost SponsorBookingRequest[] @relation("SponsorBookingHost")
2123
2171
  sponsorships SponsoredEvent[]
2124
2172
  stripeAccounts StripeAccount[]
2125
- ticketsISent Ticket[] @relation("TicketsISent")
2126
- ticketsIOwn Ticket[] @relation("TicketsIOwn")
2173
+ ticketsISent Ticket[] @relation("TicketsISent")
2174
+ ticketsIOwn Ticket[] @relation("TicketsIOwn")
2127
2175
  bashEventDonations BashEventDonation[]
2128
2176
  bashCreativeSubmissions BashCreativeSubmission[]
2129
- ticketsOnWaitlist Ticket[] @relation("TicketsOnWaitlist")
2130
- transfersFrom TicketTransfer[] @relation("TransfersFrom")
2131
- transfersTo TicketTransfer[] @relation("TransfersTo")
2132
- ticketTransferInvitesFrom TicketTransferInvite[] @relation("TicketTransferInviteFrom")
2133
- ticketTransferInvitesToUser TicketTransferInvite[] @relation("TicketTransferInviteToUser")
2134
- giftGrantsIssued TicketGiftGrant[] @relation("GiftGrantsIssued")
2135
- giftGrantsReceived TicketGiftGrant[] @relation("GiftGrantsReceived")
2136
- unblocksReceived UnblockedUserHistory[] @relation("UserUnblocksReceived")
2137
- unblocksCreated UnblockedUserHistory[] @relation("UserUnblocksMade")
2138
- suspendedBy User? @relation("SuspendedUsers", fields: [suspendedById], references: [id])
2139
- suspendedUsers User[] @relation("SuspendedUsers")
2177
+ ticketsOnWaitlist Ticket[] @relation("TicketsOnWaitlist")
2178
+ transfersFrom TicketTransfer[] @relation("TransfersFrom")
2179
+ transfersTo TicketTransfer[] @relation("TransfersTo")
2180
+ ticketTransferInvitesFrom TicketTransferInvite[] @relation("TicketTransferInviteFrom")
2181
+ ticketTransferInvitesToUser TicketTransferInvite[] @relation("TicketTransferInviteToUser")
2182
+ giftGrantsIssued TicketGiftGrant[] @relation("GiftGrantsIssued")
2183
+ giftGrantsReceived TicketGiftGrant[] @relation("GiftGrantsReceived")
2184
+ unblocksReceived UnblockedUserHistory[] @relation("UserUnblocksReceived")
2185
+ unblocksCreated UnblockedUserHistory[] @relation("UserUnblocksMade")
2186
+ suspendedBy User? @relation("SuspendedUsers", fields: [suspendedById], references: [id])
2187
+ suspendedUsers User[] @relation("SuspendedUsers")
2140
2188
  favorites UserFavorite[]
2141
2189
  publicBashRsvps PublicBashRsvp[]
2142
- following UserFollowing[] @relation("Follower")
2143
- followers UserFollowing[] @relation("Following")
2144
- connectionRequestsSent UserConnection[] @relation("ConnectionRequestsSent")
2145
- connectionRequestsReceived UserConnection[] @relation("ConnectionRequestsReceived")
2190
+ following UserFollowing[] @relation("Follower")
2191
+ followers UserFollowing[] @relation("Following")
2192
+ connectionRequestsSent UserConnection[] @relation("ConnectionRequestsSent")
2193
+ connectionRequestsReceived UserConnection[] @relation("ConnectionRequestsReceived")
2146
2194
  links UserLink[]
2147
2195
  preferences UserPreferences?
2148
2196
  rankings UserRankings?
2149
2197
  userPromoCodeRedemption UserPromoCodeRedemption[]
2150
2198
  venueLoyaltyRedemptions VenueLoyaltyRedemption[]
2151
2199
  referralCode UserReferralCode?
2152
- referralTokens UserReferralToken[] @relation("UserReferralTokens")
2153
- reportsReceived UserReport[] @relation("ReportsReceived")
2154
- reportsMade UserReport[] @relation("ReportsMade")
2155
- reportsReviewed UserReport[] @relation("ReportsReviewed")
2200
+ referralTokens UserReferralToken[] @relation("UserReferralTokens")
2201
+ reportsReceived UserReport[] @relation("ReportsReceived")
2202
+ reportsMade UserReport[] @relation("ReportsMade")
2203
+ reportsReviewed UserReport[] @relation("ReportsReviewed")
2156
2204
  userStats UserStats?
2157
2205
  userSubscription UserSubscription?
2158
2206
  vendorBid VendorBid[]
2159
- vendorBookingMessages VendorBookingMessage[] @relation("VendorMessageSender")
2207
+ vendorBookingMessages VendorBookingMessage[] @relation("VendorMessageSender")
2160
2208
  serviceAnalytics ServiceAnalytics[] // Track service analytics for this user
2161
- vendorBookingRequestsAsHost VendorBookingRequest[] @relation("VendorBookingHost")
2209
+ vendorBookingRequestsAsHost VendorBookingRequest[] @relation("VendorBookingHost")
2162
2210
  volunteerService VolunteerService[]
2163
- reviewedAmbashadorApps AmbashadorApplication[] @relation("AmbashadorReviewer")
2211
+ reviewedAmbashadorApps AmbashadorApplication[] @relation("AmbashadorReviewer")
2164
2212
 
2165
2213
  // Claiming Relations
2166
2214
  claimRequests ClaimRequest[] @relation("EventClaims")
@@ -2235,8 +2283,8 @@ model User {
2235
2283
  bashAvailability BashAvailability? @relation("UserAvailability")
2236
2284
 
2237
2285
  // Groups
2238
- ownedGroups EventGroup[] @relation("OwnedGroups")
2239
- groupMembers GroupMember[] @relation("GroupMemberships")
2286
+ ownedGroups EventGroup[] @relation("OwnedGroups")
2287
+ groupMembers GroupMember[] @relation("GroupMemberships")
2240
2288
 
2241
2289
  // Vanity paths
2242
2290
  requestedVanityPaths EventVanityPath[] @relation("VanityRequests")
@@ -2307,9 +2355,9 @@ model UserPreferences {
2307
2355
  showEventPrices Boolean @default(true)
2308
2356
 
2309
2357
  // BashFeed Preferences
2310
- bashFeedDefaultTab String @default("all") // "all", "upcoming", "live", "past", "saved", "my-posts"
2311
- bashFeedDefaultSort String @default("chronological") // "for_you", "chronological", "trending", etc.
2312
- bashFeedFilters Json? // Saved filter preferences as JSON
2358
+ bashFeedDefaultTab String @default("all") // "all", "upcoming", "live", "past", "saved", "my-posts"
2359
+ bashFeedDefaultSort String @default("chronological") // "for_you", "chronological", "trending", etc.
2360
+ bashFeedFilters Json? // Saved filter preferences as JSON
2313
2361
  /// Services discovery: keyed by service type tab, e.g. { "Entertainment": { ... } }
2314
2362
  serviceFilterSettings Json?
2315
2363
  /// Venue discovery filter bar (same pattern as serviceFilterSettings)
@@ -2588,17 +2636,19 @@ model ServiceBlock {
2588
2636
  }
2589
2637
 
2590
2638
  model AssociatedBash {
2591
- id String @id @default(cuid())
2592
- bashEventId String
2593
- invitationId String? @unique
2594
- ownerEmail String?
2595
- ownerUserId String?
2596
- isOrganizer Boolean?
2597
- isDoorStaff Boolean? @default(false)
2598
- bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2599
- invitation Invitation? @relation(fields: [invitationId], references: [id])
2600
- owner User? @relation(fields: [ownerUserId], references: [id], onDelete: Cascade)
2601
- service Service[] @relation("AssociatedBashToService")
2639
+ id String @id @default(cuid())
2640
+ bashEventId String
2641
+ invitationId String? @unique
2642
+ ownerEmail String?
2643
+ ownerUserId String?
2644
+ isOrganizer Boolean?
2645
+ isCoHost Boolean? @default(false)
2646
+ isDoorStaff Boolean? @default(false)
2647
+ organizerTitle String?
2648
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2649
+ invitation Invitation? @relation(fields: [invitationId], references: [id])
2650
+ owner User? @relation(fields: [ownerUserId], references: [id], onDelete: Cascade)
2651
+ service Service[] @relation("AssociatedBashToService")
2602
2652
 
2603
2653
  @@unique([ownerEmail, bashEventId])
2604
2654
  }
@@ -2708,6 +2758,9 @@ model Service {
2708
2758
  verifiedAt DateTime? // When verification was approved
2709
2759
  licenseNumber String? // License/registration number
2710
2760
  certifications String[] @default([]) // Array of certification names
2761
+ /// Custom scope pricing — admin-gated flag for providers who need variable/quote-based pricing
2762
+ customScopeStatus CustomScopeStatus @default(None)
2763
+ customScopeRequestNote String? // Provider's explanation of why they need custom scope
2711
2764
  bashFeedPosts BashFeedPost[]
2712
2765
  bashEventArtists BashEventArtist[]
2713
2766
  bashCreativeSubmissions BashCreativeSubmission[]
@@ -2775,7 +2828,7 @@ model StripeWebhookEvent {
2775
2828
 
2776
2829
  model StripeDispute {
2777
2830
  id String @id @default(cuid())
2778
- stripeChargeId String @unique
2831
+ stripeChargeId String @unique
2779
2832
  createdAt DateTime @default(now())
2780
2833
 
2781
2834
  @@index([stripeChargeId])
@@ -3091,9 +3144,9 @@ model Venue {
3091
3144
  lastMatchNotificationSent DateTime?
3092
3145
 
3093
3146
  /// Venue loyalty program intent (wizard + profile; redemption is future work)
3094
- loyaltyEnabled Boolean @default(false)
3095
- loyaltyTemplateIds String[] @default([])
3096
- loyaltyNotes String?
3147
+ loyaltyEnabled Boolean @default(false)
3148
+ loyaltyTemplateIds String[] @default([])
3149
+ loyaltyNotes String?
3097
3150
 
3098
3151
  bashEvents BashEvent[]
3099
3152
  service Service?
@@ -3166,7 +3219,7 @@ model Organization {
3166
3219
  secondaryVenueTypes String[] @default([])
3167
3220
  baseMembershipPriceCents Int?
3168
3221
  premiumMembershipPriceCents Int?
3169
- membershipBillingInterval String? // one_time | monthly | annual for recurring dues
3222
+ membershipBillingInterval String? // one_time | monthly | annual for recurring dues
3170
3223
  allowGuestsByDefault Boolean @default(false)
3171
3224
  defaultGuestLimit Int @default(0)
3172
3225
  visibility String @default("Public")
@@ -3180,7 +3233,7 @@ model Organization {
3180
3233
  subscriptionStatus String?
3181
3234
  stripeSubscriptionId String? @unique
3182
3235
  stripeCustomerId String?
3183
- stripeConnectedAccountId String? // Org-level Stripe account for wallet display
3236
+ stripeConnectedAccountId String? // Org-level Stripe account for wallet display
3184
3237
  inheritBrandingFromParent Boolean @default(true)
3185
3238
  latitude Float?
3186
3239
  longitude Float?
@@ -3246,24 +3299,24 @@ enum GameStatus {
3246
3299
 
3247
3300
  /// A scheduled or completed game between two team organizations within a league season.
3248
3301
  model Game {
3249
- id String @id @default(cuid())
3250
- seasonId String
3251
- season Season @relation(fields: [seasonId], references: [id], onDelete: Cascade)
3252
- homeTeamId String
3253
- awayTeamId String
3254
- homeTeam Organization @relation("HomeTeamGames", fields: [homeTeamId], references: [id], onDelete: Restrict)
3255
- awayTeam Organization @relation("AwayTeamGames", fields: [awayTeamId], references: [id], onDelete: Restrict)
3256
- scheduledAt DateTime
3257
- venueName String?
3258
- venueStreet String?
3259
- venueCity String?
3260
- venueState String?
3302
+ id String @id @default(cuid())
3303
+ seasonId String
3304
+ season Season @relation(fields: [seasonId], references: [id], onDelete: Cascade)
3305
+ homeTeamId String
3306
+ awayTeamId String
3307
+ homeTeam Organization @relation("HomeTeamGames", fields: [homeTeamId], references: [id], onDelete: Restrict)
3308
+ awayTeam Organization @relation("AwayTeamGames", fields: [awayTeamId], references: [id], onDelete: Restrict)
3309
+ scheduledAt DateTime
3310
+ venueName String?
3311
+ venueStreet String?
3312
+ venueCity String?
3313
+ venueState String?
3261
3314
  venueZipCode String?
3262
- homeScore Int?
3263
- awayScore Int?
3264
- status GameStatus @default(Scheduled)
3265
- createdAt DateTime @default(now())
3266
- updatedAt DateTime @updatedAt
3315
+ homeScore Int?
3316
+ awayScore Int?
3317
+ status GameStatus @default(Scheduled)
3318
+ createdAt DateTime @default(now())
3319
+ updatedAt DateTime @updatedAt
3267
3320
 
3268
3321
  @@index([seasonId])
3269
3322
  @@index([homeTeamId])
@@ -3272,31 +3325,31 @@ model Game {
3272
3325
  }
3273
3326
 
3274
3327
  model OrganizationMember {
3275
- id String @id @default(cuid())
3276
- organizationId String
3277
- userId String
3278
- role String @default("Member") // Owner, Admin, Coordinator, EventOrganizer, Treasurer, Member
3279
- membershipTier String @default("Base") // Base, Premium
3280
- status String @default("Pending") // Pending, Active, Suspended, Removed
3281
- joinedAt DateTime @default(now())
3282
- approvedAt DateTime?
3283
- approvedBy String?
3284
- paidUntil DateTime?
3285
- paymentStatus String? @default("Current") // Current, Overdue, Cancelled
3286
- guestLimit Int?
3287
- canInvite Boolean @default(true)
3288
- canCreateEvents Boolean @default(false)
3289
- canManageBudgets Boolean @default(false)
3290
- engagementScore Float? // Computed: weighted formula (events, recency, points, referrals)
3291
- lastActiveAt DateTime? // Last event attended
3292
- totalEventsAttended Int @default(0)
3293
- firstEventAttendedAt DateTime?
3294
- stripeSubscriptionId String? @unique // Stripe subscription ID for recurring org membership dues
3295
- jerseyNumber String?
3296
- position String?
3297
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
3298
- user User @relation("OrganizationMemberUser", fields: [userId], references: [id], onDelete: Cascade)
3299
- eventRSVPs EventRSVP[]
3328
+ id String @id @default(cuid())
3329
+ organizationId String
3330
+ userId String
3331
+ role String @default("Member") // Owner, Admin, Coordinator, EventOrganizer, Treasurer, Member
3332
+ membershipTier String @default("Base") // Base, Premium
3333
+ status String @default("Pending") // Pending, Active, Suspended, Removed
3334
+ joinedAt DateTime @default(now())
3335
+ approvedAt DateTime?
3336
+ approvedBy String?
3337
+ paidUntil DateTime?
3338
+ paymentStatus String? @default("Current") // Current, Overdue, Cancelled
3339
+ guestLimit Int?
3340
+ canInvite Boolean @default(true)
3341
+ canCreateEvents Boolean @default(false)
3342
+ canManageBudgets Boolean @default(false)
3343
+ engagementScore Float? // Computed: weighted formula (events, recency, points, referrals)
3344
+ lastActiveAt DateTime? // Last event attended
3345
+ totalEventsAttended Int @default(0)
3346
+ firstEventAttendedAt DateTime?
3347
+ stripeSubscriptionId String? @unique // Stripe subscription ID for recurring org membership dues
3348
+ jerseyNumber String?
3349
+ position String?
3350
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
3351
+ user User @relation("OrganizationMemberUser", fields: [userId], references: [id], onDelete: Cascade)
3352
+ eventRSVPs EventRSVP[]
3300
3353
  notificationPreferences OrganizationMemberPreferences?
3301
3354
 
3302
3355
  @@unique([organizationId, userId])
@@ -3308,20 +3361,20 @@ model OrganizationMember {
3308
3361
 
3309
3362
  /// Per-member notification toggles for organization channels (1:1 with OrganizationMember).
3310
3363
  model OrganizationMemberPreferences {
3311
- id String @id @default(cuid())
3312
- organizationMemberId String @unique
3313
- announcements Boolean @default(true)
3314
- eventReminders Boolean @default(true)
3315
- eventUpdates Boolean @default(true)
3316
- budgetAlerts Boolean @default(true)
3317
- proposalNotifications Boolean @default(true)
3318
- taskAssignments Boolean @default(true)
3319
- membershipUpdates Boolean @default(true)
3320
- emailNotifications Boolean @default(true)
3321
- pushNotifications Boolean @default(true)
3322
- createdAt DateTime @default(now())
3323
- updatedAt DateTime @updatedAt
3324
- organizationMember OrganizationMember @relation(fields: [organizationMemberId], references: [id], onDelete: Cascade)
3364
+ id String @id @default(cuid())
3365
+ organizationMemberId String @unique
3366
+ announcements Boolean @default(true)
3367
+ eventReminders Boolean @default(true)
3368
+ eventUpdates Boolean @default(true)
3369
+ budgetAlerts Boolean @default(true)
3370
+ proposalNotifications Boolean @default(true)
3371
+ taskAssignments Boolean @default(true)
3372
+ membershipUpdates Boolean @default(true)
3373
+ emailNotifications Boolean @default(true)
3374
+ pushNotifications Boolean @default(true)
3375
+ createdAt DateTime @default(now())
3376
+ updatedAt DateTime @updatedAt
3377
+ organizationMember OrganizationMember @relation(fields: [organizationMemberId], references: [id], onDelete: Cascade)
3325
3378
 
3326
3379
  @@index([organizationMemberId])
3327
3380
  }
@@ -3707,47 +3760,47 @@ model ServiceBookingCheckout {
3707
3760
  }
3708
3761
 
3709
3762
  model ServiceBooking {
3710
- id String @id @default(cuid())
3763
+ id String @id @default(cuid())
3711
3764
  creatorId String
3712
3765
  forUserId String
3713
3766
  daysTotalATBCents Int
3714
3767
  serviceId String
3715
- rateOption ServiceBookingRateOption @default(TimeBased)
3768
+ rateOption ServiceBookingRateOption @default(TimeBased)
3716
3769
  flatRateCents Int?
3717
- status ServiceBookingStatus @default(Pending)
3718
- bookingType ServiceBookingType @default(Request)
3770
+ status ServiceBookingStatus @default(Pending)
3771
+ bookingType ServiceBookingType @default(Request)
3719
3772
  timezone String
3720
3773
  requestedOn DateTime?
3721
3774
  requestDecisionOn DateTime?
3722
3775
  bookedOn DateTime?
3723
3776
  canceledOn DateTime?
3724
- isFreeGuest Boolean @default(false)
3725
- allowPromiseToPay Boolean @default(false)
3777
+ isFreeGuest Boolean @default(false)
3778
+ allowPromiseToPay Boolean @default(false)
3726
3779
  totalATBCents Int
3727
- subtotalATBCents Int @default(0)
3780
+ subtotalATBCents Int @default(0)
3728
3781
  bashEventId String?
3729
- isVendorBid Boolean @default(false)
3782
+ isVendorBid Boolean @default(false)
3730
3783
  vendorBidAmountCents Int?
3731
3784
  vendorEventDetails String?
3732
3785
  bashPointsApplied Int? // BashPoints credits applied to this booking
3733
3786
  bashPointsTransactionId String? // Link to BashCreditTransaction
3734
3787
  // Settlement fields for percentage-based bookings (populated at event close)
3735
- settlementBasis ServiceBookingSettlementBasis?
3736
- settlementPercentage Decimal?
3737
- settlementAmountCents Int?
3738
- settledAt DateTime?
3788
+ settlementBasis ServiceBookingSettlementBasis?
3789
+ settlementPercentage Decimal?
3790
+ settlementAmountCents Int?
3791
+ settledAt DateTime?
3739
3792
  notification Notification[]
3740
- bashEvent BashEvent? @relation(fields: [bashEventId], references: [id])
3741
- creator User @relation("BookingCreator", fields: [creatorId], references: [id])
3742
- forUser User @relation("BookingForUser", fields: [forUserId], references: [id])
3743
- service Service @relation(fields: [serviceId], references: [id])
3793
+ bashEvent BashEvent? @relation(fields: [bashEventId], references: [id])
3794
+ creator User @relation("BookingCreator", fields: [creatorId], references: [id])
3795
+ forUser User @relation("BookingForUser", fields: [forUserId], references: [id])
3796
+ service Service @relation(fields: [serviceId], references: [id])
3744
3797
  addOns ServiceBookingAddOn[]
3745
3798
  checkout ServiceBookingCheckout?
3746
3799
  bookedDays ServiceBookingDay[]
3747
3800
  additionalFees ServiceBookingFee[]
3748
3801
  messages ServiceBookingMessage[]
3749
3802
  packages ServiceBookingPackage[]
3750
- commissions BookingCommission[] @relation("BookingCommissions")
3803
+ commissions BookingCommission[] @relation("BookingCommissions")
3751
3804
  sentReminders SentReminder[]
3752
3805
 
3753
3806
  @@index([status])
@@ -4088,21 +4141,21 @@ model BashSlugHistory {
4088
4141
  }
4089
4142
 
4090
4143
  model BashEventTransferRequest {
4091
- id String @id @default(cuid())
4092
- bashEventId String
4093
- fromUserId String
4094
- toUserId String? // null when transferring to a non-user by email
4095
- toEmail String? // set when toUserId is null (non-user invite transfer)
4096
- inviteToken String? @unique // secure token embedded in the signup/claim link
4097
- keepPayoutsWithMe Boolean @default(false) // when true, creator keeps receiving payouts after transfer
4098
- status TransferRequestStatus @default(Pending)
4099
- reason String?
4100
- requestedAt DateTime @default(now())
4101
- respondedAt DateTime?
4102
- expiresAt DateTime
4103
- bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
4104
- fromUser User @relation("TransferRequestsFrom", fields: [fromUserId], references: [id], onDelete: Cascade)
4105
- toUser User? @relation("TransferRequestsTo", fields: [toUserId], references: [id], onDelete: Cascade)
4144
+ id String @id @default(cuid())
4145
+ bashEventId String
4146
+ fromUserId String
4147
+ toUserId String? // null when transferring to a non-user by email
4148
+ toEmail String? // set when toUserId is null (non-user invite transfer)
4149
+ inviteToken String? @unique // secure token embedded in the signup/claim link
4150
+ keepPayoutsWithMe Boolean @default(false) // when true, creator keeps receiving payouts after transfer
4151
+ status TransferRequestStatus @default(Pending)
4152
+ reason String?
4153
+ requestedAt DateTime @default(now())
4154
+ respondedAt DateTime?
4155
+ expiresAt DateTime
4156
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
4157
+ fromUser User @relation("TransferRequestsFrom", fields: [fromUserId], references: [id], onDelete: Cascade)
4158
+ toUser User? @relation("TransferRequestsTo", fields: [toUserId], references: [id], onDelete: Cascade)
4106
4159
 
4107
4160
  @@index([bashEventId])
4108
4161
  @@index([toUserId, status])
@@ -4348,23 +4401,23 @@ enum NotificationType {
4348
4401
  BashRatingMilestone
4349
4402
  BashFeedPost
4350
4403
  EventMilestone
4351
- WaitlistRequested // Host: someone requested a spot on your waitlist
4352
- WaitlistApproved // Attendee: host approved your waitlist request
4353
- WaitlistDenied // Attendee: host denied your waitlist request
4404
+ WaitlistRequested // Host: someone requested a spot on your waitlist
4405
+ WaitlistApproved // Attendee: host approved your waitlist request
4406
+ WaitlistDenied // Attendee: host denied your waitlist request
4354
4407
  WaitlistSpotAvailable // Waitlister: a refund opened a spot — claim it now
4355
4408
  WaitlistSpotMayBeOpen // Waitlister: someone left the venue — standby at door
4356
4409
  // Group notifications
4357
- GroupMemberPurchased // Owner: "Riley just bought a ticket — 2 more to go!"
4358
- GroupEveryoneConfirmed // Owner: "All members want to attend. Buy tickets together?"
4359
- GroupEveryonePurchased // Owner: "Your group is officially attending"
4360
- GroupMemberJoined // Owner: "Alex joined your group"
4361
- FriendsAttending // User: "3 of your friends are attending this bash"
4362
- GroupRewardProgress // Member: "Only 2 more friends needed for your group reward"
4363
- GroupUnlockOfferReceived // Member: "Special offer unlocked for your group"
4364
- HostSalesAccelerating // Host: "Your event sales increased 38% today"
4365
- HostTopPromoter // Host: "Top promoter: Alex (6 tickets today)"
4366
- HostSalesSlowing // Host: "Sales slowed today. Try sharing your event."
4367
- TicketSold // Host: a ticket was purchased for your event (debounced in webhook)
4410
+ GroupMemberPurchased // Owner: "Riley just bought a ticket — 2 more to go!"
4411
+ GroupEveryoneConfirmed // Owner: "All members want to attend. Buy tickets together?"
4412
+ GroupEveryonePurchased // Owner: "Your group is officially attending"
4413
+ GroupMemberJoined // Owner: "Alex joined your group"
4414
+ FriendsAttending // User: "3 of your friends are attending this bash"
4415
+ GroupRewardProgress // Member: "Only 2 more friends needed for your group reward"
4416
+ GroupUnlockOfferReceived // Member: "Special offer unlocked for your group"
4417
+ HostSalesAccelerating // Host: "Your event sales increased 38% today"
4418
+ HostTopPromoter // Host: "Top promoter: Alex (6 tickets today)"
4419
+ HostSalesSlowing // Host: "Sales slowed today. Try sharing your event."
4420
+ TicketSold // Host: a ticket was purchased for your event (debounced in webhook)
4368
4421
  }
4369
4422
 
4370
4423
  enum NotificationPriority {
@@ -4392,7 +4445,7 @@ enum BashEventSource {
4392
4445
  Meetup
4393
4446
  Facebook
4394
4447
  JamWith
4395
- Partner // Generic: use sourcePartnerId for partner key (e.g. 'mixlog', custom integrations)
4448
+ Partner // Generic: use sourcePartnerId for partner key (e.g. 'mixlog', custom integrations)
4396
4449
  }
4397
4450
 
4398
4451
  enum TicketStatus {
@@ -4403,7 +4456,7 @@ enum TicketStatus {
4403
4456
  LeftRadius
4404
4457
  Pending
4405
4458
  WaitlistPending // Requested a spot on a host-approval waitlist; awaiting decision
4406
- RefundPending // Refund requested; held while next waitlister is given a claim window
4459
+ RefundPending // Refund requested; held while next waitlister is given a claim window
4407
4460
  }
4408
4461
 
4409
4462
  enum DayOfWeek {
@@ -4662,6 +4715,35 @@ enum BashStatus {
4662
4715
  Archived // Unclaimed after expiration
4663
4716
  }
4664
4717
 
4718
+ /// Minimum-age policy for a bash. Used by the BashCard pill, discover filters,
4719
+ /// and (when 18+/21+) age verification at ticket checkout.
4720
+ enum AgePolicy {
4721
+ AllAges
4722
+ EighteenPlus
4723
+ TwentyOnePlus
4724
+ }
4725
+
4726
+ /// Retention policy for a user's stored government-ID image (drives expireIdImages cron + GDPR consent record)
4727
+ enum GovIdRetentionPolicy {
4728
+ ThirtyDays
4729
+ UntilIdExpires
4730
+ Indefinite
4731
+ }
4732
+
4733
+ /// Whether the user's `schoolName` was extracted by the AI vision model or confirmed/edited by the user
4734
+ enum SchoolNameSource {
4735
+ AiInferred
4736
+ UserConfirmed
4737
+ }
4738
+
4739
+ /// Admin-gated custom-scope pricing flag for service providers needing variable/quote-based pricing
4740
+ enum CustomScopeStatus {
4741
+ None
4742
+ Pending
4743
+ Approved
4744
+ Rejected
4745
+ }
4746
+
4665
4747
  /// How a user is associated with a bash (for BashFeedPost display: "Sarah attended...", "Mike is hosting...")
4666
4748
  enum BashAssociationType {
4667
4749
  Hosting
@@ -6408,30 +6490,30 @@ enum ConsentType {
6408
6490
 
6409
6491
  // Birthday offers from partner companies: users opt in once, we send minimal PII to partner APIs
6410
6492
  model BirthdayOfferPartner {
6411
- id String @id @default(cuid())
6412
- name String
6413
- slug String @unique
6414
- description String? @db.Text
6415
- apiEndpoint String // Partner API URL; API keys live in env (BIRTHDAY_PARTNER_<SLUG>_API_KEY)
6416
- config Json? // Partner-specific: e.g. sendFullDob (bool), extra fields
6417
- requiresPhone Boolean @default(false) // Part B: when true, share User.phone with partner
6418
- isActive Boolean @default(true)
6419
- createdAt DateTime @default(now())
6420
- updatedAt DateTime @updatedAt
6421
- optIns UserBirthdayOfferOptIn[]
6422
- deliveries BirthdayOfferDelivery[]
6493
+ id String @id @default(cuid())
6494
+ name String
6495
+ slug String @unique
6496
+ description String? @db.Text
6497
+ apiEndpoint String // Partner API URL; API keys live in env (BIRTHDAY_PARTNER_<SLUG>_API_KEY)
6498
+ config Json? // Partner-specific: e.g. sendFullDob (bool), extra fields
6499
+ requiresPhone Boolean @default(false) // Part B: when true, share User.phone with partner
6500
+ isActive Boolean @default(true)
6501
+ createdAt DateTime @default(now())
6502
+ updatedAt DateTime @updatedAt
6503
+ optIns UserBirthdayOfferOptIn[]
6504
+ deliveries BirthdayOfferDelivery[]
6423
6505
  catalogEntries BirthdayFreebieCatalog[]
6424
6506
 
6425
6507
  @@index([isActive])
6426
6508
  }
6427
6509
 
6428
6510
  model UserBirthdayOfferOptIn {
6429
- id String @id @default(cuid())
6511
+ id String @id @default(cuid())
6430
6512
  userId String
6431
6513
  partnerId String
6432
- optedInAt DateTime @default(now())
6514
+ optedInAt DateTime @default(now())
6433
6515
  lastSentAt DateTime? // Last time we sent this user to this partner (for idempotency)
6434
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6516
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6435
6517
  partner BirthdayOfferPartner @relation(fields: [partnerId], references: [id], onDelete: Cascade)
6436
6518
 
6437
6519
  @@unique([userId, partnerId])
@@ -6440,12 +6522,12 @@ model UserBirthdayOfferOptIn {
6440
6522
  }
6441
6523
 
6442
6524
  model BirthdayOfferDelivery {
6443
- id String @id @default(cuid())
6525
+ id String @id @default(cuid())
6444
6526
  userId String
6445
6527
  partnerId String
6446
- birthdayYear Int // Year when the send counted (for idempotency: one send per user/partner/year)
6447
- sentAt DateTime @default(now())
6448
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6528
+ birthdayYear Int // Year when the send counted (for idempotency: one send per user/partner/year)
6529
+ sentAt DateTime @default(now())
6530
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6449
6531
  partner BirthdayOfferPartner @relation(fields: [partnerId], references: [id], onDelete: Cascade)
6450
6532
 
6451
6533
  @@unique([userId, partnerId, birthdayYear])
@@ -6455,11 +6537,11 @@ model BirthdayOfferDelivery {
6455
6537
 
6456
6538
  // Birthday Rewards focused scope (v1): annual BashPoints boost idempotency
6457
6539
  model BirthdayBoostGrant {
6458
- id String @id @default(cuid())
6459
- userId String
6460
- birthdayYear Int // Year for which boost was granted
6461
- grantedAt DateTime @default(now())
6462
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6540
+ id String @id @default(cuid())
6541
+ userId String
6542
+ birthdayYear Int // Year for which boost was granted
6543
+ grantedAt DateTime @default(now())
6544
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6463
6545
 
6464
6546
  @@unique([userId, birthdayYear])
6465
6547
  @@index([userId])
@@ -6481,21 +6563,21 @@ model BirthdayRewardFavorite {
6481
6563
 
6482
6564
  // User-recorded places where they picked up a birthday reward (with optional rating)
6483
6565
  model BirthdayRewardRedemption {
6484
- id String @id @default(cuid())
6566
+ id String @id @default(cuid())
6485
6567
  userId String
6486
- placeName String // e.g. "Freddy's", "Starbucks"
6487
- redeemedAt DateTime @default(now())
6568
+ placeName String // e.g. "Freddy's", "Starbucks"
6569
+ redeemedAt DateTime @default(now())
6488
6570
  birthdayYear Int
6489
- notes String? @db.Text
6490
- difficultyScore Int? // 1-10
6491
- qualityScore Int? // 1-10
6492
- ratingComment String? @db.Text
6571
+ notes String? @db.Text
6572
+ difficultyScore Int? // 1-10
6573
+ qualityScore Int? // 1-10
6574
+ ratingComment String? @db.Text
6493
6575
  ratedAt DateTime?
6494
- offerId String? // Part B: optional FK to structured BirthdayOffer
6576
+ offerId String? // Part B: optional FK to structured BirthdayOffer
6495
6577
  /// Catalog or national reward id when marked picked up from the freebies guide
6496
6578
  catalogId String?
6497
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6498
- offer BirthdayOffer? @relation(fields: [offerId], references: [id], onDelete: SetNull)
6579
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6580
+ offer BirthdayOffer? @relation(fields: [offerId], references: [id], onDelete: SetNull)
6499
6581
  catalog BirthdayFreebieCatalog? @relation(fields: [catalogId], references: [id], onDelete: SetNull)
6500
6582
 
6501
6583
  @@index([userId])
@@ -6506,13 +6588,13 @@ model BirthdayRewardRedemption {
6506
6588
 
6507
6589
  /// Logged-in user's saved "My Birthday Plan" offer ids + location context (separate from Part B generated BirthdayPlan).
6508
6590
  model BirthdayFreebiesSavedPlan {
6509
- id String @id @default(cuid())
6510
- userId String @unique
6511
- planIds String[] @default([])
6512
- stateSlug String?
6513
- citySlug String?
6514
- updatedAt DateTime @updatedAt
6515
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6591
+ id String @id @default(cuid())
6592
+ userId String @unique
6593
+ planIds String[] @default([])
6594
+ stateSlug String?
6595
+ citySlug String?
6596
+ updatedAt DateTime @updatedAt
6597
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6516
6598
  }
6517
6599
 
6518
6600
  enum BirthdayDealSuggestionStatus {
@@ -6523,22 +6605,22 @@ enum BirthdayDealSuggestionStatus {
6523
6605
 
6524
6606
  // User-suggested birthday deals (admin can approve and add to catalog later)
6525
6607
  model BirthdayDealSuggestion {
6526
- id String @id @default(cuid())
6527
- userId String
6528
- brandOrPlaceName String
6529
- dealDescription String @db.Text
6530
- sourceWhereHeard String? @db.Text
6531
- linkUrl String? @db.Text
6532
- suggestedQualityTier BirthdayOfferQualityTier? // Suggester's experience: Awesome, Okay, or Lame
6533
- signupDaysInAdvance Int? // When requiresAdvanceSignup: how many days before birthday
6608
+ id String @id @default(cuid())
6609
+ userId String
6610
+ brandOrPlaceName String
6611
+ dealDescription String @db.Text
6612
+ sourceWhereHeard String? @db.Text
6613
+ linkUrl String? @db.Text
6614
+ suggestedQualityTier BirthdayOfferQualityTier? // Suggester's experience: Awesome, Okay, or Lame
6615
+ signupDaysInAdvance Int? // When requiresAdvanceSignup: how many days before birthday
6534
6616
  /// User-selected expiration hint while the suggestion is pending (mirrors catalog enum)
6535
6617
  suggestedExpirationType BirthdayFreebieExpirationType?
6536
- status BirthdayDealSuggestionStatus @default(Pending)
6537
- createdAt DateTime @default(now())
6538
- reviewedAt DateTime?
6539
- reviewedById String?
6540
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6541
- catalogEntry BirthdayFreebieCatalog?
6618
+ status BirthdayDealSuggestionStatus @default(Pending)
6619
+ createdAt DateTime @default(now())
6620
+ reviewedAt DateTime?
6621
+ reviewedById String?
6622
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6623
+ catalogEntry BirthdayFreebieCatalog?
6542
6624
 
6543
6625
  @@index([userId])
6544
6626
  @@index([status])
@@ -6580,38 +6662,38 @@ enum BirthdayFreebieSector {
6580
6662
  }
6581
6663
 
6582
6664
  model BirthdayFreebieCatalog {
6583
- id String @id @default(cuid())
6665
+ id String @id @default(cuid())
6584
6666
  brandOrPlaceName String
6585
- description String? @db.Text
6586
- logoUrl String? @db.Text
6587
- sector BirthdayFreebieSector @default(Other)
6667
+ description String? @db.Text
6668
+ logoUrl String? @db.Text
6669
+ sector BirthdayFreebieSector @default(Other)
6588
6670
  category BirthdayFreebieCategory
6589
6671
  expirationType BirthdayFreebieExpirationType
6590
6672
  lastVerifiedAt DateTime
6591
- requiresAdvanceSignup Boolean? @default(false)
6673
+ requiresAdvanceSignup Boolean? @default(false)
6592
6674
  source BirthdayFreebieSource
6593
6675
  partnerId String?
6594
- suggestionId String? @unique // one-to-one: at most one catalog entry per suggestion
6676
+ suggestionId String? @unique // one-to-one: at most one catalog entry per suggestion
6595
6677
  stateSlug String
6596
6678
  citySlug String?
6597
- isActive Boolean @default(true)
6598
- signupUrl String? @db.Text // Official "how to redeem" / terms link
6599
- sourceUrl String? @db.Text // Optional: reference source (e.g. NerdWallet, Krazy Coupon Lady)
6600
- appRequired Boolean @default(false)
6601
- priority Int @default(0) // Tie-break sort
6679
+ isActive Boolean @default(true)
6680
+ signupUrl String? @db.Text // Official "how to redeem" / terms link
6681
+ sourceUrl String? @db.Text // Optional: reference source (e.g. NerdWallet, Krazy Coupon Lady)
6682
+ appRequired Boolean @default(false)
6683
+ priority Int @default(0) // Tie-break sort
6602
6684
  qualityTier BirthdayOfferQualityTier? // Awesome / Okay / Lame — set by super users on approve
6603
- address String? @db.Text // For Maps and display
6604
- redemptionNotes String? @db.Text // Conditions, limitations
6605
- expirationDays Int? // when Valid30Days with custom count
6606
- isNational Boolean @default(false)
6607
- createdAt DateTime @default(now())
6608
- updatedAt DateTime @updatedAt
6609
-
6610
- partner BirthdayOfferPartner? @relation(fields: [partnerId], references: [id], onDelete: SetNull)
6611
- suggestion BirthdayDealSuggestion? @relation(fields: [suggestionId], references: [id], onDelete: SetNull)
6612
- rewardReports RewardReport[]
6685
+ address String? @db.Text // For Maps and display
6686
+ redemptionNotes String? @db.Text // Conditions, limitations
6687
+ expirationDays Int? // when Valid30Days with custom count
6688
+ isNational Boolean @default(false)
6689
+ createdAt DateTime @default(now())
6690
+ updatedAt DateTime @updatedAt
6691
+
6692
+ partner BirthdayOfferPartner? @relation(fields: [partnerId], references: [id], onDelete: SetNull)
6693
+ suggestion BirthdayDealSuggestion? @relation(fields: [suggestionId], references: [id], onDelete: SetNull)
6694
+ rewardReports RewardReport[]
6613
6695
  /// User quality votes (Awesome / Okay / Lame); one row per user per catalog entry.
6614
- votes BirthdayFreebieVote[]
6696
+ votes BirthdayFreebieVote[]
6615
6697
  birthdayRewardRedemptions BirthdayRewardRedemption[]
6616
6698
 
6617
6699
  @@index([stateSlug, citySlug])
@@ -6622,12 +6704,12 @@ model BirthdayFreebieCatalog {
6622
6704
 
6623
6705
  /// User quality vote on a catalog entry (Awesome / Okay / Lame). Drives aggregate counts and optional qualityTier updates.
6624
6706
  model BirthdayFreebieVote {
6625
- id String @id @default(cuid())
6707
+ id String @id @default(cuid())
6626
6708
  catalogId String
6627
6709
  userId String
6628
6710
  tier BirthdayOfferQualityTier
6629
- createdAt DateTime @default(now())
6630
- updatedAt DateTime @updatedAt
6711
+ createdAt DateTime @default(now())
6712
+ updatedAt DateTime @updatedAt
6631
6713
 
6632
6714
  catalog BirthdayFreebieCatalog @relation(fields: [catalogId], references: [id], onDelete: Cascade)
6633
6715
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@ -6645,15 +6727,15 @@ enum BirthdayCityResourceType {
6645
6727
  }
6646
6728
 
6647
6729
  model BirthdayCityResource {
6648
- id String @id @default(cuid())
6649
- stateSlug String
6650
- citySlug String? // null = state-level resource
6651
- type BirthdayCityResourceType
6652
- label String // e.g. "Visit Salt Lake events"
6653
- url String @db.Text
6654
- sortOrder Int @default(0)
6655
- createdAt DateTime @default(now())
6656
- updatedAt DateTime @updatedAt
6730
+ id String @id @default(cuid())
6731
+ stateSlug String
6732
+ citySlug String? // null = state-level resource
6733
+ type BirthdayCityResourceType
6734
+ label String // e.g. "Visit Salt Lake events"
6735
+ url String @db.Text
6736
+ sortOrder Int @default(0)
6737
+ createdAt DateTime @default(now())
6738
+ updatedAt DateTime @updatedAt
6657
6739
  suggestionCreatedFor BirthdayCityResourceSuggestion? @relation("CityResourceFromSuggestion")
6658
6740
 
6659
6741
  @@index([stateSlug, citySlug])
@@ -6667,21 +6749,21 @@ enum BirthdayCityResourceSuggestionStatus {
6667
6749
 
6668
6750
  // User-suggested "free things to do" links — admin approves into BirthdayCityResource
6669
6751
  model BirthdayCityResourceSuggestion {
6670
- id String @id @default(cuid())
6752
+ id String @id @default(cuid())
6671
6753
  stateSlug String
6672
6754
  citySlug String
6673
- url String @db.Text
6674
- label String? @db.Text
6675
- notes String? @db.Text
6676
- contactEmail String? @db.Text
6755
+ url String @db.Text
6756
+ label String? @db.Text
6757
+ notes String? @db.Text
6758
+ contactEmail String? @db.Text
6677
6759
  userId String?
6678
6760
  status BirthdayCityResourceSuggestionStatus @default(Pending)
6679
- createdAt DateTime @default(now())
6761
+ createdAt DateTime @default(now())
6680
6762
  reviewedAt DateTime?
6681
6763
  reviewedById String?
6682
- createdResourceId String? @unique
6683
- user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
6684
- createdResource BirthdayCityResource? @relation("CityResourceFromSuggestion", fields: [createdResourceId], references: [id], onDelete: SetNull)
6764
+ createdResourceId String? @unique
6765
+ user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
6766
+ createdResource BirthdayCityResource? @relation("CityResourceFromSuggestion", fields: [createdResourceId], references: [id], onDelete: SetNull)
6685
6767
 
6686
6768
  @@index([status])
6687
6769
  @@index([stateSlug, citySlug])
@@ -6694,18 +6776,18 @@ enum RewardReportStatus {
6694
6776
  }
6695
6777
 
6696
6778
  model RewardReport {
6697
- id String @id @default(cuid())
6698
- catalogId String
6699
- userId String
6700
- reportedAt DateTime @default(now())
6701
- reason String @db.Text
6702
- suggestedChanges String? @db.Text
6703
- status RewardReportStatus @default(Pending)
6704
- reviewedAt DateTime?
6705
- reviewedById String?
6706
- catalog BirthdayFreebieCatalog @relation(fields: [catalogId], references: [id], onDelete: Cascade)
6707
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6708
- reviewedBy User? @relation("RewardReportReviewedBy", fields: [reviewedById], references: [id], onDelete: SetNull)
6779
+ id String @id @default(cuid())
6780
+ catalogId String
6781
+ userId String
6782
+ reportedAt DateTime @default(now())
6783
+ reason String @db.Text
6784
+ suggestedChanges String? @db.Text
6785
+ status RewardReportStatus @default(Pending)
6786
+ reviewedAt DateTime?
6787
+ reviewedById String?
6788
+ catalog BirthdayFreebieCatalog @relation(fields: [catalogId], references: [id], onDelete: Cascade)
6789
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6790
+ reviewedBy User? @relation("RewardReportReviewedBy", fields: [reviewedById], references: [id], onDelete: SetNull)
6709
6791
 
6710
6792
  @@index([catalogId])
6711
6793
  @@index([userId])
@@ -6714,18 +6796,18 @@ model RewardReport {
6714
6796
 
6715
6797
  /// Reports on hard-coded national chains (nationalBirthdayRewards.ts). Super users review and update the file.
6716
6798
  model NationalChainReport {
6717
- id String @id @default(cuid())
6718
- nationalBrandId String // e.g. "national-starbucks" — id from NATIONAL_BIRTHDAY_REWARDS
6719
- nationalBrandName String // Denormalized for display
6720
- userId String
6721
- reportedAt DateTime @default(now())
6722
- reason String @db.Text
6723
- suggestedChanges String? @db.Text
6724
- status RewardReportStatus @default(Pending)
6725
- reviewedAt DateTime?
6726
- reviewedById String?
6727
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6728
- reviewedBy User? @relation("NationalChainReportReviewedBy", fields: [reviewedById], references: [id], onDelete: SetNull)
6799
+ id String @id @default(cuid())
6800
+ nationalBrandId String // e.g. "national-starbucks" — id from NATIONAL_BIRTHDAY_REWARDS
6801
+ nationalBrandName String // Denormalized for display
6802
+ userId String
6803
+ reportedAt DateTime @default(now())
6804
+ reason String @db.Text
6805
+ suggestedChanges String? @db.Text
6806
+ status RewardReportStatus @default(Pending)
6807
+ reviewedAt DateTime?
6808
+ reviewedById String?
6809
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6810
+ reviewedBy User? @relation("NationalChainReportReviewedBy", fields: [reviewedById], references: [id], onDelete: SetNull)
6729
6811
 
6730
6812
  @@index([nationalBrandId])
6731
6813
  @@index([userId])
@@ -6734,22 +6816,22 @@ model NationalChainReport {
6734
6816
 
6735
6817
  // Part B: User saved locations (birthday home base, etc.)
6736
6818
  model UserLocation {
6737
- id String @id @default(cuid())
6738
- userId String
6739
- label String? // e.g. "Home", "Work"
6740
- address1 String
6741
- address2 String?
6742
- city String
6743
- state String
6744
- zip String
6745
- country String? @default("US")
6746
- lat Float?
6747
- lng Float?
6748
- isDefault Boolean? @default(false)
6749
- createdAt DateTime @default(now())
6750
- updatedAt DateTime @updatedAt
6751
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6752
- usersWithBirthdayLocation User[] @relation("UserBirthdayLocation")
6819
+ id String @id @default(cuid())
6820
+ userId String
6821
+ label String? // e.g. "Home", "Work"
6822
+ address1 String
6823
+ address2 String?
6824
+ city String
6825
+ state String
6826
+ zip String
6827
+ country String? @default("US")
6828
+ lat Float?
6829
+ lng Float?
6830
+ isDefault Boolean? @default(false)
6831
+ createdAt DateTime @default(now())
6832
+ updatedAt DateTime @updatedAt
6833
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6834
+ usersWithBirthdayLocation User[] @relation("UserBirthdayLocation")
6753
6835
 
6754
6836
  @@index([userId])
6755
6837
  }
@@ -6763,7 +6845,7 @@ enum RedemptionMethod {
6763
6845
  }
6764
6846
 
6765
6847
  enum BirthdayOfferExpirationType {
6766
- DAY_OF // End of birthday day
6848
+ DAY_OF // End of birthday day
6767
6849
  DAYS_FROM_BDAY
6768
6850
  END_OF_MONTH
6769
6851
  VARIABLE
@@ -6784,14 +6866,14 @@ enum OfferClaimStatus {
6784
6866
  }
6785
6867
 
6786
6868
  model Brand {
6787
- id String @id @default(cuid())
6869
+ id String @id @default(cuid())
6788
6870
  name String
6789
- websiteUrl String? @db.Text
6790
- logoUrl String? @db.Text
6791
- categoryDefault String? // restaurant, coffee, dessert, retail, entertainment
6792
- isNational Boolean @default(true)
6793
- createdAt DateTime @default(now())
6794
- updatedAt DateTime @updatedAt
6871
+ websiteUrl String? @db.Text
6872
+ logoUrl String? @db.Text
6873
+ categoryDefault String? // restaurant, coffee, dessert, retail, entertainment
6874
+ isNational Boolean @default(true)
6875
+ createdAt DateTime @default(now())
6876
+ updatedAt DateTime @updatedAt
6795
6877
  offers BirthdayOffer[]
6796
6878
  locations BrandLocation[]
6797
6879
 
@@ -6799,28 +6881,28 @@ model Brand {
6799
6881
  }
6800
6882
 
6801
6883
  model BirthdayOffer {
6802
- id String @id @default(cuid())
6884
+ id String @id @default(cuid())
6803
6885
  brandId String
6804
- title String // e.g. "Free burger reward"
6805
- descriptionShort String? @db.Text
6806
- purchaseRequired Boolean @default(false)
6807
- signupRequired Boolean @default(false)
6808
- appRequired Boolean @default(false)
6809
- requiresPhone Boolean @default(false)
6886
+ title String // e.g. "Free burger reward"
6887
+ descriptionShort String? @db.Text
6888
+ purchaseRequired Boolean @default(false)
6889
+ signupRequired Boolean @default(false)
6890
+ appRequired Boolean @default(false)
6891
+ requiresPhone Boolean @default(false)
6810
6892
  redemptionMethod RedemptionMethod
6811
6893
  expirationType BirthdayOfferExpirationType
6812
- expirationDays Int? // when expirationType = DAYS_FROM_BDAY
6813
- windowStartOffsetDays Int @default(0)
6814
- termsUrl String? @db.Text
6815
- termsNotes String? @db.Text
6894
+ expirationDays Int? // when expirationType = DAYS_FROM_BDAY
6895
+ windowStartOffsetDays Int @default(0)
6896
+ termsUrl String? @db.Text
6897
+ termsNotes String? @db.Text
6816
6898
  sourceType BirthdayOfferSourceType
6817
6899
  lastVerifiedAt DateTime?
6818
- isActive Boolean @default(true)
6819
- priorityScore Int @default(0)
6820
- featuredUntil DateTime?
6821
- createdAt DateTime @default(now())
6822
- updatedAt DateTime @updatedAt
6823
- brand Brand @relation(fields: [brandId], references: [id], onDelete: Cascade)
6900
+ isActive Boolean @default(true)
6901
+ priorityScore Int @default(0)
6902
+ featuredUntil DateTime?
6903
+ createdAt DateTime @default(now())
6904
+ updatedAt DateTime @updatedAt
6905
+ brand Brand @relation(fields: [brandId], references: [id], onDelete: Cascade)
6824
6906
  claims OfferClaim[]
6825
6907
  redemptions BirthdayRewardRedemption[]
6826
6908
 
@@ -6849,15 +6931,15 @@ model BrandLocation {
6849
6931
  }
6850
6932
 
6851
6933
  model OfferClaim {
6852
- id String @id @default(cuid())
6853
- userId String
6854
- birthdayOfferId String
6855
- claimedAt DateTime @default(now())
6856
- birthdayYear Int
6857
- status OfferClaimStatus
6858
- meta Json?
6859
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6860
- birthdayOffer BirthdayOffer @relation(fields: [birthdayOfferId], references: [id], onDelete: Cascade)
6934
+ id String @id @default(cuid())
6935
+ userId String
6936
+ birthdayOfferId String
6937
+ claimedAt DateTime @default(now())
6938
+ birthdayYear Int
6939
+ status OfferClaimStatus
6940
+ meta Json?
6941
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6942
+ birthdayOffer BirthdayOffer @relation(fields: [birthdayOfferId], references: [id], onDelete: Cascade)
6861
6943
 
6862
6944
  @@index([userId])
6863
6945
  @@index([birthdayOfferId])
@@ -6865,15 +6947,15 @@ model OfferClaim {
6865
6947
  }
6866
6948
 
6867
6949
  model BirthdayPlan {
6868
- id String @id @default(cuid())
6869
- userId String
6870
- birthdayYear Int
6871
- generatedAt DateTime @default(now())
6872
- preferencesSnapshot Json // distance, filters, optimizeFor
6873
- items Json // ordered stops: plannedDate, brandId, offerId, locationId?, distanceFromHome, deadline, purchaseRequired
6874
- validFrom DateTime
6875
- validTo DateTime
6876
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6950
+ id String @id @default(cuid())
6951
+ userId String
6952
+ birthdayYear Int
6953
+ generatedAt DateTime @default(now())
6954
+ preferencesSnapshot Json // distance, filters, optimizeFor
6955
+ items Json // ordered stops: plannedDate, brandId, offerId, locationId?, distanceFromHome, deadline, purchaseRequired
6956
+ validFrom DateTime
6957
+ validTo DateTime
6958
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6877
6959
 
6878
6960
  @@index([userId])
6879
6961
  @@index([userId, birthdayYear])
@@ -6881,12 +6963,12 @@ model BirthdayPlan {
6881
6963
 
6882
6964
  // Part B: Geocoding cache to avoid repeated API calls (birthday rewards, UserLocation, etc.)
6883
6965
  model GeocodeCache {
6884
- id String @id @default(cuid())
6966
+ id String @id @default(cuid())
6885
6967
  addressQuery String @unique // Normalized query string (trimmed, collapsed whitespace)
6886
6968
  lat Float
6887
6969
  lng Float
6888
6970
  normalizedAddress String @db.Text // formatted_address from provider
6889
- createdAt DateTime @default(now())
6971
+ createdAt DateTime @default(now())
6890
6972
 
6891
6973
  @@index([addressQuery])
6892
6974
  }
@@ -7576,7 +7658,7 @@ model BashAvailability {
7576
7658
  window BashAvailabilityWindow
7577
7659
  city String
7578
7660
  state String?
7579
- customAt DateTime? // When window is Custom: specific date/time
7661
+ customAt DateTime? // When window is Custom: specific date/time
7580
7662
  expiresAt DateTime
7581
7663
  createdAt DateTime @default(now())
7582
7664
  updatedAt DateTime @updatedAt
@@ -7592,7 +7674,7 @@ model BashAvailability {
7592
7674
  model BashEventPageView {
7593
7675
  id String @id @default(cuid())
7594
7676
  bashEventId String
7595
- sessionHash String // hashed IP+UA for dedup
7677
+ sessionHash String // hashed IP+UA for dedup
7596
7678
  viewedAt DateTime @default(now())
7597
7679
 
7598
7680
  bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
@@ -7603,16 +7685,16 @@ model BashEventPageView {
7603
7685
  // ─── Phase 1: Bash Groups ────────────────────────────────────────────────────
7604
7686
 
7605
7687
  enum GroupVisibility {
7606
- Private // Default: owner curates members
7688
+ Private // Default: owner curates members
7607
7689
  OpenLink // Anyone with the group link can self-join as WantsToGo
7608
7690
  }
7609
7691
 
7610
7692
  enum GroupMemberStatus {
7611
- Going // Ticket purchased / attending
7612
- WantsToGo // Interested, no ticket yet
7613
- Maybe // Maybe attending (aligns with Invitation maybeDate)
7614
- NotGoing // Not attending (aligns with Invitation rejectedDate)
7615
- Invited // Invited by owner, not yet responded
7693
+ Going // Ticket purchased / attending
7694
+ WantsToGo // Interested, no ticket yet
7695
+ Maybe // Maybe attending (aligns with Invitation maybeDate)
7696
+ NotGoing // Not attending (aligns with Invitation rejectedDate)
7697
+ Invited // Invited by owner, not yet responded
7616
7698
  }
7617
7699
 
7618
7700
  // A group of attendees for a specific event
@@ -7620,11 +7702,11 @@ model EventGroup {
7620
7702
  id String @id @default(cuid())
7621
7703
  bashEventId String
7622
7704
  ownerId String
7623
- name String? // e.g. "Steve's Birthday Group", "Weber State Crew"
7624
- maxMembers Int? // null = unlimited
7705
+ name String? // e.g. "Steve's Birthday Group", "Weber State Crew"
7706
+ maxMembers Int? // null = unlimited
7625
7707
  visibility GroupVisibility @default(Private)
7626
7708
  allowAutoJoin Boolean @default(false) // When true, anyone can join instantly; when false, requests require approval
7627
- promoterId String? // Optional: links to event promoter for display context
7709
+ promoterId String? // Optional: links to event promoter for display context
7628
7710
  createdAt DateTime @default(now())
7629
7711
  updatedAt DateTime @updatedAt
7630
7712
 
@@ -7644,11 +7726,11 @@ model GroupMember {
7644
7726
  groupId String
7645
7727
  userId String
7646
7728
  status GroupMemberStatus @default(Invited)
7647
- ticketId String? // Set when status = Going
7729
+ ticketId String? // Set when status = Going
7648
7730
  joinedAt DateTime @default(now())
7649
7731
 
7650
- group EventGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
7651
- user User @relation("GroupMemberships", fields: [userId], references: [id], onDelete: Cascade)
7732
+ group EventGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
7733
+ user User @relation("GroupMemberships", fields: [userId], references: [id], onDelete: Cascade)
7652
7734
 
7653
7735
  @@unique([groupId, userId])
7654
7736
  @@index([groupId])
@@ -7662,18 +7744,18 @@ model GroupMember {
7662
7744
 
7663
7745
  // Host-created time-limited offer targeting a specific group
7664
7746
  model GroupUnlockOffer {
7665
- id String @id @default(cuid())
7747
+ id String @id @default(cuid())
7666
7748
  bashEventId String
7667
- ticketTierId String? // Optional: scoped to a specific tier
7668
- minGroupSize Int // Minimum members who must buy
7669
- rewardLabel String // "Free drink", "VIP upgrade", "Free table"
7670
- rewardType String // FreeDrink | VIPUpgrade | Merch | Custom
7749
+ ticketTierId String? // Optional: scoped to a specific tier
7750
+ minGroupSize Int // Minimum members who must buy
7751
+ rewardLabel String // "Free drink", "VIP upgrade", "Free table"
7752
+ rewardType String // FreeDrink | VIPUpgrade | Merch | Custom
7671
7753
  expiresAt DateTime
7672
- maxGroups Int? // null = unlimited
7673
- createdAt DateTime @default(now())
7754
+ maxGroups Int? // null = unlimited
7755
+ createdAt DateTime @default(now())
7674
7756
 
7675
- bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
7676
- ticketTier TicketTier? @relation(fields: [ticketTierId], references: [id])
7757
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
7758
+ ticketTier TicketTier? @relation(fields: [ticketTierId], references: [id])
7677
7759
  unlocks GroupUnlock[]
7678
7760
 
7679
7761
  @@index([bashEventId])
@@ -7703,38 +7785,38 @@ enum PartnerTier {
7703
7785
  }
7704
7786
 
7705
7787
  model PartnerBrand {
7706
- id String @id @default(cuid())
7707
- name String
7708
- logoUrl String?
7709
- websiteUrl String?
7710
- description String? @db.Text
7711
- tier PartnerTier @default(Standard)
7712
- isActive Boolean @default(true)
7713
- affiliateBaseUrl String?
7714
- listingFeeMonthly Int? // cents; null = affiliate-only
7715
- createdAt DateTime @default(now())
7716
- products PartnerProduct[]
7717
- adSlots PartnerAdSlot[]
7788
+ id String @id @default(cuid())
7789
+ name String
7790
+ logoUrl String?
7791
+ websiteUrl String?
7792
+ description String? @db.Text
7793
+ tier PartnerTier @default(Standard)
7794
+ isActive Boolean @default(true)
7795
+ affiliateBaseUrl String?
7796
+ listingFeeMonthly Int? // cents; null = affiliate-only
7797
+ createdAt DateTime @default(now())
7798
+ products PartnerProduct[]
7799
+ adSlots PartnerAdSlot[]
7718
7800
 
7719
7801
  @@index([isActive, tier])
7720
7802
  }
7721
7803
 
7722
7804
  model PartnerProduct {
7723
- id String @id @default(cuid())
7724
- brandId String
7725
- brand PartnerBrand @relation(fields: [brandId], references: [id], onDelete: Cascade)
7726
- name String
7727
- description String? @db.Text
7728
- imageUrl String?
7729
- priceSummary String?
7730
- affiliateUrl String
7731
- categories String[]
7732
- isActive Boolean @default(true)
7733
- sortOrder Int @default(0)
7734
- impressions Int @default(0)
7735
- clicks Int @default(0)
7736
- createdAt DateTime @default(now())
7737
- adSlots PartnerAdSlot[]
7805
+ id String @id @default(cuid())
7806
+ brandId String
7807
+ brand PartnerBrand @relation(fields: [brandId], references: [id], onDelete: Cascade)
7808
+ name String
7809
+ description String? @db.Text
7810
+ imageUrl String?
7811
+ priceSummary String?
7812
+ affiliateUrl String
7813
+ categories String[]
7814
+ isActive Boolean @default(true)
7815
+ sortOrder Int @default(0)
7816
+ impressions Int @default(0)
7817
+ clicks Int @default(0)
7818
+ createdAt DateTime @default(now())
7819
+ adSlots PartnerAdSlot[]
7738
7820
 
7739
7821
  @@index([brandId, isActive])
7740
7822
  }