# Déployer le site pour un client réel

Ce dépôt est la **démonstration** : contenus fictifs, coordonnées inventées, mot de passe
public. Ce document décrit la mise en ligne pour un client qui paie, sur son propre dépôt et
son propre hébergement.

À lire de haut en bas la première fois. Les étapes 1 et 2 se font **avant** de signer : elles
peuvent disqualifier un hébergement, et il vaut mieux le découvrir avant d'encaisser.

---

## 1. Vérifier l'hébergement avant de vendre

| Prérequis | Pourquoi | Comment vérifier |
| --- | --- | --- |
| PHP **8.3** ou plus | Contrainte du `composer.json` | `php -v` |
| Extension **pdo_mysql**, **mbstring**, **openssl**, **fileinfo** | Socle Laravel | `php -m` |
| Extension **gd** | Icônes matricielles (`.ico`, `.png`). Sans elle, le site sert l'icône vectorielle — dégradé accepté, pas une panne | `php -m \| grep gd` |
| **Cron** toutes les minutes | **Critique.** Sans lui, aucun e-mail ne part | Panneau de l'hébergeur |
| **SMTP** sortant | Confirmations, rappels, notifications | Identifiants fournis par l'hébergeur ou un service tiers |
| **HTTPS** | Obligatoire : le site collecte des données personnelles | Certificat, souvent Let's Encrypt |
| Racine web sur **`public/`** | Sinon `.env` et la base sont exposés | Configuration du vhost |
| `upload_max_filesize` ≥ **8 Mo** | Le back-office plafonne les images à 4 Mo | `php -i \| grep upload_max` |

> **Le cron est le point qui disqualifie.** Le site enregistre le rendez-vous, mais la
> confirmation, le rappel et la notification au coach partent par une file d'attente. Sans
> `schedule:run`, le client croira que le site est cassé — et il aura raison. Certains
> hébergements mutualisés d'entrée de gamme ne proposent pas de cron à la minute : le vérifier
> **avant**.

Si la racine web ne peut pas pointer sur `public/`, refuser l'hébergement plutôt que bricoler
une redirection : `.env` contient les identifiants de la base et la clé de chiffrement.

---

## 2. Rassembler les informations du client

Rien ne se déploie utilement sans ces éléments. Les réclamer en une seule fois :

- [ ] **Identité** — nom commercial, nom et titre du coach, slogan
- [ ] **SIRET** — obligatoire sur les mentions légales d'un professionnel
- [ ] **Coordonnées** — e-mail, téléphone, adresse postale complète
- [ ] **Logo** — fond transparent, et sa variante pour fond sombre si elle existe
- [ ] **Photos** — portrait, visuels de prestations (le back-office les redimensionne)
- [ ] **Prestations** — intitulé, description, durée, tarif, en présentiel ou en visio
- [ ] **Horaires** — plages de disponibilité réelles, jours de fermeture
- [ ] **CGV** — tarifs, conditions d'annulation, remboursement. **Le coach les rédige**, ou son
      conseil : ce sont ses engagements commerciaux, pas les vôtres
- [ ] **Témoignages** — avec l'accord écrit des personnes citées
- [ ] **Nom de domaine** — acheté et pointant sur l'hébergement

---

## 3. Créer le dépôt client

```bash
git clone git@github.com:Cedric331/coach-fitness.git coach-<client>
cd coach-<client>
git remote set-url origin git@github.com:<compte>/coach-<client>.git
git push -u origin main
```

Garder le dépôt de démonstration en second remote permet de rejouer les correctifs :

```bash
git remote add demo git@github.com:Cedric331/coach-fitness.git
git fetch demo && git merge demo/main    # plus tard, pour récupérer une correction
```

**Dépôt privé.** Il contiendra les contenus du client, et son historique gardera la trace de
tout ce qui y est ajouté par erreur.

---

## 4. Configurer l'environnement

Sur le serveur, `.env` — jamais dans Git :

