Skip to content

Event Flow

Flow Diagram

graph LR
    subgraph Membership
        E1["Registered"] --> L1["SendEmailVerificationNotification"]
        E2["Verified"] --> L2["VerifyUserListener"]
        E3["EmailChanged"] --> L1
    end

    subgraph Lottery
        E4["LotteryApplied"] --> L4["LotteryAppliedListener\nLotteryAppliedNotification queued"]
        E5["LotteryUpdated"] --> L5["LotteryUpdatedListener\nLotteryUpdatedNotification queued"]
        E6["LotteryWon"] --> L6["LotteryWonListener\nLotteryWonNotification queued"]
    end

    subgraph Order
        E7["OrderFinished"] --> L7["SendOrderFinishNotification\nlistener sync\nmail queued"]
        E8["OrderShipped"] --> L8["SendShipmentNotification\nlistener sync\nmail queued"]
    end

    subgraph Inquiry
        E9["InquirySent"] --> L9["InquirySentListener\nMail::send() fully sync"]
    end

Purpose

Decouples side effects (email, user state updates) from the primary business action. All 9 events are synchronously dispatched — the async boundary is at the notification layer (most notifications implement ShouldQueue).

Event Registry

Event Listener Notification Delivery
Registered SendEmailVerificationNotification VerifyEmailNotification queued mail
Verified VerifyUserListener sync DB update
EmailChanged SendEmailVerificationNotification VerifyEmailNotification queued mail
LotteryApplied LotteryAppliedListener LotteryAppliedNotification queued mail
LotteryUpdated LotteryUpdatedListener LotteryUpdatedNotification queued mail
LotteryWon LotteryWonListener LotteryWonNotification queued mail
OrderFinished SendOrderFinishNotification OrderFinishNotification queued mail
OrderShipped SendShipmentNotification ShipmentNotification queued mail
InquirySent InquirySentListener InquiryAutoReply + InquiryNotification sync Mail::send()

Registration: app/Providers/EventServiceProvider.php

Dispatch Points

Event Dispatch Location
Registered RegisterController (web)
Verified Email verification controller + email-change verify controller
EmailChanged MyPage ChangeEmail controller
LotteryApplied LotteryController::apply()
LotteryUpdated LotteryController::update()
LotteryWon SendLotteryWinnerEmailJob (scheduled, every minute)
OrderFinished SbpsPaymentController::updateStatus() + AtoneWebhookController::notify()
OrderShipped Admin ShippingController (import CSV)
InquirySent InquiryController

Lifecycle Steps

  1. Business action completes (order confirmed, lottery result published, etc.)
  2. event(new EventClass(...)) dispatched synchronously
  3. All listeners execute synchronously within the same request
  4. Listeners that send notifications: $notifiable->notify(new NotificationClass()) — most notifications implement ShouldQueue → pushed to queue driver (Redis)
  5. Queue worker picks up notification → sends mail via configured mail driver

Exception: InquirySentListener uses Mail::send() directly — fully synchronous, blocking the HTTP response.

Laravel Components Involved

  • app/Providers/EventServiceProvider.php — event → listener map
  • app/Modules/*/Events/ — event classes
  • app/Modules/*/Listeners/ — listener classes
  • app/Modules/*/Notifications/ — notification classes (ShouldQueue)

Data Mutations

Event Mutation
Verified VerifyUserListener marks user as verified in DB
LotteryWon SendLotteryWinnerEmailJob sets lotteries.is_sent = true after dispatch

Failure Paths

Scenario Behaviour
Queue worker down Queued notifications accumulate in queue; no immediate failure
InquirySentListener mail failure Sync failure — throws exception, 500 response to submitter
LotteryWonNotification::setCartUrl() on empty collection Throws — winner email fails if cart URL cannot be built
SendOrderFinishNotification duplicate getOrderProducts() call Two DB queries on every order confirmation email

Security Considerations

  • LotteryWon is dispatched inside SendLotteryWinnerEmailJob (scheduled) — is_sent flag set after event() but before queue worker delivers the notification. If worker fails, is_sent is still true → no retry → winner never notified.
  • No event sourcing or audit log of dispatched events.

Performance Considerations

  • All listeners are synchronous — heavy listeners block the HTTP response
  • InquirySentListener blocks inquiry form submission on every mail send
  • Notification queue depends on Redis availability; if Redis is down, notifications are dropped or lost depending on queue driver config
  • SendOrderFinishNotification calls getOrderProducts() twice (duplicate query)