Documentation

Jobs / Crons

Page /admin/jobs — vue des tâches programmées (Vercel Cron, Trigger.dev, externe), endpoints à brancher.

La page /admin/jobs est un viewer minimaliste des tâches programmées du boilerplate. Volontairement simple — pas de retry queue ni d'orchestrateur built-in. Tu branches le scheduler de ton choix (Vercel Cron, Trigger.dev, GitHub Actions, etc.) sur les endpoints suivants.

Endpoints cron exposés

POST /api/cron/coupon-ending          # daily — alertes "ton code expire bientôt"
POST /api/cron/purge-deleted-accounts # hourly — hard-delete au-delà de la grace period

Tous protégés par un header Authorization: Bearer ${CRON_SECRET} — voir Rate limiting & cron auth. Le helper isAuthorizedCron() fait la comparaison constant-time.

Vercel Cron — config

Dans vercel.json :

{
  "crons": [
    { "path": "/api/cron/coupon-ending", "schedule": "0 9 * * *" },
    { "path": "/api/cron/purge-deleted-accounts", "schedule": "0 * * * *" }
  ]
}

Vercel injecte automatiquement le header bearer si tu mets CRON_SECRET dans les env vars du projet.

Trigger.dev (alternative)

Le dossier trigger/ contient un README. Si tu préfères Trigger.dev (retries, workflows, exécution longue durée), définis tes jobs là-bas et call les endpoints de l'app via fetch avec le header bearer.

Visualiser les exécutions

Pour l'instant la page /admin/jobs est un placeholder. Pour un vrai viewer :

  • Si tu utilises Vercel Cron → consulte le tab "Crons" du dashboard Vercel
  • Si tu utilises Trigger.dev → embed leur dashboard ou leur API
  • Sinon : enregistre chaque exécution dans AuditLog avec action: "cron.<nom>" et lis-le dans la page (la page system-health le fait déjà pour la ligne "Dernier cron").

Audit auto

Chaque exécution réussie devrait logger :

await logAudit({
  action: "cron.coupon_ending",
  metadata: { processed: count, errors: 0 },
});

Ça permet à /admin/system de surfacer la dernière exécution + fait l'historique des runs dans /admin/audit.

Idempotence

Les crons doivent être idempotents — Vercel peut retry. Le boilerplate respecte ça naturellement :

  • coupon-ending : check notifiedAt avant d'envoyer
  • purge-deleted-accounts : delete idempotent (skip déjà supprimé)

Si tu en ajoutes de nouveaux, garde ce principe.

On this page