OneSignal Integration Documentation
Overview
The ms-notifications service now supports OneSignal as a push notification provider alongside the existing FCM (Firebase Cloud Messaging) integration. This enables multi-channel push notification delivery to maximize reach and reliability.
Key Features
Multi-Provider Push Notifications
- Dual Provider Support: Send push notifications through both FCM and OneSignal simultaneously
- Fallback Mechanism: If one service fails, the other can still deliver notifications
- Channel-Specific Routing: Choose to send through specific providers or all at once
Multi-Device Support
- Composite Primary Key: Users can register multiple devices (user_id + device_id)
- Device Types: Support for web, iOS, Android, and other device types
- Flexible IDs: Device ID can be any unique string (e.g., "web", "mobile-uuid-123")
Smart Token Management
- Nullable Tokens: Devices can have FCM token, OneSignal player ID, both, or neither
- Invalid Token Handling: Automatically marks tokens as invalid when push services report failures
- Cleanup Strategy: Only removes tokens confirmed as invalid by the service (not based on inactivity)
- 7-Day Grace Period: Invalid tokens are kept for 7 days before cleanup
Architecture
Push Notification Interface
type PushNotificationService interface {
SendNotificationToUser(userID int, payload PushNotificationPayload) error
RegisterDevice(userID int, deviceID string, token *string) error
UnregisterDevice(userID int, deviceID string) error
MarkTokenInvalid(userID int, deviceID string) error
GetName() string
}Channel Types
- Push Channels: "fcm", "onesignal", "all"/"blast"/"push" (expands to both)
- Email Channel: "email" (completely separate from push)
- WebSocket: Used only for real-time data streaming, NOT push notifications
Database Schema
-- user_devices table
CREATE TABLE user_devices (
user_id INTEGER NOT NULL,
device_id VARCHAR(255) NOT NULL,
device_name VARCHAR(255),
device_type VARCHAR(50), -- web, ios, android
fcm_token TEXT,
onesignal_player_id TEXT,
token_invalid BOOLEAN DEFAULT false,
invalid_since TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, device_id)
);API Endpoints
Device Registration
POST /devices/register
Authorization: Bearer <token>
{
"device_id": "web-browser-1",
"device_name": "Chrome on MacBook",
"device_type": "web",
"fcm_token": "fcm-token-abc123",
"onesignal_player_id": "player-id-xyz789"
}Get User Devices
GET /devices
Authorization: Bearer <token>Update Device Token
PUT /devices/:device_id/token
Authorization: Bearer <token>
{
"fcm_token": "new-fcm-token",
"onesignal_player_id": "new-player-id"
}Unregister Device
DELETE /devices/:device_id
Authorization: Bearer <token>Configuration
Environment Variables
# OneSignal Configuration
ENABLE_ONESIGNAL=true
ONESIGNAL_APP_ID=your-app-id
ONESIGNAL_API_KEY=your-api-key
# FCM Configuration (existing)
ENABLE_FCM=true
FCM_CREDENTIALS_PATH=/path/to/firebase-credentials.json
# or
FIREBASE_SERVICE_ACCOUNT_KEY={"type":"service_account"...}Notification Channels
Sending Notifications
When creating notifications through the internal API:
{
"user_id": 123,
"title": "New Message",
"message": "You have a new message",
"channels": ["push"] // Will send through both FCM and OneSignal
}Channel Options
["fcm"]- Send only through FCM["onesignal"]- Send only through OneSignal["push"]or["all"]or["blast"]- Send through both FCM and OneSignal["email"]- Send email notification (separate from push)["fcm", "email"]- Send through FCM and email
Frontend Integration
Web (Service Worker)
Both FCM and OneSignal use Web Push API. Frontend needs to:
- Register service worker
- Request notification permissions
- Get FCM token or OneSignal player ID
- Send to
/devices/registerendpoint
Mobile Apps
- iOS/Android with FCM: Get FCM token from Firebase SDK
- iOS/Android with OneSignal: Get player ID from OneSignal SDK
- Register both tokens if using dual providers
Testing
Running Integration Tests
# Run all integration tests
./scripts/run_integration_tests.sh
# Run with coverage
./scripts/run_integration_tests.sh --coverage
# Run specific tests
go test -v ./internal/tests -run TestOneSignalService
go test -v ./internal/tests -run TestNotificationChannels
go test -v ./internal/tests -run TestDeviceEndpointsTest Coverage
- OneSignal service implementation
- Multi-device registration
- Token invalidation and cleanup
- Multi-channel notification delivery
- Device management endpoints
- Channel expansion logic
Migration Notes
For Existing Systems
- Run migration:
001_add_onesignal_support.sql - Update environment variables
- No changes needed to existing FCM implementations
- WebSocket connections remain unchanged (data streaming only)
Important Considerations
- Push notifications work when apps are closed - don't clean up based on inactivity
- Both providers can coexist - users can have FCM, OneSignal, or both
- Email is a separate channel - never included in "push" or "all" broadcasts
- WebSocket is for data updates only - not for push notifications
Error Handling
Invalid Tokens
- Services report invalid tokens through specific error types
- Tokens marked as
token_invalid = truewithinvalid_sincetimestamp - Cleanup job removes tokens invalid for > 7 days
- Temporary failures don't trigger cleanup
Service Failures
- Each service failure is logged independently
- Other services continue if one fails
- Returns array of errors for debugging
Best Practices
- Multi-Device Registration: Allow users to register same device with updated tokens
- Token Refresh: Update tokens when apps refresh them
- Graceful Degradation: Continue with available services if one is down
- Channel Selection: Use "push" for maximum reach, specific channels for testing
- Monitoring: Track delivery rates per service to identify issues
Troubleshooting
Common Issues
OneSignal Not Sending
- Check ONESIGNAL_APP_ID and ONESIGNAL_API_KEY
- Verify player IDs are valid
- Check OneSignal dashboard for errors
Duplicate Notifications
- Ensure frontend doesn't register for both FCM and OneSignal browser notifications
- Check service worker implementation
Missing Notifications
- Verify device registration successful
- Check token_invalid status in database
- Review service logs for errors
WebSocket Confusion
- Remember: WebSocket is NOT for push notifications
- Used only for real-time data updates while app is open
Future Enhancements
- Add support for additional push providers (APNs direct, Pusher, etc.)
- Implement priority-based channel selection
- Add delivery confirmation tracking
- Create dashboard for push notification analytics
- Implement rate limiting per provider