# Firebase Admin SDK (FCM V1) Setup Guide for Laravel

## 🚀 Complete Setup Instructions

This guide will help you set up Firebase Cloud Messaging using the **new Firebase Admin SDK (FCM V1 API)** which replaces the deprecated legacy HTTP API.

---

## 📋 Prerequisites

1. **Firebase Project**: Must have an active Firebase project
2. **Composer**: PHP dependency manager installed
3. **Laravel**: Version 5.7 or higher

---

## 🔧 Step 1: Install Firebase Admin SDK

Install the official Firebase Admin SDK for PHP via Composer:

```bash
composer require kreait/firebase-php
```

This package provides the Firebase Admin SDK which supports the new FCM V1 API.

**Package Information:**

- Name: `kreait/firebase-php`
- Documentation: https://firebase-php.readthedocs.io/
- GitHub: https://github.com/kreait/firebase-php

---

## 🔑 Step 2: Get Firebase Service Account Credentials

### 2.1 Download Service Account JSON File

1. Go to **Firebase Console**: https://console.firebase.google.com/
2. Select your project: **disruptdemo**
3. Click the **gear icon** ⚙️ → **Project Settings**
4. Go to the **"Service accounts"** tab
5. Click **"Generate new private key"** button
6. Click **"Generate key"** in the confirmation dialog
7. A JSON file will be downloaded

### 2.2 Rename and Upload the File

The downloaded file will have a name like:

```
disruptdemo-firebase-adminsdk-xxxxx-xxxxxxxxxx.json
```

**Rename it to:**

```
disruptdemo-firebase-adminsdk-fbsvc-5d1bff0c1f.json
```

**Upload to:**

```
/storage/app/firebase/disruptdemo-firebase-adminsdk-fbsvc-5d1bff0c1f.json
```

### 2.3 Verify File Location

Your directory structure should look like:

```
your-project/
├── storage/
│   └── app/
│       └── firebase/
│           ├── .gitignore
│           ├── README.md
│           └── disruptdemo-firebase-adminsdk-fbsvc-5d1bff0c1f.json  ← Here!
```

⚠️ **SECURITY NOTE**: The `.gitignore` file ensures this credentials file won't be committed to version control.

---

## 🔐 Step 3: Configure Environment Variables

### 3.1 Update `.env` File

Open your `.env` file and add:

```env
# Firebase Admin SDK Configuration (FCM V1 API)
# Path to Firebase service account JSON file
FIREBASE_CREDENTIALS=storage/app/firebase/disruptdemo-firebase-adminsdk-fbsvc-5d1bff0c1f.json

# Optional: Firebase Project ID (auto-detected from credentials)
FIREBASE_PROJECT_ID=disruptdemo

# Legacy FCM Server Key (Deprecated - for backward compatibility)
# Only needed if using legacy HTTP API
FCM_SERVER_KEY=your_legacy_server_key_here
```

### 3.2 Explanation of Variables

- **FIREBASE_CREDENTIALS**: Relative path to service account JSON (from project root)
- **FIREBASE_PROJECT_ID**: Your Firebase project ID (optional, auto-detected)
- **FCM_SERVER_KEY**: Legacy server key (deprecated, only for backward compatibility)

---

## ⚙️ Step 4: Configuration Files (Already Created)

The following files have already been created for you:

### 4.1 Firebase Configuration

**File**: `config/firebase.php`

Contains:

- Credentials file path
- Project ID
- Default notification settings
- Legacy server key fallback

### 4.2 Firebase Service (V1 API)

**File**: `app/Services/FirebaseServiceV1.php`

This is the **new** Firebase service using Firebase Admin SDK.

**Features:**

- ✅ FCM V1 API support
- ✅ Topic-based messaging
- ✅ Token-based messaging
- ✅ Multicast messaging (batch sends)
- ✅ Token validation
- ✅ Subscribe/Unsubscribe to topics
- ✅ Comprehensive error logging

---

## 🔄 Step 5: Migrate from Legacy to V1 API

### 5.1 Option A: Use New Service Directly

To use the new Firebase Admin SDK service:

**In your controllers:**

```php
use App\Services\FirebaseServiceV1;

class NotificationController extends Controller
{
    protected $firebaseService;

    public function __construct(FirebaseServiceV1 $firebaseService)
    {
        $this->firebaseService = $firebaseService;
    }

    public function sendNotification()
    {
        $result = $this->firebaseService->sendToTopic(
            'program-123',
            'New Episode Available!',
            'Check out the latest episode',
            ['episode_id' => '123']
        );

        return response()->json($result);
    }
}
```

### 5.2 Option B: Replace Existing Service

If you want to replace the existing `FirebaseService.php`:

1. **Backup the old service:**

   ```bash
   cp app/Services/FirebaseService.php app/Services/FirebaseServiceLegacy.php
   ```

2. **Replace with new version:**

   ```bash
   cp app/Services/FirebaseServiceV1.php app/Services/FirebaseService.php
   ```

3. **Update any type hints** if needed in your controllers

### 5.3 Current Usage Points

The Firebase service is currently used in:

