Cliquez sur chaque etape pour voir les details
Reservation
Le client reserve un rendez-vous avec sa carte enregistree.
• La carte est validee via validateCustomerPaymentMethod
• Si RDV dans < 4 jours : pre-autorisation immediate via preauthorizePayment
• Si RDV dans > 4 jours : pre-autorisation differee par seven-days-preauthorization
• confirmed_on est set immediatement — plus de confirmation differee
• Email de confirmation envoye au client et au therapeute
7 jours avant — Pre-autorisation
Le cron seven-days-preauthorization cree le PaymentIntent si pas encore fait.
• Verifie que le client n'est pas bloque
• Verifie qu'il a une carte valide
• Cree un PaymentIntent en mode capture_method: manual
• Email de confirmation pre-autorisation envoye
24h avant — Rappel
Email de rappel envoye automatiquement au client.
• Envoie un rappel pour tous les RDV dans les 24 prochaines heures
• Meme email pour les deux flows (carte et sans carte)
• Plus aucune logique d'auto-confirmation
Jour J — Therapeute complete le RDV
Le therapeute clique "Completer" → paiement capture.
• Capture le PaymentIntent via Stripe
• Set capture_on, amount_received, balance_tx_id
• Email de recu envoye au client
• Le webhook balance.available distribuera les fonds plus tard
Distribution des fonds
stripe-balance-transfert distribue : therapeute + centre + commission referent.
• Calcule le % therapeute selon son plan/tier
• Transfere la part therapeute via Stripe Connect
• Accumule la part Centre Progression
• Envoie la commission referent si applicable
• Email de recu au therapeute
Cliquez sur chaque etape pour voir les details
Reservation sans carte
Le client reserve sans carte. Le RDV est confirme immediatement.
• validateCustomerPaymentMethod detecte "no_card" → customerHasCard = false
• Aucune pre-autorisation, aucun PaymentIntent
• confirmed_on set immediatement
• Email de confirmation standard envoye (meme que flow carte)
• Le lien de paiement n'est PAS envoye a la reservation
7 jours avant — Skip
seven-days-preauthorization ignore ce client (pas de carte).
• Le guard verifie les payment methods Stripe → skip si aucune carte
• Aucun echec de paiement enregistre, aucune annulation
24h avant — Rappel
Email de rappel identique au flow carte.
Jour J — Check-in par le therapeute
Le therapeute effectue le check-in. C'est le point d'entree obligatoire.
Le therapeute choisit parmi 3 options. Chaque option a un ecran de confirmation.
Si pas paye apres 48h
Le cron payment-deadline-checker bloque le client.
• Cherche les RDV avec status = completed_pending_payment et payment_deadline_at < now et capture_on IS NULL
• Set booking_blocked_reason = blocked_until_payment_completed
• Email de blocage envoye au client
• Le client ne peut plus reserver tant que la dette n'est pas reglee
Client paie via le lien
Le webhook Stripe confirme et nettoie le statut.
• Lie le PaymentIntent a l'appointment
• Enregistre amount_received, capture_on, balance_tx_id
• Clear status = NULL
• Debloque le client si blocked_until_payment_completed
• Distribution des fonds via balance.available ensuite
Client avec carte
- Le therapeute clique "Absence non justifiee"
- Le paiement est capture a 100% (montant total)
- Email de recu no-show envoye au client
- Distribution normale des fonds
Client sans carte
- Le therapeute clique "Absence non justifiee"
- Aucun paiement capture (pas de carte)
- Incrementa no_show_count
- Comportement selon le compteur ↓
1er no-show — Avertissement
Premier avertissement, pas de blocage.
• appointments.status = no_show_unpaid_first_visit
• Aucun email envoye
• Le client peut toujours reserver
• Badge dans le dashboard : "Absence (1er avertissement)"
2e no-show — Compte bloque
Le compte est bloque jusqu'a l'ajout d'une carte.
• booking_blocked_reason = blocked_until_card_added
• Email sendAddCardToUnblockEmail envoye avec lien vers /customer/add-card
• Le client ne peut plus reserver
• Badge : "Absence — Compte bloque"
Client ajoute une carte
Le client visite /customer/add-card et ajoute sa carte.
• Cree un SetupIntent (aucun montant preleve)
• Apres confirmation → booking_blocked_reason = NULL
• booking_unblocked_at = now()
• Le client redevient un client standard avec carte
• Les regles de no-show classiques s'appliquent desormais
Quand utiliser ?
Le client a paye en dehors du systeme (cash, virement, etc.).
• Le RDV passe en completed_pending_payment
• Le therapeute contacte l'admin pour valider
Admin ouvre le dashboard
Le bouton "Marquer comme payee manuellement" apparait dans les details du RDV.
• Jamais visible pour les therapeutes ou clients
• Bouton ambre dans le footer du modal de details
Raison obligatoire
L'admin doit fournir une raison avant de confirmer.
• La raison est loggee dans appointment_manual_overrides
• Avec admin_id et overridden_at
Resultat
Le RDV est marque comme complete, le client est debloque si necessaire.
• capture_on = now()
• Si le client etait bloque pour blocked_until_payment_completed → debloque
• Row inseree dans appointment_manual_overrides pour l'audit
Nouvelles colonnes DB
- appointments.status — completed_pending_payment, no_show_unpaid_first_visit
- appointments.payment_deadline_at — deadline 48h
- customers.booking_blocked_reason — blocked_until_card_added, blocked_until_payment_completed
- customers.booking_unblocked_at — timestamp deblocage
- customers.no_show_count — compteur no-shows
Nouvelle table
- appointment_manual_overrides
- id, appointment_id, admin_id, reason, overridden_at
- Log d'audit pour chaque override admin
Edge Functions modifiees
- appointments-background-tasks — Rappel uniquement, plus d'auto-confirm
- seven-days-preauthorization — Guards bloques/sans carte
- stripe-balance-transfert — Handler checkout.session.completed + guards distribution
Nouvelle Edge Function
- payment-deadline-checker — Cron toutes les 30 min
- Bloque les clients qui n'ont pas paye apres 48h
- Envoie l'email de blocage
Emails Postmark
- payment-link — Lien paiement post check-in
- payment-pending-48h — Paiement differe avec deadline
- account-blocked-payment — Compte bloque (paiement en retard)
- add-card-to-unblock — Ajouter carte apres no-shows
Nouvelles pages
- /customer/add-card — Ajout carte via Stripe Elements
- /api/therapists/appointments/checkin — Check-in API
- /api/therapists/appointments/noshow-cardless — No-show sans carte
- /api/therapists/appointments/payment-link — Generer lien paiement
- /api/admin/appointments/[id]/manual-override — Override admin
- /api/customers/add-card/* — SetupIntent + confirm
Webhooks Stripe requis
- payment_intent.succeeded — Capture paiement (existant)
- balance.available — Distribution fonds (existant)
- checkout.session.completed — Confirmation paiement Checkout (nouveau V2)