01Aperçu du projet
Admister est un marché multi-vertical. Sous un même toit, il gère des petites annonces, un tableau de voitures et de pièces, de l'immobilier avec vente et location, un marché de biens avec des boutiques de vendeurs, des biens numériques, un service de coupons et un agrégateur de prix. Chacun d'eux a son propre sous-domaine, sa propre page d'accueil et sa propre idée de ce qu'est un article.
De l'extérieur, ils ressemblent à sept produits séparés. De l'intérieur, ils sont une seule application : le service est déterminé par le nom d'hôte de la requête, et tout ce qui se trouve en dessous — comptes, argent, modération, recherche, médias, notifications — est partagé. Le projet était le nôtre de bout en bout : le modèle, le moteur, l'interface et le lancement de chaque vertical.
02Contexte et le problème
La manière habituelle de lancer plusieurs marchés est de lancer plusieurs sites web. Cela fonctionne jusqu'au deuxième : maintenant, il y a deux tables d'utilisateurs, deux files d'attente de modération, deux intégrations de paiement et deux endroits où le même bug doit être corrigé deux fois — et corrigé différemment, car d'ici là, le code a dérivé.
L'extrême opposé est tout aussi mauvais. Un site avec une catégorie appelée «Voitures» ne peut pas demander le kilométrage, le moteur et la plaque comme un tableau de voitures doit le faire, et une recherche immobilière qui ne peut pas filtrer par étage et chambres n'est pas une recherche immobilière. La tâche était de garder un seul moteur sans prétendre que sept catalogues très différents sont le même catalogue.
03Objectifs du projet
- une base de code et un compte pour tous les verticaux, avec le service choisi par le nom d'hôte ;
- attributs et filtres par vertical : des dizaines de champs pour les voitures et l'immobilier, aucun d'eux n'étant entraîné dans les autres services ;
- de l'argent en lequel le propriétaire peut avoir confiance — un solde, des factures crypto, un crédit idempotent et la réconciliation des paiements bloqués;
- raisons pour lesquelles les acheteurs reviennent : recherches sauvegardées avec notifications, badges de vendeur, enchères et achats groupés;
- deux langues et quatre devises d'affichage sans dupliquer le contenu;
- une application mobile qui communique avec un backend-for-frontend plutôt que de scraper le site.
04Ce que nous avons fait
Nous avons intégré le registre de services dans la séquence de démarrage. Une demande arrive, le nom d'hôte est comparé au registre, et à partir de ce moment, l'application sait quel vertical elle est : quels modules charger, quel ensemble d'attributs utiliser, quelle page d'accueil et quel menu afficher. Le domaine nu est le tableau des petites annonces, donc l'adresse la plus courte est aussi la plus générale.
Tout ce qui n'est pas spécifique à un vertical a été écrit une fois : comptes et sessions, le solde et les paiements, l'intégration des médias, la modération, les recherches sauvegardées, les notifications, le plan du site et l'API. Ajouter le septième service consistait principalement à écrire ses attributs et sa page d'accueil — pas un autre marché.
05Sept services, sept catalogues
- Petites annonces — le tableau général : tout, d'un vélo à un canapé, gratuit à publier.
- Voitures — véhicules, plaques et pièces, avec un ensemble d'attributs dédié de plusieurs dizaines de champs et de filtres construits dessus.
- Immobilier — vente et location, son propre ensemble d'attributs, cartes et recherche par district.
- Marché — biens avec des boutiques de vendeurs : une vitrine par vendeur, stock, commandes.
- Numérique — clés, cartes-cadeaux et eSIM : biens qui sont livrés, pas expédiés.
- Offres — coupons et codes promo des magasins partenaires.
- Prix — un agrégateur de prix : le même produit à travers les magasins, comparé, avec des clics sortants comptés.
Ils partagent le compte, le solde, la file d'attente de modération et l'index de recherche — et ne partagent rien dans leurs attributs, ce qui est le but.
06Argent : un solde, factures crypto, réconciliation
Les fonctionnalités payantes — promotion, plans de magasin, biens numériques — sont payées à partir d'un solde interne, et le solde est rechargé avec des crypto-monnaies via Payora, notre propre passerelle. Le corps de la facture est construit dans exactement une fonction, car le même corps est rejoué par le cron de réconciliation sous la même clé d'idempotence : un seul champ qui diffère entre les deux reviendrait comme un conflit et laisserait le paiement en attente.
Deux détails que nous répéterions sur n'importe quelle passerelle. La facture porte la locale propre de l'acheteur tirée de sa ligne de compte, et non de la requête web — le cron n'a pas de requête et enverrait sinon tout le monde en anglais. Et elle porte une adresse de retour qui renvoie dans le compte sur le domaine nu, de sorte qu'un acheteur qui a commencé sur le vertical automobile revient connecté, et non sur une page qui lui demande de se reconnecter.
07Confiance : modération, badges, litiges
Un marché est jugé par sa pire annonce, donc la modération n'est pas un écran secondaire ici. Chaque décision — approuver, rejeter, retirer — passe par un seul gestionnaire, et « rejeter » n'est délibérément pas la même chose que « retirer » : le premier est une réponse à l'auteur avec une raison, le second retire quelque chose qui était déjà en ligne. Deux verbes, deux lettres différentes, deux états différents dans l'enregistrement.
Les vendeurs et les boutiques portent des badges qui sont gagnés, pas achetés : depuis combien de temps le compte existe, combien de transactions ont été conclues, si le téléphone et l'email sont confirmés. L'acheteur voit le même badge partout où le vendeur apparaît, car il est calculé à un seul endroit.
08Recherche, recherches enregistrées et notifications
La recherche sait dans quel secteur elle se trouve. Sur le tableau des voitures, elle propose les caractéristiques d'une voiture ; sur l'immobilier, elle propose des chambres, un étage et un quartier ; sur le tableau général, elle reste délibérément simple. Les suggestions proviennent d'un point de terminaison à part, donc le champ répond pendant que la page est encore en cours de lecture.
Une recherche peut être enregistrée — et c'est ce qui transforme un visiteur en un retour. De nouvelles correspondances arrivent sous forme de notification web, l'abonnement appartient au compte plutôt qu'à l'onglet du navigateur, et le même mécanisme porte les événements que les gens attendent réellement : une enchère sur le point de se clôturer, un achat groupé qui a atteint son seuil.
09Une application mobile avec son propre backend
L'application ne scrappe pas le site web. Elle communique avec un backend-for-frontend qui lui est propre : un petit ensemble de points de terminaison qui répondent dans les formats dont les écrans ont besoin, avec des tokens émis séparément des sessions web. Deux chemins sont ouverts sans token — les données de référence dont l'application a besoin avant que quiconque ne se connecte, et un point de terminaison de santé.
Ce point de terminaison de santé est une adresse distincte par choix. Le registre qui surveille la flotte avait l'habitude de demander le point de terminaison de référence, et celui-ci assemble chaque dictionnaire et chaque tarif — un contrôle de vivacité ne devrait pas coûter plus que le travail. Il répond également avec la version du contrat, donc un client construit pour un ancien contrat est remarqué avant que ses utilisateurs ne le remarquent.
10Sept fronts de SEO
Sept services sur un domaine signifie sept sitemaps, sept ensembles de données structurées et une très facile façon de produire des doublons. Chaque vertical publie son propre sitemap à partir du cache, les pages de listing déclarent leur propre type de données structurées, et les pages de résultats de recherche ne prétendent jamais être canoniques pour un listing.
Le côté contenu est également automatisé : un flux éditorial arrive de Astrina, la plateforme que nous avons construite exactement pour cela, et au moment où un article arrive, le cache du sitemap pour son vertical est supprimé — sinon la nouvelle page attendrait la prochaine reconstruction et personne ne saurait pourquoi elle était manquante.
11Un canal sortant
Tout ce que l'application envoie vers l'extérieur — appels API, webhooks, flux partenaires, images qu'elle récupère, mail — passe par un seul module lié à un proxy de sortie SOCKS5, avec DNS résolu également par le proxy. Le module est fail-closed : si le proxy est indisponible, la demande est bloquée plutôt que d'être silencieusement envoyée depuis l'adresse propre du serveur.
Ce n'est pas de la décoration. Un marché tire des flux partenaires et des images distantes toute la journée ; chacun de ceux-ci est une demande qui, autrement, porterait l'adresse d'origine du site à un tiers. Le mail suit le même chemin, à travers VotreTendance, donc les lettres sont signées et le nom d'hôte du serveur n'apparaît jamais dans un en-tête.
12Pile technologique
- PHP 8.3 sans framework, un mince wrapper PDO et des déclarations préparées partout ;
- MariaDB, schéma conservé sous forme de fichiers de migration numérotés plutôt que comme la mémoire de quelqu'un ;
- média stocké en dehors de la racine web et servi par un contrôleur, donc un téléchargement n'est jamais un chemin exécutable ;
- une étape de construction qui hache les actifs et n'inclut rien qui devrait être mis en cache, avec un interrupteur d'arrêt pour quand cela ne fonctionne pas correctement ;
- sortie SOCKS5 pour chaque appel sortant, mail via YourTrend SMTP ;
- Payora pour les factures crypto, Astrina pour la connexion et le contenu éditorial, Adgora pour la publicité interne.
13Le résultat
Sept services en direct sur une seule base de code, un compte et un solde communs à tous, avec des attributs et des filtres qui diffèrent autant que les catalogues. Un nouveau vertical est un ensemble d'attributs et une page d'accueil — pas un nouveau projet, pas une seconde table d'utilisateur, pas une seconde intégration de paiement.
Ce que le propriétaire obtient au jour le jour est un endroit où regarder. La modération, l'argent, les vendeurs et le contenu sont gérés depuis le panneau de contrôle partagé de l'ensemble du groupe, et le marché les expose via une API admin signée plutôt que par un second site admin à part.
14Leçons à retenir
La leçon que nous emporterions dans le prochain marché : partagez la machinerie, pas le sens. Les comptes, l'argent, la modération et la recherche sont le même problème dans chaque secteur et doivent être écrits une seule fois. Les attributs, les filtres et la forme d'une annonce sont le produit lui-même, et les forcer dans une table universelle est la façon dont les places de marché deviennent inutilisables pour tout le monde en même temps.
La deuxième leçon concerne l'argent. L'endroit où un paiement est décrit doit être une fonction unique, car quelque chose d'autre le reproduira — un cron, une nouvelle tentative, une réconciliation — et deux descriptions d'un même paiement est le moyen le moins cher de perdre de l'argent discrètement.
Si vous construisez une place de marché, un tableau de petites annonces ou une plateforme multi-sectorielle sur un seul moteur, c'est le type de travail que nous faisons de bout en bout.



