Hajz logo
Client
Hajz

Ingénierie de marketplace de réservation — trois verticales, un modèle de réservation.

Une marketplace de réservation trois-côtés conçue comme un seul domaine de réservation rendu sur des clients consommateur, opérateur et plateforme. Trois verticales de réservation catégoriquement différentes — nuits d'hôtel, créneaux horaires, location d'actifs datés — unifiées sous un seul modèle de réservation avec une discipline stricte de locale, transitions d'état et réconciliation financière. Ingénieré de zéro à la production.

10 mois · 5 ingénieursLivré 2025
Hajz — Ingénierie de marketplace de réservation — trois verticales, un modèle de réservation.
  • 3
    Verticales sur un modèle de réservation
  • 3
    Rôles clients (consommateur · opérateur · plateforme)
  • Tri
    Matrice locale RTL + LTR complète
  • Live
    Déploiement production, premier sur le marché
Brief d'ingénierie

Le problème cadré comme ingénierie.

Une marketplace de réservation n'est pas un catalogue avec un checkout. C'est un système de réservation dont la correction est jugée à deux moments — au moment de la confirmation de réservation, et au moment où le consommateur arrive physiquement. Entre ces deux moments, l'inventaire doit être tenu, communiqué à l'opérateur, récupéré à l'annulation, et réconcilié contre l'argent qui a bougé. Chacune de ces transitions est adversariale : les consommateurs abandonnent, les opérateurs manquent les notifications, les réseaux coupent au milieu d'un webhook.

La discipline d'ingénierie ici est les machines à états de réservation sous trois sémantiques verticales hétérogènes et trois rôles clients. Les hôtels réservent des nuits. Les restaurants réservent des créneaux horaires. Les locations réservent des actifs datés avec événements de pickup et de return. Chaque verticale a sa propre topologie de disponibilité, sa propre surface d'annulation et ses propres modes d'échec — mais le domaine de réservation doit être un modèle pour que la plateforme soit opérable comme un système.

La position de Symloop depuis la revue d'architecture : unifier la machine à états de réservation, isoler les règles spécifiques à chaque verticale derrière une interface propre, et ne jamais laisser la divergence verticale s'écouler dans la console opérateur ou le path de réconciliation financière.

Ce que nous avons construit

Un système de réservation. Trois rôles clients.

Client consommateur — une surface de recherche-et-réservation où le flow de réservation est vertical-conscient mais le langage de domaine en dessous est identique à travers les verticales. Les consommateurs voient trois expériences de réservation catégoriquement différentes parce que l'ergonomie est différente ; la réservation sous-jacente, la confirmation sous-jacente et le path d'annulation sous-jacent sont un seul code path. Forte discipline locale : chaque date, devise, nombre et rendu de fuseau horaire est locale-owned, jamais ad-hoc.

Client opérateur — une console role-scoped pour le côté offre. Calendriers de disponibilité, règles de prix, contenu de listing et réservations entrantes sont des objets de première classe. Les opérateurs ne voient que les verticales qu'ils possèdent. La console est ingénierée pour des opérateurs non-techniques travaillant sous pression temporelle — un profil de performance et de surface d'erreur différent du client consommateur, traité comme un contexte de rendu séparé contre le même domaine.

Client plateforme — la console d'opérations de plateforme pour onboarder les fournisseurs, modérer les listings, résoudre les disputes et générer les rapports de réconciliation. Le rôle plateforme ne touche jamais les write paths consommateur ou opérateur — il lit l'historique de réservation et n'écrit que modération et configuration. Cette frontière est appliquée au niveau service, pas au niveau UI.

Domaine de réservation — une seule machine à états avec des transitions bien définies : inquiry → held → confirmed → fulfilled ou cancelled ou refunded. Chaque transition émet un événement que le pipeline de réconciliation financière et le pipeline de notification consomment indépendamment. Aucun code métier n'est autorisé à écrire l'état de réservation par mutation directe ; les transitions passent par l'interface de domaine.

Abstraction de paiement — une interface de passerelle de paiement qui isole le domaine de tout processeur spécifique. La plateforme parle à un contrat de paiement interne ; les processeurs concrets vivent derrière un adaptateur. Changer de processeur — ou en ajouter un second pour un nouveau marché — ne touche pas la logique de réservation.