```dotenv
APP_NAME="Studio <Nom>"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://le-domaine-du-client.fr
APP_TIMEZONE=Europe/Paris
APP_LOCALE=fr

# Mandataires de confiance. À renseigner si le site est derrière un reverse proxy
# terminant le TLS (Nginx, Apache, Cloudflare, répartiteur de charge) — le cas le
# plus courant. Sans cela, les URL générées sortent en http:// : les liens
# d'annulation envoyés par e-mail et les adresses canoniques deviennent faux.
# `*` convient quand seul le mandataire peut joindre l'application.
TRUSTED_PROXIES=*

DB_CONNECTION=mysql
DB_HOST=...
DB_DATABASE=...
DB_USERNAME=...
DB_PASSWORD=...

SESSION_DRIVER=database
QUEUE_CONNECTION=database
CACHE_STORE=database          # ou redis si disponible

MAIL_MAILER=smtp
MAIL_HOST=...
MAIL_PORT=587
MAIL_USERNAME=...
MAIL_PASSWORD=...
MAIL_FROM_ADDRESS="contact@le-domaine-du-client.fr"
MAIL_FROM_NAME="${APP_NAME}"

# Compte d'administration du coach
ADMIN_EMAIL="adresse-reelle-du-coach@exemple.fr"
ADMIN_NAME="Prénom Nom"
ADMIN_PASSWORD="un-mot-de-passe-long-et-unique"
```

**`MAIL_FROM_ADDRESS` doit appartenir au domaine du client.** Une adresse d'un autre domaine
part en spam : les enregistrements SPF et DKIM du domaine expéditeur ne couvriront pas
l'envoi.

`APP_DEBUG=false` n'est pas négociable : à `true`, une erreur affiche le contenu de `.env`,
identifiants de base compris, à qui provoque l'erreur.

---

## 5. Installer

```bash
composer install --no-dev --optimize-autoloader
npm ci && npm run build
php artisan key:generate
php artisan migrate --force
php artisan db:seed --force
php artisan storage:link
php artisan optimize          # en dernier : voir l'encadré
```

### Ce que `db:seed` installe — et n'installe pas

En `APP_ENV=production`, il pose **le socle seulement** :

- le compte administrateur ;
- les réglages du site ;
- les trois pages légales (mentions légales, confidentialité, CGV) ;
- un planning hebdomadaire par défaut, à ajuster.

Les prestations, témoignages, articles et rendez-vous de vitrine **ne sont pas installés** : de
faux témoignages sont une pratique commerciale trompeuse, et de faux rendez-vous portent des
noms de personnes qui n'existent pas. Le site démarre donc vide, et c'est voulu.

Pour monter une démonstration *sur* un serveur de production, forcer `SEED_DEMO_CONTENT=true`.

> **`optimize` en dernier.** Il met la configuration en cache, ce qui rend `.env` invisible aux
> commandes lancées ensuite. Un `db:seed` exécuté après repartirait sur les valeurs par défaut
> — mot de passe administrateur compris. Après toute modification de `.env` :
> `php artisan optimize:clear && php artisan optimize`.

Sans `ADMIN_PASSWORD`, le seeder tire un mot de passe au hasard et l'affiche **une seule
fois**. Le noter avant de fermer le terminal.

---

## 6. Planifier les tâches

```cron
* * * * * cd /chemin/du/site && php artisan schedule:run >> /dev/null 2>&1
```

Cette ligne porte les rappels de rendez-vous, la purge RGPD et le traitement de la file
d'attente. **Sans elle, aucun e-mail ne part.**

Avec un superviseur, préférer un worker dédié ; le passage planifié devient un filet de
sécurité :

```ini
[program:coach-worker]
command=php /chemin/du/site/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
```

---

## 7. Paramétrer le back-office

Se connecter sur `/admin` avec `ADMIN_EMAIL`, puis, dans l'ordre :

**Configuration → Identité**
- [ ] Nom du site, slogan, nom et titre du coach
- [ ] Logo, logo pour fond sombre, favicon

**Configuration → Coordonnées**
- [ ] E-mail, téléphone, adresse complète
- [ ] **SIRET** — sans lui, les mentions légales affichent « à compléter en back-office »

**Configuration → Confidentialité**
- [ ] Nom et adresse de l'hébergeur (obligation légale)
- [ ] Durée de conservation des données

**Contenu du site → Pages libres**
- [ ] Relire les mentions légales et la politique de confidentialité
- [ ] **Rédiger les CGV et les publier** — la trame livrée ne remplace pas les conditions
      commerciales du coach, et la page reste dépubliée tant qu'elles ne sont pas écrites

Ces pages emploient des variables — `[nom_du_coach]`, `[siret]`, `[hebergeur]`,
`[duree_conservation]` — remplacées automatiquement par les réglages ci-dessus. Le coach n'a
pas à les retoucher à chaque changement de coordonnées.

**Contenu du site**
- [ ] Prestations : intitulé, description, durée, tarif, visibilité
- [ ] Témoignages : uniquement des vrais, avec accord écrit
- [ ] FAQ, page « À propos »

