Skip to content

Deploiement Scell.io

Version: 1.0 Date: 2026-03-03


Table des matieres

  1. Infrastructure
  2. Prerequis
  3. Deploiement Backend (api.scell.io)
  4. Deploiement Frontend (scell.io)
  5. Variables d'Environnement
  6. Monitoring
  7. Troubleshooting

1. Infrastructure

Architecture de deploiement

mermaid
graph TB
    subgraph "Internet"
        U["Utilisateurs"]
        AI["Agents IA (MCP)"]
        SPDP["SuperPDP"]
        OA["OpenAPI.com"]
    end

    subgraph "Ploi.io (Scaleway)"
        subgraph "scell.io"
            FE["Frontend React<br/>Static (Vite build)<br/>dist/"]
        end

        subgraph "api.scell.io"
            BE["Laravel 12<br/>PHP 8.2+<br/>backend/public/"]
            HZ["Horizon<br/>(Queue Worker)"]
        end

        subgraph "Services Manages (Scaleway)"
            PG["PostgreSQL 17<br/>(base principale)"]
            PGS["PostgreSQL 17<br/>(base sandbox)"]
            RD["Redis 7.4<br/>(cache + sessions + queue)"]
            S3["Scaleway S3<br/>(stockage factures/docs)"]
        end
    end

    U --> FE
    U --> BE
    AI -->|"MCP JSON-RPC"| BE
    SPDP -->|"Webhooks"| BE
    OA -->|"Webhooks"| BE
    BE --> PG
    BE --> PGS
    BE --> RD
    BE --> S3
    BE -->|"API"| SPDP
    BE -->|"API"| OA
    HZ --> PG
    HZ --> RD

Composants

ComposantDomaineTypeStack
Frontendscell.ioSite statiqueReact 19 + Vite (dist/)
Backendapi.scell.ioApplication PHPLaravel 12 + PHP 8.2
Base de donnees-Service managePostgreSQL 17 (Scaleway)
Cache/Queue-Service manageRedis 7.4 (Scaleway)
Stockage-Service manageScaleway S3 (fr-par)

Hebergement Ploi.io

Ploi.io gere :

  • Le provisionning des serveurs Scaleway
  • Les certificats SSL Let's Encrypt (renouvellement automatique)
  • Le deploiement automatise via webhook Git
  • La supervision des processus (PHP-FPM, Horizon)

Serveur : Scaleway DEV1-M (3 vCPU, 4GB RAM) SSH : ssh ploi@51.15.234.246Chemins :

SiteChemin sur le serveur
Backend/home/ploi/api.scell.io/backend
Frontend/home/ploi/scell.io/frontend

2. Prerequis

Backend

ComposantVersion minimaleVerification
PHP8.2+php -v
Composer2.xcomposer --version
PostgreSQL17psql --version
Redis7.4redis-cli --version
wkhtmltopdf0.12+wkhtmltopdf --version

Extensions PHP requises :

bcmath, ctype, curl, dom, fileinfo, gd, intl, json, mbstring,
openssl, pdo, pdo_pgsql, redis, tokenizer, xml, zip

Frontend

ComposantVersion minimaleVerification
Node.js20+node --version
npm10+npm --version

Certificats SSL

Les certificats Let's Encrypt sont geres automatiquement par Ploi.io :

/etc/letsencrypt/live/api.scell.io/fullchain.pem
/etc/letsencrypt/live/api.scell.io/privkey.pem

3. Deploiement Backend (api.scell.io)

Script de deploiement

bash
#!/bin/bash
# deploy-backend.sh
set -e

cd /home/ploi/api.scell.io/backend

# 1. Mettre le site en maintenance
php artisan down --render="errors::503" --retry=60

# 2. Recuperer les derniers changements
git pull origin main

# 3. Installer les dependances (production)
composer install --no-dev --optimize-autoloader --no-interaction

# 4. Executer les migrations
php artisan migrate --force

# 5. Mettre en cache la configuration
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

# 6. Redemarrer les workers de queue
php artisan horizon:terminate
# Horizon sera redemarre automatiquement par le superviseur

# 7. Nettoyer les caches obsoletes
php artisan cache:clear

# 8. Remettre le site en ligne
php artisan up

echo "Deploiement backend termine avec succes."

Commandes post-deploiement

bash
# Verifier que Horizon tourne
php artisan horizon:status

# Verifier la sante de l'API
curl -s https://api.scell.io/health | jq .

# Verifier les migrations
php artisan migrate:status

Configuration Nginx (reference)