Abstraction de notification — une interface de messagerie sortante sur le même pattern : le domaine émet des événements, la couche de notification décide du canal de livraison (email, SMS, in-app) et du format. Le domaine ne sait pas comment une confirmation atteint un consommateur ; il sait seulement qu'une a été confirmée.

Principes d'architecture

Centrée domaine, isolée vendor, locale-complète.

Domaine de réservation unique. Un agrégat, une machine à états, un audit trail. Le comportement spécifique à chaque verticale (nombre de nuits vs. créneau horaire vs. pickup/return) vit dans des objets de politique qui implémentent une interface de réservation commune, pas dans des codebases parallèles. C'est la décision centrale qui rend la marketplace opérable.

Frontières de rôle au niveau service. Les code paths consommateur, opérateur et plateforme partagent les mêmes données mais pas la même capacité d'écriture. L'autorisation est appliquée au niveau service — l'UI ne décide pas ce qu'un utilisateur peut faire ; elle découvre ce que le service permet. Cela garde le modèle de confiance intact même quand l'UI change.

Contrat de paiement processor-agnostic. Le domaine de réservation émet des événements de mouvement de fonds contre un contrat interne. Le processeur que le marché requiert s'assied derrière ce contrat comme un adaptateur. L'expansion régionale ne signifie pas réécrire le moteur de réservation ; cela signifie implémenter un adaptateur.

Locale comme citoyen de première classe. Arabe RTL, français LTR, anglais LTR — l'application n'est pas un codebase anglais traduit. L'information de locale coule à travers chaque couche : format, calendrier, devise, fuseau horaire, tri, validation. Aucune surface du produit n'affiche un artefact locale-incorrect.

Surface SEO statique, surface de réservation dynamique. Les pages publiques sont générées statiquement au build time pour la correction SEO et la livraison edge. Le flow de réservation est dynamique, authentifié et isolé du pipeline SEO. Un crawler de moteur de recherche et un consommateur payant ne concurrencent jamais pour les mêmes ressources.

Infrastructures read et write séparées. Les reads consommateur, opérateur et plateforme scalent sur des plans différents. Les writes de réservation passent par un contrat single-writer pour que les transitions d'état restent déterministes sous charge concurrente.

Problèmes d'ingénierie qui méritent documentation

Ce qui a rendu ça difficile, et comment nous l'avons résolu.

  • 01

    Unifier trois sémantiques de réservation sans les laisser fuir

    Une réservation d'hôtel et une réservation de restaurant ressemblent au même objet de loin et sont des objets différents de près. La tentation est de construire trois modèles de réservation et de les coller ensemble dans l'UI. Cela produit trois codebases divergents et un path de réconciliation financière que personne ne fait confiance. Nous avons construit un agrégat de réservation avec des objets de politique spécifiques aux verticales — une politique de réservation hôtel, une politique restaurant, une politique location — toutes implémentant la même interface. La logique de domaine est vertical-aveugle. Le rendu est vertical-spécifique. La réconciliation est single-source.

  • 02

    Transitions d'état sous charge de réservation concurrente

    Deux consommateurs peuvent essayer de tenir la dernière chambre disponible à la même milliseconde. Les transitions d'état à trois côtés sont plus difficiles : un consommateur initie, l'opérateur confirme, un processeur de paiement acquitte, et le système doit accepter ou rejeter toute la séquence comme une transition. Nous utilisons la sémantique single-writer à la frontière de réservation, un event log append-only pour chaque changement d'état, et des clés idempotentes sur chaque side-effect entrant.

  • 03

    Correction locale à chaque couche, pas juste traduction

    L'arabe RTL n'est pas une feature de traduction — c'est une préoccupation de layout, calendrier et formatage numérique qui touche chaque path de rendu. Les créneaux horaires de restaurant doivent s'afficher dans une forme locale-correcte 12 ou 24 heures. Les séjours d'hôtel doivent rendre dans le calendrier que le consommateur reconnaît. La devise doit formater avec le séparateur de milliers que la locale attend. Nous avons fait de la locale un paramètre explicite sur chaque appel de format.

  • 04

    Discipline adaptateur sur paiement et messaging

    La plateforme doit régler l'argent et envoyer des notifications. La tentation est de câbler un processeur et un vendor messaging spécifiques directement dans le code de réservation parce que c'est plus rapide au jour 1. Au jour 300, quand le marché change ou le vendor échoue, le coût de ce raccourci est une réécriture. Nous avons mis un adaptateur de paiement et un adaptateur de notification derrière des contrats internes stricts dès le premier commit.

