# DEPLOY — Le Donut Infolab

Procédure exacte de déploiement sur le serveur **Donut Marseille**.

- Hôte : `arnaud.donut@82.66.40.209`
- OS : Ubuntu 26.04
- Sous-domaine : `infolab.ledonut-marseille.org`
- Conteneur PHP : `donut-infolab` (UID `33` = www-data côté Apache)
- BDD : conteneur existant `donut-mariadb`, réseau Docker `donut-net`
- Reverse proxy : Caddy natif sur l'hôte
- Front : SPA Vue 3 buildé (statique) servi par Caddy depuis `/srv/donut/web/infolab-front/dist/`

> ⚠️ Pré-requis DNS : créer chez OVH un record `A infolab.ledonut-marseille.org → 82.66.40.209`
> **avant** le reload Caddy (sinon échec ACME challenge).

---

## 0. Pré-requis vérifiés une fois

```bash
ssh arnaud.donut@82.66.40.209

# Le réseau donut-net existe
docker network ls | grep donut-net
# Le mariadb tourne et est joignable depuis donut-net
docker ps | grep donut-mariadb
# /srv/donut/secrets/mariadb.env est en place et lisible par root
sudo ls -l /srv/donut/secrets/mariadb.env
# Le group donut-admins existe
getent group donut-admins
```

---

## 1. Copier le backend vers le serveur

Depuis ta machine de dev (à la racine du repo) :

```bash
# Code app PHP -> /srv/donut/web/infolab/  (bind-mount dans le conteneur, UID 33)
rsync -avz --delete \
    --exclude '.git' --exclude '.idea' --exclude '.env' --exclude 'tests' \
    --exclude 'docker-compose.yml' --exclude 'Dockerfile' --exclude 'caddy.conf' \
    --exclude 'migrations' --exclude 'DEPLOY.md' --exclude 'INSTRUCTIONS.md' \
    --exclude 'frontend' --exclude 'docs' \
    ./ arnaud.donut@82.66.40.209:/tmp/infolab-app/

# Fichiers d'orchestration -> /srv/donut/compose/infolab/
rsync -avz \
    docker-compose.yml Dockerfile caddy.conf README.md DEPLOY.md .env.example \
    migrations \
    arnaud.donut@82.66.40.209:/tmp/infolab-compose/
```

Puis sur le serveur :

```bash
ssh arnaud.donut@82.66.40.209

# Code app (UID 33 = www-data du conteneur Apache)
sudo mkdir -p /srv/donut/web/infolab
sudo rsync -a --delete /tmp/infolab-app/ /srv/donut/web/infolab/
sudo chown -R 33:33 /srv/donut/web/infolab
sudo find /srv/donut/web/infolab -type d -exec chmod 755 {} \;
sudo find /srv/donut/web/infolab -type f -exec chmod 644 {} \;

# Orchestration (root:donut-admins, lisible par les admins)
sudo mkdir -p /srv/donut/compose/infolab
sudo rsync -a /tmp/infolab-compose/ /srv/donut/compose/infolab/
sudo chown -R root:donut-admins /srv/donut/compose/infolab
sudo chmod 750 /srv/donut/compose/infolab
sudo chmod 640 /srv/donut/compose/infolab/*

# Cleanup tmp
rm -rf /tmp/infolab-app /tmp/infolab-compose
```

---

## 1bis. Builder & copier le frontend (SPA Vue)

Le SPA est compilé localement (Node 22+ requis) et déployé en statique. Pas de Node sur le serveur prod.

```bash
# Sur la machine de dev, à la racine du repo
cd frontend
npm ci                  # ou `npm install` la 1re fois
npm run build           # produit frontend/dist/
ls -la dist/            # index.html + assets/ avec hash

# Copie de l'artifact vers le serveur (rsync direct, fichiers statiques)
rsync -avz --delete dist/ arnaud.donut@82.66.40.209:/tmp/infolab-front-dist/
cd ..
```

Sur le serveur :

```bash
ssh arnaud.donut@82.66.40.209
sudo mkdir -p /srv/donut/web/infolab-front/dist
sudo rsync -a --delete /tmp/infolab-front-dist/ /srv/donut/web/infolab-front/dist/
# Caddy tourne en `caddy` user — donner l'accès en lecture est suffisant
sudo chown -R caddy:caddy /srv/donut/web/infolab-front
sudo find /srv/donut/web/infolab-front -type d -exec chmod 755 {} \;
sudo find /srv/donut/web/infolab-front -type f -exec chmod 644 {} \;
rm -rf /tmp/infolab-front-dist
```

> ⚠️ Le build embarque l'URL de l'API en relatif (`/api/...`) — donc le SPA et l'API
> **doivent** être servis depuis le même domaine (ce que fait notre `caddy.conf`).

---

## 2. Créer les secrets `/srv/donut/secrets/infolab.env`

```bash
ssh arnaud.donut@82.66.40.209

DB_PASS="$(openssl rand -hex 24)"
ADMIN_TOKEN="$(openssl rand -hex 32)"

sudo tee /srv/donut/secrets/infolab.env > /dev/null <<EOF
DB_HOST=donut-mariadb
DB_PORT=3306
DB_NAME=infolab
DB_USER=infolab
DB_PASS=$DB_PASS

ADMIN_TOKEN=$ADMIN_TOKEN

CORS_ORIGIN=https://infolab.ledonut-marseille.org
APP_ENV=production
APP_DEBUG=false
EOF

sudo chown root:donut-admins /srv/donut/secrets/infolab.env
sudo chmod 640 /srv/donut/secrets/infolab.env

# Note les 2 secrets quelque part de sûr (gestionnaire de mdp) :
sudo cat /srv/donut/secrets/infolab.env | grep -E '^(ADMIN_TOKEN|DB_PASS)='
```

