Skip to content

Notification System

Volare uses Laravel’s notification system to send alerts via email and database channels.

  • In-app notifications when offers are created (database channel)
  • Daily email digests summarizing offer activity for admins
  • Daily email digests summarizing active offers for supplier users
  • System alerts requiring in-app visibility

Required env vars:

  • MAIL_MAILER=smtp
  • MAIL_HOST=mailpit (local) or SMTP server
  • MAIL_PORT=1025 (local) or SMTP port
  • MAIL_FROM_ADDRESS="noreply@volare.test"
  • MAIL_FROM_NAME="Volare"

Queue worker: Must be running for OfferCreatedNotification (queued)

Terminal window
./vendor/bin/sail artisan queue:work

Database: Notifications stored in notifications table

Notifications use different channels depending on their purpose:

NotificationChannelDelivery
OfferCreatedNotificationdatabaseQueued (async)
DailyOffersDigestNotificationmailSynchronous (via scheduled command)
SupplierOffersDigestNotificationmailSynchronous (via scheduled command)
  • Admin users — Via Role::Admin enum (Spatie permissions)
  • Supplier users — Via User.supplier_id linking users to a supplier

In-app notification sent when new offers are created. Appears in the Filament admin notification bell.

OfferObserver::created() — After SKU generation completes

Source: backend/app/Observers/OfferObserver.php

  • All users with Role::Admin
  • Users linked to offer’s supplier via: Offer → SupplierTourRate → SupplierTour → Supplier → Users
  • Merged and deduplicated before sending
[
'title' => 'New Offer Created',
'message' => 'Offer {SKU} has been created.',
'offer_id' => $offer->id,
'sku' => $offer->sku,
'final_price' => $offer->final_price,
]

Source: backend/app/Notifications/OfferCreatedNotification.php

Email sent daily at 8:00 AM Europe/Madrid to all admin users with a summary of offer activity.

Terminal window
# Normal execution (run by scheduler)
./vendor/bin/sail artisan offers:send-daily-digest
# Test with a specific "yesterday" date
./vendor/bin/sail artisan offers:send-daily-digest --date=2026-02-23

The email contains up to three sections. Empty sections are omitted.

SectionWhat it showsQuery logic
PENDING REVIEWAll current draft offersstatus = Draft (not date-bounded)
ACTIVATED YESTERDAYOffers activated the previous daystatus = Active AND activated_at within yesterday (Madrid TZ → UTC)
CREATED YESTERDAYOffers created the previous daycreated_at within yesterday (Madrid TZ → UTC)
  • Offers are grouped by product name (ProductByMarket → ProductTemplate.title)
  • Each offer row shows: SKU (linked to admin), Airport, Departure date, Price + currency
  • Draft section limited to 5 offers with “…and X more in the admin panel” overflow
  • Email is skipped entirely if all three sections are empty
  • Email is skipped if no admin users exist
  • “View All Offers” button links to the Filament offer list

Registered in routes/console.php:

Schedule::command('offers:send-daily-digest')
->dailyAt('08:00')
->timezone('Europe/Madrid')
->onOneServer();

Source: backend/app/Console/Commands/SendDailyOffersDigestCommand.php

Template: backend/resources/views/mail/offers/daily-digest.blade.php

Email sent daily at 8:00 AM Europe/Madrid to supplier-linked users showing all active offers for their supplier.

Terminal window
# Normal execution (run by scheduler)
./vendor/bin/sail artisan offers:send-supplier-digest
# Test for a specific supplier
./vendor/bin/sail artisan offers:send-supplier-digest --supplier=5
Supplier → SupplierTour → ProductTemplate → ProductByMarket → Offers (status=Active)

Only suppliers that have at least one active offer (through this chain) receive a digest.

Users linked to the supplier via User.supplier_id. Suppliers with no linked user accounts are skipped.

  • Single section showing all active offers for that supplier
  • Offers grouped by product name
  • Each row shows: SKU, Airport, Departure date, Price + currency
  • Limited to 15 offers with “…and X more in the admin panel” overflow
  • “View Supplier Tours” button links to the Filament supplier tours list
  • Subject line: “Active Offers Summary - {Supplier Name} - {date}“
Schedule::command('offers:send-supplier-digest')
->dailyAt('08:00')
->timezone('Europe/Madrid')
->onOneServer();

Source: backend/app/Console/Commands/SendSupplierOffersDigestCommand.php

Template: backend/resources/views/mail/offers/supplier-digest.blade.php

All emails use published vendor mail views with custom Volare branding:

  • Header: Volare SVG logo (replaces default Laravel logo)
  • Footer: “VOLĀRE” branding

Source: backend/resources/views/vendor/mail/html/header.blade.php, message.blade.php

Terminal window
# Send test notification to first user
./vendor/bin/sail artisan notification:test
# Send to specific email
./vendor/bin/sail artisan notification:test user@example.com

Source: backend/app/Console/Commands/SendTestNotification.php

Terminal window
# Offer created notification tests
./vendor/bin/sail artisan test --filter=OfferCreatedNotification
# Admin digest tests
./vendor/bin/sail artisan test --filter=DailyOffersDigest
# Supplier digest tests
./vendor/bin/sail artisan test --filter=SupplierOffersDigest

Test suites:

  • backend/tests/Feature/Notifications/OfferCreatedNotificationTest.php
  • backend/tests/Feature/Notifications/DailyOffersDigestNotificationTest.php
  • backend/tests/Feature/Commands/SendDailyOffersDigestCommandTest.php
  • backend/tests/Feature/Commands/SendSupplierOffersDigestCommandTest.php
  • OfferCreatedNotification is queued — queue worker must be running
  • Digest notifications are not queued — they run synchronously from scheduled commands
  • Admin users receive in-app notifications for every offer + daily email digest
  • Supplier users receive daily email digest for their supplier’s active offers only
  • SKU must be generated before notification (handled by observer)
  • Digests are skipped when there is nothing to report

Database notifications appear in Filament admin panel:

  • Notification bell icon in header
  • Unread count badge
  • Click to view details
  • Mark as read functionality

Use Mailpit for email testing:

  • Web UI: http://localhost:8025
  • SMTP: localhost:1025
  • View all sent emails without actual delivery
  • Test email templates and content
  • Queue System
  • Offer Observer Logic
  • Source: backend/app/Notifications/
  • Source: backend/app/Observers/OfferObserver.php
  • Source: backend/app/Console/Commands/SendDailyOffersDigestCommand.php
  • Source: backend/app/Console/Commands/SendSupplierOffersDigestCommand.php