Résultats

Ce qui a tourné en production, et ce que ça a changé.

  • 01

    Trois verticales de réservation — nuits, créneaux horaires, actifs datés — tournant contre un seul domaine de réservation sans dérive de comportement observable entre elles.

  • 02

    Trois rôles clients (consommateur, opérateur, plateforme) opérant sur une autorisation au niveau service sans path de fuite de privilège entre eux.

  • 03

    Surface produit trilingue complète avec discipline locale appliquée à chaque couche de rendu — aucun défaut de traduction partielle, aucun défaut de direction de layout.

  • 04

    Intégrations paiement et messaging derrière des contrats internes pour que l'expansion régionale ou le remplacement de vendor soit un changement d'adaptateur, pas une réécriture centrale.

  • 05

    Surface SEO statique déployée à l'edge avec un plan de réservation dynamique séparé — le système de réservation n'est jamais contendu par le trafic de crawl des moteurs de recherche.

  • 06

    Première plateforme de réservation intégrée opérationnelle sur le marché — une catégorie de produit qui n'existait pas avant ce système.

Stack technique
Runtime serveur typéFramework frontend typéBase relationnelleEvent log pour historiqueSurface SEO edge-deliveredService layer role-scopedPaiement isolé par adaptateurMessaging isolé par adaptateurSystème de layout RTL complet
Services d'ingénierie appliqués sur ce projet
FAQ d'ingénierie

Ce que les acheteurs techniques et fondateurs nous demandent.

01Pourquoi un seul domaine de réservation au lieu d'un par verticale ?+

Parce qu'une marketplace qui tourne trois modèles de réservation parallèles tourne aussi trois systèmes de réconciliation parallèles, trois paths d'annulation parallèles et trois consoles opérationnelles parallèles. Cette forme est indistinguable de trois produits séparés qui se trouvent partager un logo. Nous construisons un domaine de réservation et poussons les différences verticales vers des objets de politique derrière une interface stable — la plateforme reste opérable comme un système et le trail financier reste single-source.

02Comment gérez-vous le risque de dépendre d'un seul processeur de paiement ?+

Nous ne dépendons d'aucun processeur spécifique. Le domaine de réservation parle à un contrat de paiement interne. Le processeur que le marché requiert s'assied derrière ce contrat comme un adaptateur. Changer de processeurs — ou en ajouter un second pour un nouveau pays — est un changement niveau adaptateur, pas une réécriture centrale.

03Comment la plateforme est-elle défendable sous charge de réservation concurrente ?+

Sémantique single-writer à la frontière de réservation, event log append-only pour les transitions d'état, clés idempotentes sur chaque side-effect entrant. Deux consommateurs qui courent pour le dernier créneau disponible produisent exactement une réservation confirmée et exactement un rejet — jamais deux holds, jamais deux charges, jamais une ghost booking.

04Le support de locale s'étend-il au-delà de la traduction ?+

Oui. L'arabe RTL est une discipline de layout et formatage qui touche chaque path de rendu — calendrier, formatage numérique, devise, fuseau horaire, tri, rendu d'erreur de validation. Nous traitons la locale comme un paramètre de première classe sur chaque appel de format, pas un toggle global.

05Cette architecture peut-elle se transférer à d'autres marketplaces ou verticales ?+

Oui. La forme d'ingénierie — un domaine de réservation, trois rôles clients, services externes isolés par adaptateur, réconciliation event-driven, rendu locale-first — est comment nous construisons des marketplaces multi-vendors à travers toute verticale où un opérateur est matché avec un consommateur sous un contrat time-or-asset-contraint.

Vous construisez une marketplace qui doit rester correcte ?

Symloop ingénierie les marketplaces de réservation et plateformes multi-côtés où la correction, la discipline locale et l'indépendance vendor sont des décisions de design de première classe, pas des afterthoughts d'intégration.