# Recap — Tentative Vercel & rollback (pour l'agent elevaseo.com)

> Destinataire : agent travaillant sur `~/Github/eleva-rebrand/` (site marketing `elevaseo.com`).
> Auteur : agent eleva-speed (SaaS `speed.elevaseo.app`).
> Date : 2026-05-27.
> Statut : tentative de migration **annulée** le 2026-05-26. Le SaaS est revenu intégralement self-hosted. Le passage de domaine `.app → .com` reste **ouvert** côté SaaS et a des ramifications directes pour le site marketing.

---

## TL;DR

- Le 2026-05-26 on a tenté de scinder la stack `speed.elevaseo.app` en deux : **Next.js sur Vercel** + **backend (Postgres mTLS / Redis / sitespeed-worker) self-hosted**, exposé via Cloudflare Tunnel + Traefik TCP passthrough.
- Le même jour on a tout reverté. La PR `#3` (merge dev → main) a été annulée par un revert commit (`e82f377a7`). `dev` a été reset hard sur `main`.
- Le code et la doc de la migration sont **préservés** dans la branche `backup/vercel-migration` + le tag `vercel-migration-2026-05-26`, plus un tarball serveur (`~/eleva-speed-migration-backup-20260526-124532.tgz`).
- Aujourd'hui le SaaS tourne toujours sur `speed.elevaseo.app`, stack monolithique Docker. **Aucune interruption de prod.**
- Décision restée ouverte : faire passer le SaaS de `speed.elevaseo.app` à `speed.elevaseo.com` **sur la stack interne actuelle** (sans Vercel). Toutes les étapes sont listées §C de [`rollback-vercel-migration-2026-05-26.md`](./rollback-vercel-migration-2026-05-26.md).
- **C'est là que tu entres en jeu** : si le SaaS migre sur le sous-domaine `speed.elevaseo.com`, ça impacte DNS, cookies (Better Auth), CTAs marketing, SEO, intégrations Stripe / Resend / etc.

---

## 1. Contexte (1 paragraphe)

Eleva Speed est le SaaS de monitoring perf (Lighthouse / sitespeed.io / multi-régions) servi aujourd'hui à `speed.elevaseo.app`. Architecture actuelle : un seul host Docker (`docker-compose.prod.yml`) avec Next.js + Postgres + Redis + worker sitespeed, fronté par Traefik (Cloudflare Origin Certificate). Le site marketing `elevaseo.com` vit dans un repo séparé (`~/Github/eleva-rebrand/`). Les deux produits coexistent sous le même branding mais sur des domaines différents (`.com` marketing, `.app` SaaS), ce qui est techniquement propre mais marketing-suboptimal — d'où la tentative de migration vers `.com` pour les deux.

---

## 2. Implémentation tentée (PR #3, mergée puis revertée)

Stack cible :

```
speed.elevaseo.com (DNS / Vercel)
   │ mTLS Postgres (TCP 5433 via Traefik TCP passthrough)
   │ Cloudflare Access service token (HTTPS sitespeed API)
   ▼
serveur 163.172.71.169 — nouveau compose `docker-compose.server.yml`
   ├─ Postgres mTLS (TLS 1.3, scram-sha-256, certs PKI ECDSA P-256)
   ├─ Redis
   ├─ sitespeed-worker (BullMQ + Chrome + filtrage egress iptables)
   ├─ tcp-bridge (socat) pour proxy net → internal-net
   └─ cloudflared (systemd unit) pour tunnel sortant HTTPS
```

Pièces livrées dans la PR (toutes présentes sur `backup/vercel-migration`) :

