Runbook — Checklist de lancement
title: Runbook — Checklist de lancement description: Actions propriétaire avant le lancement : migration, DataFast, Stripe, Resend, crons, variables, vérifications.
Statut (2026-10-02) : le code des blocages P0 du blueprint est livré (mesure DataFast derrière le consentement, premier contact, durcissement Stripe, e-mails de facturation) ; il reste ces actions côté propriétaire, qu'aucun agent ne peut faire (tableaux de bord, DNS, secrets). Tant qu'elles ne sont pas faites, rien ne casse : DataFast, Stripe Tax, le cron et les e-mails de facturation sont inertes sans leurs variables. Références : Blueprint (tableau P0), Facturation Stripe, skills
launch-attribution,billing-stripe,transactional-email,platform-ops.Règles : aucune valeur secrète dans un fichier, une PR ou une conversation ; un compte, un site, un domaine propres à Orbit (jamais ceux d'un autre produit) ; mode test de Stripe d'abord ; un changement de variable Vercel n'atteint que les nouveaux déploiements (redéployer).
0. Ordre conseillé
- Migration de la base (section 1) : avant de fusionner la PR qui l'utilise si la base est celle de production.
- Stripe en mode test : endpoint, Tax, catalogue (section 3).
- DataFast (section 2) puis un paiement de test attribué.
- Resend (section 4),
CRON_SECRET(section 5), variables (section 6). - Vérifications de bout en bout (section 7), puis le passage en live.
1. Migration de la base
Une migration additive (deux colonnes Workspace.acquisition JSONB et Workspace.datafastVisitorId TEXT,
nulles, sans valeur par défaut) : 20261002160000_workspace_acquisition.
- GitHub → Actions → Deploy production database → Run workflow (branche
mainseulement), puis vérifier quedb:driftfinit au vert. Phase de la base :packages/db/PHASEvautpre-users(la passer àproductionle jour de la première inscription réelle : skilldatabase).
2. DataFast (mesure et attribution du revenu)
La variante avec cookie du script est servie en première partie (/js/script.js), seulement en
production, avec l'identifiant du site, et après que le visiteur a accepté la mesure d'audience
(bannière de consentement). Sans cookie, le revenu ne peut pas être rattaché à un canal.
- Créer le site DataFast d'Orbit pour
orbit.easyconnector.app(jamais celui d'un autre produit). - Vercel → variables, Production uniquement :
DATAFAST_WEBSITE_ID= l'identifiantdfid_…du site (public : il figure dans chaque page). Pas en Preview : un déploiement Preview est aussi une build de production (NODE_ENV=production) et chargerait le script. - Créer une clé API de site (
df_…, la plus étroite : elle suffit à écrire un objectif) et la poser en Production sousDATAFAST_API_TOKEN. Les autres types (dft_jeton de compte,dfbot_ingestion des robots) ne servent pas à l'app ; ne jamais les écrire dans un fichier. - Créer les objectifs (un nom par étape, exactement ces noms) :
signup,checkout_started,subscription_started. Ils sont envoyés par le serveur, avec le visiteur capturé à l'inscription. (workspace_created,first_brain_write,first_generationde la liste du skill ne sont pas encore émis : ne pas les créer tant qu'un émetteur n'existe pas.) - Créer les entonnoirs dans DataFast à partir de ces objectifs (page d'accueil →
signup→checkout_started→subscription_started). Les chiffres exacts de l'entonnoir viendront de la table de jalons d'Orbit (P1, ligne h du blueprint), pas de DataFast : DataFast ne voit pas un visiteur qui refuse les cookies. - Connecter Stripe dans le tableau de bord DataFast (attribution du revenu) avec une clé
restreinte en lecture seule du compte Stripe d'Orbit (jamais la clé secrète de l'app). C'est ce
qui rattache chaque paiement au canal : Orbit copie
datafast_visitor_iddans les métadonnées du Checkout et de l'abonnement, DataFast les lit. - En mode test de Stripe, accepter la bannière, passer par Checkout avec la carte
4242 4242 4242 4242et vérifier que le paiement apparaît attribué dans DataFast avant de passer en live. - Poser une annotation DataFast à l'heure du lancement (un pic doit s'expliquer).
- Optionnel : jeton
dfbot_pour mesurer les robots d'IA (skillseo-aeo-geo) ; plan de crawl à décider.
3. Stripe
- Compte Stripe propre à Orbit (distinct de tout autre produit), mode test d'abord.
- Valider les montants des crédits Studio de
apps/web/scripts/stripe-catalog.mjs(et de la page Facturation) ; ceux d'Orbit sont ceux du prototype. Lancer le script avec la clé test (--dry-rund'abord), puis archiver à la main les anciens produitsorbit_brain_proetorbit_brain_max. - Vercel → projet Orbit → Settings → Environment Variables :
ORBIT_STRIPE_SECRET_KEY(sk_test_en Preview) et, une fois l'endpoint créé,ORBIT_STRIPE_WEBHOOK_SECRET. - Endpoint webhook : Développeurs → Webhooks → Ajouter un endpoint
https://orbit.easyconnector.app/api/webhooks/stripe, version d'API celle du SDK (2026-09-30), description = le slug de l'app (orbit-easyconnector-app), et ces dix événements (ni plus, ni moins ; la liste est celle deWEBHOOK_EVENTS, imprimée parstripe-catalog.mjs) :checkout.session.completed,customer.subscription.created,customer.subscription.updated,customer.subscription.deleted,invoice.paid,invoice.payment_failed,invoice.payment_action_required,charge.refunded,charge.dispute.created,charge.dispute.closed(en gras : les nouveaux). Copier lewhsec_…dansORBIT_STRIPE_WEBHOOK_SECRET(un secret par endpoint : test et live sont distincts). Si un endpoint existe déjà, ajouter les cinq nouveaux événements (sinon remboursements, litiges, reçus et SCA ne sont jamais vus). - Stripe Tax : Paramètres → Tax → activer ; renseigner l'adresse d'origine, les inscriptions
fiscales (là où Orbit doit collecter), le code de taxe par défaut des produits (logiciel en
service, usage professionnel) ; puis poser
ORBIT_STRIPE_TAX=1(Production, puis Preview si le compte de test a une configuration fiscale). Tant que ce n'est pas fait, laisser vide : Stripe refuseautomatic_taxsur un compte sans configuration fiscale et Checkout échouerait. - Relancer
node apps/web/scripts/stripe-catalog.mjs(clé test,--dry-rund'abord) : il posetax_behavior: exclusivesur les prix (les montants du catalogue sont hors taxe ; Stripe ajoute la taxe à Checkout). Puis, après votre feu vert, la même chose en live avec--live. - Portail client (Paramètres → Portail client, test puis live) : activer le portail, autoriser la mise à jour du moyen de paiement, la résiliation et le changement d'intervalle (mensuel ↔ annuel) du produit Orbit, ainsi que le changement d'offre entre les produits Orbit Studio (Starter, Pro).
- Migrations de facturation : appliquer
20261002130000_billinget20261002140000_single_orbit_plan(GitHub → Actions → Deploy production database). Le workspace du fondateur retombe à 0 CU : relancerpnpm db:seedavecFOUNDER_BRAIN_CAPACITY_CU, ou le passer en modecustomdepuis l'app admin. - Essai de bout en bout en Preview (carte
4242 4242 4242 4242) : activation depuis/brain, extension d'un pas,/billing, quota. - Passer en live : relancer le script de catalogue avec la clé live et
--live, recréer l'endpoint webhook en live, posersk_live_…et lewhsec_…live en Production, redéployer. - Doublons de reçus : Orbit envoie son propre e-mail « paiement reçu » ; si vous gardez aussi les reçus de Stripe (Paramètres → E-mails des clients → Paiements réussis), le client recevra les deux. Décision à prendre : laisser les reçus de Stripe actifs et ignorer ceux d'Orbit, ou désactiver ceux de Stripe.
- Tests à faire en mode test (cartes de
billing-stripe, section 6) : un échec4000 0000 0000 0341, une carte SCA, un remboursement total (le plan retombe à 0 CU), un litige4000 0000 0000 0259. Décision à prendre (écrite dans la page Facturation) : un remboursement total de bonne volonté retire aussi la capacité. - Restreindre toute clé donnée à un MCP Stripe à la lecture seule (
rk_…), dans le shell de l'opérateur, jamais dans Vercel.
4. Resend : le domaine d'envoi
Sans SPF, DKIM et DMARC sur le domaine d'envoi, les codes de connexion tombent en spam sans erreur.
L'expéditeur est config.from de studio.mailer dans products/connectors.json
(aujourd'hui Orbit <orbit@easyconnector.app>).
- Resend (le projet branché par l'intégration Vercel Marketplace d'Orbit) → Domains → ajouter
orbit.easyconnector.app(le sous-domaine d'Orbit : sa réputation d'envoi ne dépend d'aucun autre produit de la famille). - Chez le fournisseur DNS, créer les enregistrements exactement tels que Resend les affiche : SPF
(TXT incluant Resend), DKIM (les trois enregistrements fournis), le MX de retour, puis DMARC
sur
_dmarc.orbit.easyconnector.app:v=DMARC1; p=none; rua=mailto:<une boîte surveillée>pour commencer,p=quarantineune fois les rapports propres. Cliquer Verify dans Resend jusqu'au statut « Verified ». - Seulement ensuite, faire changer
config.frompourOrbit <orbit@orbit.easyconnector.app>(une ligne deproducts/connectors.json, une PR) : changer l'expéditeur avant la vérification ferait refuser tous les e-mails (403 du fournisseur, y compris les codes de connexion). - Les envois marketing (lettre, annonces) iront un jour sur un sous-domaine séparé
(
news.orbit.easyconnector.app) avec ses propres enregistrements, jamais sur celui-ci. Il n'y en a pas encore : les e-mails de facturation sont transactionnels (pas deList-Unsubscribe). - Vérifier : se connecter, recevoir le code hors du spam ; dans Resend, le message est « Delivered », DKIM et SPF « pass ». Surveiller ensuite : plaintes < 0,3 % (viser moins), rebonds très en dessous de 4 %.
- Optionnel : webhook Resend (Svix) pour supprimer sur rebond et plainte : pas encore codé (P1, ligne k).
5. CRON_SECRET et les crons
Trois crons (apps/web/vercel.json) : generations-sweep, retention et le nouveau reconcile-stripe
(tous les jours à 05:20 UTC : il relit chez Stripe les abonnements et répare un webhook perdu).
- Générer un secret long et aléatoire (
openssl rand -hex 32) et le poser sousCRON_SECRET(Production et Preview). Vercel l'envoie enAuthorization: Bearer; sans lui, les trois crons répondent 401 (le comportement voulu : rien ne passe sans secret). - Après le déploiement : Vercel → projet → Settings → Cron Jobs → Run sur
reconcile-stripe; la réponse JSON doit direhalted: nulletrepaired: 0sur un compte propre. Unhaltednon nul se lit dans les journaux (cron.reconcile_stripe.done) ;too_many_missingveut dire une mauvaise clé Stripe (le cron a refusé d'annuler en masse). - Rotation : voir le skill
platform-ops, section 3 (changer dans Vercel, redéployer).
6. Variables d'environnement Vercel (noms seulement)
| Variable | Production | Preview | Remarque |
|---|---|---|---|
DATABASE_URL | oui | oui (branche Neon) | base propre à Orbit |
NEXTAUTH_SECRET, NEXTAUTH_URL | oui | oui | sessions |
ORBIT_STRIPE_SECRET_KEY | sk_live_ / rk_live_ | sk_test_ | jamais un STRIPE_* |
ORBIT_STRIPE_WEBHOOK_SECRET | whsec_ de l'endpoint live | whsec_ de l'endpoint de test | un par endpoint |
ORBIT_STRIPE_TAX | 1 une fois Tax configuré | vide, ou 1 si le compte de test est configuré | drapeau, pas un secret |
DATAFAST_WEBSITE_ID | dfid_… (public) | absent | le script ne charge qu'en production avec lui |
DATAFAST_API_TOKEN | df_… (secret) | absent | objectifs côté serveur ; sans lui, aucun envoi |
CRON_SECRET | oui | oui | porte des crons |
RESEND_API_KEY | injectée par l'intégration Resend | injectée | rien à copier |
ORBIT_PUBLIC_URL | https://orbit.easyconnector.app | selon le besoin |
apps/web/src/env/schema.ts refuse AUTH_SECRET, STRIPE_*, INTERNAL_ORG_SLUGS,
INTERNAL_SPEND_ALERT_USD, HIGGSFIELD(S)_* et MOTION_* : une valeur copiée d'un autre produit n'est
pas lue. NEXTAUTH_SECRET et DATABASE_URL portent le même nom ailleurs : seule la relecture peut
refuser une valeur copiée, elles doivent être propres à Orbit.
7. Vérifications avant le passage en live
- Première visite : la bannière apparaît ; aucun cookie
datafast_*niorbit_acqavant le choix ; après « Tout accepter » avec?utm_source=x&utm_campaign=essai,orbit_acqest posé (une seule fois, jamais écrasé) et le script/js/script.jsse charge. - Une inscription depuis ce lien : dans l'app admin, la page du workspace montre la section
Acquisition (source
x, campagneessai) et la vue d'ensemble compte la source. - Un paiement de test : DataFast le montre attribué ; les trois objectifs apparaissent.
- Un remboursement total de test : capacité à 0, Memories conservées ; un litige gagné la restaure.
- Le cron
reconcile-striperépond (section 5), l'endpoint webhook affiche des livraisons en 200. - Un e-mail de chaque type reçu dans les deux langues (changer la langue du membre dans son profil).
-
/api/healthsurveillé par un moniteur externe (skillplatform-ops, section 5).
8. Décisions ouvertes
- Reçus : ceux de Stripe, ceux d'Orbit, ou les deux (section 3).
- Remboursement total de bonne volonté : retire la capacité (politique actuelle) ou non.
- Expéditeur : passer
config.fromàorbit.easyconnector.appaprès vérification (section 4). - Politique de crawl des robots d'IA (
seo-aeo-geo), toujours ouverte. - Table de jalons pour l'entonnoir exact (blueprint, ligne h).