Aller au contenu principal

Déploiement

Vercel (recommandé), variables d'environnement, 18 crons QStash, configuration domaine.

Voie A — Assistant guidé (recommandé pour les premiers déploiements)

Si tu n'as jamais déployé un SaaS Next.js sur Vercel + Supabase tout seul, ouvre heartco.fr/setup et suis l'assistant en 5 étapes : création des comptes, copie des clés avec validation live, génération des secrets internes, bouton Deploy pré-formé, création du compte admin. ~30 minutes, aucun terminal requis.

La suite de ce guide couvre la Voie B — déploiement à la main pour les devs qui préfèrent contrôler chaque étape.


Vercel (recommandé)

Étapes de déploiement

  1. Créer un projet Vercel et connecter le repository Git

  2. Configurer le Framework Preset : Next.js (auto-détecté)

  3. Build Command (automatique) :

    pnpm build
    
  4. Node.js Version : 22.x

  5. Configurer les variables d'environnement (voir section suivante)

  6. Déployer — Vercel lance automatiquement le build à chaque push

Build settings

Le build nécessite 7 GB de RAM (configuré dans package.json) :

{
  "build": "NODE_OPTIONS=--max-old-space-size=7168 next build"
}

Prisma sur Vercel

Le binary target rhel-openssl-3.0.x est nécessaire pour l'environnement Vercel :

generator client {
  provider      = "prisma-client-js"
  output        = "../generated/prisma"
  binaryTargets = ["native", "rhel-openssl-3.0.x"]
}

npx prisma generate est automatiquement exécuté lors du postinstall.

Variables d'environnement (production)

Obligatoires

VariableDescriptionExemple
DATABASE_URLPostgreSQL (pgBouncer)postgresql://...?pgbouncer=true
DIRECT_URLPostgreSQL (direct, migrations)postgresql://...
AUTH_SECRETSecret NextAuth (≥32 chars)openssl rand -base64 32
NEXTAUTH_URLURL de l'apphttps://app.votre-domaine.fr
NEXT_PUBLIC_APP_URLURL publiquehttps://app.votre-domaine.fr
STRIPE_SECRET_KEYClé secrète Stripesk_live_xxxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYClé publique Stripepk_live_xxxx
STRIPE_WEBHOOK_SECRETSecret webhook Stripewhsec_xxxx
RESEND_API_KEYClé API Resendre_xxxx
UPSTASH_REDIS_REST_URLURL Redis (rate limiting)https://xxxx.upstash.io
UPSTASH_REDIS_REST_TOKENToken RedisAXxxxx
TOKEN_ENCRYPTION_KEYAES-256-GCM (64 hex chars)openssl rand -hex 32
CRON_SECRETSecret des crons (≥32 chars)openssl rand -base64 32

Stripe Price IDs

Chaque plan/module nécessite ses Price IDs Stripe (monthly + annual) :

# Plans
STRIPE_PRICE_STARTER="price_xxxx"
STRIPE_PRICE_STARTER_ANNUAL="price_xxxx"
STRIPE_PRICE_CORE="price_xxxx"
STRIPE_PRICE_CORE_ANNUAL="price_xxxx"
STRIPE_PRICE_BUSINESS="price_xxxx"
STRIPE_PRICE_BUSINESS_ANNUAL="price_xxxx"
STRIPE_PRICE_ENTERPRISE="price_xxxx"
STRIPE_PRICE_ENTERPRISE_ANNUAL="price_xxxx"
 
# Utilisateur supplémentaire
STRIPE_PRICE_EXTRA_USER="price_xxxx"
STRIPE_PRICE_EXTRA_USER_ANNUAL="price_xxxx"
 
# Modules (16 × 2 = 32 variables)
STRIPE_PRICE_MODULE_DEVIS="price_xxxx"
STRIPE_PRICE_MODULE_DEVIS_ANNUAL="price_xxxx"
# ... (voir .env.example pour la liste complète)

Optionnelles (mais recommandées)

