YYayaw
Documentation

Configuration de l'environnement de déploiement

Collecter, borner et vérifier les variables d'environnement nécessaires au déploiement.

Cette page est le guide opérateur des variables d'environnement de déploiement. Utilisez-la lors de la création d'un projet Vercel, de la restauration d'un environnement production, de la vérification d'une prévisualisation avec le même câblage fournisseur que la production, ou de la préparation du runtime Docker auto-hébergé.

Règles

  • Ne commitez jamais de secrets dans .env, .env.production ou un fichier suivi.
  • Stockez les secrets Vercel production et preview dans les variables d'environnement du projet Vercel.
  • Stockez les secrets production auto-hébergés dans le magasin de secrets de l'orchestrateur. Pour la base Compose, utilisez un fichier non suivi .env.self-host copié depuis .env.self-host.example.
  • Stockez les secrets locaux dans .env.local ou dans un .env.local récupéré avec vercel env pull.
  • Gardez les valeurs NEXT_PUBLIC_* non secrètes: elles sont exposées au bundle navigateur.
  • Préférez les réglages admin/runtime pour les non-secrets opérationnels lorsque le dashboard les supporte. Par exemple, les réglages dépôt GitHub pour l'accès au code se gèrent depuis /dashboard/admin/billing-settings; les variables d'environnement ne sont que des replis.

Workflow Vercel

Liez le checkout local au bon projet Vercel avant de récupérer ou pousser des variables:

vercel link --yes --project <project-name-or-id> --scope <team-or-user>

Ajoutez les secrets depuis le dashboard Vercel ou la CLI. Bornez les valeurs production-only à Production, les valeurs preview à Preview et les valeurs de développement local à Development:

echo "<secret-value>" | vercel env add VARIABLE_NAME production
echo "<secret-value>" | vercel env add VARIABLE_NAME preview
echo "<secret-value>" | vercel env add VARIABLE_NAME development

Après ajout ou modification de variables, redéployez l'environnement Vercel concerné. Les déploiements existants ne reçoivent pas automatiquement les nouvelles valeurs.

Récupérez une copie locale pour le développement:

vercel env pull .env.local --environment=development --yes

Récupérez les valeurs production uniquement pour un audit explicite sur une machine de confiance:

vercel env pull .env.production.local --environment=production --yes

Vérifiez que chaque clé listée dans .env.example est présente localement:

while IFS='=' read -r key _; do
  [[ -z "$key" || "$key" == \#* ]] && continue
  grep -q "^${key}=" .env.local || echo "Missing in .env.local: $key"
done < .env.example

Workflow Docker Auto-Hébergé

La base portable utilise Docker Compose avec Postgres, MinIO/S3, le serveur app Next.js standalone, un worker Page AI et Caddy:

cp .env.self-host.example .env.self-host
docker compose --env-file .env.self-host -f docker-compose.self-host.yml --profile setup run --rm migrate
docker compose --env-file .env.self-host -f docker-compose.self-host.yml up --build

Les builds Docker utilisent NEXT_BUILD_WORKERS=1 par défaut pour une génération statique Next.js stable sur de petits hôtes. Sur une machine plus large, vous pouvez l'augmenter, par exemple:

NEXT_BUILD_WORKERS=2 docker compose --env-file .env.self-host -f docker-compose.self-host.yml up --build

Les builds Docker auto-hébergés fixent aussi NEXT_STATIC_PAGE_GENERATION_TIMEOUT=180 par défaut. Cela donne aux hôtes lents assez de temps pour pré-rendre de grosses pages docs sans déclencher le timeout Next.js de 60 secondes. Baissez-le sur des builders CI rapides ou augmentez-le uniquement si les logs montrent des pages statiques légitimes en timeout.

Les builds Docker auto-hébergés rendent les pages Fumadocs dynamiquement au lieu de prégénérer toute la documentation pendant la construction d'image. Cela évite aux petits hôtes Coolify ou Docker de dépenser l'essentiel du budget de déploiement sur les docs tout en les servant normalement au runtime.

Les fichiers Compose taguent les cibles app et worker avec YAYAW_APP_IMAGE et YAYAW_WORKER_IMAGE. Gardez le même tag worker pour les services migrate et worker afin que Docker ou Coolify puisse réutiliser la cible worker au lieu de la construire deux fois.

Le déploiement Coolify managé par Yayaw utilise des images précompilées plutôt qu'un build sur la VM production. GitHub Actions construit les images app et worker sur des runners ubuntu-24.04-arm pour la plateforme linux/arm64 du Mac mini, pousse les images vers GHCR, les fait tirer par le serveur Coolify via le runner auto-hébergé privé, met à jour YAYAW_APP_IMAGE et YAYAW_WORKER_IMAGE, puis demande à Coolify de lancer le déploiement Compose. Cela conserve la release automatique sur main, déplace le build coûteux hors de la VM Mac mini et évite le quota de stockage artifacts GitHub Actions.

Coolify doit stocker ces tags d'image comme valeurs build-time et runtime, parce que Docker Compose interpole les entrées image: pendant la préparation du déploiement.

Le profil setup lance la synchronisation de schéma non interactive drizzle-kit push --force, le seed, puis bun run dynamic-data:repair-deployed-storage. Relancez-le avant le démarrage d'une base auto-hébergée fraîche et après les changements de schéma. Ce n'est pas un runner de migrations Drizzle versionnées; l'étape dynamic-data couvre les tables natives MCP ydm_* qui ne font volontairement pas partie du schéma Drizzle statique.

Ne commitez pas .env.self-host. En production, déplacez les mêmes valeurs dans le secret manager de l'hôte cible ou l'environnement Compose. Générez BETTER_AUTH_SECRET avant le premier build Docker, par exemple avec openssl rand -hex 32; le Dockerfile échoue immédiatement lorsqu'il est vide. Le flag --env-file rend les mêmes valeurs publiques disponibles aux arguments de build Docker. BETTER_AUTH_SECRET est aussi passé à next build pour éviter que l'évaluation des routes Better Auth ne retombe sur un secret de développement pendant la construction d'image. Reconstruisez l'image quand les valeurs NEXT_PUBLIC_* changent.

Migration Rolling Coolify

docker-compose.coolify.yml reste l'unité de déploiement historique pendant la validation du chemin rolling. Il remplace ensemble migrate, l'app, le worker et Caddy; il ne peut donc pas fournir une release sans interruption. Ne repointez pas les workflows automatiques development ou production vers les nouvelles ressources avant que le workflow rolling manuel ait validé le rollback.

Migrez d'abord development:

  1. Sauvegardez Postgres et MinIO. Conservez l'UUID de la ressource Compose Coolify existante afin de réutiliser ses volumes postgres_data et minio_data.
  2. Activez Connect to Predefined Network sur la ressource d'infrastructure existante. Notez les hostnames résolus postgres-<resource-uuid> et minio-<resource-uuid>.
  3. Créez une Application Coolify Docker Image depuis l'image immuable ghcr.io/<owner>/yayaw-app:<sha>. Exposez le port conteneur 3000, sans mapping de port hôte, sans nom de conteneur, et connectez-la au réseau prédéfini. Configurez les identifiants du registre GHCR dans Coolify si le package est privé; les identifiants de pull temporaires du workflow ne configurent pas le registre de l'Application.
  4. Copiez l'environnement runtime de l'app vers cette Application. Remplacez les hôtes de DATABASE_URL et S3_ENDPOINT par ceux de l'infrastructure. Utilisez d'abord un domaine development temporaire.
  5. Gardez les healthchecks actifs. L'image Docker vérifie /api/ready, qui ne renvoie 200 que si Postgres répond et si le SHA immuable de l'image correspond au SHA demandé. /api/health reste limité à la liveness.
  6. Configurez une période de grâce d'arrêt de 20 à 30 secondes dans Coolify. Next.js traite SIGTERM et termine les requêtes en vol pendant cette fenêtre.
  7. Déplacez le worker Page AI vers une ressource séparée basée sur ghcr.io/<owner>/yayaw-worker:<sha>. Il ne doit pas rester dans la stack d'infrastructure qui survit aux releases web.
  8. Sur un clone de la base, vérifiez que drizzle.__drizzle_migrations représente fidèlement les migrations SQL déjà appliquées. Le runner rolling refuse de migrer une base non vide dont le journal est absent ou vide. Ne fabriquez pas de baseline directement en production.
  9. Ajoutez COOLIFY_ROLLING_APPLICATION_UUID et NEXT_SERVER_ACTIONS_ENCRYPTION_KEY à l'environnement GitHub development. Générez la seconde valeur une fois avec openssl rand -base64 32 et conservez la même valeur entre les builds.
  10. Lancez Coolify Rolling Deploy pour development. Il tire les deux images avec retry, exécute la préparation de schéma Better Auth, les migrations Drizzle versionnées, le seed et la réparation dynamic-data pendant que l'ancienne app sert encore, puis met à jour l'Application Docker Image. Un échec de déploiement ou du smoke public sur le SHA restaure automatiquement le tag précédent; les changements de base ne sont pas annulés.
  11. Après le succès du rollout web, promouvez la ressource worker séparée vers le tag immuable yayaw-worker:<sha> émis par le workflow. Gardez l'ancien worker actif jusqu'à ce que le processus de remplacement soit sain; toutes les évolutions du worker doivent rester compatibles avec le schéma migré pendant cette bascule.
  12. Validez volontairement une mauvaise image ou un échec de readiness et confirmez que l'ancien SHA public reste disponible. Répétez ensuite la procédure en production.

Une fois la nouvelle app et le worker sains, changez la ressource Compose existante vers docker-compose.coolify.infrastructure.yml. Définissez MINIO_MEDIA_FQDN sur l'origine publique suivie de /media et MINIO_ORGANIZATION_LOGOS_FQDN sur la même origine suivie de /organization-logos; Coolify crée les routeurs de chemin stables vers MinIO. Retirez le domaine de l'ancien Caddy et assignez le domaine racine à l'Application Docker Image pendant la même bascule. Le fichier d'infrastructure n'expose aucun port hôte et ne doit pas être redéployé lors des releases applicatives normales.

Chaque migration de ce chemin doit suivre expand/contract: ajoutez d'abord un schéma compatible, déployez du code tolérant les deux versions, puis supprimez l'ancien schéma seulement après la disparition de tous les anciens conteneurs et workers. Le rollback automatique d'image ne peut pas annuler une migration de base destructive.

Environnements CI Coolify

Les déploiements Coolify auto-hébergés sont pilotés depuis GitHub Actions:

  • les pull requests déploient vers une application Coolify development partagée après réussite de la CI
  • les pushes vers main déploient vers l'application Coolify production après réussite de la CI

Configurez deux environnements GitHub avec des UUID d'applications Coolify séparés:

Environnement GitHubSecret ou variable requisUsage
developmentCOOLIFY_URLOrigine API Coolify.
developmentCOOLIFY_API_TOKENToken autorisé à mettre à jour et déployer l'app development.
developmentCOOLIFY_APPLICATION_UUIDUUID de l'app development partagée.
developmentCOOLIFY_ROLLING_APPLICATION_UUIDUUID de l'Application Docker Image utilisée par le workflow manuel de validation rolling.
developmentDEVELOPMENT_BASIC_AUTH_USERNAMEUsername HTTP Basic de l'app development protégée.
developmentDEVELOPMENT_BASIC_AUTH_PASSWORDPassword HTTP Basic de l'app development protégée.
developmentvariable DEVELOPMENT_URLURL optionnelle de smoke test. Défaut https://dev.yayaw.app; utilisez une URL joignable par le runner interne si le DNS public n'est pas encore routé.
productionCOOLIFY_URLOrigine API Coolify.
productionCOOLIFY_API_TOKENToken autorisé à déployer l'app production.
productionCOOLIFY_APPLICATION_UUIDUUID de l'app production.
productionCOOLIFY_ROLLING_APPLICATION_UUIDUUID de l'Application Docker Image production après validation en development.
development, productionBETTER_AUTH_SECRETSecret build-time requis par le build de l'image Docker Next.js.
development, productionDATABASE_URLURL de base build-time pour l'évaluation des routes serveur.
developmentPOSTGRES_ROTATION_DATABASE_URLURL candidate temporaire utilisée seulement par la rotation des identifiants et la synchronisation runtime. Gardez DATABASE_URL sur l'identifiant fonctionnel courant jusqu'au succès du premier déploiement après rotation.
development, productionsecrets build NEXT_PUBLIC_*Valeurs publiques intégrées au bundle client Docker.
development, productionNEXT_SERVER_ACTIONS_ENCRYPTION_KEYClé AES base64 stable intégrée pendant next build afin que les instances superposées acceptent les mêmes payloads Server Actions.
development, productionvariable NEXT_BUILD_WORKERSNombre de workers de build. Défaut 1 pour stabiliser les builds Docker auto-hébergés.
development, productionvariable NEXT_STATIC_PAGE_GENERATION_TIMEOUTTimeout de génération statique. Défaut 180.
development, productionvariable COOLIFY_SERVER_SSH_HOSTOverride optionnel pour charger les images sur la VM Coolify. Défaut 127.0.0.1 depuis le runner Mac mini.
development, productionvariable COOLIFY_SERVER_SSH_PORTPort SSH optionnel. Défaut 2222.
development, productionvariable COOLIFY_SERVER_SSH_USERUtilisateur SSH optionnel. Défaut yannis.
development, productionvariable COOLIFY_SERVER_SSH_KEY_PATH ou secret COOLIFY_SERVER_SSH_KEYClé SSH optionnelle. Le runner Mac mini utilise par défaut /Users/yannis/.ssh/coolify_vm_ed25519.
development, productionvariable COOLIFY_SERVER_KNOWN_HOSTS_PATHKnown-hosts optionnel. Défaut /Users/yannis/.ssh/known_hosts_coolify.

Le préflight de release CMS synchronise aussi le contrat base, stockage privé, preview signé, personnalisation et maintenance worker vers l'app et le worker Coolify. Configurez ces secrets d'environnement GitHub :

  • S3_ACCESS_KEY_ID, S3_ENDPOINT et S3_SECRET_ACCESS_KEY
  • CMS_PREVIEW_SIGNING_SECRET, CMS_PERSONALIZATION_RATE_LIMIT_SECRET et CMS_PERSONALIZATION_FORM_CONTEXT_SECRET, chacun d'au moins 32 caractères ; gardez le secret de contexte de formulaire dédié
  • STORAGE_TRANSFER_SIGNING_SECRET optionnel lorsque les tokens de transfert stockage ne doivent pas partager le secret de signature des previews
  • DATABASE_URL dans les deux environnements
  • MINIO_ROOT_PASSWORD, POSTGRES_PASSWORD et le temporaire POSTGRES_ROTATION_DATABASE_URL et POSTGRES_ROTATION_PREVIOUS_PASSWORD en development

Configurez STORAGE_PROVIDER=s3, STORAGE_MEDIA_BUCKET=media, STORAGE_MEDIA_STAGING_BUCKET=media-staging, STORAGE_CMS_FORM_BUCKET=cms-form-submissions, CMS_PERSONALIZATION_CLIENT_IP_HEADER=x-real-ip, PAGE_AI_WORKER_MAINTENANCE_MS=60000, S3_REGION=us-east-1 et S3_FORCE_PATH_STYLE=true comme variables d'environnement GitHub. STORAGE_PUBLIC_BASE_URL est optionnel si NEXT_PUBLIC_BASE_URL désigne déjà la même origine publique. S3_SIGNED_PUBLIC_ENDPOINT est une variable optionnelle pour une origine d'upload direct explicitement configurée. Ne persistez pas de phase de rollout comme variable GitHub : les workflows de déploiement et de rollout dérivent et valident la phase sûre reader, freeze ou exact à partir de la flotte active avant de synchroniser les flags runtime correspondants.

Préparez une seule fois les identifiants development, hors déploiement :

database_password="$(openssl rand -hex 32)"
storage_password="$(openssl rand -hex 32)"
database_fingerprint="$(
  printf '%s' "$database_password" | shasum -a 256 | awk '{print $1}'
)"
rotation_database_url="$(
  printf 'postgresql://yayaw:%s@postgres:5432/yayaw' "$database_password"
)"