1. **NotificationController** (`app/Http/Controllers/NotificationController.php`)
   - `subscribe()` method
   - `unsubscribe()` method
2. **WebhookClient** (`app/Http/Controllers/WebhookClient.php`)
   - `sendNewAudioNotification()` method

---

## ✅ Step 6: Verify Installation

### 6.1 Test Firebase Connection

Open terminal and run:

```bash
php artisan tinker
```

Then execute:

```php
>>> app(\App\Services\FirebaseServiceV1::class)->messaging();
```

**Expected Result:**

- Should return a Firebase Messaging object
- No errors should appear

**If you see errors:**

- Check that the service account JSON file exists
- Verify the path in `.env` is correct
- Ensure the JSON file is valid

### 6.2 Test Topic Subscription

```bash
php artisan tinker
```

```php
>>> $service = app(\App\Services\FirebaseServiceV1::class);
>>> $result = $service->subscribeToTopic('test_token_123', 'test-topic');
>>> dd($result);
```

**Expected Result:**

```php
[
  "success" => true,
  "message" => "Successfully subscribed to topic",
  "topic" => "test-topic"
]
```

### 6.3 Send Test Notification

⚠️ **Note**: You need a valid FCM token to receive the notification.

```bash
php artisan tinker
```

```php
>>> $service = app(\App\Services\FirebaseServiceV1::class);
>>> $result = $service->sendToTopic(
...     'test-topic',
...     'Hello from Firebase!',
...     'Firebase Admin SDK is working correctly!',
...     ['type' => 'test', 'timestamp' => now()]
... );
>>> dd($result);
```

**Expected Result:**

```php
[
  "success" => true,
  "message" => "Notification sent successfully",
  "data" => [
    "message_id" => "projects/disruptdemo/messages/0:1234567890",
    "topic" => "test-topic"
  ]
]
```

---

## 📊 Step 7: Update Existing Code (Optional)

### 7.1 Update WebhookClient.php

If you want to use the new service in `WebhookClient.php`:

**Current code** (line 498-531):

```php
protected function sendNewAudioNotification($audio, $program)
{
    try {
        $topic = "program-{$program->id}";
        $title = "🎵 New Audio Available!";
        $body = "{$audio->audio_title} - {$program->name}";

        $data = [
            'type' => 'new_audio',
            'program_id' => (string) $program->id,
            'audio_id' => (string) $audio->id,
            'audio_title' => $audio->audio_title,
            'audio_url' => url("/audio/{$audio->audio_slug}"),
        ];

        $result = $this->firebaseService->sendToTopic($topic, $title, $body, $data);

        // Rest of code...
    }
}
```

**New code** (with FirebaseServiceV1):

```php
use App\Services\FirebaseServiceV1;

class WebhookClient extends Controller
{
    protected $firebaseService;

    public function __construct(FirebaseServiceV1 $firebaseService)
    {
        $this->firebaseService = $firebaseService;
    }

    protected function sendNewAudioNotification($audio, $program)
    {
        try {
            $topic = "program-{$program->id}";
            $title = "🎵 New Audio Available!";
            $body = "{$audio->audio_title} - {$program->name}";

            $data = [
                'type' => 'new_audio',
                'program_id' => (string) $program->id,
                'audio_id' => (string) $audio->id,
                'audio_title' => $audio->audio_title,
                'audio_url' => url("/audio/{$audio->audio_slug}"),
            ];

            $result = $this->firebaseService->sendToTopic($topic, $title, $body, $data);

            if ($result['success']) {
                \Log::info("Push notification sent for new audio", [
                    'program_id' => $program->id,
                    'audio_id' => $audio->id,
                    'message_id' => $result['data']['message_id'] ?? null,
                ]);
            }
        } catch (\Exception $e) {
            \Log::error("Failed to send push notification for new audio", [
                'error' => $e->getMessage(),
            ]);
        }
    }
}
```

### 7.2 Update NotificationController.php

**Current constructor:**

```php
use App\Services\FirebaseService;

public function __construct(FirebaseService $firebaseService)
{
    $this->firebaseService = $firebaseService;
}
```

**New constructor:**

```php
use App\Services\FirebaseServiceV1;

public function __construct(FirebaseServiceV1 $firebaseService)
{
    $this->firebaseService = $firebaseService;
}
```

The rest of the code remains the same! The new service maintains the same method signatures.

---

## 🎯 Step 8: Testing in Production

### 8.1 Test with Real Users

1. **User subscribes to a program:**

   - User clicks "Notify Me" button
   - FCM token is saved to database
   - Token is subscribed to topic (e.g., "program-123")

2. **New audio is added:**

   - Webhook receives new audio
   - `sendNewAudioNotification()` is called
   - Notification sent to all subscribers

3. **User receives notification:**
   - On web: Browser notification appears
   - On mobile: Push notification appears

### 8.2 Monitor Logs

Check Laravel logs for Firebase operations:

```bash
tail -f storage/logs/laravel.log | grep -i firebase
```

**Look for:**

- "Token subscribed to topic"
- "Push notification sent to topic"
- "Firebase initialization error" (if something went wrong)

