Developer Guide

Architecture Overview

Design Pattern

Platform implements Model-View-Controller (MVC) architecture with service layer separation. Each component has specific responsibility for maintainability and scalability.

Core Components

  • Models: Data representation and database interaction
  • Views: Presentation layer and user interface
  • Controllers: Request handling and business logic coordination
  • Services: Reusable business logic implementation
  • Middleware: Request/response filtering and modification

Request Lifecycle

  1. HTTP request received by web server
  2. Request routed to appropriate controller
  3. Middleware stack processes request
  4. Controller invokes service methods
  5. Service interacts with models
  6. Data retrieved from database
  7. Response formatted and returned
  8. View renders final output

Development Environment

Local Setup

Prerequisites

- PHP 8.1 or higher
- Composer 2.0+
- MySQL 8.0+ or PostgreSQL 13+
- Node.js 16+ with npm
- Git version control
- Code editor (VS Code recommended)

Installation Steps

# Clone repository
git clone https://github.com/yourcompany/casino-platform.git
cd casino-platform
Install PHP dependencies
composer install
Install Node dependencies
npm install
Copy environment configuration
cp .env.example .env
Generate application key
php artisan key:generate
Run database migrations
php artisan migrate
Seed initial data
php artisan db:seed
Compile frontend assets
npm run dev
Start development server
php artisan serve

Environment Configuration

.env File Structure

APP_NAME=Casino Platform
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost:8000
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=casino_db
DB_USERNAME=root
DB_PASSWORD=
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

Directory Structure

Application Core

/app
├── Controllers/
│   ├── API/              # API endpoint controllers
│   ├── Auth/             # Authentication controllers
│   ├── Admin/            # Admin panel controllers
│   └── Player/           # Player interface controllers
├── Models/
│   ├── User.php          # User model
│   ├── Game.php          # Game model
│   ├── Transaction.php   # Transaction model
│   └── Bonus.php         # Bonus model
├── Services/
│   ├── GameService.php   # Game business logic
│   ├── PaymentService.php # Payment processing
│   ├── BonusService.php  # Bonus management
│   └── ReportService.php # Reporting logic
├── Middleware/
│   ├── Authenticate.php  # Authentication check
│   ├── CheckBalance.php  # Balance validation
│   └── RateLimiter.php   # Rate limiting
├── Validators/
│   ├── DepositValidator.php
│   ├── WithdrawalValidator.php
│   └── RegistrationValidator.php
└── Helpers/
    ├── CurrencyHelper.php
    ├── DateHelper.php
    └── FormatHelper.php

Creating Custom Modules

Module Structure

Step 1: Create Controller

<?php
namespace App\Controllers;
class LoyaltyController extends BaseController
{
protected $loyaltyService;
public function __construct(LoyaltyService $service)
{
    $this->loyaltyService = $service;
}

public function index()
{
    $points = $this->loyaltyService->getUserPoints(
        $this->getCurrentUser()->id
    );
    
    return $this->view('loyalty.index', [
        'points' => $points
    ]);
}

public function redeem(Request $request)
{
    $validator = new RedeemValidator($request->all());
    
    if (!$validator->validate()) {
        return $this->error($validator->errors(), 422);
    }
    
    $result = $this->loyaltyService->redeemPoints(
        $this->getCurrentUser()->id,
        $request->input('points')
    );
    
    if ($result) {
        return $this->success('Points redeemed successfully');
    }
    
    return $this->error('Insufficient points', 400);
}
}

Step 2: Create Service