**Agenda**
- [ ] Plages horaires hebdomadaires réelles
- [ ] Délai de prévenance, rappel automatique
- [ ] Fermetures exceptionnelles (congés)

**Configuration → Référencement**
- [ ] Description du site, image de partage
- [ ] Laisser **« Autoriser les moteurs de recherche » désactivé** jusqu'à l'ouverture

---

## 8. Vérifier avant d'ouvrir

```bash
curl -sI https://le-domaine.fr | head -1                 # 200
curl -s  https://le-domaine.fr/robots.txt                # désigne le plan du site
curl -s  https://le-domaine.fr/sitemap.xml | head -5     # URL en https:// et bon domaine
php artisan appointments:remind --dry-run                # rappels à venir, sans envoi
php artisan privacy:purge --dry-run                      # purge RGPD, à blanc
```

**Si `sitemap.xml` affiche `http://` ou le mauvais domaine, `TRUSTED_PROXIES` est en cause.**
C'est le symptôme le plus courant et le plus discret.

À faire à la main :

- [ ] **Réserver un créneau de bout en bout** avec une vraie adresse, et vérifier que le coach
      et le client reçoivent leur e-mail. C'est le test qui compte : il valide le cron, la
      file d'attente et le SMTP d'un coup
- [ ] Cliquer le lien d'annulation reçu par e-mail — il doit être en `https://`
- [ ] Envoyer un message par le formulaire de contact
- [ ] Ouvrir le site sur un téléphone
- [ ] Vérifier que les mentions légales n'affichent plus « à compléter »
- [ ] Vérifier que les CGV sont publiées et accessibles
- [ ] Passer une page dans l'outil de test des résultats enrichis de Google

---

## 9. Ouvrir

1. Activer **« Autoriser les moteurs de recherche »** en back-office
2. Vérifier que `robots.txt` ne bloque plus l'indexation
3. Soumettre `sitemap.xml` dans la Search Console
4. Faire changer son mot de passe au coach

---

## 10. Exploitation

**Sauvegardes** — la base **et** `storage/app/public`. Une sauvegarde de base seule restaure un
site sans aucune image. Vérifier qu'une restauration fonctionne : une sauvegarde jamais testée
n'est pas une sauvegarde.

**Mise à jour depuis la démonstration**

```bash
git fetch demo && git merge demo/main
composer install --no-dev --optimize-autoloader
npm ci && npm run build
php artisan migrate --force
php artisan optimize:clear && php artisan optimize
```

Ne jamais rejouer `db:seed` sur un site en service : il réécrit les pages légales et remettrait
les textes livrés par-dessus ceux du client.

**Remise au client** — lui transmettre ses identifiants, l'adresse du back-office, et le
prévenir que le mot de passe oublié fonctionne par e-mail. Une prise en main d'une demi-heure
sur les prestations et l'agenda évite l'essentiel du support.

---

## 11. Dépannage

| Symptôme | Cause la plus probable |
| --- | --- |
| Aucun e-mail ne part | Cron absent. Vérifier `schedule:run`, puis `php artisan queue:work --once` |
| E-mails en spam | `MAIL_FROM_ADDRESS` hors du domaine, ou SPF/DKIM non configurés |
| Liens d'e-mail en `http://` | `TRUSTED_PROXIES` non renseigné |
| Images téléversées invisibles | `php artisan storage:link` non rejoué sur le serveur |
| Modification de `.env` sans effet | Configuration en cache : `php artisan optimize:clear` |
| Erreur 500 après déploiement | `storage/` et `bootstrap/cache/` non inscriptibles |
| Téléversement d'image qui échoue | `upload_max_filesize` sous 8 Mo |
| Mentions légales « à compléter » | SIRET non renseigné en back-office |
| Aucun créneau proposé | Aucune plage horaire, ou aucune prestation réservable |

---

## Ce que le site ne fait pas

À dire au client **avant** la vente, pour éviter le malentendu :

- **Pas d'encaissement en ligne.** Les paiements se règlent hors site.
- **Pas de bandeau cookies**, et c'est tenable : le site ne dépose que deux cookies techniques,
  exemptés de consentement. Cela impose en contrepartie une mesure d'audience sans cookie
  (Plausible, Fathom, Matomo sans cookie). **Coller un script Google Analytics obligerait à
  ajouter un bandeau de consentement**, qui n'existe pas dans le site.
- **Pas de rendu serveur.** Les métadonnées sont rendues côté serveur et Google indexe le
  contenu ; des moteurs plus rudimentaires peuvent ne pas le faire.
- **Pas de gestion multi-coachs.** Un site, un professionnel.
