# Runbook — Test prod du pipeline crawl Firecrawl (2026-07-23)

Cible : serveur `seo-insigght-99` (163.172.71.169) — app systemd (`seo-insight-web`, `seo-insight-analytics`) + stack Firecrawl Docker déployée le 22/07 sur `/data/firecrawl/stack` (API loopback `127.0.0.1:3002`). Déploiement = `./seo-insight-update.sh` (force `origin/main`).

## Pré-requis (avant merge main)

- [ ] Durcissements mergés sur dev : pool de claim worker (concurrence 4) + résilience poll/annulation batch.
- [ ] Suites vertes (racine + services/analytics, 2 runs consécutifs sur crawl-onpage).
- [ ] Validation explicite Bastien : « merge sur main ».

## 1. Merge & pré-vol (poste local)

```bash
cd ~/Github/seo-insight
git checkout main && git pull
git merge dev --ff-only && git push        # 72+ commits, migrations 0043→0066 incluses
```

## 2. Env prod (serveur, AVANT le deploy)

En SSH (`sgwsnlcupaqyxdqux@163.172.71.169`), dans un shell **bash** :

```bash
# La clé réelle de la stack :
grep FIRECRAWL_API_KEY /data/firecrawl/stack/.env
# L'ajouter à l'env de l'app (sudo -u seoinsight, fichier .env.production de /opt/seo-insight) :
#   FIRECRAWL_API_URL=http://127.0.0.1:3002
#   FIRECRAWL_API_KEY=<clé fc-…>
```

Vérifs préalables :
```bash
curl -s http://127.0.0.1:3002/ | head -c 60          # API Firecrawl up (loopback)
docker compose -f /data/firecrawl/stack/docker-compose.yaml ps   # tous healthy
systemctl status seo-insight-web seo-insight-analytics --no-pager | grep Active
sudo -u postgres psql -lqt | grep seo_insight        # tranche seo_insight vs seo_insight_prod
```

## 3. Units systemd (F3 — deploy.sh ne les recopie PAS)

```bash
diff /opt/seo-insight/deploy/systemd/seo-insight-analytics.service /etc/systemd/system/seo-insight-analytics.service
# si diff (fix HOST=127.0.0.1 + WORKER_CONCURRENCY à venir) :
sudo cp /opt/seo-insight/deploy/systemd/seo-insight-analytics.service /etc/systemd/system/ && sudo systemctl daemon-reload
```

## 4. Déploiement (poste local, fenêtre creuse — migrations lourdes)

```bash
./seo-insight-update.sh          # ssh → deploy/deploy.sh : reset main, wasm, bun install, cargo, db:migrate, next build, restart
```

Post-migration (serveur) : `ANALYZE` sur les tables touchées par 0043→0066 (au minimum keywords et satellites — cf. serveur-prod.md F5).

## 5. Vérifications post-deploy (serveur)

```bash
ss -tlnp | grep -E "3000|8787|3002"    # 3000 et 8787 en 127.0.0.1 UNIQUEMENT ; 3002 loopback
journalctl -u seo-insight-analytics -n 20 --no-pager   # démarré sans erreur env
```

## 6. Smoke test réel (UI prod dash.seoinsight.app)

Mot-clé de test : un mot-clé du site ADVMFR (le tien — jamais un client). Depuis /keywords/planning :
1. Ouvrir l'Overview → carte « Crawler » → clic. Attendu : pastille « En cours », toast « Crawl : X ok… » ≤ 2 min, complétude à jour.
2. « Relancer l'analyse » (profil sémantique). Attendu : profil régénéré, `flags: []` (plus de « rendu JS suspecté »).
3. Pendant le crawl : lancer un import CSV (petit fichier) — attendu : il N'attend PAS la fin du crawl (preuve du pool de claim).
4. Double-clic « Crawler » → « Crawl déjà en cours » (garde 409).
5. En DB prod : `select totals from analytics_jobs order by created_at desc limit 3;` — totals honnêtes (crawled+blocked+failed = nb concurrents).

## 7. Rollback

- App : `git reset --hard <sha précédent de main>` sur le serveur + re-deploy — MAIS les migrations 0043→0066 ne sont pas réversibles automatiquement → en cas de pépin post-migration, on répare en avant (fix forward), pas en arrière.
- Pipeline crawl seul : retirer `FIRECRAWL_API_URL` de l'env + restart analytics → les jobs crawl-onpage échouent proprement (message clair), le reste de l'app est intact.

## Critères GO/NO-GO du test

GO si : job done avec totals cohérents, crawlStatus posés, sémantique sans flags JS, imports non bloqués pendant un crawl, `ss` propre. NO-GO → rollback pipeline (retrait env) + analyse.
