# Integration Guide: Connecting Your Application to the Notification Microservice

This guide explains how to integrate the notification microservice with your existing application.

## Table of Contents

1. [Prerequisites](#prerequisites)
2. [Initial Setup](#initial-setup)
3. [Database Configuration](#database-configuration)
4. [Redis Configuration](#redis-configuration)
5. [API Integration](#api-integration)
6. [Authentication Setup](#authentication-setup)
7. [Client-Side Integration](#client-side-integration)
8. [Deployment](#deployment)

---

## Prerequisites

- Node.js 18+ installed
- MySQL 8+ running
- Redis 6+ running
- Your existing application (can be any language/framework)

---

## Initial Setup

### 1. Clone/Setup the Microservice

```bash
cd /path/to/nestjs
npm install
```

### 2. Configure Environment Variables

Copy `.env` file and update with your credentials:

```bash
cp env.example .env
```

Edit `.env` with your actual values:

```env
# Database
DB_HOST=your-mysql-host
DB_PORT=3306
DB_USERNAME=your-db-user
DB_PASSWORD=your-db-password
DB_DATABASE=notification_db

# Redis
REDIS_HOST=your-redis-host
REDIS_PORT=6379
REDIS_PASSWORD=your-redis-password

# JWT Secrets (generate strong random strings)
JWT_SECRET=your-strong-jwt-secret-here
JWT_REFRESH_SECRET=your-strong-refresh-secret-here

# Application
NODE_ENV=production
PORT=3000
API_PREFIX=api/v1
```

### 3. Run Database Migrations

```bash
npm run migration:run
```

This creates all necessary tables in your database.

---

## Database Configuration

### Option A: Shared Database (Development)

If you want to use the same MySQL instance as your existing app:

1. Create a separate database:
```sql
CREATE DATABASE notification_db;
```

2. Update `.env` with the database name
3. Run migrations

### Option B: Separate Database (Production Recommended)

Use a dedicated MySQL instance for the notification service for better isolation and scaling.

---

## Redis Configuration

### Option A: Shared Redis (Development)

If using the same Redis instance:

1. Use a different database number:
```env
REDIS_DB=1  # Use 1 instead of 0 to avoid conflicts
```

2. The service uses key prefix `notification:` to avoid conflicts

### Option B: Dedicated Redis (Production Recommended)

Use a separate Redis instance for better performance and isolation.

---

## API Integration

### Step 1: Create a Project (Platform Admin)

First, you need to create a project to get API credentials. You can do this via:

**Option A: Using Platform Admin API**

```bash
# 1. Login as platform admin
curl -X POST http://localhost:3000/api/v1/platform/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@platform.com",
    "password": "admin-password"
  }'

# Response contains platform_jwt_token

# 2. Create a project
curl -X POST http://localhost:3000/api/v1/platform/projects \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_PLATFORM_JWT_TOKEN" \
  -d '{
    "name": "My Application",
    "status": "active",
    "plan": "starter",
    "billingEmail": "billing@myapp.com",
    "webhookUrl": "https://myapp.com/webhooks/notifications",
    "webhookSecret": "my-webhook-secret",
    "pusherConfig": {
      "appId": "your-pusher-app-id",
      "key": "your-pusher-key",
      "secret": "your-pusher-secret",
      "cluster": "us2"
    }
  }'

# Response contains apiKey and apiSecret - SAVE THESE!
```

**Option B: Direct Database Insert (Not Recommended for Production)**

You can manually insert a project into the database, but you'll need to hash the API secret yourself.

### Step 2: Store API Credentials Securely

Store the API key and secret in your application's secure configuration:

**Node.js Example:**
```javascript
// config/notification.js
module.exports = {
  notificationService: {
    baseUrl: process.env.NOTIFICATION_SERVICE_URL || 'http://localhost:3000',
    apiKey: process.env.NOTIFICATION_API_KEY,
    apiSecret: process.env.NOTIFICATION_API_SECRET,
  }
};
```

**Python Example:**
```python
# config/notification.py
import os

NOTIFICATION_SERVICE_URL = os.getenv('NOTIFICATION_SERVICE_URL', 'http://localhost:3000')
NOTIFICATION_API_KEY = os.getenv('NOTIFICATION_API_KEY')
NOTIFICATION_API_SECRET = os.getenv('NOTIFICATION_API_SECRET')
```

---

## Authentication Setup

### API Key Authentication (Server-to-Server)

For server-to-server communication (event ingestion, user management), use API Key authentication:

**Node.js Example:**
```javascript
const axios = require('axios');

async function sendEvent(eventData) {
  const response = await axios.post(
    `${config.notificationService.baseUrl}/api/v1/events`,
    eventData,
    {
      headers: {
        'X-API-Key': config.notificationService.apiKey,
        'X-API-Secret': config.notificationService.apiSecret,
        'Content-Type': 'application/json',
      },
    }
  );
  return response.data;
}

// Usage
await sendEvent({
  type: 'pending_transaction',
  payload: {
    transactionId: 'TX_123',
    amount: 50000,
    currency: 'NGN',
    status: 'pending',
  },
  clientEventId: 'client_event_123',
});
```

**Python Example:**
```python
import requests

def send_event(event_data):
    response = requests.post(
        f"{NOTIFICATION_SERVICE_URL}/api/v1/events",
        json=event_data,
        headers={
            'X-API-Key': NOTIFICATION_API_KEY,
            'X-API-Secret': NOTIFICATION_API_SECRET,
            'Content-Type': 'application/json',
        }
    )
    return response.json()

# Usage
send_event({
    'type': 'pending_transaction',
    'payload': {
        'transactionId': 'TX_123',
        'amount': 50000,
        'currency': 'NGN',
        'status': 'pending',
    },
    'clientEventId': 'client_event_123',
})
```

**PHP Example:**
```php
<?php
function sendEvent($eventData) {
    $ch = curl_init('http://localhost:3000/api/v1/events');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($eventData));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'X-API-Key: ' . getenv('NOTIFICATION_API_KEY'),
        'X-API-Secret: ' . getenv('NOTIFICATION_API_SECRET'),
        'Content-Type: application/json',
    ]);
    $response = curl_exec($ch);
    curl_close($ch);
    return json_decode($response, true);
}
?>
```

---

## Client-Side Integration

### Step 1: User Registration/Login

Your application should register users with the notification service:

**Node.js Example:**
```javascript
async function registerUserWithNotifications(userData) {
  const response = await axios.post(
    `${config.notificationService.baseUrl}/api/v1/users`,
    {
      email: userData.email,
      password: userData.password, // Or generate a random password
      fullName: userData.fullName,
      externalUserId: userData.id, // Your app's user ID
      roles: userData.roles || ['user'],
    },
    {
      headers: {
        'X-API-Key': config.notificationService.apiKey,
        'X-API-Secret': config.notificationService.apiSecret,
        'Content-Type': 'application/json',
      },
    }
  );
  return response.data;
}
```

### Step 2: Real-time Notifications (Pusher)

For real-time notifications, integrate Pusher on the client side:

**JavaScript/React Example:**
```javascript
import Pusher from 'pusher-js';

// Initialize Pusher
const pusher = new Pusher('YOUR_PUSHER_KEY', {
  cluster: 'us2',
  authEndpoint: 'http://localhost:3000/api/v1/users/me/pusher-auth',
  auth: {
    headers: {
      Authorization: `Bearer ${userJwtToken}`,
    },
  },
});

// Subscribe to user's private channel
const channel = pusher.subscribe(`private-user-${userId}`);

// Listen for notifications
channel.bind('notification', (data) => {
  console.log('New notification:', data);
  // Display notification
  showNotification(data);
  // Play sound if provided
  if (data.sound) {
    playSound(data.sound);
  }
});
```

**React Native Example:**
```javascript
import Pusher from 'pusher-js/react-native';

const pusher = new Pusher('YOUR_PUSHER_KEY', {
  cluster: 'us2',
  authEndpoint: 'http://localhost:3000/api/v1/users/me/pusher-auth',
  auth: {
    headers: {
      Authorization: `Bearer ${userJwtToken}`,
    },
  },
});

const channel = pusher.subscribe(`private-user-${userId}`);
channel.bind('notification', handleNotification);
```

### Step 3: Push Notifications (FCM/APNs)

Update user's push tokens when they log in:

**Node.js Example:**
```javascript
async function updatePushTokens(userId, fcmToken, apnsToken) {
  // First, user needs to login to get JWT token
  const loginResponse = await axios.post(
    `${config.notificationService.baseUrl}/api/v1/auth/login`,
    {
      email: userEmail,
      password: userPassword,
    },
    {
      headers: {
        'X-API-Key': config.notificationService.apiKey,
        'X-API-Secret': config.notificationService.apiSecret,
      },
    }
  );

  const jwtToken = loginResponse.data.accessToken;

  // Update push tokens
  await axios.patch(
    `${config.notificationService.baseUrl}/api/v1/users/me/push-tokens`,
    {
      fcm: fcmToken,
      apns: apnsToken,
    },
    {
      headers: {
        Authorization: `Bearer ${jwtToken}`,
        'Content-Type': 'application/json',
      },
    }
  );
}
```

---

## Webhook Integration

If you configured a webhook URL, the service will send events to your application:

**Node.js Webhook Handler Example:**
```javascript
const express = require('express');
const crypto = require('crypto');

app.post('/webhooks/notifications', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const event = req.headers['x-webhook-event'];
  const payload = req.body;

  // Verify HMAC signature
  const hmac = crypto.createHmac('sha256', process.env.WEBHOOK_SECRET);
  hmac.update(JSON.stringify(payload));
  const expectedSignature = `sha256=${hmac.digest('hex')}`;

  if (signature !== expectedSignature) {
    return res.status(401).send('Invalid signature');
  }

  // Handle webhook event
  switch (event) {
    case 'notification.delivered':
      console.log('Notification delivered:', payload.data);
      break;
    case 'notification.acknowledged':
      console.log('Notification acknowledged:', payload.data);
      break;
    case 'quota.warning':
      console.log('Quota warning:', payload.data);
      break;
    case 'quota.exceeded':
      console.log('Quota exceeded:', payload.data);
      break;
  }

  res.status(200).send('OK');
});
```

---

## Deployment

### Option A: Docker Deployment

Create a `Dockerfile`:

```dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

EXPOSE 3000

CMD ["npm", "run", "start:prod"]
```

Create `docker-compose.yml`:

```yaml
version: '3.8'

services:
  notification-service:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - mysql
      - redis
    volumes:
      - ./certs:/app/certs  # For Firebase service account

  mysql:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: notification_db
    volumes:
      - mysql_data:/var/lib/mysql

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data

volumes:
  mysql_data:
  redis_data:
```

### Option B: Kubernetes Deployment

See Kubernetes manifests in `k8s/` directory (create as needed).

### Option C: Cloud Deployment

**AWS:**
- Deploy to ECS/EKS
- Use RDS for MySQL
- Use ElastiCache for Redis
- Use ALB for load balancing

**Google Cloud:**
- Deploy to Cloud Run or GKE
- Use Cloud SQL for MySQL
- Use Memorystore for Redis

**Azure:**
- Deploy to App Service or AKS
- Use Azure Database for MySQL
- Use Azure Cache for Redis

---

## Testing the Integration

### 1. Test Health Endpoint

```bash
curl http://localhost:3000/health
```

### 2. Test Event Ingestion

```bash
curl -X POST http://localhost:3000/api/v1/events \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "test_event",
    "payload": {"message": "Hello World"}
  }'
```

### 3. Test User Registration

```bash
curl -X POST http://localhost:3000/api/v1/users \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test@example.com",
    "password": "password123",
    "fullName": "Test User",
    "roles": ["user"]
  }'
```

---

## Common Integration Patterns

### Pattern 1: Event-Driven Integration

```javascript
// In your application, when an event occurs:
async function handleTransactionCreated(transaction) {
  // 1. Process transaction in your app
  await processTransaction(transaction);

  // 2. Send event to notification service
  await sendEvent({
    type: 'transaction_created',
    payload: {
      transactionId: transaction.id,
      amount: transaction.amount,
      userId: transaction.userId,
    },
    clientEventId: `tx_${transaction.id}`,
  });
}
```

### Pattern 2: User Sync Integration

```javascript
// Sync users from your app to notification service
async function syncUsers() {
  const users = await getUsersFromYourDatabase();
  
  await axios.post(
    `${config.notificationService.baseUrl}/api/v1/users/sync`,
    { users: users.map(u => ({
      email: u.email,
      externalUserId: u.id,
      fullName: u.name,
      roles: u.roles,
    })) },
    {
      headers: {
        'X-API-Key': config.notificationService.apiKey,
        'X-API-Secret': config.notificationService.apiSecret,
      },
    }
  );
}
```

### Pattern 3: Rule-Based Notifications

```javascript
// Create rules for your business logic
async function setupNotificationRules() {
  const rules = [
    {
      name: 'High Value Transaction',
      condition: "event.type == 'transaction' && event.payload.amount > 100000",
      targetRoles: ['admin', 'finance'],
      title: 'High Value Transaction Alert',
      message: 'Transaction {{event.payload.transactionId}} for {{event.payload.amount}}',
      active: true,
    },
    // ... more rules
  ];

  for (const rule of rules) {
    await createRule(rule); // Use JWT auth for this
  }
}
```

---

## Troubleshooting

### Issue: "Project context not set"

**Solution:** Make sure you're sending `X-API-Key` and `X-API-Secret` headers with API key authenticated requests.

### Issue: "Invalid API key"

**Solution:** Verify your API key and secret are correct. Check the project status is 'active' in the database.

### Issue: "JWT token expired"

**Solution:** Implement token refresh logic:

```javascript
async function getValidToken() {
  if (isTokenExpired(jwtToken)) {
    const response = await axios.post(
      `${baseUrl}/api/v1/auth/refresh`,
      { refreshToken: refreshToken }
    );
    jwtToken = response.data.accessToken;
    refreshToken = response.data.refreshToken;
  }
  return jwtToken;
}
```

### Issue: Notifications not being delivered

**Solution:**
1. Check Pusher configuration in project settings
2. Verify user has active status
3. Check notification delivery logs
4. Verify webhook URL is accessible (if configured)

---

## Next Steps

1. **Set up monitoring**: Add logging and monitoring for the notification service
2. **Configure alerts**: Set up alerts for quota warnings
3. **Scale horizontally**: Deploy multiple instances behind a load balancer
4. **Implement retry logic**: Add retry logic for failed API calls
5. **Cache tokens**: Cache JWT tokens to reduce authentication overhead

---

## Support

For issues or questions:
- Check the API documentation in Postman collection
- Review the implementation status in `IMPLEMENTATION_STATUS.md`
- Check logs: `logs/app.log` (if configured)