Le fichier nginx.conf.example a la racine du projet contient la configuration de reference :

nginx
server {
    listen 443 ssl http2;
    server_name api.scell.io;

    root /home/ploi/api.scell.io/backend/public;
    index index.php;

    ssl_certificate /etc/letsencrypt/live/api.scell.io/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.scell.io/privkey.pem;

    # CORS headers
    add_header Access-Control-Allow-Origin "https://scell.io" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-API-Key, X-Tenant-Key, X-API-Key, X-Scell-API-Key, mcp-session-id" always;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # SSE pour MCP streaming
    location /mcp/stream {
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 3600s;
        try_files $uri /index.php?$query_string;
    }
}

Superviseur Horizon

Ploi.io configure automatiquement le superviseur pour Horizon :

ini
[program:horizon]
process_name=%(program_name)s
command=php /home/ploi/api.scell.io/backend/artisan horizon
autostart=true
autorestart=true
user=ploi
redirect_stderr=true
stdout_logfile=/home/ploi/api.scell.io/backend/storage/logs/horizon.log
stopwaitsecs=3600

Taches planifiees (Cron)

bash
# Ajouter au crontab de l'utilisateur ploi
* * * * * cd /home/ploi/api.scell.io/backend && php artisan schedule:run >> /dev/null 2>&1

Taches planifiees automatiques :

CommandeFrequenceDescription
fiscal:daily-closingQuotidien 00:05 UTCCloture fiscale journaliere
fiscal:monthly-closing1er du moisCloture fiscale mensuelle
fiscal:integrity-checkQuotidien 02:00 UTCVerification d'integrite
fiscal:check-version-changeQuotidienDetection changement de version
billing:generate-monthly-invoices1er du moisFactures tenants
superpdp:sync-statusesToutes les 5 minSynchronisation statuts
horizon:snapshotToutes les 5 minMetriques Horizon

4. Deploiement Frontend (scell.io)

Script de deploiement

bash
#!/bin/bash
# deploy-frontend.sh
set -e

cd /home/ploi/scell.io/frontend

# 1. Recuperer les derniers changements
git pull origin main

# 2. Installer les dependances
npm ci

# 3. Build de production
npm run build

echo "Deploiement frontend termine. Le dossier dist/ est pret."

Le dossier dist/ genere par Vite est servi directement par Nginx comme site statique.

Configuration Nginx

