Checklist variables d'environnement : production Vercel
Compagnon de vercel-dashboard-checklist.md. La liste EXHAUSTIVE (184 vars) vit dans .env.example et le schéma typé dans src/env/server.ts (fail-soft : une var absente = "", l'app démarre mais la feature se dégrade EN…
Compagnon de
vercel-dashboard-checklist.md. La liste EXHAUSTIVE (184 vars) vit dans.env.exampleet le schéma typé danssrc/env/server.ts(fail-soft : une var absente ="", l'app démarre mais la feature se dégrade EN SILENCE). Ce fichier ne liste que les vars dont l'absence a un impact opérationnel réel, avec ce qui casse et comment le voir.Vérification rapide :
vercel env ls productionoupnpm env:pull:productionpuis diff avec.env.example. Depuis l'audit du 11 juin 2026, toute var manquante côté pipeline se repère dans les logs viafailureKind: "config_missing".
Tier 0 — L'app ne fonctionne pas sans
| Var | Ce qui casse si absente | Signal |
|---|---|---|
DATABASE_URL (+ alias Neon, auto-injectées) | Tout. | 500 globaux |
NEXTAUTH_SECRET | Sessions invalides, personne ne peut se connecter | Boucle de login |
RESEND_API_KEY + RESEND_DOMAIN | Auth entière (l'OTP à six chiffres est le SEUL provider — le magic link a été retiré, security-identity/0267) + tous les emails | Provider "Disabled" dans NextAuth |
NEXT_PUBLIC_APP_URL | URLs absolues fausses (liens d'invitation, callbacks, self-fetch) | Liens cassés dans les emails |
KV_REST_API_URL + KV_REST_API_TOKEN (auto Upstash) | Cache /api/me, rate limiting (fallback mémoire par instance) | rate-limit en mode dégradé |
Tier 1 — L'argent
| Var | Ce qui casse | Signal |
|---|---|---|
STRIPE_SECRET_KEY | Checkout, billing portal, Connect, refunds | getStripeClient throw → 500 sur achat |
STRIPE_WEBHOOK_SECRET | Aucun webhook traité → crédits achetés jamais livrés, plans jamais provisionnés | Signatures rejetées dans les logs |
NEXT_PUBLIC_STRIPE_PRO_/MAX_* (price IDs) | Plan introuvable au checkout | Erreur au clic "Upgrade" |
AI_GATEWAY_API_KEY | Le chat = le produit payant ne répond plus | chat.stream.error avec failureKind: auth_failed/config_missing |
Tier 2 — Le pipeline de données (la cause des "datas manquantes")
| Var | Ce qui casse | Signal |
|---|---|---|
CRON_SECRET | Les 71 crons déclarés dans vercel.json répondent tous 401 — plus aucun refresh, reset crédits, digest… | cron.*.missing_secret / unauthorized |
QSTASH_TOKEN + QSTASH_CURRENT_SIGNING_KEY + QSTASH_NEXT_SIGNING_KEY | Tous les jobs async (indexation stores, briefings, vitals, AEO, backfills). Les jobs lourds refusent désormais le fallback inline sur Vercel | jobs.enqueue.inline_fallback ou throw "QStash is required" |
FIRECRAWL_API_KEY | Scraping JS-rendered (le maillon le plus riche des deep-scans) → records partiels | Sonde /admin/ai/intelligence/health + failureKind: config_missing |
APIFY_TOKEN + APIFY_SHOPIFY_DATASET_ID + APIFY_*_ACTOR_ID | Ad Library (Meta/TikTok/Google/Pinterest) + dataset discovery → colonnes Ads vides | Sonde Apify du health panel |
BROWSERBASE_API_KEY + BROWSERBASE_PROJECT_ID | Scans tracking navigateur (pixels, consent) | Scans tracking en échec |
GOOGLE_PAGESPEED_API_KEY | Vitals PSI (rapports performance stores) | jobs.worker.failed sur fetch-psi |
BLOB_READ_WRITE_TOKEN (auto Vercel Blob) | Uploads images + rapports PSI bruts | upload.failed |
AD_LIBRARY_PROVIDER | Sélection du provider ads (défaut sain si absente) | — |
Tier 3 — Connecteurs & confort (dégradation propre, à brancher quand utilisés)
- OAuth connecteurs :
GOOGLE_CLIENT_ID/SECRET/REDIRECT_URI,META_APP_ID/SECRET/REDIRECT_URI,NOTION_*,FIGMA_*, le connecteur concerné affiche "non configuré". - Anti-bot :
NEXT_PUBLIC_TURNSTILE_SITE_KEY(+ secret), sans elles, l'OTP repose sur rate-limit + lockout seuls. - Voice :
HUME_API_KEY/HUME_SECRET_KEY/NEXT_PUBLIC_HUME_CONFIG_ID. - SEO data :
AHREFS_API_KEY,DATAFORSEO_API_KEY,DATOS_API_KEY, colonnes SEO/traffic vides sinon. - Proxy scraping :
BRIGHTDATA_*, la chaîne fetch-providers saute ce maillon. - Analytics :
DATAFAST_*(la lecture admin exigeDATAFAST_API_TOKENetDATAFAST_WEBSITE_ID: le token seul ne désigne pas un site),CLICKHOUSE_URL. - Trustpilot :
TRUSTPILOT_API_KEY+TRUSTPILOT_BUSINESS_UNIT_ID(Trustpilot Business, Integrations > API). Facultatives : la ligne « Rated … out of 5 » des pages agents (readTrustpilotSummary,src/lib/seo/trustpilot.ts) lit, dans cet ordre, l'API quand les deux clés sont posées et qu'elle répond, puis la note et le nombre d'avis qu'un admin a lus sur le profil public et saisis dans/admin/content/agent-status(sectiontrustpilotdePlatformConfig, avec l'adresse du profil), puis rien. Une réponse valide de l'API fait foi, même sous le seuil : elle ne retombe pas sur une lecture manuelle plus ancienne. Dans les deux cas la ligne n'apparaît qu'à partir de cinq avis (TRUSTPILOT_MIN_REVIEWS) ; jamais de valeur par défaut ni d'estimation. - Growth → Postiz :
POSTIZ_API_KEY(Public API). Sans elle, aucun bouton « Draft in Postiz » sur/admin/content/growth: le handoff manuel reste.POSTIZ_API_URLseulement pour un Postiz auto-hébergé. - Growth → Remotion :
GITHUB_TOKENavecactions: writesurBoostEcom/boostecom.apppour « Lancer un rendu » (dispatch decreative-render.yml). Côté GitHub,STUDIO_SOURCE_TOKENest obligatoire et limité à la lecture deBoostEcom/Ecosystem: le workflow checkout le runtime Studio sur un SHA immuable puis ne persiste pas ce credential.BLOB_READ_WRITE_TOKENreste optionnel (sans lui, artefact de run seulement).CREATIVE_RENDER_CALLBACK_SECRETetCREATIVE_RENDER_CALLBACK_URLrèglent la ligneGenerationRequestquand elle existe. - Contenu → voix off :
ELEVENLABS_API_KEY+ELEVENLABS_VOICE_IDsur Vercel aussi (services/creative/voiceover.ts) : c'est ce qui permet à une recrue de synthétiser une lecture depuis/opsen une action, le MP3 atterrissant sur Blob (BLOB_READ_WRITE_TOKENau runtime). Sans elles, aucun bouton, et le cockpit nomme la valeur manquante. - Siège créatif → le tenant Fondateur :
INTERNAL_ORG_SLUGS. Elle est structurante depuis l'ADR 0026, pas seulement tarifaire : l'organisation qu'elle nomme EST la plateforme, et sa boutique est la marque sur laquelle/ops/creative/studios'ouvre. Absente, le siège ne se rabat sur aucune organisation (volontairement : l'ancien repli ouvrait la boutique personnelle du fondateur), il nomme ce qui manque et on ne produit rien depuis/ops. Elle décide aussi du tarif : sans elle, nos propres rendus sont comptés au markup client. - Ops :
ADMIN_EMAIL,COST_ALERT_EMAIL(alertes coûts),GOOGLE_SITE_VERIFICATION/BING_SITE_VERIFICATION. - Dev console / flotte (
docs/architecture/dev-console.md§8, itembacklog/inbox/2723) :GITHUB_FLEET_TOKEN— token d'écriture (repository_dispatch). Absent, le moteur Claude Code Action refuse (engine-not-configured) ; le deep link local et Cursor continuent. Ne jamais y mettre la valeur deGITHUB_TOKEN, qui est un credential de lecture pour l'ingestion.GITHUB_FLEET_REPO—owner/namevisé ; absente, défautBoostEcom/boostecom.app.GITHUB_WEBHOOK_SECRET— signature HMAC-SHA256 de/api/webhooks/github. Absente, toute livraison répond 401 (fail closed délibéré) : lesAgentRunrestent figés et aucune ligne de roadmap n'avance. Signal :fleet.github_webhook.rejecteddans les logs, et la liste de livraisons côté GitHub.CURSOR_API_KEY— moteur de secours, utilisé quand GitHub Actions ne démarre plus de jobs (cf.AGENTS.md). Absente, ce moteur est refusé.
- Signaux de pilier (
docs/architecture/pillar-signals.md, itembacklog/commerce-systems/3081) : cinq bascules, qu'aucun agent n'allume ; décisions D1-D4 tranchées le 2026-09-27 (docs/ops/operator-decisions.md). Absentes, le comportement est celui décidé ci-dessous.VITALS_SHOPIFY_RUM_ENABLED— pull quotidien ShopifyQLweb_performance. Allumée seulement après la vérification S8a (requête live en 2026-07 + fixture).GOOGLE_SEARCH_CONSOLE_ENABLED— décision D1 : oui, mais reste éteinte tant que la vérification Google de l'app OAuth et la mise à jour de la politique de confidentialité ne sont pas faites (scope sensiblewebmasters.readonly, requêtes gardées 16 mois).TRACKING_SCHEDULED_RESCAN_ENABLED— décision D2 : allumée par défaut (absente = allumée). Crontracking-rescanmensuel (le 2 du mois), plans payants, boutiques déjà scannées ;0oufalsel'éteint (minutes Browserbase).GEO_CITATION_RUNS_PER_PROMPT— décision D3 : absente, 3 sur un plan payant et 1 sinon ; un entier 1..5 surcharge les deux (dépense modèle).PIXEL_REFERRER_CAPTURE_ENABLED— décision D4 : oui, mais reste éteinte tant que l'extension pixel n'envoie pasreferrerHost(hors de ce dépôt ; hôte IA seul, soumis au consentement).
Règles d'hygiène
- Toute nouvelle var : déclarer dans
src/env/server.ts(schéma typé) +.env.example+ ce fichier si Tier 0-2. - Rotation de clé : QStash a deux clés (
CURRENT+NEXT) précisément pour la rotation sans coupure, utiliser les deux champs. - Build vs runtime : Neon n'expose pas
DATABASE_URLau build par défaut, c'est PRÉVU, le schema guard gère (voir CLAUDE.md §Schema sync). - Après tout ajout : redéployer (les vars ne sont lues qu'au déploiement) puis vérifier
/admin/ai/intelligence/health(sondes Apify/QStash/Firecrawl/CRT/CommonCrawl) et l'absence defailureKind: config_missingdans les logs.