Yayaw
Documentation

Procédures opérationnelles

Runbooks d'exploitation pour les tâches de maintenance courantes.

Régénérer Les Actions DB

bun run generate:actions

Lancez 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.

  1. Pointez les enregistrements DNS apex vers l'ingress Coolify/reverse proxy auto-hébergé et vérifiez le TLS de yayaw.app.

  2. Configurez www.yayaw.app sur le reverse proxy pour rediriger vers yayaw.app avec le statut 308.

  3. Gardez les domaines .eu retirés uniquement comme redirections du reverse proxy avec le statut 308: routez yayaw.eu et www.yayaw.eu vers yayaw.app. Les projets compagnons doivent suivre le même modèle, par exemple table.yayaw.eu vers table.yayaw.app.

  4. Définissez les variables d'environnement production:

NEXT_PUBLIC_BASE_URL=https://yayaw.app
BETTER_AUTH_TRUSTED_ORIGINS=https://*.yayaw.app
  1. Gardez une branche Git durable preview, routez preview.yayaw.app vers l'application Coolify adossée à cette branche, puis définissez le NEXT_PUBLIC_BASE_URL de prévisualisation:

NEXT_PUBLIC_BASE_URL=https://preview.yayaw.app
  1. Ne gardez pas d'anciens hôtes de prévisualisation comme domaines actifs après vérification de preview.yayaw.app.

  2. Redéployez les applications Coolify production et prévisualisation afin que les builds reçoivent l'URL publique de base.

  3. 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é

  1. 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-host
  1. Lancez 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 migrate
  1. Démarrez ou mettez à jour le runtime:

docker compose --env-file .env.self-host -f docker-compose.self-host.yml up --build -d
  1. Confirmez que Caddy atteint l'app et que les en-têtes Host/X-Forwarded-* sont préservés en ouvrant le DEPLOYMENT_URL configuré.

  2. Téléversez une ressource média et confirmez qu'elle est servie depuis le STORAGE_PUBLIC_BASE_URL configuré.

  3. Confirmez que bun run worker:page-ai tourne via le service Compose worker lorsque PAGE_AI_QUEUE_DRIVER=db-worker.

  4. 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.

  1. 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.ts

La 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.

  1. Juste avant la bascule, créez un nouveau snapshot Postgres ou pg_dump et prouvez qu'il peut être restauré. Notez les tags immuables des images app et worker à utiliser pour le rollback.

  2. 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 service app est une indisponibilité plus large mais acceptable. Ne définissez pas encore l'attestation.

  3. 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 un 2xx Better Auth ou un 4xx de validation:

curl --include --request POST \
  --header 'content-type: application/json' \
  --data '{}' \
  https://yayaw.app/api/auth/sign-in/email
  1. Uniquement après vérification de la sauvegarde et du blocage externe, définissez BETTER_AUTH_17_WRITES_PAUSED=true sur 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 migrate

Pour 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

  1. Modifiez src/lib/scripts/seed.ts.

  2. Appliquez le seed:

bun run seed
  1. Relancez les checks applicatifs:

bun run check
bunx tsc --noEmit
bun run build

Retirer 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 :

  1. Inventoriez uniquement les pages globales dont le chemin est /table/docs ou commence par /table/docs/. Conservez les pages marketing /table et de démonstration /table/example.

  2. Vérifiez la publication de chaque destination sous /en/docs/table et /fr/docs/table, puis la redirection de chaque ancienne adresse.

  3. 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.

  4. Archivez la page relue avec yayaw_pages_archive, d’abord avec dryRun, puis avec son expectedRevisionId exact, confirm: true et un motif. L’archivage conserve l’historique immuable des révisions.

  5. 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

  1. Webhook du plugin Better Auth Stripe:

stripe listen --forward-to https://<staging-domain>/api/auth/stripe/webhook
  1. Webhook ponctuel custom:

stripe listen --forward-to https://<staging-domain>/api/billing/stripe/webhook
  1. Dé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.paid

invoice.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-webhooks

Limite optionnelle:

bun run billing:replay-webhooks -- --limit=20

Régénérer Les Artefacts Source Fumadocs

bun run docs:generate

Régénérer Les Fichiers Assistants LLM

bun run docs:llm:generate

Lancez 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 check

Si le changement docs touche les routes, imports ou rendu MDX, lancez aussi:

bunx tsc --noEmit
bun run build

Gardez 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,admin

Ré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:check

Si 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

  1. Confirmez que /dashboard/admin/billing-settings active l'accès dépôt GitHub.

  2. Confirmez la présence du dépôt, de l'ID GitHub App et de l'ID d'installation.

  3. Confirmez que BILLING_CODE_ACCESS_GITHUB_APP_PRIVATE_KEY existe dans l'environnement de déploiement cible.

  4. Utilisez une organisation de test payante avec code-access:read.

  5. Soumettez un username GitHub depuis /dashboard/organization/code-access.

  6. Confirmez que code_access_github_accounts enregistre l'invitation ou l'état d'accès actif.

  7. 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

  1. Confirmez que STORAGE_PROVIDER=s3 est configuré avec les clés S3/MinIO et STORAGE_PUBLIC_BASE_URL.

  2. Téléversez une image depuis /dashboard/content/media.

  3. Confirmez qu'une ligne media_assets est créée pour l'organisation active.

  4. Confirmez que l'URL publique charge.

  5. Ouvrez l'éditeur de page et liez la ressource à un champ image.

  6. Publiez la page et confirmez que la page publique rend la ressource choisie.

  7. 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

  1. Définissez PUBLIC_DOMAIN_PROVIDER=manual-dns.

  2. Configurez PUBLIC_DOMAIN_CNAME_TARGET ou PUBLIC_DOMAIN_IPV4_TARGETS.

  3. Ajoutez un domaine depuis les réglages d'organisation ou yayaw_org_domain_add.

  4. Publiez le challenge TXT affiché dans le dashboard.

  5. Pointez le hostname vers le proxy inverse.

  6. Lancez l'action de check/vérification et confirmez que le domaine devient verified.

  7. Ouvrez l'hôte personnalisé et confirmez que les pages publiques rendent tandis que /dashboard, /auth, /api, /docs, /o et /ingest restent bloqués.

Réinitialiser La Base Locale

bun run db:reset

Dépanner Les Problèmes De Build

  1. Régénérez les artefacts:

bun run generate:actions
bun run docs:generate
  1. Relancez les checks:

bun run check
bunx tsc --noEmit
bun run build

Dépanner Les Blocages esbuild / Drizzle

Symptômes:

  • bun run docs:generate ne termine pas

  • bun run db:generate ou bun run db:push reste bloqué

Actions:

  1. Relancez la commande une fois pour confirmer la sortie de timeout des scripts safe.

  2. Réinstallez les dépendances:

rm -rf node_modules
bun install
  1. Réessayez:

bun run docs:generate
bun run db:generate
bun run db:push