- `docker-compose.server.yml` (backend stack séparée)
- `services/postgres/{Dockerfile, pg_hba.conf, postgresql.conf}` (mTLS)
- `services/sitespeed-worker/{Dockerfile, worker-egress-init.sh}` (anti-SSRF iptables)
- `scripts/tls/{issue-ca,issue-server,issue-client}.sh` (PKI ECDSA P-256)
- `docs/superpowers/specs/2026-05-26-vercel-migration-design.md` (865 lignes)
- `docs/superpowers/plans/2026-05-26-vercel-migration-plan.md` (2161 lignes)
- `docs/deploy-runbook.md` (runbook one-shot 14 sections, "🧑 TOI" vs "💻 COPIER")
- `docs/observability-decision.md` (comparatif 7 outils OSS — recommandation : **GlitchTip**)
- `docs/server-deploy.md` (runbook backend)
- `.vercelignore`, suppression Dockerfile, refactor `lib/env.ts` + `next.config.ts` pour Vercel
- Migration `lib/db/index.ts` pour mTLS client (cert/key via env + bundle PKI)

Tous ces fichiers vivent encore sur `backup/vercel-migration` — tu peux les lire avec `git show backup/vercel-migration:<path>` sans changer de branche.

---

## 3. Rollback (ce qui a été défait le 2026-05-26)

Détails complets : [`docs/migrations/rollback-vercel-migration-2026-05-26.md`](./rollback-vercel-migration-2026-05-26.md). Résumé :

| Couche               | Action de rollback                                                                                                                          | État après           |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| Git `main`           | Revert commit `e82f377a7` (PR `#3` annulée, audit trail intact)                                                                             | propre               |
| Git `dev`            | `reset --hard origin/main` + force-push                                                                                                     | aligné sur main      |
| Docker stack serveur | `eleva-speed-server` containers + network supprimés ; volumes data conservés sous `/data/eleva-speed-server/{pg,redis,results}` (au cas où) | supprimé             |
| OLD prod stack       | `eleva-speed-prod` **jamais arrêtée** — production en continu pendant toute la tentative                                                    | inchangée            |
| Traefik              | Entrypoint `:5433` retiré + port `5433:5433` retiré du compose Traefik                                                                      | n'écoute que :80/443 |
| UFW                  | `ufw delete allow 5433/tcp` (manuel sudo)                                                                                                   | refermé              |
| cloudflared systemd  | `stop && disable` (tunnel CF reste créé côté dashboard Zero Trust, réversible)                                                              | inactif              |

**Note importante** : la raison du rollback n'est **pas documentée explicitement** dans le repo. Le revert commit ne donne pas de motif. Si tu as besoin du "pourquoi", demande à Bastien — pas d'inférer.

---

## 4. État actuel (2026-05-27)

- **Domaine SaaS** : `speed.elevaseo.app` (inchangé).
- **Hosting SaaS** : 100 % self-hosted Docker sur `163.172.71.169` (`docker-compose.prod.yml`).
- **Domaine marketing** : `elevaseo.com` (ton terrain).
- **Branding** : email contact / from / Resend etc. sont sur `elevaseo.com` (cf. memoire `userEmail = bastien@elevaseo.com`).
- **Migration Vercel** : parquée. Resurrectable depuis `backup/vercel-migration` + tarball serveur. Cheatsheet de résurrection en bas de `docs/migrations/rollback-vercel-migration-2026-05-26.md`.
- **Observability error monitoring** : décision parquée — **GlitchTip** (Sentry-SDK-compatible, ~3 containers) candidat. Plan d'install post-cutover (cf. mémoire `project-error-monitoring-todo`). Pour le debug local, **d3k mandaté** (`pnpm dev:agent` uniquement, jamais `pnpm dev`).

---

## 5. Ramifications pour `elevaseo.com` (à intégrer dans ta planification)

### 5.1 Domaine `speed.elevaseo.com` — non décidé mais préparé

Si Bastien tranche pour migrer le SaaS de `.app` à `.com` (probable à terme — c'est l'intention derrière la tentative Vercel), il y aura un sous-domaine `speed.elevaseo.com` sous **ta** racine DNS. Toutes les étapes côté SaaS sont listées §C de [`rollback-vercel-migration-2026-05-26.md`](./rollback-vercel-migration-2026-05-26.md) :

- **DNS** : record `A speed → 163.172.71.169` sur la zone `elevaseo.com` (orange cloud CF recommandé).
- **Traefik label** : `Host(\`speed.elevaseo.com\`)`ou compound`Host(.com) || Host(.app)` pendant transition.
- **Cert** : déjà couvert par le CF Origin Certificate `*.elevaseo.com` (default cert Traefik).

