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 periodTous 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
AuditLogavecaction: "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: checknotifiedAtavant d'envoyerpurge-deleted-accounts: delete idempotent (skip déjà supprimé)
Si tu en ajoutes de nouveaux, garde ce principe.