<?php
namespace App\Services;
class LoyaltyService
{
protected $pointsModel;
protected $transactionService;
public function __construct(
    LoyaltyPoints $pointsModel,
    TransactionService $transactionService
) {
    $this->pointsModel = $pointsModel;
    $this->transactionService = $transactionService;
}

public function getUserPoints(int $userId): int
{
    $cache_key = "loyalty:points:{$userId}";
    
    return Cache::remember($cache_key, 300, function() use ($userId) {
        return $this->pointsModel->where('user_id', $userId)
                                 ->sum('points');
    });
}

public function redeemPoints(int $userId, int $points): bool
{
    $available = $this->getUserPoints($userId);
    
    if ($available < $points) {
        return false;
    }
    
    $amount = $this->calculateRedemptionValue($points);
    
    DB::beginTransaction();
    
    try {
        // Deduct points
        $this->pointsModel->create([
            'user_id' => $userId,
            'points' => -$points,
            'type' => 'redemption',
            'description' => "Redeemed {$points} points"
        ]);
        
        // Credit account
        $this->transactionService->credit($userId, $amount, [
            'type' => 'loyalty_redemption',
            'reference' => "LP_{$points}"
        ]);
        
        DB::commit();
        Cache::forget("loyalty:points:{$userId}");
        
        return true;
    } catch (\Exception $e) {
        DB::rollBack();
        Log::error('Loyalty redemption failed', [
            'user_id' => $userId,
            'points' => $points,
            'error' => $e->getMessage()
        ]);
        
        return false;
    }
}

private function calculateRedemptionValue(int $points): float
{
    return $points * 0.01; // 100 points = $1
}
}

Step 3: Create Model

<?php
namespace App\Models;
class LoyaltyPoints extends Model
{
protected $table = 'loyalty_points';
protected $fillable = [
    'user_id',
    'points',
    'type',
    'description'
];

protected $casts = [
    'points' => 'integer',
    'created_at' => 'datetime'
];

public function user()
{
    return $this->belongsTo(User::class);
}

public static function awardPoints(int $userId, int $points, string $reason)
{
    return self::create([
        'user_id' => $userId,
        'points' => $points,
        'type' => 'earned',
        'description' => $reason
    ]);
}
}

Step 4: Register Routes

<?php
// routes/web.php
Route::middleware(['auth'])->group(function() {
Route::get('/loyalty', [LoyaltyController::class, 'index'])
->name('loyalty.index');
Route::post('/loyalty/redeem', [LoyaltyController::class, 'redeem'])
     ->name('loyalty.redeem');
});

Step 5: Create Migration

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateLoyaltyPointsTable extends Migration
{
public function up()
{
Schema::create('loyalty_points', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->integer('points');
$table->enum('type', ['earned', 'redemption', 'expired']);
$table->text('description')->nullable();
$table->timestamps();
        $table->index('user_id');
        $table->index('type');
        $table->index('created_at');
    });
}

public function down()
{
    Schema::dropIfExists('loyalty_points');
}
}

Payment Gateway Integration

Creating Payment Processor

Step 1: Create Adapter Interface

<?php
namespace App\Services\Payments;
interface PaymentProcessorInterface
{
public function createDeposit(array $data): array;
public function processWithdrawal(array $data): array;
public function handleCallback(array $data): bool;
public function getTransactionStatus(string $transactionId): string;
public function refundTransaction(string $transactionId): bool;
}

Step 2: Implement Processor