→ **Côté toi** : prévoir le record DNS, ne pas le squatter pour autre chose, et anticiper la coexistence éventuelle des deux endpoints pendant la transition.

### 5.2 Cookies Better Auth & sessions cross-domain

Le SaaS utilise **Better Auth**. Aujourd'hui les cookies de session sont scopés sur `speed.elevaseo.app`. Si le SaaS passe à `speed.elevaseo.com` :

- Les sessions actives sur `.app` deviennent invalides côté `.com` (cookie sur mauvais domaine). C'est un cutover propre, pas un dual-mode silencieux.
- Si tu mets ou met**ras** un jour de l'auth sur le site marketing `elevaseo.com` (login préview, espace client, etc.), il y aura **collision potentielle de cookies** au niveau `domain=.elevaseo.com`. À cadrer avec Bastien si ce cas se présente : décider du `cookieDomain` Better Auth (`speed.elevaseo.com` strict vs `.elevaseo.com` partagé).

→ **Côté toi** : ne JAMAIS poser de cookie `Domain=.elevaseo.com` sans coordination avec le SaaS. Préférer `Domain=elevaseo.com` (host strict) ou un sous-domaine dédié type `www.elevaseo.com`.

### 5.3 CTAs / liens marketing → SaaS

Tous les CTAs du site marketing qui pointent vers le SaaS (sign-up, login, pricing, dashboard) doivent rester variabilisés via env var **et pas en dur**. Recommandation :

```ts
// env du site marketing
NEXT_PUBLIC_SAAS_URL=https://speed.elevaseo.app   // aujourd'hui
// après migration .com :
NEXT_PUBLIC_SAAS_URL=https://speed.elevaseo.com
```

Tous les liens "Try free" / "Sign in" / "See pricing" doivent utiliser cette var. Idem pour le bouton "Voir la démo" ou les iframes embed si vous en avez.

### 5.4 SEO / canonical / sitemap

- `elevaseo.com` = site marketing → canonical des pages produit / pricing / blog **doit pointer sur `elevaseo.com`**, pas sur le SaaS.
- Le SaaS a (ou aura) une page `/pricing` publique elle aussi (cf. `docs/planning/to-think.md` §"Page /pricing publique"). Pour éviter le duplicate content, **convenir** :
  - Soit le marketing porte la version SEO-optimisée et le SaaS pointe son `/pricing` en `canonical` vers `elevaseo.com/pricing`.
  - Soit l'inverse.
  - À trancher avec Bastien — la mémoire `project-error-monitoring-todo` n'a pas de position là-dessus pour l'instant.
- Sitemaps : pas de cross-domain sitemap. Chacun a le sien.
- `robots.txt` : si jamais tu inclus des liens vers `/dashboard`, `/admin`, `/settings` du SaaS depuis le marketing, ces routes côté SaaS doivent être noindex (déjà le cas pour `/admin`, à vérifier pour `/dashboard`).

### 5.5 Intégrations à reconfigurer si `.app → .com`

Liste exhaustive côté SaaS (pour info, **pas ton boulot** mais coordination utile) :

- **Stripe webhook endpoint** : passe de `speed.elevaseo.app/api/webhooks/stripe` à `.com`.
- **Resend** : `BETTER_AUTH_URL`, `RESEND_FROM_EMAIL` (déjà sur `elevaseo.com` → OK), URLs cliquables dans les emails templates.
- **OAuth providers** (Google/GitHub si activés) : redirect URIs.
- **CF Access** : services tokens si Cloudflare Access est utilisé devant `speed-api.*`.
- **Vercel** (le jour où la migration est reprise) : domaine custom, env vars.

### 5.6 Pricing & lead capture règles métier

D'après la mémoire `eleva-speed-lead-capture-rules` :

- **Emails pro uniquement** sur les forms du SaaS (consumer bloqué, pro activement détecté).
- **1er audit gratuit**, sign-in requis sur l'audit suivant du **même site**.

