# TERRE FORTE — Backend Laravel · Guide de déploiement (cPanel/Plesk)

Ce document décrit le déploiement en production du backend **Laravel 11 + MySQL 8** de TERRE FORTE SARLU, avec le back-office **Filament**, sur un hébergement mutualisé cPanel/Plesk. Il fait suite à la phase 1 \(frontend SPA\) et prépare la connexion du site public à l'API.

Suivez les étapes dans l'ordre : chaque étape suppose la précédente réussie.

---

## 1. Architecture cible

| Composant | URL | Rôle |
| --- | --- | --- |
| Frontend \(phase 1\) | `https://www.terreforte.gn` | Site public \(SPA statique\), consomme l'API |
| API REST | `https://api.terreforte.gn/api/*` | Backend Laravel, données métier |
| Back-office | `https://api.terreforte.gn/admin` | Administration Filament |

```mermaid mode=edit
flowchart LR
  V[Visiteur] -->|HTTPS| W[www.terreforte.gn<br/>Frontend]
  W -->|fetch /api| A[api.terreforte.gn<br/>Laravel API]
  Ad[Administrateur] -->|HTTPS| F[api.terreforte.gn/admin<br/>Filament]
  A --> DB[(MySQL 8)]
  F --> DB
```

Deux options d'hébergement des sous-domaines :

- **Option A \(recommandée, la plus simple sur mutualisé\)** — une seule application Laravel, un seul domaine `api.terreforte.gn`. L'API est servie sur `/api/*` et le back-office sur `/admin`. Aucune configuration multi-domaine à faire côté Laravel.

- **Option B \(sous-domaine admin dédié\)** — un second domaine `admin.terreforte.gn` pointant vers le **même** dossier `public/`. Le back-office reste accessible sur `/admin` de ce domaine aussi ; l'intérêt est purement cosmétique \(URL dédiée\). À n'utiliser que si vous tenez à cette URL.

Le reste du guide suit l'**Option A**.

---

## 2. Prérequis \(à vérifier avant de commencer\)

Dans cPanel, assurez-vous de disposer de :

- **PHP 8.2 ou 8.3** sélectionnable \(MultiPHP Manager\) ;

- **MySQL 8** \(ou MariaDB 10.6+\) et l'outil *MySQL Databases* ;

- **Subdomains** \(création de `api.terreforte.gn`\) ;

- **Terminal** cPanel ou accès **SSH** \(pour Composer et `artisan`\) ;

- **Cron Jobs** ;

