Accueil › Nos Projets › VenueHarbour
Un système d'exploitation complet pour restaurants, développé de zéro pour le restaurant La Mar à Marbella — couvrant les réservations clients, les plans de salle en temps réel, les commandes en cuisine, les paiements en table, le suivi de présence du personnel par reconnaissance faciale et les programmes de fidélité. Conçu pour être licencié à d'autres établissements en tant que produit SaaS.
69
Tables de Base de Données
~100
Composants Vue 3
60+
Classes de Service
15+
Cycles de Sprint
Le Défi
La Mar, un restaurant et bar à Marbella, fonctionnait avec des réservations téléphoniques déconnectées, des plannings papier et des systèmes de paiement séparés. Ils avaient besoin d'une plateforme unifiée où les clients réservent en ligne avec des retenues de carte Stripe, le personnel de cuisine travaille depuis un affichage en direct, les responsables de salle voient l'état des tables en temps réel, et toute l'opération se connecte de la réservation jusqu'à la conformité fiscale.
Aucune solution du marché ne pouvait gérer la combinaison de la loi fiscale espagnole Verifactu, les flux clients multilingues, les plans de salle en temps réel via Pusher, et l'ambition de licencier le système à d'autres établissements sous la marque VenueHarbour. Chaque composant a dû être développé de zéro — conçu sur mesure pour la façon dont La Mar opère réellement.
Ce Qui a Été Livré
Stack Technique
Backend
Frontend
Mobile
Une application Android indépendante pour le personnel offre un accès offline-first aux réservations, commandes, additions et au KDS depuis leur appareil mobile. Développée avec React Native, Expo et WatermelonDB — le delta sync maintient les données locales à jour sans téléchargement complet à chaque prise de service.
Base de Données
Temps Réel
Paiements
Biométrique
Passes
Hébergement
PDF / QR
Fonctionnalités Clés
Le personnel pointe à un kiosque tablette via son visage. Alimenté par Azure Face API avec un seuil de confiance de 0,85. De façon critique, seul un person_id est jamais stocké — aucune image biométrique brute ni embedding facial ne touche la base de données. C'est la garantie architecturale ferme : les données biométriques restent dans Azure, et notre système ne voit qu'un identifiant opaque qu'il ne peut pas inverser.
Un code PIN de secours avec hachage bcrypt et blocage après 5 tentatives garantit que l'accès n'est jamais bloqué si l'éclairage ou l'angle de la caméra provoque un échec de reconnaissance. Entièrement conforme au RGPD par conception — pas par politique — car il n'y a tout simplement rien de biométrique à violer.
Les passes d'abonnement sont émis sous forme de fichiers .pkpass natifs (Apple Wallet) et de tokens JWT Google Wallet. Le code QR intégré se régénère toutes les 60 secondes en utilisant TOTP (RFC 6238 — le même standard que les applications d'authentification à deux facteurs comme Google Authenticator).
Une capture d'écran du pass de quelqu'un d'autre est inutile 60 secondes plus tard. Les attaques de relecture sont bloquées par la table lm_pass_totp_log qui enregistre chaque scan avec un horodatage — si la même fenêtre TOTP est présentée deux fois, elle est rejetée quelle que soit la fraîcheur apparente du code.
Les responsables construisent leur disposition de tables avec un éditeur glisser-déposer. Le personnel voit une vue en direct où les couleurs des tuiles de table passent du rouge → vert à mesure que les tickets KDS sont complétés — donnant un pouls visuel de l'occupation de chaque table et de l'avancement du repas. Alimenté par les canaux privés Pusher, mis à jour en quelques millisecondes après une action en cuisine.
Les commandes de l'application serveur apparaissent instantanément sur le KDS. Un cycle de vie en 4 états (nouveau → en préparation → prêt → complété) avec protection de concurrence par comparaison et échange garantit que deux membres du personnel de cuisine ne peuvent pas accidentellement modifier le même ticket simultanément. Une file d'attente hors ligne basée sur Dexie.js gère les interruptions réseau sans perdre une seule commande.
Les réservations capturent une retenue de carte, pas un débit immédiat. La retenue est libérée à l'annulation ou capturée à l'arrivée. Chaque transaction UE applique la 3D Secure. Les clés d'idempotence (lm_pi_{booking_id}_{action}) empêchent les doubles débits même si le webhook Stripe se déclenche deux fois. Les retenues approchant la limite de 7 jours sont automatiquement ré-autorisées via WP Cron.
Chaque vente écrit un enregistrement immuable dans lm_fiscal_records avec un hash SHA-256 chaîné à l'entrée précédente — satisfaisant les exigences Verifactu de l'AEAT espagnole. Le mode S0 (hash uniquement) est en production. La transmission SOAP S1 à l'AEAT est complètement développée, en attente du certificat mTLS de l'autorité fiscale.
Profils clients complets : historique complet des réservations, préférences alimentaires et allergies, statut VIP, notes internes du personnel, étiquettes et solde de fidélité. Les emails NPS post-visite s'envoient automatiquement 24 heures après l'arrivée. Une réponse 4 étoiles ou plus génère automatiquement une invitation vers Google Reviews — convertissant les clients satisfaits en avis publics sans suivi manuel.
Un registre de fidélité immuable en ajout seul enregistre chaque événement d'accumulation et d'utilisation — les lignes ne sont jamais mises à jour, uniquement insérées. SELECT FOR UPDATE dans chaque transaction d'utilisation empêche les requêtes concurrentes de créer des soldes négatifs — l'équivalent au niveau base de données d'un mutex. Les taux d'accumulation sont configurables par établissement, découplés du flux de réservation via les hooks d'action WordPress.
Architecture du Système
Guest browser → Cloudflare (CDN + DDoS + SSL)
→ Google Cloud VM (Nginx + PHP 8.2)
→ WordPress MU-plugin loader (lamar-loader.php)
→ 60+ Service Classes → $wpdb->prepare()
→ MySQL VM (dedicated, 10.154.0.11)
// Vue 3 front-end layer
Vue 3 AJAX → admin-ajax.php
→ check_ajax_referer()
→ Service class
→ MySQL
// Real-time layer
Pusher private channels
→ Floor plan · KDS · Checks · Messaging
// Payment layer
Stripe → SCA/3DS holds → Webhooks
→ Booking lifecycle state machine
// Biometric layer
Azure Face API → person_id only
→ lm_staff_faces → clock_events
// Wallet pass layer
Apple Wallet (.pkpass)
Google Wallet JWT
→ TOTP (60s rotating QR)
→ lm_pass_totp_log (replay prevention)
Décisions d'Ingénierie
Aucune donnée biométrique brute stockée
Uniquement le person_id d'Azure Face API — conformité RGPD par architecture, pas par politique. Il n'y a rien de biométrique à violer.
Pusher fire-and-forget via wp_remote_post
Non-bloquant — les événements Pusher sont envoyés sans attendre de réponse, ainsi les mises à jour en temps réel n'ajoutent aucune latence à la requête qui les a déclenchées.
SELECT FOR UPDATE sur tous les rachats de fidélité
Mutex au niveau de la base de données — pas un verrou applicatif. Les requêtes de rachat concurrentes sont mises en file d'attente au niveau de la ligne ; aucune condition de course ne peut créer un solde de fidélité négatif.
Les passes TOTP utilisent RFC 6238
Le même standard que Google Authenticator et Authy — un algorithme éprouvé pour les mots de passe à usage unique basés sur le temps avec une solide protection contre la relecture.
Clés d'idempotence Stripe sur chaque mutation
Retry de webhook sécurisé par conception. Si Stripe déclenche un webhook deux fois en raison d'un délai d'attente, le second appel est rejeté au niveau de l'API — le débit n'a jamais lieu deux fois.
MU-plugins PHP comme framework applicatif
WordPress est la couche d'infrastructure — base de données, authentification, cron, administration. Les 54 classes de service constituent l'application. Aucune activation de plugin n'est requise ; le système se charge inconditionnellement au démarrage.
L'Échelle en un Coup d'Œil
Une application PHP de véritable grande envergure — pas un thème avec quelques plugins par-dessus.
69
Tables de Base de Données
2,400+
Clés de Traduction
90+
Migrations de BD
5
Langues Clients (EN/ES/FR/DE/NL)