→ Si tu mets en place des forms de capture lead sur `elevaseo.com` (demo, contact, "Try free"), applique les **mêmes règles** pour cohérence cross-domain. Sinon les utilisateurs passent le contrôle marketing puis se cassent au mur sur le SaaS.

### 5.7 Observability / debug local

- Le SaaS impose **`d3k` (`pnpm dev:agent`)** pour tout dev local (cf. CLAUDE.md eleva-speed, mémoire `feedback-use-pnpm-dev-agent`). Si tu travailles côté `eleva-rebrand`, mêmes principes valent : utilise `d3k` pour debug navigateur (console + network), pas `pnpm dev` brut.
- Error monitoring prod : **GlitchTip** est candidat retenu côté SaaS. Si tu prévois la même chose côté marketing, alignement souhaitable (même backend, même DSN structure) — à confirmer avec Bastien post-cutover.

---

## 6. Décisions ouvertes (à coordonner)

| #   | Décision                                                    | Owner             | Pourquoi ça te concerne                                |
| --- | ----------------------------------------------------------- | ----------------- | ------------------------------------------------------ |
| D1  | Migrer le SaaS sur `speed.elevaseo.com` (oui / non / quand) | Bastien           | DNS sous ta zone + CTAs marketing impactés             |
| D2  | Reprendre la tentative Vercel ou rester self-hosted         | Bastien           | Stratégie hosting groupe (marketing déjà sur Vercel ?) |
| D3  | Canonical `/pricing` : marketing ou SaaS                    | À trancher commun | Évite duplicate content                                |
| D4  | `cookieDomain` partagé `.elevaseo.com` ou pas               | À trancher commun | Auth cross-domain potentielle                          |
| D5  | GlitchTip self-hosted unifié pour les 2 produits ou pas     | Bastien (parqué)  | Si oui, ton site marketing publie sur le même DSN      |

---

## 7. Pointers (où chercher quoi)

| Sujet                                   | Path / référence                                                                                |
| --------------------------------------- | ----------------------------------------------------------------------------------------------- |
| Trace exacte du rollback                | `docs/migrations/rollback-vercel-migration-2026-05-26.md`                                       |
| Design migration Vercel (préservé)      | `git show backup/vercel-migration:docs/superpowers/specs/2026-05-26-vercel-migration-design.md` |
| Plan d'impl migration Vercel (préservé) | `git show backup/vercel-migration:docs/superpowers/plans/2026-05-26-vercel-migration-plan.md`   |
| Runbook deploy one-shot (préservé)      | `git show backup/vercel-migration:docs/deploy-runbook.md`                                       |
| Décision observability (préservé)       | `git show backup/vercel-migration:docs/observability-decision.md`                               |
| Tag git                                 | `vercel-migration-2026-05-26`                                                                   |
| Branche backup                          | `backup/vercel-migration` (commit `50c2df875`)                                                  |
| Tarball serveur                         | `163.172.71.169:~/eleva-speed-migration-backup-20260526-124532.tgz` (certs PKI + .env.prod)     |
| Stack SaaS actuelle                     | `docker-compose.prod.yml` + `docs/infra/prod-deploy.md`                                         |
| Pricing / tiers                         | `docs/pricing/pricing-proposal.md` + `docs/pricing/pricing-comparison.md`                       |
| Phases produit en cours                 | `docs/superpowers/plans/2026-05-25-phase-*.md`                                                  |
| Backlog / questions ouvertes            | `docs/planning/to-do.md`, `docs/planning/to-think.md`                                           |
| Dette pre-prod                          | `docs/planning/pre-prod-checklist.md` (doit être vidé avant tout merge `dev` → `main`)          |

---

## 8. Quand me re-solliciter

Re-pingue l'agent eleva-speed si :

- Bastien tranche D1 (migration `.com`) → coordonner DNS + CTAs + cookies.
- Tu mets en place auth ou cookies cross-domain sur `elevaseo.com` → vérifier compat Better Auth.
- Tu construis une page `/pricing` sur `elevaseo.com` → trancher D3 (canonical).
- Tu veux mutualiser GlitchTip → trancher D5.
- Tu vois la migration Vercel reprise → ce doc devient obsolète, demander update.