---

## 3. Créer la BDD + le user MariaDB + appliquer les migrations

```bash
# Le script apply.sh fait tout : crée la base, le user, applique les .sql
# Idempotent : peut être ré-exécuté sans danger (table schema_migrations).
sudo /srv/donut/compose/infolab/migrations/apply.sh
```

Tu dois voir :
- `apply  001_init_schema.sql`
- `apply  002_seed_categories.sql`
- résumé avec `categories_count = 6`

---

## 4. Build + start du conteneur

```bash
cd /srv/donut/compose/infolab
sudo docker compose --env-file /srv/donut/secrets/infolab.env up -d --build

# Vérifie qu'il tourne et écoute en local sur 127.0.0.1:8003
docker ps | grep donut-infolab
ss -ltn | grep 8003

# Sonde de vie via le port mappé en local
curl -s http://127.0.0.1:8003/api/health
# {"status":"ok","time":"..."}
```

Si la sonde renvoie `degraded`, vérifier les logs :
```bash
docker logs --tail 100 donut-infolab
```

---

## 5. Vhost Caddy (sert le SPA + reverse_proxy l'API)

Le `caddy.conf` fait deux choses :
- `/api/*` -> reverse_proxy vers le conteneur PHP `127.0.0.1:8003`
- tout le reste -> sert `/srv/donut/web/infolab-front/dist/` (SPA), fallback `index.html`

```bash
grep -n 'infolab' /etc/caddy/Caddyfile

# Si manquant, ajouter en fin de Caddyfile :
echo 'import /srv/donut/compose/infolab/caddy.conf' | sudo tee -a /etc/caddy/Caddyfile

# Valider la syntaxe puis recharger
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
```

Caddy va négocier le certificat Let's Encrypt (à condition que le DNS A
record soit en place — voir avertissement en tête de fichier).

Vérifier qu'il sert bien le SPA et l'API :

```bash
curl -sI https://infolab.ledonut-marseille.org/                 # SPA -> 200 text/html
curl -sI https://infolab.ledonut-marseille.org/api/health       # API -> 200 application/json
curl -sI https://infolab.ledonut-marseille.org/whatever-fake    # SPA fallback -> 200 index.html
```

---

## 6. Vérification finale

```bash
# Depuis la machine de dev (TLS terminé par Caddy)
curl -s https://infolab.ledonut-marseille.org/api/health
curl -s https://infolab.ledonut-marseille.org/api/categories | head -c 400

# Smoke tests complets (lit ADMIN_TOKEN depuis le secret côté serveur)
ssh arnaud.donut@82.66.40.209 'sudo bash -c "
  TOKEN=\$(grep ^ADMIN_TOKEN= /srv/donut/secrets/infolab.env | cut -d= -f2-)
  INFOLAB_URL=https://infolab.ledonut-marseille.org ADMIN_TOKEN=\$TOKEN \
      /srv/donut/compose/infolab/tests/smoke.sh
"'
```

Si tout est vert : `OK : 11 / FAIL : 0`.

---

## 7. Cycle de mise à jour (pour plus tard)

```bash
# Backend PHP
rsync -avz --delete --exclude '.git' --exclude '.env' \
    public/ src/ arnaud.donut@82.66.40.209:/srv/donut/web/infolab/

# Frontend Vue (build à chaque release)
(cd frontend && npm ci && npm run build)
rsync -avz --delete frontend/dist/ \
    arnaud.donut@82.66.40.209:/srv/donut/web/infolab-front/dist/

# Si changement Dockerfile / docker-compose / migrations :
rsync -avz docker-compose.yml Dockerfile migrations/ \
    arnaud.donut@82.66.40.209:/srv/donut/compose/infolab/

ssh arnaud.donut@82.66.40.209 << 'EOF'
  sudo /srv/donut/compose/infolab/migrations/apply.sh   # nouvelle migration éventuelle
  cd /srv/donut/compose/infolab
  sudo docker compose --env-file /srv/donut/secrets/infolab.env up -d --build
  sudo chown -R 33:33 /srv/donut/web/infolab
  sudo chown -R caddy:caddy /srv/donut/web/infolab-front
EOF
```

---

## Points à valider une fois en prod

- [ ] DNS `A infolab.ledonut-marseille.org → 82.66.40.209` ajouté chez OVH
- [ ] Certificat Let's Encrypt négocié OK (`caddy.log` côté hôte)
- [ ] `ADMIN_TOKEN` archivé dans le gestionnaire de mots de passe partagé
- [ ] `tests/smoke.sh` vert depuis l'extérieur
- [ ] SPA accessible : `https://infolab.ledonut-marseille.org/` renvoie la page d'accueil
- [ ] SPA routing OK : `https://infolab.ledonut-marseille.org/projects` aussi (pas de 404 — fallback Caddy)
- [ ] Conteneur `donut-infolab` visible dans Dozzle (logs Apache + PHP via stderr)
- [ ] Pas de fuite : `curl -I https://infolab.ledonut-marseille.org/.env` → 403/404
