# Notifications ## Tier-to-channel mapping | Tier | Price | Email | Push (PWA) | WhatsApp | SMS | |------------|--------|-------|------------|----------|-----------| | Free | £0 | ✓ weekly digest | ✗ | ✗ | ✗ | | Basic | £0.99 | ✓ daily | ✓ daily | ✓ daily | ✗ | | Plus | £2.49 | ✓ | ✓ | ✓ | ✓ max 1/day triggered | | Pro | £3.99 | ✓ | ✓ | ✓ | ✓ max 3/day triggered | ## NotificationDispatchService Reads user tier via Cashier, returns allowed channels: ```php public function channelsFor(User $user): array // Returns e.g. ['mail', 'vonage-whatsapp'] for Basic tier // Returns ['mail', 'vonage-whatsapp', 'vonage-sms'] for Plus+ ``` Never fire SMS unless confidence ≥ 70 AND user is Plus/Pro. Never fire more than 1 notification per user per day unless they are Pro tier. Log every sent notification to `alerts` table. ## Laravel Notification class One `FuelPriceAlert` notification class with `via()` returning channels based on tier. Subject line / message copy adapts based on `recommendation` and `confidence`. ## WhatsApp (Vonage) - Provider: Vonage Messages API (WhatsApp channel) - PHP package: `vonage/client` - Template: utility category (one-way alert) — pre-approved template required by Meta - Opt-in: phone number + OTP flow (see otp_verifications table) - User must have `whatsapp_verified_at` set — never send to unverified numbers - Cost: ~0.3–0.5p per message (utility rate) - Message format: keep under 160 chars. Include station name, price, and recommendation reason. ## SMS (Vonage — Plus/Pro only) - Same Vonage client, SMS channel - Triggered only (not daily) — fires when signal strength ≥ 2 AND price event warrants it - Plus: max 8 SMS/month (enforced via alerts table count) - Pro: max 30 SMS/month - Cost: ~3.5p per message UK ## Email - Driver: Mailgun (configured in .env) - Free tier: weekly digest every Monday 8am - Basic+: daily summary if recommendation is not `no_signal` - Use Mailable classes, not raw Mail::send - Templates in `resources/views/emails/` ## Push notifications (OneSignal) - Free plan: up to 10,000 subscribers - Player ID stored in `users.push_token` - Use OneSignal REST API — no official Laravel package needed, simple HTTP call - PWA service worker setup required (separate task) - Basic+: daily push alongside email ## Queue All notifications are dispatched as queued jobs — never send synchronously. Use `FuelAlertNotificationJob` dispatched per user. Queue: `notifications` (separate from default queue for priority control).