### 8.3 Check Database

Verify subscriptions are being stored:

```sql
SELECT * FROM fcm_tokens WHERE topic LIKE 'program-%';
```

---

## 📱 Step 9: Frontend Updates (Optional)

Your frontend already uses Firebase SDK. No changes needed unless you want to update to the latest version.

**Current files:**

- `public/firebase-messaging-sw.js` - Service worker
- `public/js/notification-bell.js` - Notification UI

These files work with both legacy and V1 API.

---

## 🔍 Troubleshooting

### Problem: "Firebase credentials file not found"

**Solution:**

1. Verify file exists: `ls -la storage/app/firebase/`
2. Check path in `.env` matches actual location
3. Ensure file permissions allow reading (644)

### Problem: "Invalid service account"

**Solution:**

1. Download a fresh service account JSON from Firebase Console
2. Verify it's from the correct project (disruptdemo)
3. Check JSON file is valid (use `cat` or text editor)

### Problem: "Failed to send notification"

**Solution:**

1. Check FCM token is valid
2. Verify topic exists and has subscribers
3. Check Firebase project has Cloud Messaging enabled
4. Review logs: `storage/logs/laravel.log`

### Problem: "Class not found: Kreait\Firebase\Factory"

**Solution:**

```bash
composer require kreait/firebase-php
composer dump-autoload
```

### Problem: Notifications work in development but not production

**Solution:**

1. Ensure `.env` has correct `FIREBASE_CREDENTIALS` path
2. Verify service account JSON uploaded to production server
3. Check file permissions on production
4. Clear config cache: `php artisan config:clear`

---

## 📚 API Reference

### FirebaseServiceV1 Methods

#### `messaging()`

Get Firebase Messaging instance.

```php
$messaging = $service->messaging();
```

#### `subscribeToTopic($token, $topic)`

Subscribe device token to a topic.

```php
$result = $service->subscribeToTopic('fcm_token_here', 'program-123');
```

**Returns:**

```php
[
    'success' => true,
    'message' => 'Successfully subscribed to topic',
    'topic' => 'program-123'
]
```

#### `unsubscribeFromTopic($token, $topic)`

Unsubscribe device token from a topic.

```php
$result = $service->unsubscribeFromTopic('fcm_token_here', 'program-123');
```

#### `sendToTopic($topic, $title, $body, $data = [])`

Send notification to all subscribers of a topic.

```php
$result = $service->sendToTopic(
    'program-123',
    'New Episode!',
    'Check out our latest episode',
    ['episode_id' => '456', 'type' => 'new_episode']
);
```

**Returns:**

```php
[
    'success' => true,
    'message' => 'Notification sent successfully',
    'data' => [
        'message_id' => 'projects/disruptdemo/messages/0:...',
        'topic' => 'program-123'
    ]
]
```

#### `sendToTokens($tokens, $title, $body, $data = [])`

Send notification to specific device tokens.

```php
$result = $service->sendToTokens(
    ['token1', 'token2', 'token3'],
    'Hello!',
    'Notification to specific users',
    ['custom' => 'data']
);
```

#### `sendMulticast($tokens, $title, $body, $data = [])`

Efficiently send to multiple tokens (recommended for batch sends).

```php
$result = $service->sendMulticast(
    $tokenArray,
    'Bulk Notification',
    'Message to many users',
    ['campaign' => 'promo-2024']
);
```

#### `validateToken($token)`

Check if an FCM token is valid.

```php
$isValid = $service->validateToken('fcm_token_here');
// Returns: true or false
```

---

## 🔄 Migration Checklist

- [ ] Install `kreait/firebase-php` package
- [ ] Download and upload service account JSON file
- [ ] Add `FIREBASE_CREDENTIALS` to `.env`
- [ ] Verify `config/firebase.php` exists
- [ ] Test Firebase connection with tinker
- [ ] Update controller to use `FirebaseServiceV1`
- [ ] Test topic subscription
- [ ] Test sending notification
- [ ] Monitor logs for errors
- [ ] Test in production environment

---

## 📖 Additional Resources

- **Firebase Admin SDK Docs**: https://firebase.google.com/docs/admin/setup
- **FCM V1 Migration Guide**: https://firebase.google.com/docs/cloud-messaging/migrate-v1
- **kreait/firebase-php Docs**: https://firebase-php.readthedocs.io/
- **FCM Best Practices**: https://firebase.google.com/docs/cloud-messaging/concept-options

---

## 🎉 Conclusion

You've successfully set up Firebase Admin SDK (FCM V1 API) in your Laravel application!

**What you have now:**

- ✅ Modern FCM V1 API support
- ✅ Future-proof implementation
- ✅ Better error handling
- ✅ Topic and token-based messaging
- ✅ Multicast support for batch sends
- ✅ Comprehensive logging

**Next steps:**

1. Upload your service account JSON file
2. Test the connection
3. Update controllers to use new service
4. Monitor logs and test notifications
5. Deploy to production

Need help? Check the troubleshooting section or review the logs at `storage/logs/laravel.log`.
