# Premire Warehousing API

Premire Warehousing is a Laravel-based RESTful API project for warehouse management. It provides APIs for user authentication, scheduling, trailers, locations, services, equipments, invoices, clients, and teams management.

---

## Features

-   User authentication (login, password reset, create password)
-   Trailer management (create, out-trailer, yard check)
-   Schedule management (CRUD operations, log in/out, extra info)
-   Real-time schedule updates via WebSocket (no page refresh needed)
-   Locations and doors management
-   Services and equipments management
-   Client and invoice management
-   Team management
-   Role-based access control (Admin, Manager, Driver)
-   Dashboard statistics and common metrics
-   Mobile push notifications via OneSignal (Android & iOS)

---

## Requirements

-   PHP >= 8.2
-   Laravel 11.x
-   MySQL / PostgreSQL / SQLite
-   Composer
-   Node.js & NPM (for frontend assets and Reverb server)
-   Redis (required for WebSocket broadcasting)
-   AWS S3 for file storage (optional)
-   OneSignal for push notifications (optional, for mobile app)

---

## Installation

1. Clone the repository:

```bash
git clone https://github.com/hyperspace-ventures/PremiereWarehousingBackend
cd PremiereWarehousingBackend
```

2. Install dependencies:

```bash
composer install
npm install
```

3. Set up environment:

```bash
cp .env.example .env
php artisan key:generate
```

4. **Set up encryption configuration:**

```bash
# Create encryption secret file for secure environment variable encryption
echo "base64:$(openssl rand -base64 32)" > config/encryption.secret
```

5. Configure your .env file with database and other settings

6. **Encrypt sensitive environment variables:**

```bash
# Encrypt AWS credentials
php artisan app:encrypt-env-value AWS_ACCESS_KEY_ID
php artisan app:encrypt-env-value AWS_SECRET_ACCESS_KEY

# Encrypt database passwords
php artisan app:encrypt-env-value DB_PASSWORD
php artisan app:encrypt-env-value AUDIT_DB_PASSWORD

# Encrypt email service password
php artisan app:encrypt-env-value MAIL_PASSWORD

# Encrypt Google Maps API key
php artisan app:encrypt-env-value GOOGLE_MAPS_API_KEY
```

7. Run migrations:

```bash
php artisan migrate
```

8. Serve the application:

```bash
php artisan serve
```

## Security Features

### Environment Variable Encryption

The application uses a custom encryption system to secure sensitive environment variables:

-   **Encryption Secret**: Stored in `config/encryption.secret` (generated during setup)
-   **Supported Variables**: AWS credentials, database passwords, email passwords, API keys
-   **Encryption Command**: `php artisan app:encrypt-env-value {KEY_NAME}`
-   **Automatic Decryption**: Values are automatically decrypted at runtime

### Security Headers

-   X-Content-Type-Options: Prevents MIME type sniffing
-   X-Frame-Options: Protects against clickjacking
-   X-XSS-Protection: Enables browser XSS filtering
-   Content-Security-Policy: Prevents XSS and data injection
-   Strict-Transport-Security: Enforces HTTPS (when available)

### Rate Limiting

-   Authentication endpoints: 5 requests/minute
-   Public endpoints: 50 requests/minute
-   Read-only endpoints: 100 requests/minute
-   Admin endpoints: 60 requests/minute
-   General API endpoints: 120 requests/minute

## Authentication

-   JWT-based authentication is implemented using `tymon/jwt-auth`.

## Middleware

-   `EnsureUserHasRole` restricts access based on user roles:
    -   **Admin:** Full access to all API endpoints
    -   **Manager:** Access to schedules, trailers, services, and some dashboard data
    -   **Driver:** Access to schedules, logging actions (log in/out/completed), and trailers

## Dependencies

### Production Dependencies

-   **laravel/framework** ^11.31
-   **laravel/sanctum** ^4.0
-   **laravel/reverb** ^1.0 (WebSocket server)
-   **tymon/jwt-auth** ^2.1
-   **barryvdh/laravel-dompdf** ^3.1
-   **intervention/image** 2.7
-   **league/flysystem-aws-s3-v3** ^3.0
-   **aws/aws-sdk-php** ^3.0 (AWS S3, etc.)
-   **owen-it/laravel-auditing** ^14.0

### Development Dependencies

-   **phpunit/phpunit** ^11.0.1
-   **fakerphp/faker** ^1.23
-   **mockery/mockery** ^1.6
-   **nunomaduro/collision** ^8.1
-   **laravel/sail** ^1.26
-   **laravel/pint** ^1.13

## Troubleshooting

