🎉 Push Notification Integration - Complete Summary¶
✅ Phases 1-3 Completed¶
All three phases of Firebase Cloud Messaging (FCM) integration are complete and ready for testing.
📦 What You Get¶
Database Layer¶
- ✅ DeviceToken Model - Stores FCM tokens with user/device metadata
- ✅ Alembic Migration - Creates
notify.device_tokenstable with optimized indexes - ✅ Push Templates - Transaction/security alerts already in template seed
Backend Logic¶
- ✅ Firebase Service - Singleton wrapper for FCM Admin SDK
- ✅ Celery Tasks - Async push notification sending with retry logic
- ✅ Template Integration - Push channel support in notify pipeline
API Endpoints¶
- ✅ Device Registration - POST
/api/v1/notifications/devices/register - ✅ List Tokens - GET
/api/v1/notifications/devices/ - ✅ Manage Tokens - Activate/deactivate/delete operations
- ✅ Authentication - JWT-protected endpoints
🚀 Quick Start (3 Steps)¶
1️⃣ Setup Firebase¶
# Create Firebase project at https://console.firebase.google.com
# Download service account JSON
# Set environment variables:
export FIREBASE_PROJECT_ID="your-project-id"
export FIREBASE_CREDENTIALS_PATH="/app/firebase-credentials.json"
2️⃣ Install & Migrate¶
3️⃣ Test Registration¶
curl -X POST http://localhost:8000/api/v1/notifications/devices/register \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fcm_token": "YOUR_FCM_TOKEN",
"platform": "mobile",
"device_name": "Test Device"
}'
📁 Files Created/Modified¶
New Files¶
utils/notify/firebase.py- Firebase service wrapperrouters/device_tokens.py- Device management endpointsalembic/versions/564f2g8a1h3b_*.py- Database migrationPUSH_NOTIFICATIONS_SETUP.md- Complete setup guide (this doc)
Modified Files¶
models/notify.py- Added DeviceToken modelcontroller/notify.py- Extended queue_template_notification()utils/notify/tasks.py- Enhanced push task implementationcore/config.py- Added Firebase configurationmain.py- Registered device_tokens router
🔗 Architecture¶
┌──────────────────────────────────────────────────────────────┐
│ REST API (FastAPI) │
├──────────────────────────────────────────────────────────────┤
│ POST /api/v1/notifications/devices/register │
│ ↓ │
│ Device Token Management Endpoints (routers/device_tokens) │
└──────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────┐
│ Notification Controller │
├──────────────────────────────────────────────────────────────┤
│ queue_template_notification(): │
│ - Accepts "push" channel │
│ - Formats template with placeholders │
│ - Stores message in queue (status="pending") │
│ - Triggers high-priority async send │
└──────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────┐
│ Celery Worker (Async Tasks) │
├──────────────────────────────────────────────────────────────┤
│ send_message() → send_via_service() │
│ ↓ │
│ Extracts push-specific data from message.udf: │
│ - title │
│ - push_data (context/metadata) │
│ - image_url │
│ ↓ │
│ async send_push_notification() │
└──────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────┐
│ Firebase Service (utils/notify/firebase.py) │
├──────────────────────────────────────────────────────────────┤
│ firebase_service.send_notification(): │
│ - Validates FCM token │
│ - Sends to Firebase Admin SDK │
│ - Handles errors & token invalidation │
│ - Returns message ID or error │
└──────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────┐
│ Firebase Cloud Messaging (Google Infrastructure) │
├──────────────────────────────────────────────────────────────┤
│ - Stores subscription │
│ - Routes to mobile/web device │
│ - Delivers via platform-specific protocol │
│ - Handles retries & backoff │
└──────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────┐
│ Mobile App / Web App (Phase 4) │
├──────────────────────────────────────────────────────────────┤
│ Firebase SDK receives notification │
│ ↓ │
│ System displays to user │
│ ↓ │
│ App can handle notification payload │
└──────────────────────────────────────────────────────────────┘
💾 Database Schema¶
device_tokens Table¶
CREATE TABLE notify.device_tokens (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES core.identity(id) ON DELETE CASCADE,
fcm_token VARCHAR UNIQUE NOT NULL,
platform VARCHAR NOT NULL, -- 'mobile' or 'web'
device_name VARCHAR, -- e.g., "iPhone 14", "Chrome"
is_active BOOLEAN DEFAULT TRUE,
last_used_at TIMESTAMP WITH TIMEZONE,
created_on TIMESTAMP WITH TIMEZONE DEFAULT NOW(),
updated_on TIMESTAMP WITH TIMEZONE DEFAULT NOW()
);
-- Indexes for performance
CREATE INDEX ix_notify_device_tokens_user_id ON notify.device_tokens(user_id);
CREATE INDEX ix_notify_device_tokens_fcm_token ON notify.device_tokens(fcm_token);
CREATE INDEX ix_notify_device_tokens_platform ON notify.device_tokens(platform);
CREATE INDEX ix_notify_device_tokens_is_active ON notify.device_tokens(is_active);
🎯 Key Features¶
✨ Automatic Token Management¶
- Register tokens via
/devices/registerendpoint - Automatically reactivate duplicate tokens
- Track device metadata (platform, name)
- Mark inactive when token expires
⚡ Async Message Processing¶
- Queued via Celery for reliable delivery
- Circuit breaker pattern for provider failures
- Exponential backoff for retries
- Dead letter queue for failed messages
🔐 Security¶
- FCM tokens encrypted in database (like SMS/email fields)
- All endpoints JWT-authenticated
- User can only manage their own tokens
- Firebase credentials via environment variables
📊 Template System¶
- Reuse existing template infrastructure
- Support multiple languages (en, pt, fr)
- Dynamic placeholder substitution
- Store titles, data, images in message payload
📖 Usage Patterns¶
Send Transaction Alert¶
queue_template_notification(
db=session,
channel="push",
template_name="INTERNAL_TRANSFER",
receiver=device_token, # FCM token from device_tokens table
sender="CodeForge Banking",
placeholders={
"debit_name": "John",
"credit_name": "Jane",
"amount": "500.00",
"currency": "USD",
"debit_account": "123456789",
"credit_account": "987654321",
"transaction_reference_id": "TXN123456"
},
service="push",
priority=True, # Send immediately
language="en"
)
Push to Multiple Users¶
# Get all active tokens for a segment
tokens = db.query(DeviceToken).filter(
DeviceToken.is_active == True,
DeviceToken.platform == "mobile"
).all()
# Send to each
for token in tokens:
queue_template_notification(
db=session,
channel="push",
template_name="PROMOTION",
receiver=token.fcm_token,
sender="Promotions",
placeholders={...},
service="push"
)
# Or use Firebase topic-based approach (Phase 4)
firebase_service.subscribe_to_topic(
[t.fcm_token for t in tokens],
"promotion_alerts"
)
🔄 Message Flow Example¶
1. User completes transaction
↓
2. API calls queue_template_notification()
- channel="push"
- template_name="INTERNAL_TRANSFER"
- receiver="{FCM_TOKEN}"
- placeholders={transaction details}
↓
3. Message created in database (status="pending")
↓
4. Celery worker picks up message
- Calls send_message(message_id)
- Fetches message from DB
↓
5. send_via_service() routes to Firebase
- Extracts title, body, data from template
- Calls send_push_notification()
↓
6. Firebase sends notification
- Validated FCM token
- Sends via Firebase Admin SDK
↓
7. Message status updated ("sent" or "failed")
↓
8. User receives notification on device
- Firebase SDK processes
- System displays alert
📋 Checklist - Next Steps¶
Before Production¶
- [ ] Obtain Firebase project credentials
- [ ] Set environment variables
- [ ] Run alembic migration
- [ ] Install firebase-admin package
- [ ] Test device registration endpoint
- [ ] Test push notification sending
Phase 4 - Mobile/Web Integration¶
- [ ] Setup Flutter Firebase messaging
- [ ] Setup React service worker
- [ ] Register tokens on app launch
- [ ] Handle notification display
- [ ] Test end-to-end flow
Monitoring & Operations¶
- [ ] Setup logging for FCM operations
- [ ] Monitor failed messages
- [ ] Track token expiration rate
- [ ] Monitor Celery queue health
📚 Documentation¶
- Setup Guide: PUSH_NOTIFICATIONS_SETUP.md
- Code: See inline comments in firebase.py, device_tokens.py
- API Docs: Auto-generated at /docs (FastAPI swagger)
🎓 Key Technologies¶
| Technology | Purpose |
|---|---|
| Firebase Admin SDK | Backend push notification delivery |
| FCM (Firebase Cloud Messaging) | Google's cross-platform messaging |
| Celery | Async task queue for message processing |
| Redis | Celery broker & result backend |
| SQLAlchemy | Device token persistence |
| FastAPI | RESTful device management APIs |
💡 Design Decisions¶
- Why Firebase over OneSignal?
- Free tier (no cost for startup)
- Native Flutter/React integration
- Better Android/iOS support
-
No additional vendor lock-in
-
Why Celery for push?
- Reliable, horizontal scaling
- Retry logic with exponential backoff
- Monitoring & dead letter queue
-
Consistent with SMS/Email pattern
-
Why separate device_tokens table?
- Tracks multiple devices per user
- Enables platform-specific targeting
- Efficient token lifecycle management
-
Better querying for analytics
-
Why queue messages?
- Decouples from external API
- Handles temporary FCM unavailability
- Provides audit trail
- Enables retry strategies
✉️ Support¶
Questions? Check: 1. PUSH_NOTIFICATIONS_SETUP.md - Complete setup guide 2. utils/notify/firebase.py - Inline documentation 3. controller/notify.py - Queue implementation 4. Firebase Docs - Official guide
Status: ✅ Ready for Phase 4 (Mobile/Web Integration)
Last Updated: April 10, 2026
Implementation Time: ~2 hours for Phases 1-3