Zooterrapia
Un système de réservation complet pour une ferme thérapeutique, de la découverte des services au paiement sécurisé. Le backend Express gère un algorithme de disponibilité multi-facteurs avec des transactions isolées pour empêcher les doubles réservations. Le frontend Next.js 15 offre un parcours de réservation fluide avec intégration Stripe. Le tout est orchestré dans un monorepo Turborepo avec types partagés.
Le contexte
Un centre de médiation animale propose des séances thérapeutiques assistées par des animaux pour des publics variés : enfants, personnes âgées, personnes en situation de handicap. La gestion des rendez-vous se faisait manuellement, avec les risques d'erreurs et de doubles réservations que cela implique. Zooterrapia digitalise l'ensemble du parcours, de la découverte des services au paiement sécurisé, tout en offrant aux administrateurs un tableau de bord complet pour piloter l'activité.
L'architecture
Le projet est structuré en monorepo avec pnpm workspaces et Turborepo, composé de trois packages : frontend, backend et shared.
Le backend Express 5 suit une architecture en couches (routes → controllers → services → models). 13 modèles Sequelize définissent le schéma PostgreSQL. Le cœur de la logique métier réside dans le service de réservation, qui utilise des transactions SERIALIZABLE avec verrouillage de lignes pour garantir qu'aucun créneau ne soit réservé deux fois, même sous charge concurrente. Le système de paiement s'appuie sur les Payment Intents Stripe avec un handler de webhooks idempotent pour confirmer les paiements en temps réel.
Le frontend Next.js 15 (React 19, App Router) combine Server Components pour les pages publiques avec ISR et Client Components pour le widget de réservation multi-étapes et le dashboard admin. L'intégration Stripe Elements offre un formulaire de paiement sécurisé directement dans le parcours de réservation.
Le package shared centralise les types TypeScript, les schémas de validation Zod et les constantes, garantissant la cohérence entre frontend et backend à la compilation.
Les défis techniques
Prévention des doubles réservations. Le risque principal d'un système de réservation est le double-booking sous charge concurrente. La solution utilise des transactions PostgreSQL au niveau d'isolation SERIALIZABLE avec verrouillage de lignes via Sequelize. Un mécanisme de retry avec backoff exponentiel gère les erreurs de sérialisation de manière transparente pour l'utilisateur.
Algorithme de disponibilité multi-facteurs. Calculer les créneaux disponibles n'est pas trivial : il faut combiner les templates hebdomadaires du praticien, les exceptions ponctuelles, les dates bloquées et les réservations existantes pour chaque créneau. Le service d'availability résout cette hiérarchie en cascade et retourne les créneaux avec leur capacité restante en temps réel.
Automatisation email et suivi. Quatre jobs cron tournent en parallèle : rappels 24h avant le rendez-vous, expiration des réservations impayées, demandes de feedback post-séance et résumé quotidien Telegram pour l'administrateur. Chaque envoi est tracé dans un modèle EmailLog pour assurer l'auditabilité complète.
L'échelle du projet
- Backend : 13 modèles Sequelize, 15+ migrations, 11 controllers, transactions SERIALIZABLE, webhooks Stripe
- Frontend : Next.js 15 App Router, widget de réservation multi-étapes, dashboard admin complet, Stripe Elements
- Sécurité : JWT avec refresh tokens httpOnly, rate limiting (auth 10/15min, booking 3/min), validation Zod, Helmet
- Infrastructure : Docker multi-stage, Docker Compose 5 services, Caddy reverse proxy avec SSL auto, CI/CD GitHub Actions
L'état actuel
Le backend et le frontend sont fonctionnels avec l'ensemble du parcours de réservation, le paiement Stripe et le dashboard admin. Le système de cron jobs et d'emails automatisés est en place. Le déploiement Docker Compose avec Caddy est configuré pour la production. Les prochaines étapes sont les tests E2E Playwright et la mise en ligne.