<?php
namespace App\Services\Payments\Processors;
use App\Services\Payments\PaymentProcessorInterface;
class StripeProcessor implements PaymentProcessorInterface
{
protected $apiKey;
protected $client;
public function __construct()
{
    $this->apiKey = config('payments.stripe.secret_key');
    $this->client = new \Stripe\StripeClient($this->apiKey);
}

public function createDeposit(array $data): array
{
    try {
        $paymentIntent = $this->client->paymentIntents->create([
            'amount' => $data['amount'] * 100, // Convert to cents
            'currency' => strtolower($data['currency']),
            'customer' => $this->getOrCreateCustomer($data['user_id']),
            'metadata' => [
                'user_id' => $data['user_id'],
                'transaction_id' => $data['transaction_id']
            ],
            'return_url' => $data['return_url']
        ]);
        
        return [
            'status' => 'success',
            'payment_id' => $paymentIntent->id,
            'client_secret' => $paymentIntent->client_secret,
            'redirect_url' => null
        ];
    } catch (\Stripe\Exception\ApiErrorException $e) {
        Log::error('Stripe deposit failed', [
            'error' => $e->getMessage(),
            'data' => $data
        ]);
        
        return [
            'status' => 'error',
            'message' => $e->getMessage()
        ];
    }
}

public function processWithdrawal(array $data): array
{
    try {
        $payout = $this->client->payouts->create([
            'amount' => $data['amount'] * 100,
            'currency' => strtolower($data['currency']),
            'destination' => $data['bank_account_id'],
            'metadata' => [
                'user_id' => $data['user_id'],
                'transaction_id' => $data['transaction_id']
            ]
        ]);
        
        return [
            'status' => 'success',
            'payout_id' => $payout->id,
            'estimated_arrival' => $payout->arrival_date
        ];
    } catch (\Stripe\Exception\ApiErrorException $e) {
        Log::error('Stripe withdrawal failed', [
            'error' => $e->getMessage(),
            'data' => $data
        ]);
        
        return [
            'status' => 'error',
            'message' => $e->getMessage()
        ];
    }
}

public function handleCallback(array $data): bool
{
    $signature = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? '';
    $webhookSecret = config('payments.stripe.webhook_secret');
    
    try {
        $event = \Stripe\Webhook::constructEvent(
            $data['payload'],
            $signature,
            $webhookSecret
        );
        
        switch ($event->type) {
            case 'payment_intent.succeeded':
                return $this->handleDepositSuccess($event->data->object);
                
            case 'payment_intent.payment_failed':
                return $this->handleDepositFailed($event->data->object);
                
            case 'payout.paid':
                return $this->handleWithdrawalSuccess($event->data->object);
                
            default:
                Log::info('Unhandled Stripe webhook', ['type' => $event->type]);
                return true;
        }
    } catch (\Exception $e) {
        Log::error('Stripe webhook processing failed', [
            'error' => $e->getMessage()
        ]);
        
        return false;
    }
}

public function getTransactionStatus(string $transactionId): string
{
    try {
        $paymentIntent = $this->client->paymentIntents->retrieve($transactionId);
        
        return match($paymentIntent->status) {
            'succeeded' => 'completed',
            'processing' => 'pending',
            'requires_payment_method' => 'pending',
            'requires_confirmation' => 'pending',
            'canceled' => 'cancelled',
            default => 'failed'
        };
    } catch (\Exception $e) {
        return 'unknown';
    }
}

public function refundTransaction(string $transactionId): bool
{
    try {
        $refund = $this->client->refunds->create([
            'payment_intent' => $transactionId
        ]);
        
        return $refund->status === 'succeeded';
    } catch (\Exception $e) {
        Log::error('Stripe refund failed', [
            'transaction_id' => $transactionId,
            'error' => $e->getMessage()
        ]);
        
        return false;
    }
}

private function getOrCreateCustomer(int $userId): string
{
    $user = User::find($userId);
    
    if ($user->stripe_customer_id) {
        return $user->stripe_customer_id;
    }
    
    $customer = $this->client->customers->create([
        'email' => $user->email,
        'name' => $user->first_name . ' ' . $user->last_name,
        'metadata' => ['user_id' => $userId]
    ]);
    
    $user->update(['stripe_customer_id' => $customer->id]);
    
    return $customer->id;
}

private function handleDepositSuccess($paymentIntent): bool
{
    $transactionId = $paymentIntent->metadata->transaction_id;
    
    $transaction = Transaction::find($transactionId);
    if (!$transaction) {
        return false;
    }
    
    return app(TransactionService::class)->completeDeposit($transactionId);
}

private function handleDepositFailed($paymentIntent): bool
{
    $transactionId = $paymentIntent->metadata->transaction_id;
    
    return app(TransactionService::class)->failTransaction(
        $transactionId,
        $paymentIntent->last_payment_error->message ?? 'Payment failed'
    );
}

private function handleWithdrawalSuccess($payout): bool
{
    $transactionId = $payout->metadata->transaction_id;
    
    return app(TransactionService::class)->completeWithdrawal($transactionId);
}
}

Step 3: Register Processor

<?php
// config/payments.php
return [
'processors' => [
'stripe' => [
'class' => \App\Services\Payments\Processors\StripeProcessor::class,
'secret_key' => env('STRIPE_SECRET_KEY'),
'publishable_key' => env('STRIPE_PUBLISHABLE_KEY'),
'webhook_secret' => env('STRIPE_WEBHOOK_SECRET')
],
'coinbase' => [
'class' => \App\Services\Payments\Processors\CoinbaseProcessor::class,
'api_key' => env('COINBASE_API_KEY')
]
]
];