printf '%s' "$database_password" | gh secret set POSTGRES_PASSWORD --env development
printf '%s' "$rotation_database_url" \
  | gh secret set POSTGRES_ROTATION_DATABASE_URL --env development
printf '%s' "$storage_password" | gh secret set MINIO_ROOT_PASSWORD --env development
printf '%s' "$storage_password" | gh secret set S3_SECRET_ACCESS_KEY --env development
gh variable set CMS_DATABASE_CREDENTIALS_FINGERPRINT \
  --env development \
  --body "$database_fingerprint"

Le mot de passe de base est volontairement une valeur hexadécimale brute de 32 octets afin de ne pas nécessiter d'encodage URL. Pour un volume development existant, laissez DATABASE_URL sur l'identifiant fonctionnel courant pendant le build des images de PR. Le workflow transmet cette URL active à l'étape de rotation, qui en extrait le mot de passe brut en mémoire sans l'exposer dans les logs. Définissez POSTGRES_ROTATION_PREVIOUS_PASSWORD explicitement seulement si l'URL active emploie un encodage de mot de passe non pris en charge. Le job de déploiement n'utilise POSTGRES_ROTATION_DATABASE_URL qu'une fois les images disponibles : il teste l'identifiant candidat via l'alias privé yayaw-postgres-development; si nécessaire, il utilise un fichier env distant en permission 0600 pour modifier le rôle, reteste le nouvel identifiant puis synchronise l'URL candidate vers Coolify. Il s'arrête avant toute mutation des env Coolify si aucun identifiant ne fonctionne.

Après le premier déploiement development réussi avec l'identifiant tourné, promouvez l'URL candidate conservée puis supprimez le secret candidat temporaire :

printf '%s' "$rotation_database_url" \
  | gh secret set DATABASE_URL --env development
gh secret delete POSTGRES_ROTATION_DATABASE_URL --env development

Supprimez également POSTGRES_ROTATION_PREVIOUS_PASSWORD si le fallback explicite a été configuré.

Pour un volume neuf sans application en cours d'exécution, définissez aussi DATABASE_URL avec la même URL candidate avant le premier build. Ne remplacez jamais seulement DATABASE_URL et POSTGRES_PASSWORD sur un volume existant avant la fin du workflow de rotation.

Les workflows ont aussi besoin des permissions packages du dépôt: les jobs de build utilisent packages: write pour publier ghcr.io/<owner>/yayaw-app:<sha> et ghcr.io/<owner>/yayaw-worker:<sha>, tandis que les jobs de déploiement Coolify utilisent packages: read pour tirer ces images depuis le runner auto-hébergé.

L'app development partagée est volontairement mutable: chaque pull request force la branche technique coolify/development du dépôt vers le SHA de tête de la PR, met à jour la git_branch de l'app dans Coolify vers cette branche stable et déploie sans forcer de rebuild. Cela évite les échecs lorsqu'une branche PR mergée est supprimée avant que Coolify clone le dépôt, tout en laissant BuildKit réutiliser les layers entre development et production. GitHub Actions sérialise les déploiements development avec le groupe de concurrence development-coolify-deploy, ce qui garde l'environnement prévisible pendant que les nouvelles runs attendent la fin du déploiement en cours.

Gardez l'origine development privée. Préférez un hostname Tailscale-only ou activez HTTP Basic au niveau de l'app Coolify tout en renvoyant X-Robots-Tag: noindex, nofollow, noarchive. Le smoke test part du runner auto-hébergé avec les secrets Basic Auth development; ce runner doit donc atteindre l'URL protégée.

Socle Production

Ces valeurs sont requises avant qu'un déploiement production puisse servir l'app correctement:

VariableOù la récupérerIndication
NODE_ENVRuntime VercelGénéralement défini par la plateforme. Ne surchargez pas sauf pour déboguer un runtime non Vercel.
NEXT_PUBLIC_BASE_URLDomaines VercelDéfinir sur l'origine publique canonique, par exemple https://yayaw.app.
BETTER_AUTH_SECRETSecret managerValeur longue, aléatoire et stable pour cookies et tokens Better Auth.
DATABASE_URLFournisseur PostgresUtiliser la connection string poolée production lorsque le fournisseur en expose une.
BETTER_AUTH_TRUSTED_ORIGINSDomaines de déploiementAjouter les origines preview/local en liste séparée par virgules. L'hôte canonique et sa variante www sont dérivés de NEXT_PUBLIC_BASE_URL.
CADDY_HOST_PORTEnv application CoolifyPort hôte du conteneur Caddy Compose. Défaut production 3080; utilisez par exemple 3081 pour l'app development partagée.
MINIO_API_HOST_PORTEnv application CoolifyPort hôte de l'API S3-compatible MinIO. Défaut production 9000; utilisez par exemple 9100 en development.
MINIO_CONSOLE_HOST_PORTEnv application CoolifyPort hôte de la console MinIO. Défaut production 9001; utilisez par exemple 9101 en development.
VERCEL_URLRuntime VercelDéfini automatiquement par Vercel. Garder hors du .env local sauf reproduction plateforme.

