Push Notifications Architecture
System Overview
ZÈYA's push notification system is built on Expo Push Notification Service and provides reliable, real-time notifications across iOS and Android platforms. The system handles everything from user registration to delivery tracking and analytics.
Architecture Diagram
┌─────────────────────────────────────────────────────────────────────────┐
│ ZÈYA Push Notification System │
└─────────────────────────────────────────────────────────────────────────┘
┌──────────────────┐ ┌──────────────────┐
│ Mobile Apps │ │ Backend API │
│ (iOS/Android) │ │ (Laravel) │
└────────┬─────────┘ └────────┬─────────┘
│ │
│ 1. Request Push Permissions │
│ ────────────────────────────────────────────────────▶│
│ │
│ 2. Get Expo Push Token │
│ ◀────────────────────────────────────────────────────│
│ (ExponentPushToken[xxx]) │
│ │
│ 3. Register Token with Backend │
│ ────────────────────────────────────────────────────▶│
│ POST /api/user/save-phone-token │
│ { token, device_id, platform } │
│ │
│ │
│ ┌──────────────────┴─────────────────┐
│ │ MySQL Database │
│ │ │
│ │ ┌─────────────────────────────┐ │
│ │ │ mobile_devices │ │
│ │ │ - id │ │
│ │ │ - user_id │ │
│ │ │ - token (Expo token) │ │
│ │ │ - device_id │ │
│ │ │ - platform │ │
│ │ └─────────────────────────────┘ │
│ │ │
│ └────────────────────────────────────┘
│ │
│ │
│ ┌──────────────────┴─────────────────┐
│ │ Event Trigger │
│ │ (Swap Match, Message, etc.) │
│ └──────────────────┬─────────────────┘
│ │
│ ┌──────────────────▼─────────────────┐
│ │ NotificationController │
│ │ ::sendNotification() │
│ │ │
│ │ 1. Check user settings │
│ │ 2. Validate user preferences │
│ └──────────────────┬─────────────────┘
│ │
│ ┌──────────────────▼─────────────────┐
│ │ NotificationService │
│ │ ::send() │
│ │ │
│ │ 1. Fetch user devices │
│ │ 2. Create notification records │
│ │ 3. Prepare Expo messages │
│ └──────────────────┬─────────────────┘
│ │
│ │
│ ┌──────────────────▼─────────────────┐
│ │ Expo Push Service │
│ │ (expo.dev) │
│ │ │
│ │ - Receives push request │
│ │ - Returns ticket ID │
│ │ - Queues for delivery │
│ └──────────────────┬─────────────────┘
│ │
│ │ Ticket Response
│ │
│ ┌──────────────────▼─────────────────┐
│ │ Update Notification Status │
│ │ │
│ │ ┌─────────────────────────────┐ │
│ │ │ notifications │ │
│ │ │ - notification_id │ │
│ │ │ - user_id │ │
│ │ │ - notification_content │ │
│ │ │ - is_send = true │ │
│ │ │ - ticket_id │ │
│ │ │ - is_delivered │ │
│ │ │ - is_open │ │
│ │ └─────────────────────────────┘ │
│ └────────────────────────────────────┘
│ │
│ │
│ ┌──────────────────▼─────────────────┐
│ │ Expo Delivers to Device │
│ │ │
│ │ iOS: APNs │
│ │ Android: FCM │
│ └──────────────────┬─────────────────┘
│ │
│ 4. Receive Push Notification │
│ ◀────────────────────────────────────────────────────│
│ { title, body, data } │
│ │
│ 5. Display Notification │
│ - Show banner/alert │
│ - Play sound │
│ - Update badge count │
│ │
│ │
│ 6. User Taps Notification │
│ - Open app │
│ - Navigate to content (deep link) │
│ │
│ 7. Mark Notification as Read │
│ ────────────────────────────────────────────────────▶│
│ GET /api/notification/{id}/read │
│ │
│ ┌──────────────────▼─────────────────┐
│ │ Update: is_open = true │
│ └────────────────────────────────────┘
│ │
│ │
│ ┌──────────────────▼─────────────────┐
│ │ Background: Fetch Receipts │
│ │ (ProcessExpoReceipts Job) │
│ │ │
│ │ - Query pending notifications │
│ │ - Fetch delivery receipts │
│ │ - Update is_delivered status │
│ └────────────────────────────────────┘
│ │
│ │
│ ┌──────────────────▼─────────────────┐
│ │ Analytics & Monitoring │
│ │ │
│ │ - Delivery rates │
│ │ - Open rates │
│ │ - Error tracking │
│ │ - Performance metrics │
│ └────────────────────────────────────┘
│ │
Bulk Notification Flow
For sending notifications to multiple users (e.g., promotional campaigns):
┌─────────────────────────────────────────────────────────────────────────┐
│ Bulk Notification Processing │
└─────────────────────────────────────────────────────────────────────────┘
┌──────────────────┐
│ Admin Panel │
│ or API Request │
└────────┬─────────┘
│
│ POST /api/admin/send-notification-all
│ { title, text, data }
│
▼
┌────────────────────────────────────┐
│ SendBulkNotifications Job │
│ (Coordinator) │
│ │
│ 1. Query active users │
│ WHERE notification_enabled = 1 │
│ │
│ 2. Chunk users into batches (50) │
│ │
│ 3. Dispatch batch jobs │
└────────┬───────────────────────────┘
│
├───────────┬───────────┬───────────┬───────────┐
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ Batch │ │ Batch │ │ Batch │ │ Batch │ │ Batch │
│ 1 │ │ 2 │ │ 3 │ │ 4 │ │ N │
│ (50) │ │ (50) │ │ (50) │ │ (50) │ │ (50) │
└───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘
│ │ │ │ │
└───────────┴───────────┴───────────┴───────────┘
│
▼
┌──────────────────────────┐
│ SendNotificationBatch │
│ Job (Worker) │
│ │
│ 1. Get user devices │
│ 2. Bulk insert records │
│ 3. Send to Expo │
│ 4. Update statuses │
│ │
│ Retry on failure (3x) │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ Queue Workers │
│ │
│ Worker 1 ───┐ │
│ Worker 2 ───┼─▶ Process │
│ Worker 3 ───┘ Parallel│
│ Worker N │
└──────────────────────────┘
Data Flow
1. Token Registration
Mobile App Backend Database
│ │ │
│──── Get Token ────────▶│ │
│ │ │
│◀─── Return Token ──────│ │
│ │ │
│──── Save Token ───────▶│ │
│ (POST /save-token) │ │
│ │ │
│ │──── Insert/Update ────▶│
│ │ mobile_devices │
│ │ │
│ │◀─── Success ───────────│
│ │ │
│◀─── 200 OK ────────────│ │
2. Send Notification
Trigger Event Controller Service Expo Device
│ │ │ │ │
│──── sendNotification() │ │ │
│ │ │ │ │
│ │──── send() ───────▶│ │ │
│ │ │ │ │
│ │ │──── Create ──────▶│ │
│ │ │ Records │ │
│ │ │ │ │
│ │ │──── Push ────────▶│ │
│ │ │ Message │ │
│ │ │ │ │
│ │ │◀─── Ticket ID ────│ │
│ │ │ │ │
│ │ │──── Update ──────▶│ │
│ │ │ Status │ │
│ │ │ │ │
│ │ │ │──── Deliver ─────▶│
│ │ │ │ │
│ │ │ │ │◀─── Display
3. User Interaction
Device Mobile App Backend Database
│ │ │ │
│──── Tap ────────────▶│ │ │
│ Notification │ │ │
│ │ │ │
│ │──── Mark as Read ─────▶│ │
│ │ (GET /read) │ │
│ │ │ │
│ │ │──── Update ──────▶│
│ │ │ is_open=true │
│ │ │ │
│ │ │◀─── Success ──────│
│ │ │ │
│ │◀─── 200 OK ────────────│ │
│ │ │ │
│ │──── Navigate to ──────▶│ │
│ │ Content (deep link)│ │
Components Breakdown
Backend Components
| Component | Location | Purpose |
|---|---|---|
| NotificationController | app/Http/Controllers/NotificationController.php | Handles API endpoints for notifications |
| NotificationService | app/Services/NotificationService.php | Core notification sending logic |
| SendBulkNotifications | app/Jobs/SendBulkNotifications.php | Coordinator for bulk sends |
| SendNotificationBatch | app/Jobs/SendNotificationBatch.php | Processes notification batches |
| ProcessExpoReceipts | app/Jobs/ProcessExpoReceipts.php | Fetches delivery receipts |
| Notification Model | app/Models/Notification.php | Database model |
| MobileDevice Model | app/Models/MobileDevice.php | Device token storage |
Mobile App Components
| Component | Location | Purpose |
|---|---|---|
| usePushNotifications | src/share/useNotifications.js | Main notification hook |
| Permission Manager | Built into hook | Handles permission requests |
| Token Manager | Built into hook | Manages Expo push token |
| Notification Handler | Built into hook | Processes incoming notifications |
| Event Emitter | src/share/emitter.js | Cross-component events |
| Deep Link Handler | Navigation layer | Handles notification taps |
Database Schema
Entity Relationship Diagram
┌─────────────────────┐
│ users │
│ │
│ - user_id (PK) │
│ - username │
│ - email │
│ - name │
│ - status │
└──────────┬──────────┘
│ 1
│
│ N
┌──────────▼──────────┐ ┌─────────────────────┐
│ mobile_devices │ │ user_settings │
│ │ │ │
│ - id (PK) │ │ - id (PK) │
│ - user_id (FK) │ │ - user_id (FK) │
│ - token │ │ - setting_name │
│ - device_id │ │ - setting_value │
│ - platform │ └─────────────────────┘
└──────────┬──────────┘
│ 1
│
│ N
┌──────────▼──────────────────────────┐
│ notifications │
│ │
│ - notification_id (PK) │
│ - user_id (FK) │
│ - mobile_devices_id (FK) │
│ - notification_content (JSON) │
│ - notification_type │
│ - is_send (boolean) │
│ - is_delivered (boolean) │
│ - is_open (boolean) │
│ - ticket_id (Expo ticket) │
│ - error_message │
│ - created_at │
│ - updated_at │
│ - deleted_at │
└─────────────────────────────────────┘
Notification Lifecycle States
┌────────────────────────────────────────────────────────────┐
│ Notification State Machine │
└────────────────────────────────────────────────────────────┘
[Created]
│
│ API receives request
│ Record inserted in DB
│
▼
[Queued]
│
│ Job picks up notification
│ Prepares Expo message
│
▼
[Sent] ──────────────────┐
│ │
│ is_send = true │ is_send = false
│ ticket_id set │ error_message set
│ │
▼ ▼
[Pending Receipt] [Failed]
│ │
│ Waiting for │ Retry logic
│ delivery │ (max 3 attempts)
│ │
▼ └──────▶ [Permanently Failed]
[Delivered] ─────────────┐
│ │
│ is_delivered=true │ is_delivered=false
│ │ error_message set
│ │
▼ ▼
[Shown to User] [Delivery Failed]
│
│ User sees notification
│ on device
│
├────────────┬──────────┐
│ │ │
▼ ▼ ▼
[Dismissed] [Expired] [Opened]
│
│ User taps notification
│ App opens
│ Mark as read API called
│
▼
[Read]
│
│ is_open = true
│ User navigated to content
│
▼
[Completed]
Performance Characteristics
Throughput
- Single notification: ~50-100ms
- Batch (50 users): ~2-5 seconds
- Bulk (10,000 users): ~3-5 minutes (with 5 queue workers)
Scalability
- Queue-based architecture supports horizontal scaling
- Can handle 100,000+ notifications per hour
- Add more queue workers for increased throughput
- Database indexes optimize query performance
Reliability
- 3 retry attempts per failed notification
- Exponential backoff (60s between retries)
- Delivery receipt tracking
- Error logging and monitoring
Integration Points
External Services
-
Expo Push Service (
expo.dev)- Sends notifications to devices
- Returns ticket IDs for tracking
- Provides delivery receipts
-
Apple Push Notification Service (APNs)
- Used by Expo for iOS devices
- Handles iOS notification delivery
-
Firebase Cloud Messaging (FCM)
- Used by Expo for Android devices
- Handles Android notification delivery
-
Firebase Realtime Database
- Syncs badge counts
- Real-time notification data
- Chat notification tracking
Internal Services
-
Queue System (Laravel Queue)
- Redis or Database driver
- Job processing and retries
- Background task management
-
MySQL Database
- Notification records
- Device tokens
- User preferences
- Analytics data
-
Event System
- Triggers notifications on events
- Swap matches, messages, etc.
- Decoupled architecture
Security Model
Authentication & Authorization
┌─────────────────────────────────────────────┐
│ Security Layers │
└─────────────────────────────────────────────┘
1. API Authentication
├─ JWT Bearer Token
├─ Token expiration
└─ User identity verification
2. Device Token Security
├─ One-way storage (encrypted at rest)
├─ User-device association
└─ Token rotation on re-registration
3. Notification Authorization
├─ User ownership verification
├─ Notification preference checks
└─ Admin-only endpoints protected
4. Data Privacy
├─ Minimal PII in notification payload
├─ Deep links for detailed data
└─ User consent for notifications
5. Rate Limiting
├─ Per-user rate limits
├─ Per-IP rate limits
└─ Admin endpoint throttling
Monitoring & Observability
Key Metrics
-
Delivery Metrics
- Sent rate
- Delivery rate
- Open rate
- Failure rate
-
Performance Metrics
- Processing time
- Queue length
- Worker utilization
- API response time
-
Error Metrics
- Failed sends
- Invalid tokens
- Network errors
- Timeout errors
Logging
[2026-01-20 10:30:45] INFO: Notification sent
{
"user_id": 123,
"notification_id": 456,
"ticket_id": "xxx-xxx",
"device_id": 789
}
[2026-01-20 10:30:50] WARNING: Notification delivery failed
{
"user_id": 123,
"notification_id": 456,
"error": "DeviceNotRegistered",
"details": "Token is no longer valid"
}
[2026-01-20 10:35:00] INFO: Bulk notification completed
{
"total_users": 10000,
"total_batches": 200,
"batch_size": 50,
"duration_seconds": 180
}
Related Documentation
- API Push Notifications - Detailed backend implementation
- Mobile App Push Notifications - Mobile app implementation
- API Architecture - Overall API architecture
- Mobile App Architecture - Mobile app architecture