Notification System
Volare uses Laravel’s notification system to send alerts via email and database channels.
When to Use
Section titled “When to Use”- 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
Configuration
Section titled “Configuration”Required env vars:
MAIL_MAILER=smtpMAIL_HOST=mailpit(local) or SMTP serverMAIL_PORT=1025(local) or SMTP portMAIL_FROM_ADDRESS="noreply@volare.test"MAIL_FROM_NAME="Volare"
Queue worker: Must be running for OfferCreatedNotification (queued)
./vendor/bin/sail artisan queue:workDatabase: Notifications stored in notifications table
Architecture
Section titled “Architecture”Channels
Section titled “Channels”Notifications use different channels depending on their purpose:
| Notification | Channel | Delivery |
|---|---|---|
| OfferCreatedNotification | database | Queued (async) |
| DailyOffersDigestNotification | mail | Synchronous (via scheduled command) |
| SupplierOffersDigestNotification | mail | Synchronous (via scheduled command) |
Recipient Determination
Section titled “Recipient Determination”- Admin users — Via
Role::Adminenum (Spatie permissions) - Supplier users — Via
User.supplier_idlinking users to a supplier
Offer Created Notification
Section titled “Offer Created Notification”In-app notification sent when new offers are created. Appears in the Filament admin notification bell.
Trigger
Section titled “Trigger”OfferObserver::created() — After SKU generation completes
Source: backend/app/Observers/OfferObserver.php
Recipients
Section titled “Recipients”- All users with
Role::Admin - Users linked to offer’s supplier via:
Offer → SupplierTourRate → SupplierTour → Supplier → Users - Merged and deduplicated before sending
Database Payload
Section titled “Database Payload”[ '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
Daily Admin Digest
Section titled “Daily Admin Digest”Email sent daily at 8:00 AM Europe/Madrid to all admin users with a summary of offer activity.
Command
Section titled “Command”# 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-23Sections
Section titled “Sections”The email contains up to three sections. Empty sections are omitted.
| Section | What it shows | Query logic |
|---|---|---|
| PENDING REVIEW | All current draft offers | status = Draft (not date-bounded) |
| ACTIVATED YESTERDAY | Offers activated the previous day | status = Active AND activated_at within yesterday (Madrid TZ → UTC) |
| CREATED YESTERDAY | Offers created the previous day | created_at within yesterday (Madrid TZ → UTC) |
Display Rules
Section titled “Display Rules”- 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
Schedule
Section titled “Schedule”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
Supplier Active Offers Digest
Section titled “Supplier Active Offers Digest”Email sent daily at 8:00 AM Europe/Madrid to supplier-linked users showing all active offers for their supplier.
Supplier Digest Command
Section titled “Supplier Digest Command”# 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=5How Suppliers Are Matched to Offers
Section titled “How Suppliers Are Matched to Offers”Supplier → SupplierTour → ProductTemplate → ProductByMarket → Offers (status=Active)Only suppliers that have at least one active offer (through this chain) receive a digest.
Supplier Recipients
Section titled “Supplier Recipients”Users linked to the supplier via User.supplier_id. Suppliers with no linked user accounts are skipped.
Supplier Display Rules
Section titled “Supplier Display Rules”- 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}“
Supplier Schedule
Section titled “Supplier Schedule”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
Email Branding
Section titled “Email Branding”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
Testing Notifications
Section titled “Testing Notifications”Artisan Command
Section titled “Artisan Command”# Send test notification to first user./vendor/bin/sail artisan notification:test
# Send to specific email./vendor/bin/sail artisan notification:test user@example.comSource: backend/app/Console/Commands/SendTestNotification.php
Pest Tests
Section titled “Pest Tests”# 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=SupplierOffersDigestTest suites:
backend/tests/Feature/Notifications/OfferCreatedNotificationTest.phpbackend/tests/Feature/Notifications/DailyOffersDigestNotificationTest.phpbackend/tests/Feature/Commands/SendDailyOffersDigestCommandTest.phpbackend/tests/Feature/Commands/SendSupplierOffersDigestCommandTest.php
Business Rules
Section titled “Business Rules”OfferCreatedNotificationis 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
Filament Integration
Section titled “Filament Integration”Database notifications appear in Filament admin panel:
- Notification bell icon in header
- Unread count badge
- Click to view details
- Mark as read functionality
Local Development
Section titled “Local Development”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
Related
Section titled “Related”- 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