Réglages optionnels de pool base:

VariableQuand la définir
DATABASE_POOL_MAXAugmenter seulement si le fournisseur DB supporte plus de connexions par runtime.
DATABASE_IDLE_TIMEOUT_SECONDSAjuster le cycle de vie idle pour les déploiements non-serverless.
DATABASE_MAX_LIFETIME_SECONDSAjuster la rotation de connexions pour les runtimes long-lived.
DATABASE_CONNECT_TIMEOUT_SECONDSAjuster le démarrage sur réseaux privés lents.
DATABASE_STATEMENT_TIMEOUT_SECONDSAjouter un timeout serveur par statement pour chaque connexion DB.
DATABASE_PREPARE_STATEMENTSGarder false pour les connexions production pooler/serverless sauf support explicite du fournisseur.
CMS_DASHBOARD_FULL_METRICSGarder false sauf si la base est optimisée pour les agrégats complets de publication et activité CMS.

Base De Données

DATABASE_URL est requis par le runtime applicatif, les scripts setup, les seeds et les opérations Drizzle.

Pour le déploiement Coolify auto-hébergé, la synchronisation de schéma et les seeds production tournent dans le service Compose migrate avant le démarrage de l'app et du worker. Gardez le DATABASE_URL production dans Coolify ou le secret store de l'orchestrateur afin que l'étape de setup résolve les noms de services Docker internes comme postgres.

Pour les fournisseurs hébergés qui n'exécutent pas la pile Compose auto-hébergée, lancez l'opération de schéma Drizzle choisie depuis un runner capable d'atteindre la base production avant de promouvoir la nouvelle version.

Pour les fournisseurs Postgres hébergés:

  1. Créez la base production.
  2. Ouvrez le panneau des connection strings.
  3. Copiez la connection string poolée lorsqu'elle existe.
  4. Stockez-la comme DATABASE_URL dans Vercel Production et Preview, ou dans le secret store auto-hébergé.
  5. Utilisez une base de développement séparée pour Vercel Development, .env.local local ou .env.self-host.

Si le fournisseur expose des URL directes et poolées, préférez l'URL poolée pour les fonctions Vercel. L'app utilise déjà un pool production conservateur de trois connexions par runtime afin d'éviter d'épuiser les limites serverless.

Hôte Canonique Et Auth

Définissez:

NEXT_PUBLIC_BASE_URL=https://yayaw.app
BETTER_AUTH_TRUSTED_ORIGINS=https://*.yayaw.app,https://*.vercel.app

NEXT_PUBLIC_BASE_URL pilote les URL canoniques, l'URL de base Better Auth, les métadonnées OAuth, les liens sitemap/robots et les URL absolues de ressources.

Ne définissez pas NEXT_PUBLIC_SITE_URL; l'application ne le lit pas. Ne définissez pas BETTER_AUTH_URL pour les nouveaux déploiements; Better Auth reçoit son URL de base depuis NEXT_PUBLIC_BASE_URL.

Le domaine de prévisualisation branch-backed est https://preview.yayaw.app et suit la branche durable preview.

Les hôtes .eu retirés peuvent rester attachés uniquement comme redirections Vercel 308 vers leurs remplaçants .app, comme yayaw.eu et www.yayaw.eu vers yayaw.app. Ils ne doivent pas servir de trafic dashboard/auth ni figurer dans BETTER_AUTH_TRUSTED_ORIGINS.

Stripe Billing

Stripe a trois secrets requis lorsque la facturation est activée:

VariableOù la récupérerNotes
STRIPE_SECRET_KEYStripe Dashboard, Developers, API keysUtilisez sk_live_... en production et sk_test_... en staging/local.
STRIPE_WEBHOOK_SECRETStripe Dashboard, Developers, Webhooks, signing secret endpoint abonnementUtilisé par l'endpoint webhook Better Auth Stripe.
STRIPE_ONE_TIME_WEBHOOK_SECRETStripe Dashboard, Developers, Webhooks, signing secret endpoint achat ponctuelUtilisé par l'endpoint custom one-time checkout.

Créez deux endpoints webhook Stripe pour la production:

https://yayaw.app/api/auth/stripe/webhook
https://yayaw.app/api/billing/stripe/webhook

Utilisez le signing secret du premier endpoint pour STRIPE_WEBHOOK_SECRET et celui du second pour STRIPE_ONE_TIME_WEBHOOK_SECRET. Ne réutilisez pas le secret d'un endpoint pour l'autre.

L'endpoint abonnement doit recevoir les événements de checkout abonnement et de cycle de vie billing. L'endpoint one-time a seulement besoin de checkout.session.completed pour les achats lifetime.

Les prix des produits de facturation sont gérés depuis /dashboard/admin/billing-products ou via le plan de contrôle MCP. Les Stripe Price IDs sont stockés en base après synchronisation catalogue; ce ne sont pas des secrets de déploiement.

Liens Livrables D'Accès Au Code

Ces valeurs sont des URL non secrètes optionnelles affichées sur /dashboard/organization/code-access après un achat payant qui débloque l'accès au code:

VariableExempleQuand l'utiliser
BILLING_CODE_ACCESS_REPOSITORY_URLhttps://github.com/Yayaw-eu/yayawLien vers le dépôt privé après attribution de l'accès GitHub.
BILLING_CODE_ACCESS_DOWNLOAD_URLhttps://github.com/Yayaw-eu/yayaw/releasesLien vers artifacts de release ou archives.
BILLING_CODE_ACCESS_DOCUMENTATION_URLhttps://docs.yayaw.appLien vers la documentation de setup ou d'usage.
BILLING_CODE_ACCESS_SUPPORT_URLmailto:support@yayaw.appLien support pour les problèmes d'accès.

Laissez une valeur vide lorsque le livrable requiert un provisioning manuel.

GitHub Code Access

L'accès dépôt production doit utiliser une GitHub App, pas un personal access token. L'app permet à Yayaw d'inviter les clients payants dans le dépôt configuré avec l'accès lecture seule pull, sans stocker les identifiants GitHub d'un utilisateur humain.

Créer La GitHub App

Créez l'app depuis le compte qui possède le dépôt privé:

GitHub organization -> Settings -> Developer settings -> GitHub Apps -> New GitHub App

Valeurs recommandées:

ChampValeur
GitHub App nameYayaw Code Access
Homepage URLURL de production, par exemple https://yayaw.app
WebhookDésactivé sauf future fonctionnalité GitHub callbacks
Where can this GitHub App be installedOnly on this account