Game Provider Integration

Creating Provider Adapter

Step 1: Define Interface

<?php
namespace App\Services\Games;
interface GameProviderInterface
{
public function authenticate(): bool;
public function fetchGames(): array;
public function launchGame(int $gameId, int $userId, string $mode): string;
public function getBalance(int $userId): float;
public function processRound(array $data): array;
}

Step 2: Implement Provider

<?php
namespace App\Services\Games\Providers;
use App\Services\Games\GameProviderInterface;
class PragmaticPlayProvider implements GameProviderInterface
{
protected $apiUrl;
protected $secureLogin;
protected $securePassword;
public function __construct()
{
    $this->apiUrl = config('games.pragmatic.api_url');
    $this->secureLogin = config('games.pragmatic.secure_login');
    $this->securePassword = config('games.pragmatic.secure_password');
}

public function authenticate(): bool
{
    try {
        $response = $this->makeRequest('authenticate', [
            'secureLogin' => $this->secureLogin,
            'securePassword' => $this->securePassword
        ]);
        
        return $response['error'] === 0;
    } catch (\Exception $e) {
        Log::error('Pragmatic authentication failed', [
            'error' => $e->getMessage()
        ]);
        return false;
    }
}

public function fetchGames(): array
{
    $response = $this->makeRequest('getGameList', [
        'casinoID' => config('games.pragmatic.casino_id')
    ]);
    
    if ($response['error'] !== 0) {
        throw new \Exception('Failed to fetch games');
    }
    
    return array_map(function($game) {
        return [
            'external_id' => $game['gameID'],
            'name' => $game['gameName'],
            'category' => $this->mapCategory($game['type']),
            'thumbnail' => $game['thumbnail'],
            'has_demo' => $game['freeRoundSupport'] === 1,
            'rtp' => $game['rtp'] ?? null
        ];
    }, $response['gameList']);
}

public function launchGame(int $gameId, int $userId, string $mode): string
{
    $game = Game::find($gameId);
    $user = User::find($userId);
    
    $params = [
        'casinoID' => config('games.pragmatic.casino_id'),
        'gameID' => $game->external_id,
        'playerID' => $user->id,
        'playerName' => $user->username,
        'currency' => $user->currency_code,
        'language' => $user->language ?? 'en',
        'returnURL' => route('games.close'),
        'lobbyURL' => route('games.lobby')
    ];
    
    if ($mode === 'demo') {
        $params['mode'] = 'fun';
    }
    
    $response = $this->makeRequest('authenticate', $params);
    
    if ($response['error'] !== 0) {
        throw new \Exception($response['description']);
    }
    
    // Create session record
    GameSession::create([
        'user_id' => $userId,
        'game_id' => $gameId,
        'session_token' => $response['sessionToken'],
        'mode' => $mode,
        'currency_code' => $user->currency_code,
        'balance_start' => $user->balance
    ]);
    
    return $response['gameURL'];
}

public function getBalance(int $userId): float
{
    $user = User::find($userId);
    return $user->balance + $user->bonus_balance;
}

public function processRound(array $data): array
{
    // Validate signature
    if (!$this->validateSignature($data)) {
        return $this->errorResponse('Invalid signature', 1);
    }
    
    $userId = $data['playerID'];
    $roundId = $data['roundID'];
    $betAmount = $data['betAmount'] ?? 0;
    $winAmount = $data['winAmount'] ?? 0;
    
    DB::beginTransaction();
    
    try {
        $user = User::lockForUpdate()->find($userId);
        
        if (!$user) {
            return $this->errorResponse('Player not found', 2);
        }
        
        // Process bet
        if ($betAmount > 0) {
            if ($user->balance < $betAmount) {
                return $this->errorResponse('Insufficient balance', 3);
            }
            
            $user->balance -= $betAmount;
            
            Transaction::create([
                'user_id' => $userId,
                'type' => 'bet',
                'amount' => $betAmount,
                'balance_before' => $user->balance + $betAmount,
                'balance_after' => $user->balance,
                'currency_code' => $user->currency_code,
                'status' => 'completed',
                'reference_id' => $roundId
            ]);
        }
        
        // Process win
        if ($winAmount > 0) {
            $user->balance += $winAmount;
            
            Transaction::create([
                'user_id' => $userId,
                'type' => 'win',
                'amount' => $winAmount,
                'balance_before' => $user->balance - $winAmount,
                'balance_after' => $user->balance,
                'currency_code' => $user->currency_code,
                'status' => 'completed',
                'reference_id' => $roundId
            ]);
        }
        
        $user->save();
        
        DB::commit();
        
        return [
            'error' => 0,
            'balance' => $user->balance,
            'currency' => $user->currency_code
        ];
        
    } catch (\Exception $e) {
        DB::rollBack();
        
        Log::error('Game round processing failed', [
            'user_id' => $userId,
            'round_id' => $roundId,
            'error' => $e->getMessage()
        ]);
        
        return $this->errorResponse('Processing error', 4);
    }
}

private function makeRequest(string $endpoint, array $params): array
{
    $url = $this->apiUrl . '/' . $endpoint;
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode !== 200) {
        throw new \Exception("API request failed with code {$httpCode}");
    }
    
