/** * Pro-Trial-Expiry-Cron * * Läuft alle 6h. Findet alle Profiles deren `pro_trial_expires_at` abgelaufen * ist und die noch auf `plan = 'pro'` stehen. * * Revoke-Logik (CONSERVATIVE-Fallback): * - Wenn `stripeSubId` IS NULL → revoke (zurück auf 'free') * - Wenn `stripeSubId` gesetzt → NICHT revoken (User hat während Trial * upgraded ODER hatte schon Stripe-Abo). Stripe-Webhook hält den State, * der Trial läuft formal aus, der Abo-Plan überdauert. * * TODO (siehe project_demographic_pro_trial_reward.md): Stripe-API-Sync * (subscription.status='active') als zusätzliche Sicherheit. Aktuell * stripeSubId-presence als Indikator (kann stale sein). Wenn das Probleme * macht: stripe.subscriptions.retrieve(subId) hinzufügen. * * Memory: project_demographic_pro_trial_reward.md */ import { consola } from "consola"; const SIX_HOURS = 6 * 60 * 60 * 1000; export default defineNitroPlugin((nitro) => { if (import.meta.dev) { consola.info("[pro-trial-cron] Skipping cron in dev mode"); return; } consola.info("[pro-trial-cron] Starting (6h interval)"); // Initial run after 60s (let server boot) const initialTimer = setTimeout(() => { runRevoke().catch(() => {}); }, 60_000); const interval = setInterval(() => { runRevoke().catch(() => {}); }, SIX_HOURS); nitro.hooks.hook("close", () => { clearTimeout(initialTimer); clearInterval(interval); }); }); async function runRevoke() { try { const db = usePrisma(); const now = new Date(); // Find expired trials still on 'pro' (or 'standard' legacy) const expired = await db.profile.findMany({ where: { proTrialExpiresAt: { lt: now, not: null }, plan: { in: ["pro", "standard"] }, }, select: { id: true, stripeSubId: true, proTrialExpiresAt: true, }, }); if (expired.length === 0) { consola.info("[pro-trial-cron] No expired trials"); return; } let revoked = 0; let kept = 0; for (const p of expired) { // CONSERVATIVE: any stripeSubId presence keeps the user on pro if (p.stripeSubId) { kept++; continue; } try { await db.profile.update({ where: { id: p.id }, data: { plan: "free" }, }); revoked++; } catch (err: any) { consola.error( `[pro-trial-cron] Failed to revoke user ${p.id}:`, err?.message ?? err, ); } } consola.success( `[pro-trial-cron] revoked ${revoked} users from trial-pro, kept ${kept} (Stripe-Abo)`, ); } catch (err: any) { consola.error("[pro-trial-cron] run failed:", err?.message ?? err); } }