VariableDescription
MISTRAL_API_KEYCopilote IA (Mistral)
PUSHER_APP_ID / PUSHER_SECRET / NEXT_PUBLIC_PUSHER_KEYTemps réel
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRETOAuth Google
MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRETOAuth Microsoft
SUPABASE_URL / SUPABASE_SERVICE_KEYStorage Supabase
WEBHOOK_SECRETHMAC webhooks sortants
ADMIN_CHALLENGE_SECRET2FA panel admin

Crons (tâches planifiées)

HeartCo utilise 18 crons QStash définis dans apps/web/src/lib/qstash-schedules.ts et enregistrés via POST /api/admin/setup-crons (idempotent — appeler une fois après le premier déploiement).

Quotidiens (14 crons)

CronScheduleDescription
/api/cron/check-trial09:00Expiration des trials + notifs J-1
/api/cron/trial-expiry06:00Downgrade auto FREE à expiration trial
/api/cron/trial-reminder08:00Email rappel trial J-3 et J-1
/api/cron/demo-reset03:00Reset données de démo chaque nuit
/api/cron/expire-quotes00:00Expiration automatique des devis
/api/cron/recurring-invoices07:00Génération des factures récurrentes
/api/cron/calendar-reminders06:00Rappels événements calendrier J+1
/api/cron/appointment-reminders08:00Rappels rendez-vous clients
/api/cron/inactivity-checker10:00Détection inactivité + séquences re-engagement
/api/dunning/enroll11:00Auto-enroll factures en retard dans dunning
/api/dunning/execute14:00Exécution des étapes dunning en cours
/api/dunning/winback09:00Campagnes win-back factures recouvrées
/api/recouvrement/cron01:00Transitions factures SENT/PARTIALLY_PAID → OVERDUE
/api/crons/signatures-expiry02:00Expiration signatures PENDING > 7 jours

Jours ouvrés (1 cron)

CronScheduleDescription
/api/relances/cronLun-Ven 09:00Envoi des relances factures (jours ouvrés)

Hebdomadaires (2 crons)

CronScheduleDescription
/api/cron/privilege-auditLundi 02:00Audit hebdo comptes dormants
/api/crons/deals-decayLundi 04:00Décroissance probabilité deals inactifs > 30j

Mensuel (1 cron)

CronScheduleDescription
/api/cron/reset-usage1er du mois 00:00Reset mensuel compteurs freemium

Timeouts (configurés dans apps/web/vercel.json)

DuréeRoutes
30s (défaut Vercel)invoice send, webhooks Stripe/Resend
60srelances, demo-reset, dunning, recurring-invoices, privilege-audit

Configuration domaine

Architecture recommandée

votre-domaine.fr          → Landing page / marketing
app.votre-domaine.fr      → Dashboard (application SaaS)

Redirections automatiques

HeartCo gère automatiquement dans le middleware :

Domaine sourceDestination
heartco.ch / www.heartco.ch301 → heartco.fr
heartco.com301 → app.heartco.fr
app.heartco.fr/dashboard/*Autorisé (application)
heartco.fr/dashboard301 → app.heartco.fr/dashboard

CORS (app mobile)

Les origines autorisées pour l'app mobile Expo :

// Production
"heartco.fr", "heartco.com", "app.heartco.fr"
 
// Développement
"localhost", "192.168.*", "10.*", "172.*"

Méthodes : GET, POST, DELETE, OPTIONS Headers : Content-Type, Authorization, x-trpc-source

Checklist déploiement

  • Toutes les variables obligatoires sont configurées
  • Les Price IDs Stripe correspondent à l'environnement (live, pas test)
  • NEXTAUTH_URL pointe vers l'URL de production
  • NEXT_PUBLIC_APP_URL est identique
  • Le webhook Stripe est configuré pour l'URL de production
  • Le DNS pointe vers Vercel
  • SSL est activé (automatique avec Vercel)
  • Les crons fonctionnent (vérifier les logs Vercel)
  • Le seed de production est exécuté (si nécessaire)
  • Le domaine email (Resend) est vérifié

◀ Sécurité · Sommaire · Tests ▶