    return json_decode($response, true);
}

private function validateSignature(array $data): bool
{
    $signature = $data['signature'] ?? '';
    unset($data['signature']);
    
    $string = http_build_query($data) . $this->securePassword;
    $calculated = md5($string);
    
    return hash_equals($calculated, $signature);
}

private function mapCategory(string $type): string
{
    return match($type) {
        'slot' => 'slots',
        'table' => 'table',
        'live' => 'live',
        default => 'other'
    };
}

private function errorResponse(string $message, int $code): array
{
    return [
        'error' => $code,
        'description' => $message
    ];
}
}

Database Queries

Query Builder Examples

Basic Queries

// Select with conditions
$users = DB::table('users')
    ->where('status', 'active')
    ->where('balance', '>', 100)
    ->orderBy('created_at', 'desc')
    ->limit(10)
    ->get();
// Join tables
$transactions = DB::table('transactions')
->join('users', 'users.id', '=', 'transactions.user_id')
->select('transactions.*', 'users.username')
->where('transactions.status', 'completed')
->get();
// Aggregates
$totalDeposits = DB::table('transactions')
->where('type', 'deposit')
->where('status', 'completed')
->sum('amount');
// Group by
$dailyStats = DB::table('transactions')
->select(
DB::raw('DATE(created_at) as date'),
DB::raw('SUM(CASE WHEN type = "deposit" THEN amount ELSE 0 END) as deposits'),
DB::raw('SUM(CASE WHEN type = "withdrawal" THEN amount ELSE 0 END) as withdrawals')
)
->whereBetween('created_at', [$startDate, $endDate])
->groupBy('date')
->get();

Complex Queries

// Subquery
$highRollers = DB::table('users')
    ->whereIn('id', function($query) {
        $query->select('user_id')
              ->from('transactions')
              ->where('type', 'bet')
              ->groupBy('user_id')
              ->havingRaw('SUM(amount) > ?', [10000]);
    })
    ->get();
// Common Table Expression
$activeUsers = DB::table('game_sessions')
->select('user_id')
->where('started_at', '>=', now()->subDays(7))
->groupBy('user_id');
report = DB::table(DB::raw("({
activeUsers->toSql()}) as active"))
    ->mergeBindings($activeUsers)
    ->join('users', 'users.id', '=', 'active.user_id')
    ->select('users.*')
    ->get();

Testing

Unit Tests

Service Test Example

