S5 · Build
playbook/S5-build.md
S5 — Build (J7–11)
Objectif : passer du spec à un produit live sur domaine custom, Stripe live (vraie carte qui débite), E2E Playwright qui passe en CI. 5 jours, pas plus.
Durée
5 journées (J7–11). C'est la station la plus longue et la seule qui justifie 5 jours.
Inputs
04-spec.md(3 features + AC)04-design-tokens.jsonwireframes/(5 écrans)templates/saas-base/(à scaffolder en v0 — voir bootstrap S5)~/.atelier.env(tokens : VERCEL_TOKEN, SUPABASE_ACCESS_TOKEN, STRIPE_SECRET_KEY, GITHUB_TOKEN, RESEND_API_KEY, POSTHOG_API_KEY)
Output (livrables verrouillés)
- Repo GitHub privé (peut devenir public en S6)
- URL
https://{domaine-custom}qui répond 200 sur la home - Stripe LIVE keys configurées (pas test) ; 1 vraie transaction passée par Martin
- Playwright E2E tests qui passent en CI (golden path : signup → onboarding → 1 feature core → upgrade)
- README projet :
pnpm devmarche en 1 commande depuis un clone fresh - 📱 Gate Telegram : URL live + screenshot Stripe txn + lien Playwright run
Critères de verrouillage
- URL live publique sur le domaine custom (DNS pointé via Vercel, SSL OK).
- Une vraie carte a débité via Stripe LIVE. Martin teste lui-même avec sa carte perso → refund. Screenshot du Payment Intent succeeded dans Stripe Dashboard.
- Playwright E2E vert sur les 3 features v1 + le golden path. Workflow GitHub Actions configuré.
pnpm devmarche en fresh clone : un dev externe (ou agent) qui clone +pnpm install+ remplit.env.local+pnpm devdoit voir le produit fonctionner en localhost en < 10 min.- 0 secret committé au repo.
.env*dans.gitignore, secrets dans GitHub Actions secrets + Vercel env vars. - Posthog branché et au moins 3 events trackés (signup, activation event, upgrade click).
Stack figée (pas négociable per sprint)
Next.js 14 (app router)
+ Tailwind CSS
+ shadcn/ui (composants)
+ Lucide icons
Supabase (auth + Postgres + RLS)
Stripe (Checkout + Customer Portal + webhooks)
Resend (email transactionnel)
Vercel (hosting + preview deployments)
Playwright (E2E)
Posthog (analytics + feature flags)
GitHub Actions (CI + Playwright run)
Le template templates/saas-base/ doit pré-câbler tout ça. Pas d'install à chaque sprint.
Process
J7 — Setup repo + scaffold (1 jour)
gh repo create atelier-{sprint_slug}(privé)- Copier
templates/saas-base/→ repo - Renommer toutes les occurrences
saas-base→{nom S3} - Connect Supabase :
supabase init+supabase link --project-ref {ref}+supabase db push - Connect Stripe : créer les products dans Stripe Dashboard + écrire
lib/stripe.tsavec les price IDs - Connect Vercel :
vercel link+ push env vars + premier deploy preview - Custom domain :
vercel domains add {domain.com}+ pointer DNS
J8 — Feature 1 (1 jour)
J9 — Feature 2. J10 — Feature 3.
Chaque jour : 1 feature complète selon les AC du spec. Pas de "je commence Feature 2 avant d'avoir fini Feature 1". Définit "fini" = tous les AC cochés + tests Playwright passants pour cette feature.
J11 — Stripe live + Playwright CI + Posthog (1 jour)
Matin :
- Activer Stripe LIVE (passage de test → live keys)
- Tester avec ta vraie carte → refund
- Configurer webhooks Stripe →
app/api/webhooks/stripe/route.ts(signature verify obligatoire)
Après-midi :
- Compléter la suite Playwright (golden path E2E)
- GitHub Actions workflow
e2e.yml→ run on PR - Posthog SDK : signup event, activation event, upgrade_clicked event
Soir :
- Smoke test full sur prod URL (par Martin lui-même OU agent via gstack browser skill)
- Gate Telegram envoie URL + screenshot Stripe txn + lien Playwright run
Bootstrap de la template saas-base/
Le template n'existe pas encore. À scaffolder UNE FOIS, puis réutilisé pour tous les sprints. Structure cible :
templates/saas-base/
├── README.md # comment cloner pour un nouveau sprint
├── package.json
├── pnpm-lock.yaml
├── tsconfig.json
├── tailwind.config.ts
├── next.config.js
├── .env.example # toutes les vars listées
├── .gitignore
├── components/
│ └── ui/ # shadcn components
├── lib/
│ ├── supabase.ts
│ ├── stripe.ts
│ ├── resend.ts
│ ├── posthog.ts
│ └── utils.ts
├── app/
│ ├── layout.tsx
│ ├── page.tsx # landing
│ ├── (auth)/login/page.tsx
│ ├── (auth)/signup/page.tsx
│ ├── (auth)/callback/route.ts
│ ├── (dashboard)/app/page.tsx
│ ├── (dashboard)/settings/page.tsx
│ ├── pricing/page.tsx
│ └── api/
│ ├── webhooks/stripe/route.ts
│ └── webhooks/resend/route.ts
├── supabase/
│ ├── config.toml
│ └── migrations/
│ └── 00_init.sql # users, subscriptions, audit_log
├── tests/
│ └── e2e/
│ ├── auth.spec.ts
│ ├── stripe.spec.ts
│ └── golden-path.spec.ts
├── .github/workflows/
│ ├── ci.yml
│ └── e2e.yml
└── scripts/
├── bootstrap-sprint.sh # clone + rename + env setup
└── deploy-prod.sh # vercel --prod + db push
Scaffold-le UNE FOIS, ensuite réutilisable. C'est ce qui rend Atelier vendable plus tard : un solopreneur qui achète Atelier hérite de cette template + du playbook.
Prompt canonique (Builder agent v1)
Tu es S5 Builder d'Atelier. Tu reçois startup.json après S4 (spec + tokens + wireframes).
Tu travailles dans un dossier {runs}/build/ qui contient un clone fresh de templates/saas-base/ déjà renommé pour ce sprint.
Tu produis dans l'ordre :
J7 — Setup
- Vérifier que pnpm install + pnpm dev marche
- Connecter Supabase + push migrations (tu lis supabase/migrations/00_init.sql et tu adaptes pour les features du spec)
- Créer les Stripe products + récupérer price IDs
- vercel deploy preview + custom domain
J8-J10 — Une feature par jour
- Lis features_v1[i] du startup.json
- Code la feature en suivant les AC
- Écris Playwright spec pour cette feature
- Commit + push + vérifier que le preview Vercel marche
- Mets à jour startup.json.s5_build avec les progress
J11 — Stripe live + CI + Posthog
- Swap test keys → live keys (DEMANDE confirmation humaine via gate Telegram)
- Smoke test avec gstack browser : signup → activate → upgrade → checkout
- Run Playwright en CI
- Branche Posthog
- Écris BUILD_READY.txt avec URL prod + screenshot Stripe txn
Tu signales tout problème > 30 min de stuck. Tu ne t'auto-overscope pas — si une AC est tordue, tu reviens au spec S4 et tu demandes clarification.
Stack à utiliser STRICTEMENT (pas de substitution) :
{stack list}
State input :
<input>
{startup_json_after_s4}
</input>
Anti-patterns
- Démarrer avec un template "from scratch" au lieu de
saas-base/→ tu vas perdre 2 jours à recâbler Stripe/Supabase. Le template est obligatoire. - "Je vais ajouter une 4ème feature parce que c'est facile" → STOP. Le scope est figé S4. Note dans
OUT_OF_SCOPE_DISCOVERED.md, on verra en sprint suivant. - Skip Playwright "pas le temps" → c'est le seul garde-fou contre la régression. Sans, tu shippes un produit qui sera cassé à J20.
- Stripe test pendant S6 → non. Stripe live doit être prouvé en S5. Si Stripe test marche mais live échoue, c'est en S5 qu'on découvre.
- Secrets dans le repo → audit obligatoire avant push.
git secretsou check manuel des.env*files. - Pas de webhook signature verify sur les routes Stripe → faille de sécurité. Le template doit l'inclure par défaut.
Lien S6
L'URL prod live + le Stripe LIVE + le repo sont les inputs canoniques de S6. La landing (qui est app/page.tsx du repo) est déjà coded en S5 — S6 va l'affiner avec du copy Hormozi-style et ajouter le tracking de conversion.
Update startup.json (après S5)
{
"current_station": "S6",
"s5_build": {
"completed_at": "<iso8601>",
"telegram_gate_approved_at": "<iso8601>",
"repo_url": "https://github.com/{owner}/atelier-{slug}",
"live_url": "https://{domain}.com",
"custom_domain_pointed": true,
"stripe_live": true,
"supabase_project_ref": "...",
"e2e_passing": true,
"playwright_run_url": "https://github.com/.../actions/runs/...",
"posthog_project_id": "..."
}
}