- **SSL/TLS** \(AutoSSL gratuit Let's Encrypt\) ;

- extensions PHP requises activées : `pdo_mysql`, `mbstring`, `openssl`, `tokenizer`, `xml`, `ctype`, `json`, `bcmath`, `fileinfo`, `curl`, `gd` ou `imagick` \(miniatures/images\).

Si le **Terminal** n'est pas disponible sur votre offre, lisez l'encadré « Sans terminal » à l'étape 4 : vous préparerez les dépendances en local puis les téléverserez.

---

## 3. Étape 1 — Créer la base MySQL

1. cPanel → **MySQL Databases**.

2. Créez la base : `terreforte_db` \(cPanel préfixe souvent par votre utilisateur, ex. `moncompte_terreforte_db`\).

3. Créez l'utilisateur : `terreforte_user` avec un **mot de passe fort** \(générez-le, ne réutilisez pas un mot de passe existant\).

4. Ajoutez l'utilisateur à la base avec **ALL PRIVILEGES**.

5. Notez ces 4 valeurs, elles iront dans `.env` :

| Variable | Valeur typique sur mutualisé |
| --- | --- |
| `DB_CONNECTION` | `mysql` |
| `DB_HOST` | `localhost` |
| `DB_DATABASE` | `moncompte_terreforte_db` |
| `DB_USERNAME` | `moncompte_terreforte_user` |
| `DB_PASSWORD` | *\(le mot de passe créé\)* |

Le jeu de caractères reste le défaut cPanel \(`utf8mb4` / `utf8mb4_unicode_ci`\) : Laravel le force par connexion, inutile de le modifier manuellement.

---

## 4. Étape 2 — Créer le sous-domaine et le dossier

1. cPanel → **Subdomains** → créez `api` pour le domaine `terreforte.gn`.

2. **Point critique** : définissez la *Document Root* sur le dossier <strong>`public`</strong> de l'application :

```
/home/<votre_compte>/terreforte-api/public
```

Le code Laravel doit s'installer dans `/home/<votre_compte>/terreforte-api` \(et surtout **pas** dans un dossier exposé directement au web\). Le point d'entrée web est uniquement `public/`.

3. Activez **SSL/TLS \(AutoSSL\)** pour `api.terreforte.gn`, puis testez que `https://api.terreforte.gn` répond \(page vide ou 404 Laravel est normal à ce stade\).

> **Si vous ne pouvez pas modifier la Document Root** \(certaines offres l'imposent\) : installez l'app dans `public_html/terreforte-api` et placez à la racine du sous-domaine un `.htaccess` qui réécrit tout vers `terreforte-api/public/`. Cette solution de contournement est plus fragile ; privilégiez le changement de Document Root.

---

## 5. Étape 3 — Déployer le code

Deux méthodes, au choix :

**Méthode Git \(recommandée\)** — cPanel → **Git Version Control** → *Clone* votre dépôt dans `/home/<votre_compte>/terreforte-api`. Vous pourrez ensuite faire *Pull* à chaque mise à jour.

**Méthode upload** — téléversez l'archive du projet via **File Manager**, décompressez-la dans `/home/<votre_compte>/terreforte-api`.

---

## 6. Étape 4 — Installer les dépendances

Ouvrez le **Terminal** cPanel, puis :

```bash
cd ~/terreforte-api
composer install --no-dev --optimize-autoloader
```

> **Sans terminal** : sur votre machine locale, exécutez `composer install --no-dev --optimize-autoloader`, puis téléversez le dossier `vendor/` obtenu dans le projet en ligne. Répétez à chaque modification de `composer.json`. Vous devrez aussi lancer les commandes `php artisan` \(étapes 6 à 8\) depuis un environnement capable de les exécuter : soit le Terminal cPanel, soit un script ponctuel.

---

## 7. Étape 5 — Configurer l'environnement `.env`

1. Dupliquez `.env.example` en `.env` \(File Manager, ou `cp .env.example .env`\).

2. Générez la clé d'application :

```bash
php artisan key:generate
```

3. Renseignez les valeurs de production. Extrait de `.env` :

```plaintext
APP_NAME="TERRE FORTE"
APP_ENV=production
APP_DEBUG=false
APP_KEY=                     # généré par key:generate
APP_URL=https://api.terreforte.gn
APP_TIMEZONE=Africa/Conakry
APP_LOCALE=fr

LOG_CHANNEL=stack
LOG_LEVEL=error

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=moncompte_terreforte_db
DB_USERNAME=moncompte_terreforte_user
DB_PASSWORD=changez_moi

# Stockage public des médias (photos produits, réalisations, couvertures)
FILESYSTEM_DISK=public

# Compte administrateur initial (créé par le seeder — voir étape 6)
ADMIN_USERNAME=Brams224gn
ADMIN_EMAIL=admin@terreforte.gn
ADMIN_PASSWORD=azerty

# Origines autorisées à appeler l'API (le frontend public)
CORS_ALLOWED_ORIGINS=https://www.terreforte.gn,https://terreforte.gn
```

> ⚠️ **Sécurité — à faire avant la mise en ligne** : `ADMIN_PASSWORD=azerty` est un mot de passe **très faible**. Changez-le pour un mot de passe long \(16+ caractères, aléatoire\) **avant** d'exposer le back-office, ou connectez-vous puis modifiez-le immédiatement depuis Filament. Le mot de passe ne doit **jamais** apparaître dans le frontend public.

`APP_DEBUG=false` est obligatoire en production : sans cela, les erreurs exposent des chemins, requêtes SQL et variables d'environnement.

---

## 8. Étape 6 — Migrations, données et compte administrateur

```bash
php artisan migrate --seed --force
```

Cette commande crée toutes les tables \(voir le *Modèle de données*\) puis exécute les seeders, qui :

- créent le **compte administrateur** `Brams224gn` \(défini par `ADMIN_*` dans `.env`\) ;

- insèrent les **paramètres du site** \(téléphones, WhatsApp, e-mail, réseaux, carte\) ;

- chargent les **catégories** \(produits, réalisations, actualités, médias\) et un **contenu de démonstration** réaliste aligné sur la phase 1.

Pour réinitialiser complètement la base \(⚠️ **efface toutes les données**\) : `php artisan migrate:fresh --seed --force`.

---

## 9. Étape 7 — Lien de stockage et permissions

```bash
php artisan storage:link
chmod -R 775 storage bootstrap/cache
```

`storage:link` crée le lien symbolique `public/storage` → `storage/app/public`, indispensable pour servir les images téléversées depuis Filament. Si la commande échoue \(lien symbolique bloqué sur mutualisé\), créez le lien via le File Manager ou signalez-le : une alternative par route de téléchargement est possible.

---

## 10. Étape 8 — Optimisations de production

```bash
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan filament:optimize
```

À rejouer après **chaque** modification de configuration, route ou vue. Pour repartir d'un état non caché pendant un diagnostic : `php artisan optimize:clear`.

---

## 11. Étape 9 — Tâche planifiée \(cron\)

cPanel → **Cron Jobs** → ajoutez une tâche **toutes les minutes** :

```bash
/usr/local/bin/php /home/<votre_compte>/terreforte-api/artisan schedule:run >> /dev/null 2>&1
```

Vérifiez le chemin réel du binaire PHP avec `which php` dans le Terminal \(il peut être `/usr/local/bin/php`, `/usr/bin/php`, ou un chemin MultiPHP\). Cette tâche est requise par le planificateur Laravel.

---

## 12. Étape 10 — HTTPS, CORS et durcissement

- **HTTPS obligatoire** : forcez le schéma via un `AppServiceProvider` \(`URL::forceScheme('https')` en production\) et activez « Force HTTPS Redirect » dans cPanel. Corrigez `APP_URL` en `https://`.

- **CORS** : limitez les origines à votre frontend \(`CORS_ALLOWED_ORIGINS`\). N'utilisez pas `*` en production.

- **Limitation de débit** : les routes `POST /api/contact` et `POST /api/quotes` sont protégées par un *throttle* \(voir la référence API\) pour freiner le spam.

- **Secrets** : `.env` hors du dossier public, jamais versionné. `APP_KEY` unique par environnement.

- **Back-office** : le mot de passe admin changé, et idéalement une protection d'accès supplémentaire au sous-domaine admin \(règle IP cPanel ou mot de passe HTTP si disponible\).

---

## 13. Vérification finale

| # | Test | Résultat attendu |
| --- | --- | --- |
| 1 | Ouvrir `https://api.terreforte.gn/api/activities` | JSON `{ "data": [...] }` |
| 2 | Ouvrir `https://api.terreforte.gn/api/products` | JSON paginé |
| 3 | Ouvrir `https://api.terreforte.gn/admin` | Écran de connexion Filament |
| 4 | Se connecter avec `Brams224gn` | Accès au tableau de bord |
| 5 | Créer/modifier un produit dans Filament | Visible immédiatement dans `GET /api/products` |
| 6 | Téléverser une image dans Filament | URL d'image accessible publiquement |
| 7 | Soumettre le formulaire de contact du frontend | Ligne créée dans `contact_messages` |
| 8 | Console navigateur du frontend | Aucune erreur CORS |

---

## 14. Sauvegardes et maintenance

- **Base** : cPanel → *Backup* ou *phpMyAdmin* → export régulier ; activez une sauvegarde automatique si l'offre le permet.

- **Fichiers** : sauvegardez `storage/app/public` \(médias\) en plus du code.

- **Mises à jour** : `git pull`, puis `composer install --no-dev`, `php artisan migrate --force`, et rejouez les caches de l'étape 8.

---

## 15. Dépannage

- **Erreur 500 au chargement** : consultez `storage/logs/laravel.log`. Causes fréquentes : `APP_KEY` manquante, identifiants `DB_*` erronés, permissions sur `storage/` et `bootstrap/cache/`.

- **404 en accès à **<strong>`/api/...`</strong> : la Document Root ne pointe pas sur `public/`, ou le `.htaccess` de `public/` est absent \(le module Apache `mod_rewrite` doit être actif\).

- **Erreurs CORS dans la console du frontend** : vérifiez `CORS_ALLOWED_ORIGINS` \(doit inclure l'origine exacte du site, protocole compris\) puis `php artisan config:clear`.

- **Images non affichées après upload** : `php artisan storage:link` non exécuté ou lien symbolique bloqué \(voir étape 7\).

- <strong>`composer`</strong>** introuvable** : utilisez la méthode locale de l'étape 4.

- **Après modification du **<strong>`.env`</strong> : exécutez toujours `php artisan config:clear` \(ou `config:cache`\) pour que les changements soient pris en compte.

