Domain: Event

Scenario: Event Lifecycle (Create → Update → Sync → Complete)

1. Business Goal

Event is the core entity for ticket-based commerce (flash sales, live shows, parties). When a curator creates an Event, the system automatically creates:

  1. A Product (ticket type) linked to the Event
  2. A Post (social commerce content) for promoters to resell
  3. Guest management (invitee list with check-in/verification)

2. Trigger & Entry

API Method Description Request Body
/product-event/v2 POST Create event (V2 - auto-creates post) { title, startDate, venue, location, poster, tickets[], lineups[] }
/product-event/:id PUT Update event Event update DTO
/product-event/:id/details GET Get event details -
/product-event/:id/related-posts GET Get related posts -
/posts/curator/from-event POST Create post from event CreatePostRequest
/posts/curator/toggle-sync POST Toggle event sync { postId, syncEnabled }

3. Data Flow (Sequence)

sequenceDiagram
    participant Curator as Curator (User)
    participant API as EventController
    participant Service as ProductEventV2Service
    participant DB as PostgreSQL
    participant Queue as BullMQ
    participant Post as PostModule
    participant Shopify as Shopify (optional)

    Curator->>API: POST /product-event/v2
    API->>Service: createEvent()

    Note over Service: 1. Validate input
    Service->>DB: BEGIN TRANSACTION

    Note over Service: 2. Create Event record
    Service->>DB: INSERT Event
    DB-->>Service: event.id

    Note over Service: 3. Create EventMedia records
    Service->>DB: INSERT EventMedia[]

    Note over Service: 4. Create EventLineup records
    Service->>DB: INSERT EventLineup[]

    Note over Service: 5. Create Product (ticket) linked to Event
    Service->>DB: INSERT Product (eventId=event.id)

    Note over Service: 6. Create ProductVariant for each ticket
    Service->>DB: INSERT ProductVariant[]

    Service->>DB: COMMIT

    Note over Service: 7. Create auto-post (if enabled)
    Service->>Post: createPostFromEvent()
    Post->>DB: INSERT Post (createFromEventId, postType=EVENT)

    Note over Service: 8. Trigger downstream sync
    Service->>Queue: event.created (productId, eventId)
    Queue->>Shopify: Sync product to Shopify (optional)

    Service-->>Curator: { event, post, product }

4. DB Operations (Chronological)

Step Table Action PK/FK Touched Notes
1 Event INSERT id (PK), curatorId (FK) status = UPCOMING
2 EventMedia INSERT id (PK), eventId (FK) poster images
3 EventLineup INSERT id (PK), eventId (FK) performers/speakers
4 Product INSERT id (PK), eventId (FK), merchantId (FK) listingType = TICKET
5 ProductVariant INSERT id (PK), productId (FK) ticket types (GA, VIP, etc.)
6 Post INSERT id (PK), creatorId (FK), createFromEventId (FK) postType = EVENT
7 PostMedia INSERT id (PK), postId (FK) copy from EventMedia

5. Event/Queue Messages

Message Producer → Consumer Payload Snippet
event.created EventModule → ProductQueue { eventId, productId, curatorId }
event.updated EventModule → PostSyncQueue { oldEvent, newEvent, syncCategories }
event.status.changed EventModule → ProductQueue { eventId, oldStatus, newStatus }
event.completed CronJob → EventModule { eventIds[] }

6. Event → Post Sync Logic

When syncEnabled = true on a Post, Event changes propagate:

// Event field → Post field mapping
Event.titlePost.headline
Event.titlePost.title
Event.venue + date    → Post.subTitle
Event.posterPost.media, Post.coverImages

// Sync categories
type SyncCategory = 'metadata' | 'variants';

// Metadata sync: content fields
// Variant sync: relatedProducts (ticket products)

Trigger: Event update → ProductEventPublisherPOST_SYNC queue → EventSyncTrigger

7. File Map (Top 5 Must-Read)

File Purpose
src/product-event/product-event.controller.ts HTTP endpoints
src/product-event-v2/product-event-v2.service.ts V2 create logic (auto-post)
src/product-event-core/product-event.entity.ts Domain entity
src/posts/curator/posts-curator.service.ts Post creation from event
src/post-sync/event-sync-trigger.ts Sync orchestration

8. DB Schema Snippet (Prisma)

model Event {
  id                     String      @id @default(uuid()) @db.Uuid
  curatorId              String      @map("curator_id") @db.Uuid
  status                 EventStatus @default(UPCOMING)
  title                  String
  startDate              DateTime    @map("start_date") @db.Timestamptz()
  endDate                DateTime?   @map("end_date") @db.Timestamptz()
  venue                  String
  location               String
  poster                 Json?       // [ProductCoverImage]
  allowAutoComplete      Boolean     @default(true)
  messageInfo            Json        @default("{\"smsMaxLimit\": 3}")
  isAddressRevealEnabled Boolean     @default(false)
  addressRevealConfig    Json?
  isTaxEnabled           Boolean     @default(false)
  taxConfig              Json?
  deletedAt              DateTime?   @map("deleted_at")

  // Relations
  product        Product[]
  lineups        EventLineup[]
  medias         EventMedia[]
  messages       EventMessage[]
  guests         EventGuestToEvent[]
  createdAt      DateTime    @default(now()) @map("created_at")
  updatedAt      DateTime    @updatedAt @map("updated_at")
}

model EventLineup {
  id           String   @id @db.Uuid
  eventId      String   @map("event_id") @db.Uuid
  title        String
  introduction String?
  poster       Json?
  order        Int      @default(0)
  isHeadliner  Boolean  @default(false)
  Event        Event    @relation(fields: [eventId], references: [id])

  @@index([eventId])
}

model EventMedia {
  id        String    @id @db.Uuid
  eventId   String    @map("event_id") @db.Uuid
  src       String
  position  Int
  mediaType MediaType @default(IMAGE)
  Event     Event     @relation(fields: [eventId], references: [id], onDelete: Cascade)

  @@index([eventId])
}

enum EventStatus {
  UPCOMING
  ON_HOLD
  CANCELED
  COMPLETED
}

9. Event Status Flow

stateDiagram-v2
    [*] --> UPCOMING: Create event
    UPCOMING --> ON_HOLD: Manual pause
    ON_HOLD --> UPCOMING: Resume
    UPCOMING --> COMPLETED: endDate passed + autoComplete
    UPCOMING --> CANCELED: Manual cancel
    COMPLETED --> [*]
    CANCELED --> [*]

10. Guest Management (KAT-8848)

API Method Description
/product-event/guests POST Create guest
/product-event/guests/groups POST Create guest group
/product-event/:eventId/guests POST Add guests to event
/product-event/guest-verification/check-in POST Guest check-in
model EventGuest {
  id          String   @id @default(uuid()) @db.Uuid
  userId      String   @map("user_id") @db.Uuid
  firstName   String   @map("first_name")
  lastName    String   @map("last_name")
  fullName    String   @map("full_name")
  email       String?
  phoneNumber String?  @map("phone_number")
  groups      EventGuestToGroup[]
  events      EventGuestToEvent[]
  deletedAt   DateTime? @map("deleted_at")
}

model EventGuestToEvent {
  id          String           @id @default(uuid()) @db.Uuid
  eventId     String           @map("event_id") @db.Uuid
  guestId     String           @map("guest_id") @db.Uuid
  status      EventGuestStatus @default(INVITED)
  checkedInAt DateTime?        @map("checked_in_at")
  checkedInBy String?          @map("checked_in_by") @db.Uuid
}

results matching ""

    No results matching ""