Permissions de dépôt:

PermissionAccès
AdministrationRead and write
MetadataRead-only, accordé automatiquement par GitHub

Administration: Read and write est requis car Yayaw appelle l'API GitHub collaborators pour inviter le username demandé dans le dépôt. L'app n'a pas besoin de permission Contents pour le flux actuel: le client reçoit l'accès dépôt normal via son propre compte GitHub.

Installer La GitHub App

Après création:

  1. Générez une clé privée depuis les réglages de l'app et téléchargez le .pem.
  2. Installez l'app sur le compte ou l'organisation propriétaire.
  3. Sélectionnez uniquement le dépôt auquel les clients payants doivent accéder.
  4. Copiez l'App ID depuis les réglages.
  5. Copiez l'installation ID depuis l'URL d'installation.

L'URL d'installation ressemble généralement à ceci pour une organisation:

https://github.com/organizations/Yayaw-eu/settings/installations/12345678

Le segment numérique final est l'ID d'installation de la GitHub App.

Stocker Le Secret GitHub App

Stockez la clé privée dans l'environnement cible. Pour Vercel:

vercel env add BILLING_CODE_ACCESS_GITHUB_APP_PRIVATE_KEY production
vercel env add BILLING_CODE_ACCESS_GITHUB_APP_PRIVATE_KEY preview

Le dashboard Vercel est l'endroit le plus sûr pour coller une valeur PEM multiligne avec le fournisseur hébergé. Pour un .env.local ou fichier secret auto-hébergé, collez la clé multiligne entre guillemets ou échappez les sauts de ligne sur une ligne:

printf 'BILLING_CODE_ACCESS_GITHUB_APP_PRIVATE_KEY="%s"\n' "$(perl -0pe 's/\n/\\n/g' yayaw-code-access.pem)" >> .env.local

Le runtime accepte les séquences \n échappées et les reconvertit en vrais sauts de ligne avant de signer le JWT GitHub App. Si une plateforme aplatit le PEM en une ligne avec des espaces entre header, body et footer, Yayaw le normalise en PEM au runtime.

Configurer Les Valeurs Non Secrètes GitHub

Préférez l'UI admin pour les valeurs non secrètes:

/dashboard/admin/billing-settings

Définissez:

Réglage adminValeur
EnabledOn
RepositoryYayaw-eu/yayaw ou le dépôt cible exact
GitHub App IDApp ID numérique depuis les réglages GitHub App
GitHub App installation IDInstallation ID numérique depuis l'URL d'installation

Des replis d'environnement existent pour les déploiements qui ont besoin de config au démarrage:

BILLING_CODE_ACCESS_GITHUB_REPOSITORY=Yayaw-eu/yayaw
BILLING_CODE_ACCESS_GITHUB_APP_ID=123456
BILLING_CODE_ACCESS_GITHUB_APP_INSTALLATION_ID=12345678
BILLING_CODE_ACCESS_GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"

Repli Token Local Ou Staging

Utilisez BILLING_CODE_ACCESS_GITHUB_TOKEN uniquement pour les environnements locaux ou staging sans GitHub App:

BILLING_CODE_ACCESS_GITHUB_REPOSITORY=Yayaw-eu/yayaw
BILLING_CODE_ACCESS_GITHUB_TOKEN=github_pat_...

Le propriétaire du token doit pouvoir ajouter des collaborateurs au dépôt. Pour un token fine-grained, accordez l'accès au seul dépôt cible et incluez la permission d'administration de dépôt nécessaire aux invitations. N'utilisez pas ce repli en production sauf contournement d'incident avec plan de rotation.

E-mail

RESEND_API_KEY active les e-mails transactionnels d'invitation, reset, magic link et facturation.

Pour la récupérer:

  1. Vérifiez le domaine d'envoi dans Resend pour l'e-mail production.
  2. Créez une clé API server-side dans Resend.
  3. Stockez-la comme RESEND_API_KEY dans l'environnement cible.
  4. Envoyez un e-mail de test depuis la surface admin des e-mails transactionnels après déploiement.

Définissez EMAIL_SENDER sur un expéditeur vérifié du domaine Resend, par exemple team@yayaw.app. Définissez EMAIL_SUPPORT sur l'adresse support affichée dans les modèles et EMAIL_USERNAME sur le nom affiché. Ces variables sont des défauts bootstrap et replis; après la première connexion admin, Admin > Site Settings > Email est prioritaire au runtime.

L'absence de RESEND_API_KEY ne casse pas le traitement des webhooks de facturation, mais ignore les e-mails transactionnels.

Fournisseurs OAuth

Ces valeurs sont optionnelles et requises uniquement lorsque le fournisseur correspondant est activé:

FournisseurVariablesOù les récupérer
GitHub OAuthGITHUB_CLIENT_ID, GITHUB_CLIENT_SECRETRéglages GitHub OAuth App. Distinct de la GitHub App d'accès au code.
Google OAuthGOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRETClient OAuth Google Cloud Console.
Facebook OAuthFACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRETRéglages Meta developer app.

Utilisez l'origine production de NEXT_PUBLIC_BASE_URL lors de la configuration des redirect URIs OAuth.

Object Storage

Le stockage média est optionnel jusqu'à l'utilisation d'upload, miniatures, logos ou génération d'images. Définissez STORAGE_PROVIDER=s3 pour MinIO, S3, R2 ou un autre fournisseur compatible S3.

Variables communes:

VariableOù la récupérer
STORAGE_PROVIDERDéfinir sur s3.
STORAGE_MEDIA_BUCKETNom du bucket des ressources média. Défaut media.
STORAGE_MEDIA_STAGING_BUCKETBucket privé des téléversements directs en staging. Le self-host fourni utilise media-staging.
STORAGE_CMS_FORM_BUCKETBucket privé durable des pièces jointes client. Le self-host fourni utilise cms-form-submissions.
STORAGE_PUBLIC_BASE_URLOrigine publique des objets pour stockage compatible S3, servant /<bucket>/<key>. Utilisez l'origine app ou CDN seulement si ces préfixes de bucket sont routés vers le stockage objet.
STORAGE_TRANSFER_SIGNING_SECRETSecret dédié facultatif des grants privés same-origin opaques. Il se replie sur le secret de preview ou d'auth et doit fournir au moins 32 caractères en production.
CMS_PERSONALIZATION_FORM_CONTEXT_SECRETSecret dédié obligatoire pour la provenance éphémère des formulaires CMS publics. Générez au moins 32 caractères aléatoires et ne l'exposez jamais au navigateur ou au contenu CMS.
S3_SIGNED_PUBLIC_ENDPOINTOrigine d'API S3 publique explicite et facultative pour les uploads signés directs quand l'hébergeur app ne supporte pas la limite CMS de 250 Mo. Ne jamais renseigner l'endpoint Docker interne.