<?php
namespace Tests\Unit\Services;
use Tests\TestCase;
use App\Services\BonusService;
use App\Models\User;
use App\Models\Bonus;
class BonusServiceTest extends TestCase
{
protected $bonusService;
public function setUp(): void
{
    parent::setUp();
    $this->bonusService = app(BonusService::class);
}

public function test_can_claim_deposit_bonus()
{
    $user = User::factory()->create(['balance' => 0]);
    
    $bonus = Bonus::factory()->create([
        'type' => 'deposit_match',
        'percentage' => 100,
        'max_bonus' => 500,
        'wagering_requirement' => 35
    ]);
    
    $result = $this->bonusService->claimBonus(
        $user->id,
        $bonus->code,
        100
    );
    
    $this->assertTrue($result);
    $this->assertEquals(100, $user->fresh()->bonus_balance);
}

public function test_cannot_claim_bonus_without_deposit()
{
    $user = User::factory()->create();
    $bonus = Bonus::factory()->create(['min_deposit' => 20]);
    
    $result = $this->bonusService->claimBonus(
        $user->id,
        $bonus->code,
        10
    );
    
    $this->assertFalse($result);
}

public function test_bonus_wagering_calculation()
{
    $user = User::factory()->create();
    $userBonus = UserBonus::factory()->create([
        'user_id' => $user->id,
        'bonus_amount' => 100,
        'wagering_requirement' => 35
    ]);
    
    $required = $this->bonusService->calculateWageringRequired($userBonus->id);
    
    $this->assertEquals(3500, $required);
}
}

Integration Tests

API Endpoint Test

<?php
namespace Tests\Feature\API;
use Tests\TestCase;
use App\Models\User;
class GameAPITest extends TestCase
{
protected $user;
protected $token;
public function setUp(): void
{
    parent::setUp();
    
    $this->user = User::factory()->create();
    $this->token = $this->user->createToken('test')->plainTextToken;
}

public function test_can_list_games()
{
    $response = $this->withHeaders([
        'Authorization' => 'Bearer ' . $this->token
    ])->getJson('/api/v1/games');
    
    $response->assertStatus(200)
             ->assertJsonStructure([
                 'status',
                 'data' => [
                     'games' => [
                         '*' => [
                             'id',
                             'name',
                             'provider',
                             'category'
                         ]
                     ]
                 ]
             ]);
}

public function test_can_launch_game()
{
    $game = Game::factory()->create();
    
    $response = $this->withHeaders([
        'Authorization' => 'Bearer ' . $this->token
    ])->postJson('/api/v1/games/' . $game->id . '/launch', [
        'mode' => 'real'
    ]);
    
    $response->assertStatus(200)
             ->assertJsonStructure([
                 'status',
                 'data' => [
                     'session_id',
                     'launch_url'
                 ]
             ]);
}

public function test_cannot_launch_game_without_balance()
{
    $this->user->update(['balance' => 0]);
    $game = Game::factory()->create(['min_bet' => 1]);
    
    $response = $this->withHeaders([
        'Authorization' => 'Bearer ' . $this->token
    ])->postJson('/api/v1/games/' . $game->id . '/launch', [
        'mode' => 'real'
    ]);
    
    $response->assertStatus(400);
}
}

Debugging

Logging

Application Logs

// Different log levels
Log::debug('Debug information', ['data' => $data]);
Log::info('User logged in', ['user_id' => $userId]);
Log::warning('Low balance detected', ['balance' => $balance]);
Log::error('Payment failed', ['error' => $exception->getMessage()]);
Log::critical('Database connection lost');
// Custom channels
Log::channel('payments')->info('Payment processed', $data);
Log::channel('games')->error('Game launch failed', $error);

Performance Profiling

Query Logging

DB::enableQueryLog();
// Your code here
$queries = DB::getQueryLog();
foreach ($queries as $query) {
Log::debug('Query', [
'sql' => $query['query'],
'time' => $query['time']
]);
}

Deployment

Production Checklist

Configuration

# Set environment to production
APP_ENV=production
APP_DEBUG=false
Enable optimizations
php artisan config:cache
php artisan route:cache
php artisan view:cache
Set proper permissions
chmod -R 755 /var/www/casino
chmod -R 775 /var/www/casino/storage
chmod -R 775 /var/www/casino/bootstrap/cache
Enable opcache
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000

Zero-Downtime Deployment

Deployment Script

#!/bin/bash
Enable maintenance mode
php artisan down
Pull latest code
git pull origin main
Install dependencies
composer install --no-dev --optimize-autoloader
npm install --production
npm run build
Run migrations
php artisan migrate --force
Clear and rebuild caches
php artisan config:cache
php artisan route:cache
php artisan view:cache
Restart services
sudo systemctl restart php8.1-fpm
sudo systemctl restart nginx
Disable maintenance mode
php artisan up
echo "Deployment completed successfully"
Casino Clone