Add comprehensive project documentation and architecture guidelines
Establishes core rules and conventions for the FuelAlert Laravel application: architecture patterns (fat services, thin controllers), database schema with partitioned station_prices table, multi-tier notification system with Vonage and OneSignal, 4-signal scoring engine for fuel price recommendations, Stripe subscription tiers, Livewire classic component structure, and Pest testing standards.
This commit is contained in:
68
notifications.md
Normal file
68
notifications.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# 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).
|
||||
Reference in New Issue
Block a user