### Encryption Issues

If you encounter encryption-related errors:

1. **"Secret file not found" error:**

    ```bash
    # Regenerate the encryption secret
    echo "base64:$(openssl rand -base64 32)" > config/encryption.secret
    ```

2. **"Failed to encrypt the value" error:**

    - Ensure the encryption secret file exists and is readable
    - Check that the value you're trying to encrypt is not empty
    - Verify the key is in the allowed whitelist

3. **"Could not decrypt existing value" warning:**
    - The existing value may not be encrypted
    - Re-encrypt the value using the encryption command

### Environment Setup Issues

-   Ensure all required environment variables are set in `.env`
-   Verify database connection settings
-   Check that all encrypted values are properly formatted

## Scheduled Tasks & Cron Jobs

The application includes several scheduled tasks that need to be set up on the server for proper operation:

### Required Scheduled Commands

1. **Report Cleanup** (`reports:cleanup-expired-drafts`)

    - **Schedule**: Daily at 2:00 AM
    - **Purpose**: Removes expired draft reports
    - **Command**: `php artisan reports:cleanup-expired-drafts`

2. **Report Scheduling** (`reports:schedule-batch`)

    - **Schedule**: Every 30 minutes (at :00 and :30)
    - **Purpose**: Schedules report generation jobs and handles missed schedules
    - **Command**: `php artisan reports:schedule-batch`

3. **Queue Processing** (`queue:work --stop-when-empty`)
    - **Schedule**: Every minute
    - **Purpose**: Processes queued jobs (reports, emails, etc.)
    - **Command**: `php artisan queue:work --stop-when-empty`

### Server Setup

#### 1. Configure Laravel Scheduler (CRON)

Add this single cron entry to your server's crontab:

```bash
# Edit crontab
crontab -e

# Add this line (replace with your actual project path)
* * * * * cd /var/www/html/PremiereWarehousingBackend && php artisan schedule:run >> /dev/null 2>&1
```

#### 2. Verify Setup

Test that the scheduler is working:

```bash
# Check scheduled commands
php artisan schedule:list

# Test individual commands
php artisan reports:cleanup-expired-drafts --dry-run
php artisan reports:schedule-batch
php artisan queue:work --stop-when-empty

# Run scheduler manually
php artisan schedule:run
```

### Troubleshooting Scheduled Tasks

1. **Commands not running:**

    - Verify cron is installed and running: `systemctl status cron`
    - Check cron logs: `tail -f /var/log/cron`
    - Ensure PHP CLI is available: `which php`

2. **Permission issues:**

    - Ensure Laravel has write permissions: `chmod -R 775 storage bootstrap/cache`
    - Check file ownership: `chown -R www-data:www-data /path/to/project`

3. **Queue not processing:**
    - Test queue connection: `php artisan queue:work --once`
    - Check queue configuration in `.env`
    - Verify database connection

## API Documentation

-   API endpoints are documented using Swagger/OpenAPI
-   Access API documentation at `/api/documentation` when the application is running

## Real-Time WebSocket Functionality

The application includes real-time WebSocket functionality using **Laravel Reverb** to provide instant updates to connected clients without requiring page refreshes.

### Overview

Real-time WebSocket broadcasting enables:

-   **Instant Schedule Updates**: When Admin/Manager creates or updates a schedule, it automatically appears on Driver Portal in real-time
-   **Location-Based Channels**: Drivers subscribe to their location's channel (`schedule.location.{locationId}`) to receive only relevant updates
-   **Secure Authentication**: WebSocket connections require valid JWT authentication tokens
-   **Automatic Reconnection**: Clients automatically reconnect if the connection is lost

### Technology Stack

-   **Laravel Reverb**: Official Laravel WebSocket solution for real-time communication
-   **Laravel Broadcasting**: Built-in broadcasting system using Redis pub/sub
-   **Redis**: Required for pub/sub communication between Laravel and Reverb server
-   **PM2**: Process manager for running Reverb server in production

### Architecture

```
Laravel Model (Schedule)
    ↓ Model Events (created/updated/deleted)
ScheduleEvent (Broadcast)
    ↓ broadcast()
Laravel Broadcasting System
    ↓ Redis Pub/Sub
Reverb WebSocket Server
    ↓ WebSocket Protocol
Frontend Client (Next.js/React)
```

### Requirements

-   **Redis**: Required for pub/sub communication
-   **Node.js & NPM**: Required for PM2 process manager (production)
-   **PM2**: Recommended for running Reverb server in production

### Configuration

Add the following environment variables to your `.env` file:

```env
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=your-app-id
REVERB_APP_KEY=your-app-key
REVERB_APP_SECRET=your-app-secret
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SCHEME=http
```

**Generate Reverb keys:**

```bash
php artisan reverb:install
```

This command will generate and display the keys to add to your `.env` file.

**Note**: In production, use `https` and `wss` schemes, and ensure `REVERB_HOST` is set to your public domain.

### Running Reverb Server

**Development:**

```bash
php artisan reverb:start
```

**Production (using PM2):**

```bash
pm2 start ecosystem.config.cjs
pm2 save
```

### Channel Authorization

WebSocket channels are protected by authentication. The application uses location-based channels:

-   **Channel Pattern**: `schedule.location.{locationId}`
-   **Authorization**: Users must be authenticated and have access to the location
-   **Endpoint**: `/api/broadcasting/auth`

### Events Broadcasted

-   **Schedule Created**: When a new schedule is created
-   **Schedule Updated**: When an existing schedule is modified
-   **Schedule Deleted**: When a schedule is removed

### Apache Proxy (Production)

When using Apache in production, update your virtual host configs so WebSocket traffic is proxied to Reverb:

-   **Location**: `/etc/apache2/sites-available/`
-   **Files to update**: `000-default.conf` (HTTP) and `000-default-le-ssl.conf` (HTTPS)

Add the WebSocket proxy and fallback directives as described in **SOCKET_SETUP_GUIDE.md** (Step 7: Configure Apache Proxy).

### Documentation

For detailed implementation guides, see:

-   **Backend Implementation**: `SOCKET_IMPLEMENTATION_BACKEND.md`
-   **Frontend Implementation**: `../PremiereWarehousingDriver/SOCKET_IMPLEMENTATION_FRONTEND.md`
-   **Production Setup**: `SOCKET_SETUP_GUIDE.md`

### Troubleshooting

1. **WebSocket connection fails:**

    - Verify Redis is running: `redis-cli ping`
    - Check Reverb server is running: `pm2 status` or `php artisan reverb:start`
    - Verify environment variables are set correctly
    - Check firewall allows WebSocket port (default: 8080)

2. **No real-time updates received:**

    - Verify client is subscribed to the correct channel
    - Check authentication token is valid
    - Verify channel authorization is working
    - Check browser console for WebSocket connection errors

3. **Reverb server won't start:**
    - Ensure Redis is running and accessible
    - Check port 8080 is not already in use
    - Verify all required environment variables are set

## Mobile Push Notifications

The application supports push notifications for mobile devices (Android and iOS) using **OneSignal**.

### Overview

Push notifications enable:

-   **Device Token Management**: Save and update device tokens; backend registers with OneSignal
-   **Custom Data Support**: Pass custom data with notifications for app navigation
-   **Background Notifications**: Support for content-available flag for background updates
-   **Image Support**: Rich notifications with images (mutable content)

### API Endpoint

**Save/Update Device Token:**

-   **Endpoint**: `POST /api/mobile/save-device-token`
-   **Access**: Driver role only
-   **Request Body**:
    ```json
    {
        "device_token": "fcm-or-apns-token",
        "device_type": "android",
        "device_id": "optional-device-id"
    }
    ```

### Configuration

Add the following to your `.env` file:

```env
# OneSignal Push Notifications
ONESIGNAL_APP_ID=your-onesignal-app-id
ONESIGNAL_REST_API_KEY=your-onesignal-rest-api-key
```

Get these from [OneSignal Dashboard](https://dashboard.onesignal.com) → Your App → Settings → Keys & IDs. Configure FCM (Android) and APNS (iOS) in the OneSignal dashboard.



### Usage

**Sending Push Notifications:**

```php
use App\Helpers\OneSignalHelper;

// Send to a user by ID
OneSignalHelper::sendPushNotification(
    $userId,
    'Notification Title',
    'Notification message',
    ['custom' => 'data', 'schedule_id' => 123]
);

// Send with content-available flag (background notification)
OneSignalHelper::sendPushNotification(
    $userId,
    'Background Update',
    'Data sync completed',
    ['sync_id' => 456],
    1 // isContentAvailable
);
```

### Error Handling

-   Push notification errors are automatically logged and won't break the system
-   Methods return `false` on failure, allowing your code to continue
-   All exceptions are logged with detailed context for debugging

### Database

The `device_tokens` table stores:

-   One device token per user (enforced)
-   Automatic handling of duplicate tokens across users
-   Backend sends via external_id (user_id); app must call OneSignal.login(user_id)


## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Submit a pull request


## License

This project is proprietary software owned by Premiere Warehousing.
