Procédures opérationnelles
Runbooks d'exploitation pour les tâches de maintenance courantes.
Régénérer Les Actions DB
bun run generate:actionsLancez cette commande après des changements de schéma Drizzle. Commitez les fichiers générés avec le changement de schéma afin que TypeScript et les tests de contrats authz voient la même surface d'actions base de données que le runtime.
Changer Le Domaine Production
La production Yayaw est servie canoniquement depuis https://yayaw.app.
Pointez les enregistrements DNS apex vers l'ingress Coolify/reverse proxy auto-hébergé et vérifiez le TLS de
yayaw.app.Configurez
www.yayaw.appsur le reverse proxy pour rediriger versyayaw.appavec le statut308.Gardez les domaines
.euretirés uniquement comme redirections du reverse proxy avec le statut308: routezyayaw.euetwww.yayaw.euversyayaw.app. Les projets compagnons doivent suivre le même modèle, par exempletable.yayaw.euverstable.yayaw.app.Définissez les variables d'environnement production:
NEXT_PUBLIC_BASE_URL=https://yayaw.app
BETTER_AUTH_TRUSTED_ORIGINS=https://*.yayaw.appGardez une branche Git durable
preview, routezpreview.yayaw.appvers l'application Coolify adossée à cette branche, puis définissez leNEXT_PUBLIC_BASE_URLde prévisualisation:
NEXT_PUBLIC_BASE_URL=https://preview.yayaw.appNe gardez pas d'anciens hôtes de prévisualisation comme domaines actifs après vérification de
preview.yayaw.app.Redéployez les applications Coolify production et prévisualisation afin que les builds reçoivent l'URL publique de base.
Mettez à jour les callbacks et webhooks tiers qui stockent des origines absolues: fournisseurs OAuth, webhooks Stripe, URLs de retour du portail de facturation, liens e-mail et réglages analytics/site.
Déployer Le Runtime Auto-Hébergé
Copiez le fichier exemple et renseignez les secrets production hors git:
cp .env.self-host.example .env.self-host
perl -0pi -e "s/^BETTER_AUTH_SECRET=$/BETTER_AUTH_SECRET=$(openssl rand -hex 32)/m" .env.self-hostLancez la synchronisation de schéma et le seed:
docker compose --env-file .env.self-host -f docker-compose.self-host.yml --profile setup run --rm migrateDémarrez ou mettez à jour le runtime:
docker compose --env-file .env.self-host -f docker-compose.self-host.yml up --build -dConfirmez que Caddy atteint l'app et que les en-têtes
Host/X-Forwarded-*sont préservés en ouvrant leDEPLOYMENT_URLconfiguré.Téléversez une ressource média et confirmez qu'elle est servie depuis le
STORAGE_PUBLIC_BASE_URLconfiguré.Confirmez que
bun run worker:page-aitourne via le service ComposeworkerlorsquePAGE_AI_QUEUE_DRIVER=db-worker.Sauvegardez Postgres et le stockage objet ensemble avant toute release risquée.
Basculer Une Base Existante Vers Better Auth 1.7
La migration 0050_better_auth_1_7_stable reste additive pour permettre le
rollback, mais elle change l'identité des comptes et ajoute des contraintes
d'unicité. Le processus refuse de l'exécuter sur une base existante tant que
l'opérateur n'atteste pas que les écritures auth sont réellement suspendues.
BETTER_AUTH_17_WRITES_PAUSED ne bloque aucune requête à lui seul et ne remplace
jamais une isolation à l'ingress ou au niveau du processus.
Répétez l'opération sur une restauration récente de production. Exposez d'abord les colonnes additives de préparation, puis lancez le préflight et corrigez chaque blocage avant de planifier la production:
DATABASE_URL=<url-du-clone-restaure> \
bun src/lib/scripts/auth/better-auth-1-7-prepare.ts
DATABASE_URL=<url-du-clone-restaure> \
bun src/lib/scripts/auth/better-auth-1-7-preflight.tsLa commande de préparation est idempotente et la migration 0050 répète les
mêmes colonnes avec IF NOT EXISTS. Exécutez-la en production avant la
fenêtre d'indisponibilité afin d'attribuer à chaque client
client_credentials une allowlist client_credentials_scopes revue
explicitement et, si le propriétaire est ambigu, un reference_id
d'organisation. Les seuls scopes machine autorisés sont
control-plane:read, control-plane:write, control-plane:publish et
control-plane:admin; ne copiez jamais openid, profil, e-mail, accès
offline ni aucun autre scope délégué utilisateur. Les identifiants et
secrets clients existants restent inchangés. Le chemin de migration du
déploiement rejoue cette préparation de façon idempotente avant le préflight
bloquant.
Juste avant la bascule, créez un nouveau snapshot Postgres ou
pg_dumpet prouvez qu'il peut être restauré. Notez les tags immuables des images app et worker à utiliser pour le rollback.Bloquez en externe toutes les méthodes sur
/api/authà l'ingress avec une réponse de maintenance. Vérifiez qu'aucune origine publique alternative ne contourne cette règle. Sur un déploiement Compose à hôte unique, arrêter l'ancien serviceappest une indisponibilité plus large mais acceptable. Ne définissez pas encore l'attestation.Vérifiez le blocage depuis l'extérieur du réseau de déploiement. Avec une règle d'ingress, cette requête volontairement invalide et sans effet doit renvoyer le statut de maintenance, normalement
503, et non un2xxBetter Auth ou un4xxde validation:
curl --include --request POST \
--header 'content-type: application/json' \
--data '{}' \
https://yayaw.app/api/auth/sign-in/emailUniquement après vérification de la sauvegarde et du blocage externe, définissez
BETTER_AUTH_17_WRITES_PAUSED=truesur le processus de migration. C'est une attestation opérateur non secrète et temporaire:
# Auto-hébergé : définissez temporairement la valeur dans .env.self-host non suivi.
docker compose --env-file .env.self-host \
-f docker-compose.self-host.yml --profile setup run --rm migratePour le runner rolling Coolify, définissez la variable d'environnement
GitHub production BETTER_AUTH_17_WRITES_PAUSED à true, puis lancez ou
relancez le déploiement. Le runner transfère uniquement le booléen normalisé
dans son fichier d'environnement de migration privé en mode 600 et ne
l'affiche pas. Le garde distingue une base fraîche, une base où 0050 est déjà
appliquée et une base existante en attente. Les deux états existants exécutent
le préflight complet des données Better Auth avant db:migrate. L'état en
attente exige l'attestation ; une base appliquée l'exige aussi lorsque l'app
actuellement servie n'annonce pas le contrat de readiness stable-1.7, ce
qui ferme une nouvelle tentative après un rollback beta volontaire. Pour la ressource historique
docker-compose.coolify.yml, définissez la même variable Compose temporaire
et non secrète dans Coolify uniquement après activation du blocage externe,
puis retirez-la dès la fin du service de migration.
6. Déployez ensemble le serveur Better Auth et l'UI, puis lancez les smoke tests
critiques auth, OAuth, SCIM, Stripe, invitations et passkeys en maintenant le
blocage externe des écritures pour les utilisateurs normaux. Pendant la
suspension, le script rolling vérifie l'endpoint de session Better Auth
anonyme depuis l'intérieur du nouveau conteneur applicatif ; il n'assouplit
jamais la règle publique /api/auth pour ce smoke.
7. Définissez immédiatement BETTER_AUTH_17_WRITES_PAUSED=false ou supprimez la
variable de l'environnement de migration, puis retirez le blocage d'ingress
et rouvrez le trafic auth. Laisser l'attestation active est une erreur
opérationnelle.
8. Si un rollback applicatif est nécessaire, redéployez ensemble l'ancien
serveur et l'ancienne UI sans annuler la migration 0050. Désactivez le flag
enable-scim-plugin avant le démarrage du serveur beta : la migration 0050
conserve les tables SCIM beta vides sous des noms réservés au rollback,
tandis que les tables stables exposées sous les noms publics ont une forme
volontairement incompatible. Avant une nouvelle tentative, suspendez à
nouveau les écritures auth, rejouez le backfill issuer/clé de compte validé
de la migration 0050, vérifiez que chaque client OAuth machine possède encore
un propriétaire utilisateur et une référence vers une organisation dont il
est membre, puis relancez le préflight. La beta peut avoir créé des comptes
avec un issuer nul ou des clients OAuth aux métadonnées additives incomplètes
pendant la fenêtre de rollback. Chaque déploiement ultérieur avec 0050 déjà
journalisée relance le préflight et échoue tant qu'une réparation subsiste.
Après la migration 0050, le runner Coolify refuse de démarrer
automatiquement une image précédente qui n'annonce pas le contrat de
readiness Better Auth 1.7 stable. Un premier cutover en échec s'arrête donc
pour intervention opérateur; maintenez le blocage externe /api/auth. Pour
restaurer volontairement la beta, définissez enable-scim-plugin=false dans
le flag managé en base et dans tout fournisseur de flags distant, redémarrez
la beta derrière le blocage d'ingress, puis vérifiez depuis le réseau privé
que /api/auth/scim/v2/ServiceProviderConfig est indisponible avant de
rouvrir le trafic. Le rollback automatique redevient disponible dès que
l'image live précédente annonce le contrat de rollback stable-1.7.
Une base fraîche ou une base propre dont le journal contient déjà la migration
0050 pendant qu'une app stable-1.7 sert le trafic ne demande pas l'attestation
unique de suspension des écritures. Une base appliquée derrière un runtime beta
ou inconnu exige de nouveau la suspension et la preuve d'ingress externe. Toute
dérive du journal, tout schéma partiellement migré ou toute réparation de compte
créée par un rollback échoue explicitement et doit d'abord être résolu sur une
restauration.
Mettre À Jour Les Feature Flags Seedés
Modifiez
src/lib/scripts/seed.ts.Appliquez le seed:
bun run seedRelancez les checks applicatifs:
bun run check
bunx tsc --noEmit
bun run buildRetirer l’ancien miroir de documentation Table
La documentation publique provient du catalogue bilingue documentation-page
et est servie sous /[locale]/docs/*. Les anciennes pages du CMS de pages sous
/table/docs sont obsolètes : des redirections permanentes préservent leurs liens.
Ne recréez et ne republiez jamais ce miroir avec migrate-table-pages-to-cms.ts.
Pour retirer un miroir existant :
Inventoriez uniquement les pages globales dont le chemin est
/table/docsou commence par/table/docs/. Conservez les pages marketing/tableet de démonstration/table/example.Vérifiez la publication de chaque destination sous
/en/docs/tableet/fr/docs/table, puis la redirection de chaque ancienne adresse.Examinez les identifiants des dernières révisions et des révisions publiées. Un brouillon éditorial plus récent doit être relu avant archivage.
Archivez la page relue avec
yayaw_pages_archive, d’abord avecdryRun, puis avec sonexpectedRevisionIdexact,confirm: trueet un motif. L’archivage conserve l’historique immuable des révisions.Revérifiez les redirections et les pages canoniques après archivage et conservez les reçus d’audit. Ne supprimez pas les entrées de documentation.
Pour la documentation actuelle, utilisez /dashboard/content/documentation afin
de relire l’anglais et le français ensemble, corriger les erreurs de validation
et publier la révision vérifiée. Le statut brouillon ne suffit pas à conclure
qu’une page est obsolète.
Maintenir Le Snapshot De Repli Fumadocs Yayaw Table
Fumadocs rend le catalogue Documentation bilingue publié depuis Postgres sous
/[locale]/docs/table/*. Les fichiers dans content/docs/{en,fr}/table restent
uniquement le seed initial et le snapshot explicite de rollback/repli ; ils ne
sont plus la source éditoriale courante après la bascule en base. Les Super
Admins gèrent les contenus anglais et français publiés depuis
/dashboard/content/documentation.
Pour actualiser volontairement le snapshot de repli, mettez à jour les deux
dossiers, utilisez des liens relatifs comme ./setup et gardez les fichiers
meta.json anglais et français dans le même ordre. Lancez
bun run docs:check-translations et bun run docs:check-links, puis utilisez la
commande d'import Documentation explicite uniquement si le snapshot validé doit
remplacer des révisions importées depuis Git et restées intactes.
Valider Les Webhooks De Facturation En Staging
Webhook du plugin Better Auth Stripe:
stripe listen --forward-to https://<staging-domain>/api/auth/stripe/webhookWebhook ponctuel custom:
stripe listen --forward-to https://<staging-domain>/api/billing/stripe/webhookDéclenchez des événements:
stripe trigger checkout.session.completed
stripe trigger customer.subscription.updated
stripe trigger customer.subscription.deleted
stripe trigger invoice.payment_failed
stripe trigger invoice.paidinvoice.payment_failed et invoice.paid doivent atteindre l'endpoint Stripe
du plugin Better Auth sur /api/auth/stripe/webhook. L'endpoint custom des
achats ponctuels sur /api/billing/stripe/webhook traite volontairement
uniquement checkout.session.completed.
Rejouer Les Webhooks Ponctuels Échoués
Quand le traitement d'un webhook ponctuel échoue à cause d'un incident transitoire, rejouez les événements échoués:
bun run billing:replay-webhooksLimite optionnelle:
bun run billing:replay-webhooks -- --limit=20Régénérer Les Artefacts Source Fumadocs
bun run docs:generateRégénérer Les Fichiers Assistants LLM
bun run docs:llm:generateLancez cette commande après une modification de content/llm/llm-source.md. Ne
modifiez pas AGENTS.md, GEMINI.md ni .github/copilot-instructions.md
manuellement.
Lancer Une Passe Docs Complète
Utilisez ceci lors de changements documentaires larges:
bun run docs:generate
bun run docs:check-links
bun run docs:check-translations
bun run docs:llm:generate
bun run docs:llm:check
bun run checkSi le changement docs touche les routes, imports ou rendu MDX, lancez aussi:
bunx tsc --noEmit
bun run buildGardez les docs anglaises canoniques. Lorsque la tâche demande les docs localisées, mettez à jour le miroir français dans la même PR.
Gérer Les Clés MCP Production
Émettre une clé MCP production pour un utilisateur:
bun run mcp:key -- issue --email [email protected] --permissions read,write,publish,adminRévoquer une clé MCP production:
bun run mcp:key -- revoke --key-id <api-key-id>Faites une rotation en émettant d'abord la clé de remplacement, en mettant à
jour le secret client, en vérifiant yayaw_status, puis en révoquant l'ancienne
clé.
Valider L'Intégrité De Documentation
bun run docs:check-links
bun run docs:check-translations
bun run docs:llm:checkSi docs:llm:check échoue, régénérez avec bun run docs:llm:generate et
revoyez le diff des fichiers assistants générés avant commit.
Vérifier L'Accès Au Code GitHub
Confirmez que
/dashboard/admin/billing-settingsactive l'accès dépôt GitHub.Confirmez la présence du dépôt, de l'ID GitHub App et de l'ID d'installation.
Confirmez que
BILLING_CODE_ACCESS_GITHUB_APP_PRIVATE_KEYexiste dans l'environnement de déploiement cible.Utilisez une organisation de test payante avec
code-access:read.Soumettez un username GitHub depuis
/dashboard/organization/code-access.Confirmez que
code_access_github_accountsenregistre l'invitation ou l'état d'accès actif.Confirmez dans GitHub que l'invitation au dépôt donne un accès lecture seule.
En staging sans GitHub App, utilisez BILLING_CODE_ACCESS_GITHUB_TOKEN
uniquement comme solution de repli temporaire explicite.
Vérifier Le Stockage Média
Confirmez que
STORAGE_PROVIDER=s3est configuré avec les clés S3/MinIO etSTORAGE_PUBLIC_BASE_URL.Téléversez une image depuis
/dashboard/content/media.Confirmez qu'une ligne
media_assetsest créée pour l'organisation active.Confirmez que l'URL publique charge.
Ouvrez l'éditeur de page et liez la ressource à un champ image.
Publiez la page et confirmez que la page publique rend la ressource choisie.
Si les miniatures sont activées pour ce type de ressource, confirmez qu'une URL de miniature est créée ou qu'un échec non bloquant de miniature est enregistré.
Vérifier Le DNS Manuel De Domaine Public
Définissez
PUBLIC_DOMAIN_PROVIDER=manual-dns.Configurez
PUBLIC_DOMAIN_CNAME_TARGETouPUBLIC_DOMAIN_IPV4_TARGETS.Ajoutez un domaine depuis les réglages d'organisation ou
yayaw_org_domain_add.Publiez le challenge TXT affiché dans le dashboard.
Pointez le hostname vers le proxy inverse.
Lancez l'action de check/vérification et confirmez que le domaine devient
verified.Ouvrez l'hôte personnalisé et confirmez que les pages publiques rendent tandis que
/dashboard,/auth,/api,/docs,/oet/ingestrestent bloqués.
Réinitialiser La Base Locale
bun run db:resetDépanner Les Problèmes De Build
Régénérez les artefacts:
bun run generate:actions
bun run docs:generateRelancez les checks:
bun run check
bunx tsc --noEmit
bun run buildDépanner Les Blocages esbuild / Drizzle
Symptômes:
bun run docs:generatene termine pasbun run db:generateoubun run db:pushreste bloqué
Actions:
Relancez la commande une fois pour confirmer la sortie de timeout des scripts safe.
Réinstallez les dépendances:
rm -rf node_modules
bun installRéessayez:
bun run docs:generate
bun run db:generate
bun run db:push