# 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
