# Redis Setup Tutorial for We-Care-Cloud

This tutorial will guide you through setting up Redis for device token settings caching in your Laravel application.

## Table of Contents
1. [What is Redis?](#what-is-redis)
2. [Why Use Redis for Device Tokens?](#why-use-redis-for-device-tokens)
3. [Installation](#installation)
4. [Configuration](#configuration)
5. [Testing Redis Connection](#testing-redis-connection)
6. [Syncing Existing Data](#syncing-existing-data)
7. [Usage](#usage)
8. [Troubleshooting](#troubleshooting)

---

## What is Redis?

Redis (Remote Dictionary Server) is an in-memory data structure store that can be used as a database, cache, and message broker. It's extremely fast because it stores data in memory rather than on disk.

## Why Use Redis for Device Tokens?

- **Performance**: Redis is much faster than database queries (microseconds vs milliseconds)
- **Scalability**: Handles high-frequency read operations efficiently
- **Real-time Updates**: Perfect for tracking online/offline status
- **Reduced Database Load**: Offloads frequent queries from your main database

---

## Installation

### Windows (Using Laragon)

Laragon includes Redis support. Follow these steps:

#### Option 1: Using Laragon's Built-in Redis (Recommended)

1. **Open Laragon**
2. **Go to Menu → Tools → Redis**
3. **Click "Start Redis"** (if not already running)
4. Redis will start on default port `6379`

#### Option 2: Manual Installation on Windows

1. **Download Redis for Windows:**
   - Visit: https://github.com/microsoftarchive/redis/releases
   - Download the latest `Redis-x64-*.zip` file
   - Or use WSL2 (Windows Subsystem for Linux) for better performance

2. **Extract and Run:**
   ```powershell
   # Extract to C:\redis
   # Run Redis server
   cd C:\redis
   redis-server.exe
   ```

3. **Install Redis as Windows Service (Optional):**
   ```powershell
   redis-server --service-install
   redis-server --service-start
   ```

### Linux (Ubuntu/Debian)

```bash
# Update package list
sudo apt update

# Install Redis
sudo apt install redis-server

# Start Redis service
sudo systemctl start redis-server

# Enable Redis to start on boot
sudo systemctl enable redis-server

# Check Redis status
sudo systemctl status redis-server
```

### macOS

```bash
# Using Homebrew
brew install redis

# Start Redis
brew services start redis

# Or run manually
redis-server
```

---

## Configuration

### 1. Install PHP Redis Extension

#### Windows (Laragon)

Laragon usually includes the Redis PHP extension. If not:

1. **Check if extension is loaded:**
   ```php
   php -m | grep redis
   ```

2. **If not installed, download from:**
   - https://pecl.php.net/package/redis
   - Or use Laragon's extension manager

3. **Enable in php.ini:**
   ```ini
   extension=redis
   ```

#### Linux

```bash
# Install PHP Redis extension
sudo apt install php-redis

# Or compile from source
pecl install redis
```

#### macOS

```bash
brew install php-redis
```

### 2. Install Composer Package

The project already uses Laravel's built-in Redis support. Ensure `predis` or `phpredis` is available:

```bash
# Check if predis is installed (Laravel 11 uses it by default)
composer show | grep predis
```

If not installed, add to `composer.json`:

```json
{
    "require": {
        "predis/predis": "^2.0"
    }
}
```

Then run:
```bash
composer install
```

### 3. Configure Laravel Environment

Edit your `.env` file:

```env
# Redis Configuration
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_DB=0
REDIS_CLIENT=predis

# Cache Database (separate from default)
REDIS_CACHE_DB=1
```

### 4. Verify Database Configuration

Check `config/database.php` - it should already have Redis configuration:

```php
'redis' => [
    'client' => env('REDIS_CLIENT', 'predis'),
    'default' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_DB', 0),
    ],
    'cache' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_CACHE_DB', 1),
    ],
],
```

---

## Testing Redis Connection

### 1. Test via Laravel Tinker

```bash
php artisan tinker
```

```php
// Test Redis connection
Redis::ping();
// Should return: "PONG"

// Set a test value
Redis::set('test_key', 'test_value');

// Get the value
Redis::get('test_key');
// Should return: "test_value"

// Delete test key
Redis::del('test_key');
```

### 2. Test via Command Line

```bash
# Test Redis service
redis-cli ping
# Should return: PONG

# Connect to Redis CLI
redis-cli

# Inside Redis CLI:
SET test "Hello Redis"
GET test
# Should return: "Hello Redis"

DEL test
EXIT
```

### 3. Test Device Token Service

```bash
php artisan tinker
```

```php
use App\Services\RedisDeviceTokenService;
use App\Models\DeviceTokenSetting;

// Get a device token from database
$deviceToken = DeviceTokenSetting::first();

// Sync to Redis
RedisDeviceTokenService::syncFromDatabase($deviceToken);

// Get from Redis
$redisData = RedisDeviceTokenService::getDeviceToken(
    $deviceToken->user_id,
    $deviceToken->device_id
);

// Should return array with device token data
dd($redisData);
```

---

## Syncing Existing Data

### Sync All Device Tokens to Redis

Run the artisan command to sync all existing device tokens:

```bash
php artisan device-tokens:sync-redis
```

This will:
- Read all device tokens from the database
- Store them in Redis with proper structure
- Show progress and summary

### Force Re-sync (if needed)

```bash
php artisan device-tokens:sync-redis --force
```

### Verify Sync

```bash
php artisan tinker
```

```php
use App\Services\RedisDeviceTokenService;
use App\Models\DeviceTokenSetting;

$dbCount = DeviceTokenSetting::whereNull('logout_at')->count();
echo "Database count: {$dbCount}\n";

// Check Redis (this is approximate)
$redis = Redis::connection();
$keys = $redis->keys('device_token:*');
echo "Redis keys count: " . count($keys) . "\n";
```

---

## Usage

### Automatic Syncing

Device tokens are automatically synced to Redis when:
- A new device token is created
- An existing device token is updated
- A device token is deleted

This happens through model events in `DeviceTokenSetting` model.

### Manual Operations

```php
use App\Services\RedisDeviceTokenService;

// Store device token
RedisDeviceTokenService::storeDeviceToken($userId, $deviceId, [
    'device_token' => 'fcm_token_here',
    'device_info' => 'Device Info',
    'device_type' => 'android',
    'is_online' => 0,
    'last_seen_at' => now()->toDateTimeString(),
]);

// Get device token
$device = RedisDeviceTokenService::getDeviceToken($userId, $deviceId);

// Get all offline device tokens for a user
$tokens = RedisDeviceTokenService::getOfflineDeviceTokens($userId);

// Update online status
RedisDeviceTokenService::updateDeviceTokenStatus($userId, $deviceId, [
    'is_online' => 1,
    'last_seen_at' => now()->toDateTimeString(),
]);

// Delete device token
RedisDeviceTokenService::deleteDeviceToken($userId, $deviceId);
```

### In Chat Push Notifications

The `sendMobileChatPushNotification` function now:
1. First tries to get device tokens from Redis (fast)
2. Falls back to database if Redis is unavailable
3. Updates online status automatically
4. Sends push notifications efficiently

---

## Starting Redis

### Windows (Laragon)

**Method 1: Via Laragon Menu**
1. Open Laragon
2. Menu → Tools → Redis
3. Click "Start Redis"

**Method 2: Via Command Line**
```powershell
# If installed as service
redis-server --service-start

# Or run directly
redis-server
```

### Linux

```bash
# Start Redis service
sudo systemctl start redis-server

# Check status
sudo systemctl status redis-server

# Stop Redis
sudo systemctl stop redis-server

# Restart Redis
sudo systemctl restart redis-server
```

### macOS

```bash
# Start Redis service
brew services start redis

# Stop Redis
brew services stop redis

# Or run manually
redis-server
```

### Verify Redis is Running

```bash
# Check if Redis is running
redis-cli ping
# Should return: PONG

# Check Redis info
redis-cli info server
```

---

## Troubleshooting

### Issue: "Connection refused" Error

**Solution:**
1. Check if Redis is running:
   ```bash
   redis-cli ping
   ```

2. If not running, start Redis:
   - Windows (Laragon): Menu → Tools → Redis → Start
   - Linux: `sudo systemctl start redis-server`
   - macOS: `brew services start redis`

3. Verify port 6379 is not blocked by firewall

### Issue: "Class 'Redis' not found"

**Solution:**
1. Install PHP Redis extension:
   - Windows: Use Laragon's extension manager
   - Linux: `sudo apt install php-redis`
   - macOS: `brew install php-redis`

2. Enable in `php.ini`:
   ```ini
   extension=redis
   ```

3. Restart PHP-FPM/web server

### Issue: "Predis not found"

**Solution:**
```bash
composer require predis/predis
```

### Issue: Data not syncing to Redis

**Solution:**
1. Check Redis connection:
   ```php
   php artisan tinker
   Redis::ping();
   ```

2. Check model events are working:
   ```php
   $deviceToken = DeviceTokenSetting::first();
   $deviceToken->touch(); // Should trigger sync
   ```

3. Manually sync:
   ```bash
   php artisan device-tokens:sync-redis
   ```

### Issue: Redis memory full

**Solution:**
1. Check Redis memory usage:
   ```bash
   redis-cli info memory
   ```

2. Clear old keys (be careful!):
   ```bash
   redis-cli FLUSHDB
   ```

3. Re-sync data:
   ```bash
   php artisan device-tokens:sync-redis
   ```

### Issue: Slow performance

**Solution:**
1. Check Redis is using in-memory storage (not disk)
2. Monitor Redis performance:
   ```bash
   redis-cli --latency
   ```

3. Check for too many keys:
   ```bash
   redis-cli DBSIZE
   ```

---

## Redis Commands Reference

### Basic Commands

```bash
# Connect to Redis CLI
redis-cli

# Ping Redis
PING

# Set a key
SET key value

# Get a key
GET key

# Delete a key
DEL key

# Check if key exists
EXISTS key

# Get all keys (use with caution on large datasets)
KEYS *

# Get keys matching pattern
KEYS device_token:*

# Get database size
DBSIZE

# Clear current database
FLUSHDB

# Clear all databases
FLUSHALL

# Get info
INFO

# Monitor commands in real-time
MONITOR
```

### Device Token Specific

```bash
# Get device token data
HGETALL device_token:USER_ID:DEVICE_ID

# Get user's device list
SMEMBERS user_devices:USER_ID

# Check TTL (time to live)
TTL device_token:USER_ID:DEVICE_ID
```

---

## Performance Tips

1. **Use Redis for frequent reads**: Device token lookups happen frequently, Redis is perfect for this
2. **Set appropriate TTL**: Device tokens expire after 7 days automatically
3. **Monitor memory**: Keep an eye on Redis memory usage
4. **Use connection pooling**: Laravel handles this automatically
5. **Fallback to database**: The code automatically falls back if Redis is unavailable

---

## Security Considerations

1. **Password Protection**: Set a Redis password in production:
   ```env
   REDIS_PASSWORD=your_secure_password
   ```

2. **Network Security**: Bind Redis to localhost in production:
   ```conf
   bind 127.0.0.1
   ```

3. **Firewall**: Only allow Redis connections from your application server

---

## Additional Resources

- [Redis Official Documentation](https://redis.io/documentation)
- [Laravel Redis Documentation](https://laravel.com/docs/redis)
- [Predis Documentation](https://github.com/predis/predis)

---

## Support

If you encounter any issues:
1. Check the logs: `storage/logs/laravel.log`
2. Verify Redis is running: `redis-cli ping`
3. Test connection in Tinker: `php artisan tinker`
4. Check Redis logs (location depends on installation)

---

**Last Updated:** 2025-01-XX
**Version:** 1.0

