222 lines
6.8 KiB
Markdown
222 lines
6.8 KiB
Markdown
# FCM (Firebase Cloud Messaging) Implementation Guide
|
|
|
|
## Overview
|
|
|
|
This document describes the complete FCM push notification implementation for Sojorn, covering both the Go backend and Flutter client. The system supports Android, iOS, and Web platforms.
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
│ Flutter App │────▶│ Go Backend │────▶│ Firebase FCM │
|
|
│ (Android/Web) │ │ Push Service │ │ Cloud Messaging │
|
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
│ │ │
|
|
│ POST /notifications/device │
|
|
│ (Register FCM Token) │
|
|
│ │ │
|
|
│ │ SendPush() │
|
|
│ │──────────────────────▶│
|
|
│ │ │
|
|
│◀──────────────────────│◀──────────────────────│
|
|
│ Push Notification │ │
|
|
```
|
|
|
|
---
|
|
|
|
## Backend Configuration
|
|
|
|
### Required Environment Variables
|
|
|
|
```env
|
|
# Firebase Cloud Messaging (FCM)
|
|
FIREBASE_CREDENTIALS_FILE=/opt/sojorn/firebase-service-account.json
|
|
FIREBASE_WEB_VAPID_KEY=BNxS7_your_actual_vapid_key_here
|
|
```
|
|
|
|
### Firebase Service Account JSON
|
|
|
|
Download from Firebase Console > Project Settings > Service Accounts > Generate New Private Key
|
|
|
|
The JSON file should contain:
|
|
- `project_id`
|
|
- `private_key`
|
|
- `client_email`
|
|
|
|
---
|
|
|
|
## Database Schema
|
|
|
|
### `user_fcm_tokens` Table
|
|
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS user_fcm_tokens (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
user_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
|
|
token TEXT NOT NULL,
|
|
device_type TEXT, -- 'web', 'android', 'ios', 'desktop'
|
|
last_updated TIMESTAMPTZ DEFAULT NOW(),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
UNIQUE(user_id, token) -- Prevents duplicate tokens per device
|
|
);
|
|
```
|
|
|
|
**Key Features:**
|
|
- Composite unique constraint on `(user_id, token)` prevents duplicate registrations
|
|
- `device_type` column supports platform-specific logic
|
|
- `ON DELETE CASCADE` ensures tokens are cleaned up when user is deleted
|
|
|
|
---
|
|
|
|
## Push Notification Triggers
|
|
|
|
| Event | Handler | Recipient | Data Payload |
|
|
|-------|---------|-----------|--------------|
|
|
| New Follower | `user_handler.go:Follow` | Followed user | `type`, `follower_id` |
|
|
| Follow Request | `user_handler.go:Follow` | Target user | `type`, `follower_id` |
|
|
| Follow Accepted | `user_handler.go:AcceptFollowRequest` | Requester | `type`, `follower_id` |
|
|
| New Chat Message | `chat_handler.go:SendMessage` | Receiver | `type`, `conversation_id`, `encrypted` |
|
|
| Comment on Post | `post_handler.go:CreateComment` | Post author | `type`, `post_id`, `post_type`, `target` |
|
|
| Post Saved | `post_handler.go:SavePost` | Post author | `type`, `post_id`, `post_type`, `target` |
|
|
| Beacon Vouched | `post_handler.go:VouchBeacon` | Beacon author | `type`, `beacon_id`, `target` |
|
|
| Beacon Reported | `post_handler.go:ReportBeacon` | Beacon author | `type`, `beacon_id`, `target` |
|
|
|
|
---
|
|
|
|
## Data Payload Structure
|
|
|
|
All push notifications include a `data` payload for deep linking:
|
|
|
|
```json
|
|
{
|
|
"type": "comment|save|reply|chat|new_follower|follow_request|beacon_vouch",
|
|
"post_id": "uuid", // For post-related notifications
|
|
"conversation_id": "uuid", // For chat notifications
|
|
"follower_id": "uuid", // For follow notifications
|
|
"beacon_id": "uuid", // For beacon notifications
|
|
"target": "main_feed|quip_feed|beacon_map|secure_chat|profile|thread_view"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Flutter Client Implementation
|
|
|
|
### Initialization Flow
|
|
|
|
1. **Android 13+ Permission Check**: Explicitly request `POST_NOTIFICATIONS` permission
|
|
2. **Firebase Permission Request**: Request FCM permissions via SDK
|
|
3. **Token Retrieval**: Get FCM token (with VAPID key for web)
|
|
4. **Backend Registration**: POST token to `/notifications/device`
|
|
5. **Set up Listeners**: Handle token refresh and message callbacks
|
|
|
|
### Deep Linking (Message Open Handling)
|
|
|
|
The Flutter client handles these notification types:
|
|
|
|
| Type | Navigation Target |
|
|
|------|-------------------|
|
|
| `chat`, `new_message` | SecureChatScreen with conversation |
|
|
| `save`, `comment`, `reply` | Based on `target` field (home/quips/beacon) |
|
|
| `new_follower`, `follow_request` | Profile screen of follower |
|
|
| `beacon_vouch`, `beacon_report` | Beacon map |
|
|
|
|
### Logout Flow
|
|
|
|
On logout, the client:
|
|
1. Calls `DELETE /notifications/device` with the current token
|
|
2. Deletes the token from Firebase locally
|
|
3. Resets initialization state
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
### Register Device Token
|
|
|
|
```http
|
|
POST /api/v1/notifications/device
|
|
Authorization: Bearer <JWT>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"fcm_token": "device_token_here",
|
|
"platform": "android|ios|web|desktop"
|
|
}
|
|
```
|
|
|
|
### Unregister Device Token
|
|
|
|
```http
|
|
DELETE /api/v1/notifications/device
|
|
Authorization: Bearer <JWT>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"fcm_token": "device_token_here"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Token Not Registering
|
|
|
|
1. Check Firebase is initialized properly
|
|
2. Verify `FIREBASE_CREDENTIALS_FILE` path is correct
|
|
3. For web, ensure `FIREBASE_WEB_VAPID_KEY` is set
|
|
4. Check network connectivity to Go backend
|
|
|
|
### Notifications Not Arriving
|
|
|
|
1. Verify token exists in `user_fcm_tokens` table
|
|
2. Check Firebase Console for delivery reports
|
|
3. Ensure app hasn't restricted background data
|
|
4. On Android 13+, verify POST_NOTIFICATIONS permission
|
|
|
|
### Invalid Token Cleanup
|
|
|
|
The `PushService` automatically removes invalid tokens when FCM returns `messaging.IsRegistrationTokenNotRegistered` error.
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
### Manual Token Verification
|
|
|
|
```sql
|
|
SELECT user_id, token, device_type, last_updated
|
|
FROM user_fcm_tokens
|
|
WHERE user_id = 'your-user-uuid';
|
|
```
|
|
|
|
### Send Test Notification
|
|
|
|
Use Firebase Console > Cloud Messaging > Send test message with the device token.
|
|
|
|
---
|
|
|
|
## Platform-Specific Notes
|
|
|
|
### Android
|
|
|
|
- Target SDK 33+ requires `POST_NOTIFICATIONS` runtime permission
|
|
- Add to `AndroidManifest.xml`:
|
|
```xml
|
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
|
```
|
|
|
|
### Web
|
|
|
|
- Requires valid VAPID key from Firebase Console
|
|
- Service worker must be properly configured
|
|
- HTTPS required (except localhost)
|
|
|
|
### iOS
|
|
|
|
- Requires APNs configuration in Firebase
|
|
- Provisioning profile must include push notification capability
|