Pour un stockage S3 same-origin ou derrière CDN, proxifiez chaque préfixe de bucket public vers le stockage objet avant le repli app. Les buckets publics intégrés sont /media/* pour les médias téléversés et /organization-logos/* pour les logos d'organisation. Si STORAGE_PUBLIC_BASE_URL pointe directement vers une origine de stockage objet dédiée, cette origine doit servir les mêmes chemins /<bucket>/<key>.

Créez les buckets de staging et de formulaires avant d'activer leurs écritures et ne leur accordez aucun accès anonyme. Limitez le nettoyage par cycle de vie du fournisseur au bucket ou préfixe de staging ; le worker Page AI pilote le ledger de rétention à 180 jours des photos de formulaires et reprend les suppressions interrompues. Définissez CMS_PERSONALIZATION_CLIENT_IP_HEADER=x-real-ip avec le Caddy fourni, qui écrase ce header, ou utilisez un autre header mono-valeur possédé par le proxy seulement après avoir vérifié que l'ingress retire les valeurs client. Gardez le worker actif avec PAGE_AI_QUEUE_DRIVER=db-worker en self-host.

Les transferts privés utilisent par défaut un grant applicatif same-origin opaque, donc S3_ENDPOINT peut rester privé. Sur une plateforme dont la limite de corps entrant est plus faible, définissez S3_SIGNED_PUBLIC_ENDPOINT sur une origine d'API S3 HTTPS publique et sûre ; seuls les uploads deviennent des PUT directs conditionnels, tandis que les téléchargements privés restent derrière le proxy applicatif. Autorisez l'origine app, PUT, Content-Type, Content-Length et If-None-Match dans la politique CORS de ce bucket. Les octets de staging promus restent un tombstone sans écrasement pendant l'expiration du grant et une stabilisation de 24 heures. Le reaper répète la suppression et n'enregistre le nettoyage qu'après son DELETE final.

Activez les écritures de prototypes exacts dans cet ordre :

  1. Déployez le reader compatible avec CMS_LEGACY_PROTOTYPE_WRITES_ENABLED=true et CMS_PROTOTYPE_RUNTIME_V2_WRITES_ENABLED=false.
  2. Vous pouvez lancer le workflow manuel CMS Prototype Runtime Rollout avec reader et le SHA complet déjà déployé pour prouver la flotte reader.
  3. Lancez ensuite ce workflow de confiance avec exact. Il vérifie ou crée les buckets privés, synchronise freeze, redéploie chaque ressource app/worker typée sur le SHA complet demandé et enregistre UUID de ressource, UUID de déploiement, digest, nom d'image, commit et jeu complet d'identifiants des conteneurs actifs dans un reçu durable version 1. Chaque conteneur actif doit prouver séparément le SHA et les valeurs legacy, v2, staging et opération de rollout attendues.
  4. Après avoir revérifié qu'aucun déploiement plus récent n'a invalidé la preuve de drain, le workflow fait passer le reçu de issued à activating, synchronise legacy false, v2 true, staged uploads true et CMS_PROTOTYPE_ROLLOUT_OPERATION_ID, puis redéploie et revérifie toutes les ressources. L'UUID de déploiement exact doit être nouveau ; UUID de ressource typée, digest, nom d'image et SHA complet restent identiques.
  5. Le workflow vérifie l'état runtime final, réinspecte tous les conteneurs exacts et transmet ce JSON frais directement à la consommation du reçu dans la même étape shell. La consommation active le floor de base avant toute écriture de gate. Seule l'opération consommée courante peut autoriser un nouveau prototypeGateV2.

Le workflow récupère toujours ses scripts de control plane depuis le main de confiance courant ; le SHA de déploiement demandé est une preuve, jamais du code de workflow exécutable. Si une exécution échoue après activating, le handler d'échec peut seulement restaurer puis redéployer freeze. Reprenez explicitement la même opération avec resume_operation_id et sa chaîne de confirmation. La reprise exige le même environnement, dépôt, SHA de déploiement, ressources typées et images, ainsi qu'une nouvelle tentative de preuve live avec sa propre expiration. Le parent immuable conserve le SHA de control plane qui l'a émis ; la tentative enfant reprise enregistre et valide le SHA du main de confiance courant. Elle ne peut ni créer un reçu actif concurrent ni revenir au reader.

Si la flotte a déjà avancé vers un SHA descendant strict alors qu'un ancien reçu reste activating, ne reprenez pas l'ancien SHA et ne faites pas de rollback. Lancez exact sur le descendant live avec superseded_operation_id, superseded_deploy_sha et la confirmation exact:<nouveau-sha>:supersede:<ancien-sha>:<ancien-operation-id>. Le workflow prouve l'ascendance Git, redéploie et revérifie le descendant en freeze, puis crée et active atomiquement le reçu de remplacement en liant l'ancien comme terminal superseded. Le remplacement conserve les UUID de ressources typées et prouve de nouveaux UUID de déploiement. La supersession ne fait jamais avancer le runtime floor ; seule la consommation du remplacement le fait.

Le déploiement automatique normal de production reste réservé au reader. Le déploiement de PR development partagé résout sa phase avec les scripts du main de confiance : il garde bootstrap/reader en reader, ou préserve freeze uniquement lorsque la configuration Coolify et chaque conteneur app/worker live prouvent déjà freeze. Il ne peut initier freeze depuis reader ou exact et n'active jamais exact.

Pour une évolution ultérieure du renderer en development :

  1. Lancez CMS Prototype Runtime Rollout avec freeze sur le SHA complet actuellement déployé.
  2. Relancez le déploiement de la PR cible. Sous le lock partagé development-coolify-deploy, il préserve freeze, déploie le nouveau SHA immuable de la PR, puis prouve que chaque conteneur app/worker live expose ce SHA et les flags freeze. Une ressource Compose development unique est prouvée comme un seul déploiement contenant les deux images attendues, avec un digest d'image agrégé stable et le jeu complet d'IDs de conteneurs app/worker.
  3. Lancez CMS Prototype Runtime Rollout avec exact sur ce même SHA de PR. Il crée et consomme le reçu suivant, fait avancer l'opération courante et conserve l'opération initiale du floor.

Pour une évolution ultérieure du renderer en production :

  1. Lancez CMS Prototype Runtime Rollout avec freeze sur le SHA complet actuellement déployé.
  2. Déclenchez manuellement Coolify Rolling Deploy avec le SHA complet cible appartenant à l'historique de main et freeze-upgrade:<sha-complet>. Le workflow refuse de construire tant que l'état configuré et chaque conteneur app/worker live ne sont pas déjà gelés. Build, migration, rollout worker et rollout app restent ensuite sous le lock freeze partagé, puis l'étape finale prouve que le SHA et les images cibles sont toujours live en freeze.
  3. Lancez CMS Prototype Runtime Rollout avec exact sur ce même SHA. Il crée et consomme le reçu suivant, fait avancer l'opération courante et conserve l'opération initiale du floor.

Le job normal ne simule jamais cette transition. Une fois le floor actif, n'utilisez jamais reader comme reset et ne réactivez jamais les writers legacy.

Les migrations 0047_cms_prototype_runtime_floor et 0049_cms_prototype_rollout_receipt_supersession rendent cette frontière durable. Elles persistent les reçus parents et tentatives immuables, contraignent chaque état à sens unique issuedactivatingconsumed, ou la branche de récupération terminale explicite activatingsuperseded, puis verrouillent les writers de sessions pendant le backfill sûr de tout gate exact préexistant avec une opération initiale/courante synthétique irréversible. La consommation d'un reçu active le singleton indépendant. Son timestamp d'activation et sa première opération sont immuables ; l'ID du premier contexte reste nul jusqu'au premier nouveau gate exact, puis devient immuable. Les reçus consommés ultérieurs ne peuvent que faire avancer current_v2_rollout_operation_id. Les sessions exactes existantes continuent leurs mises à jour ordinaires sans rejouer la GUC transactionnelle ; un gate exact nouvellement ajouté doit porter l'opération courante. La chaîne synthétique de backfill ne constitue jamais une autorisation suffisante : l'opération courante doit aussi correspondre à un reçu réellement consommé avant l'ajout d'un autre gate exact. Le floor ne peut être ni supprimé, ni tronqué, ni réinitialisé, ni annulé par l'expiration/suppression de la session d'origine. Des triggers de base de données et des gardes writer dans la même transaction sérialisent les écritures legacy de session, composant, page, review, publication et média sur ce singleton. Réinitialiser un flag d'environnement ne peut donc pas rouvrir les mutations legacy. Les lectures legacy, dry-runs purs, lectures idempotentes d'uploads terminés, annulations/expirations et nettoyages média restent disponibles. Un commit média refusé par ce floor supprime l'objet promu, tandis que le nettoyage d'un upload préparé reste repris par le reaper.

Le workflow manuel constitue aussi la frontière de sûreté des binaires en rolling : chaque ressource doit exécuter le SHA immuable en freeze avant qu'une ressource passe en exact. Ne modifiez pas ces flags directement et ne contournez pas ce workflow, car les anciens binaires ne contiennent pas toutes les gardes applicatives du floor.

Le préflight stockage de l'image worker requiert HeadBucket, l'optionnel CreateBucket, GetBucketPolicy, GetBucketAcl, PutObject, GetObject et DeleteObject sur les buckets staging et formulaires. Il n'affiche jamais les identifiants de stockage ni les erreurs provider complètes.

Pendant le setup, bun run seed téléverse les ressources par défaut de variables globales de site dans le bucket média sous global/site-variables/* et écrit ces URL publiques dans l'entrée site-variables/main. Les URL de ressources personnalisées existantes sont préservées lorsque le seed est relancé.

Variables de stockage compatible S3:

VariableOù la récupérer
S3_ENDPOINTEndpoint fournisseur, par exemple http://minio:9000.
S3_REGIONRégion fournisseur. Utilisez us-east-1 pour MinIO sauf configuration différente.
S3_ACCESS_KEY_IDIdentifiant de stockage server-side.
S3_SECRET_ACCESS_KEYIdentifiant de stockage server-side.
S3_FORCE_PATH_STYLEDéfinir true pour MinIO et la plupart des endpoints compatibles S3 locaux.

N'exposez jamais S3_ACCESS_KEY_ID ou S3_SECRET_ACCESS_KEY au navigateur ni dans une variable NEXT_PUBLIC_*.

S3_SIGNED_PUBLIC_ENDPOINT est optionnel et n'est jamais déduit de S3_ENDPOINT. En production, sa présence impose HTTPS, un hostname DNS public multi-label, sans credentials, query ni fragment. Il active uniquement les PUT directs signés ; les downloads restent derrière le proxy same-origin de l'app. Avant de définir cette variable, configurez le CORS du bucket pour l'origine de l'app, PUT et les headers Content-Type, Content-Length et If-None-Match. STORAGE_TRANSFER_SIGNING_SECRET peut fournir un secret dédié aux tokens opaques de transfert ; sinon le runtime se replie volontairement sur CMS_PREVIEW_SIGNING_SECRET, puis BETTER_AUTH_SECRET. Le secret effectif en production doit contenir au moins 32 caractères.

Domaines Publics

Les domaines publics d'organisation utilisent PUBLIC_DOMAIN_PROVIDER.

VariableUsage
PUBLIC_DOMAIN_PROVIDERvercel pour la gestion Vercel project-domain ou manual-dns pour la vérification DNS auto-hébergée.
APP_MANAGED_HOSTSHôtes possédés par l'app, séparés par virgules, que les clients ne peuvent pas réclamer.
RESERVED_PUBLIC_DOMAIN_SUFFIXESSuffixes supplémentaires que les clients ne peuvent pas réclamer. .vercel.app est toujours réservé.
PUBLIC_DOMAIN_CNAME_TARGETCible CNAME DNS manuel affichée aux opérateurs.
PUBLIC_DOMAIN_IPV4_TARGETSCibles A-record DNS manuel séparées par virgules.
PUBLIC_DOMAIN_TXT_PREFIXPréfixe TXT de vérification, défaut _yayaw.
VERCEL_TOKENRequis uniquement pour le fournisseur Vercel.
VERCEL_PROJECT_IDRequis uniquement pour le fournisseur Vercel.
VERCEL_TEAM_IDScope équipe Vercel optionnel.

manual-dns génère un challenge TXT de propriété et vérifie le DNS public. Il n'automatise ni les changements chez le fournisseur DNS ni l'émission de certificats TLS.

OpenAI

Les fonctions de génération IA requièrent:

OPENAI_API_KEY=

Créez la clé depuis la page API keys de la plateforme OpenAI et stockez-la côté serveur dans l'environnement cible. Elle active le repli IA de composants, Page AI et la génération d'images lorsque les feature flags et réglages runtime correspondants sont actifs.

Toggles runtime IA optionnels:

VariableDéfautUsage
OPENAI_COMPONENTS_AI_FALLBACKtrueActive le repli IA pour inférence et classification de composants.
OPENAI_IMAGE_GENERATION_ENABLEDtrueActive la génération d'images du page builder lorsqu'une clé API existe.
OPENAI_IMAGE_MODELgpt-image-1.5Modèle de génération d'images.
PAGE_AI_QUEUE_DRIVERAutodirect localement, vercel-queue sur Vercel, ou db-worker pour un worker long-lived. La production auto-détecte Vercel et choisit sinon db-worker.
PAGE_AI_DEEP_REFINEMENTfalseToggle qualité interne, non exposé dans les réglages admin.
PAGE_AI_WORKER_POLL_MS1500Intervalle de polling pour le driver worker base de données.
PAGE_AI_WORKER_MAINTENANCE_MS60000Intervalle de rétention durable, nettoyage des objets orphelins et purge des buckets anti-abus.
PAGE_AI_WORKER_IDVideIdentifiant optionnel pour un worker long-lived.

Analytics

Choisissez un fournisseur analytics et un mode de capture:

NEXT_PUBLIC_ANALYTICS_PROVIDER=umami
NEXT_PUBLIC_ANALYTICS_CAPTURE_MODE=hybrid

Fournisseurs supportés: posthog, umami, none. Le mode de capture peut être hybrid, server ou client. hybrid est le défaut et enregistre des événements facturation/auth fiables côté serveur tout en gardant l'analytics produit navigateur. server ne rend pas de scripts analytics navigateur et envoie les vues CMS plus les conversions depuis le serveur applicatif. client conserve la capture uniquement navigateur.

Les événements de conversion serveur incluent checkout_started, purchase_completed, subscription_started, subscription_updated, subscription_cancel_scheduled, subscription_canceled et payment_failed. Les événements de facturation incluent revenue, value, currency, plan, product_key et les IDs Stripe pour la réconciliation. Les événements Stripe en mode test sont suivis avec billing_mode=test et is_test_data=true, mais ne comptent pas comme conversion, revenue ou value sauf activation du réglage admin Track Stripe Test Billing Analytics. Le montant test original reste dans test_amount_cents et test_revenue pour le débogage.

PostHog

La capture client et les feature flags utilisent les valeurs PostHog publiques:

NEXT_PUBLIC_POSTHOG_KEY=
NEXT_PUBLIC_POSTHOG_HOST=https://eu.i.posthog.com
NEXT_PUBLIC_POSTHOG_ENABLE_LOCAL=false

Les analytics dashboard côté serveur utilisent les valeurs PostHog privées:

POSTHOG_PERSONAL_API_KEY=
POSTHOG_PROJECT_ID=
POSTHOG_API_HOST=https://eu.posthog.com
POSTHOG_ORG_ID_PROPERTY=organization_id
POSTHOG_FLAG_LOOKUP_TIMEOUT_MS=

Récupérez la clé projet publique et l'ID projet depuis les réglages PostHog. Créez une personal API key avec l'accès suffisant à l'API Query et stockez-la comme POSTHOG_PERSONAL_API_KEY. Gardez POSTHOG_ORG_ID_PROPERTY=organization_id sauf changement de la propriété d'événement analytics dans le produit. Définissez POSTHOG_FLAG_LOOKUP_TIMEOUT_MS uniquement si les lookups de feature flags PostHog côté serveur ont besoin d'un timeout différent du défaut 1500 millisecondes.

Umami

La capture client utilise les valeurs Umami publiques:

NEXT_PUBLIC_UMAMI_HOST_URL=https://analytics.example.com
NEXT_PUBLIC_UMAMI_SCRIPT_URL=
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
NEXT_PUBLIC_UMAMI_DOMAINS=
NEXT_PUBLIC_UMAMI_AUTO_TRACK=true

Les lectures dashboard côté serveur et la capture serveur utilisent les valeurs Umami privées:

UMAMI_API_URL=https://analytics.example.com
UMAMI_WEBSITE_ID=
UMAMI_API_TOKEN=
UMAMI_API_KEY=
UMAMI_USERNAME=
UMAMI_PASSWORD=
UMAMI_CMS_EVENT_PAGE_SIZE=1000

Utilisez soit UMAMI_API_TOKEN (ou l'alias legacy UMAMI_API_KEY), soit UMAMI_USERNAME plus UMAMI_PASSWORD pour les lectures de données dashboard. La capture d'événements serveur utilise Umami /api/send; elle a donc seulement besoin de UMAMI_API_URL et UMAMI_WEBSITE_ID.

Plan De Contrôle MCP

Le MCP production ne requiert pas de variable d'environnement dans le runtime applicatif. Les clients se connectent à /api/mcp avec une clé API Better Auth ou un access token OAuth.

Les tests stdio locaux peuvent utiliser:

YAYAW_MCP_API_KEY=
YAYAW_MCP_LOCAL_USER_ID=

Créez, inspectez et révoquez les clés MCP avec:

bun run mcp:key

Stockez les clés client de confiance hors du dépôt et passez-les au client comme YAYAW_MCP_API_KEY.

Transforms Runtime Dynamic Data

Définissez DYNAMIC_DATA_RUNTIME_TRANSFORM_SECRET uniquement lorsque des routes runtime dynamiques déployées utilisent des transforms de valeur hmac_sha256, par exemple un code de pairing transformé en code_hash stocké.

DYNAMIC_DATA_RUNTIME_TRANSFORM_SECRET=$(openssl rand -hex 32)

Stockez la valeur comme secret server-only dans l'orchestrateur. Sa rotation change les futures sorties HMAC; faites-la donc avec une migration de données spécifique au produit ou une fenêtre d'expiration des pairing sessions.

Mode Maintenance

Le mode maintenance est optionnel:

MAINTENANCE_MODE=false
MAINTENANCE_MODE_END_DATE=

Définissez MAINTENANCE_MODE=true uniquement lorsque l'app doit servir la surface de maintenance. Utilisez MAINTENANCE_MODE_END_DATE pour le contexte opérateur.

Métadonnées De Déploiement

Les déploiements Vercel reçoivent automatiquement les métadonnées runtime. Les déploiements auto-hébergés peuvent fournir des métadonnées statiques:

VariableUsage
DEPLOYMENT_PROVIDERvercel, static ou local; vide auto-détecte.
DEPLOYMENT_URLURL publique de déploiement hors Vercel.
DEPLOYMENT_ENVLabel d'environnement, par exemple production ou preview.
DEPLOYMENT_GIT_COMMIT_SHASHA de commit pour statut dashboard/plan de contrôle.
DEPLOYMENT_GIT_COMMIT_REFRef ou nom de branche.

Checklist De Déploiement

Avant promotion:

  1. L'environnement cible possède chaque variable requise de .env.example ou .env.self-host.example.
  2. La prévisualisation a soit des valeurs fournisseurs équivalentes à la production, soit des valeurs staging explicites.
  3. NEXT_PUBLIC_BASE_URL correspond à l'origine HTTPS publique de l'environnement.
  4. Stripe a deux endpoints webhook et chaque secret d'endpoint est mappé à la variable correspondante.
  5. L'accès au code GitHub a soit les réglages admin plus BILLING_CODE_ACCESS_GITHUB_APP_PRIVATE_KEY, soit les replis d'environnement explicites pour dépôt, App ID, installation ID et clé privée.
  6. Les variables Resend, PostHog, S3, OpenAI et OAuth ne sont présentes que lorsque ces fonctions sont activées.
  7. Coolify ou l'orchestrateur possède le DATABASE_URL runtime utilisé par le service Compose migrate, et les environnements GitHub possèdent la valeur build-time DATABASE_URL requise par next build.
  8. Un nouveau déploiement ou redémarrage de conteneur a été déclenché après la dernière modification de variable.
  9. Lancez les barrières qualité locales avant de merger des changements de config de déploiement:
bun run check
bun run docs:generate
bun run docs:check-links
bun run docs:check-translations
bun run docs:llm:check
bunx tsc --noEmit
bun run build

Références Fournisseurs