nginx
server {
    listen 443 ssl http2;
    server_name scell.io www.scell.io;

    root /home/ploi/scell.io/frontend/dist;
    index index.html;

    ssl_certificate /etc/letsencrypt/live/scell.io/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/scell.io/privkey.pem;

    # SPA fallback
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Cache des assets statiques
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Variables d'environnement frontend

Le fichier .env.production :

bash
VITE_API_URL=https://api.scell.io/api/v1
VITE_APP_NAME=Scell.io
VITE_REVERB_APP_KEY=scell-key
VITE_REVERB_HOST=api.scell.io
VITE_REVERB_PORT=443
VITE_REVERB_SCHEME=https

Ces variables sont integrees au build Vite (prefixe VITE_).


5. Variables d'Environnement

Backend (backend/.env)

Application

VariableDescriptionExemple
APP_NAMENom de l'applicationScell.io
APP_ENVEnvironnementproduction
APP_KEYCle de chiffrement (generer avec php artisan key:generate)base64:...
APP_DEBUGMode debug (toujours false en production)false
APP_TIMEZONEFuseau horaireEurope/Paris
APP_URLURL de base de l'APIhttps://api.scell.io
APP_LOCALELangue par defautfr

Base de donnees

VariableDescriptionExemple
DB_CONNECTIONDriver de BDDpgsql
DB_HOSTHote PostgreSQLrdb-xxx.scw.cloud
DB_PORTPort5432
DB_DATABASENom de la basescell_production
DB_USERNAMEUtilisateurscell
DB_PASSWORDMot de passe***
DB_HOST_SANDBOXHote BDD sandbox (optionnel)127.0.0.1
DB_DATABASE_SANDBOXBase sandboxscell_sandbox

Cache et Queue

VariableDescriptionExemple
CACHE_STOREDriver de cacheredis
CACHE_PREFIXPrefixe des cles cachescell_
QUEUE_CONNECTIONDriver de queueredis
SESSION_DRIVERDriver de sessionredis
REDIS_HOSTHote Redisredis-xxx.scw.cloud
REDIS_PORTPort Redis6379
REDIS_PASSWORDMot de passe Redis***
HORIZON_PREFIXPrefixe Horizonscell_horizon:

Mail

VariableDescriptionExemple
MAIL_MAILERDriver mailsmtp
MAIL_HOSTServeur SMTPsmtp.tem.scw.cloud
MAIL_PORTPort SMTP587
MAIL_USERNAMEUtilisateur SMTP***
MAIL_PASSWORDMot de passe SMTP***
MAIL_ENCRYPTIONChiffrementtls
MAIL_FROM_ADDRESSAdresse d'envoinoreply@scell.io

Services externes

VariableDescriptionExemple
GOOGLE_CLIENT_IDOAuth Googlexxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRETSecret Google OAuth***
OPENAPI_BASE_URLURL OpenAPI.comhttps://esignature.openapi.com
OPENAPI_SANDBOX_URLURL sandbox OpenAPIhttps://test.esignature.openapi.com
OPENAPI_BEARER_TOKENToken OpenAPI.com***
SUPERPDP_API_URLURL SuperPDPhttps://api.superpdp.tech
SUPERPDP_API_KEYCle API SuperPDP***
SUPERPDP_WEBHOOK_SECRETSecret webhooks SuperPDP***
SUPERPDP_SANDBOXMode sandbox SuperPDPfalse
BULKGATE_APPLICATION_IDID app BulkGate (SMS)***
BULKGATE_APPLICATION_TOKENToken BulkGate***

INSEE (verification SIRET)

VariableDescriptionExemple
INSEE_API_URLURL API Sirenehttps://api.insee.fr/entreprises/sirene/V3.11
INSEE_CLIENT_IDID client INSEE***
INSEE_CERT_PATHCertificat mTLSstorage/certs/insee-client.pem
INSEE_KEY_PATHCle privee mTLSstorage/certs/insee-client.key

Stockage S3

VariableDescriptionExemple
AWS_ACCESS_KEY_IDAccess key ScalewaySCW...
AWS_SECRET_ACCESS_KEYSecret key***
AWS_DEFAULT_REGIONRegionfr-par
AWS_BUCKETBucketscell-storage
AWS_ENDPOINTEndpoint S3https://s3.fr-par.scw.cloud
AWS_USE_PATH_STYLE_ENDPOINTPath styletrue

MCP

VariableDescriptionExemple
MCP_ENABLEDActiver le serveur MCPtrue
MCP_SESSION_TTLDuree de session (secondes)3600
MCP_SESSION_DRIVERDriver de session MCPredis
MCP_RATE_LIMITRequetes par minute60

Conformite fiscale

VariableDescriptionExemple
FISCAL_COMPLIANCE_ENABLEDActiver la conformite fiscaletrue
FISCAL_EDITOR_NAMENom de l'editeurQR Communication SAS
FISCAL_EDITOR_SIRETSIRET de l'editeur12345678900001
FISCAL_LICENSE_NUMBERNumero de licence NF525NF525-2026-001
FISCAL_ANCHOR_PROVIDERProvider d'ancragerfc3161_tsa
FISCAL_TSA_URLURL du TSAhttps://freetsa.org/tsr
FISCAL_RETENTION_YEARSDuree de retention (annees)6

PDF

VariableDescriptionExemple
SNAPPY_PDF_BINARYChemin wkhtmltopdf/usr/bin/wkhtmltopdf
SNAPPY_IMAGE_BINARYChemin wkhtmltoimage/usr/bin/wkhtmltoimage

6. Monitoring

Horizon Dashboard

Laravel Horizon fournit un dashboard web pour superviser les queues :

URL : https://api.scell.io/horizonAcces : Restreint aux administrateurs (authentification Sanctum + role admin).

Le dashboard affiche :

  • Etat des workers (actifs, en pause, termines)
  • Metriques de throughput (jobs/minute)
  • Jobs en attente, en cours, echoues
  • Temps d'execution moyen
  • Historique des jobs

Logs Laravel

Les logs sont stockes dans backend/storage/logs/ :

FichierDescription
laravel.logLog general de l'application
horizon.logLog du worker Horizon
scheduler.logLog du planificateur

Configuration dans config/logging.php :

php
'channels' => [
    'stack' => ['driver' => 'stack', 'channels' => ['single']],
    'single' => ['driver' => 'single', 'path' => storage_path('logs/laravel.log'), 'level' => 'info'],
],

En production, le niveau de log est info (pas de debug).

Health Checks

Le endpoint /health retourne l'etat de l'API :

bash
curl -s https://api.scell.io/health | jq .
json
{
  "status": "ok",
  "timestamp": "2026-03-03T14:30:00+00:00"
}

Le MCP health_check tool fournit un diagnostic plus detaille (database, cache).

Metriques recommandees

MetriqueSourceSeuil d'alerte
Temps de reponse API (p95)Nginx access log> 500ms
Queue pending jobsHorizon> 1000
Queue failed jobsHorizon> 0
Espace disqueServeur< 20% libre
Memoire PHPPHP-FPM> 80% utilise
Connexions PostgreSQLPG> 80% du max
Redis memoireRedis> 80% du max

7. Troubleshooting

Erreurs communes

"Connection refused" sur l'API

Symptome : L'API retourne une erreur 502 Bad Gateway.

Causes possibles :

  1. PHP-FPM n'est pas demarre
  2. Le socket Unix n'existe pas

Solution :

bash
# Verifier le statut de PHP-FPM
sudo systemctl status php8.2-fpm

# Redemarrer si necessaire
sudo systemctl restart php8.2-fpm

# Verifier le socket
ls -la /var/run/php/php8.2-fpm.sock

Les jobs de queue ne s'executent pas

Symptome : Les factures restent au statut "pending", les webhooks ne sont pas envoyes.

Solution :

bash
# Verifier Horizon
cd /home/ploi/api.scell.io/backend
php artisan horizon:status

# Si termine, redemarrer
php artisan horizon:terminate
# Le superviseur le relancera automatiquement

# Verifier les jobs echoues
php artisan queue:failed

# Relancer les jobs echoues
php artisan queue:retry all

Erreur de migration

Symptome : SQLSTATE[42P07]: Duplicate table ou SQLSTATE[42P01]: Undefined table.

Solution :

bash
# Verifier l'etat des migrations
php artisan migrate:status

# Si une migration est bloquee, ne JAMAIS la modifier en production
# Creer une nouvelle migration corrective a la place

Probleme de certificat SSL

Symptome : cURL error 60: SSL certificate problem

Solution :

bash
# Verifier les certificats
sudo certbot certificates

# Renouveler manuellement si necessaire
sudo certbot renew --force-renewal

# Verifier la configuration Nginx
sudo nginx -t
sudo systemctl reload nginx

Solde insuffisant pour un tenant

Symptome : Erreur 402 "Solde insuffisant" lors de la creation de facture.

Solution :

bash
# Verifier le solde du tenant (via Tinker)
php artisan tinker
>>> Tenant::find('uuid-du-tenant')->balance
# 0.00

# Crediter manuellement (admin)
curl -X POST https://api.scell.io/api/v1/admin/users/{userId}/credit \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -d '{ "amount": 100.00, "reason": "Recharge manuelle" }'

Redis saturee

Symptome : MISCONF Redis is configured to save RDB snapshots

Solution :

bash
# Verifier l'utilisation memoire
redis-cli info memory

# Nettoyer les sessions MCP expirees
php artisan tinker
>>> App\Models\McpSession::where('expires_at', '<', now())->delete()

# Vider le cache si necessaire
php artisan cache:clear

Performance degradee

Symptome : Temps de reponse > 1 seconde.

Diagnostic :

bash
# Verifier que les caches sont actifs
php artisan config:cache
php artisan route:cache

# Verifier les requetes lentes PostgreSQL
# Dans psql :
SELECT query, calls, mean_time, total_time
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 10;

# Verifier les index manquants
php artisan tinker
>>> DB::select("SELECT schemaname, tablename, indexname FROM pg_indexes WHERE schemaname = 'public' ORDER BY tablename")

FAQ technique

Q : Comment regenerer la cle APP_KEY ?

bash
php artisan key:generate
# ATTENTION : invalide toutes les sessions et tokens existants

Q : Comment ajouter un nouveau worker Horizon ?

Editer config/horizon.php et ajouter un nouveau superviseur dans la section environments.

Q : Comment debugger un webhook SuperPDP ?

Les webhooks sont traces dans la table processed_webhooks. Consulter les logs :

bash
grep "SuperPDP" /home/ploi/api.scell.io/backend/storage/logs/laravel.log | tail -20

Q : Comment forcer une cloture fiscale journaliere ?

bash
php artisan fiscal:daily-closing --force

Q : Ou sont stockes les fichiers (factures PDF, documents KYB) ?

En production, les fichiers sont sur Scaleway S3 (bucket scell-storage). En local, ils sont dans backend/storage/app/.

Q : Comment acceder a la base de donnees en production ?

bash
ssh ploi@51.15.234.246
psql -h rdb-xxx.scw.cloud -U scell -d scell_production

Documentation Scell.io