All Projects

Terungal — place de marché de cuisine sénégalaise

Projet personnel à ambition professionnelle : une place de marché de plats sénégalais multi-restaurants, conçue en microservices (18 services Spring Boot, 4 BFF, 3 applications Angular) et développée avec Claude Code.

Terungal — place de marché de cuisine sénégalaise
JavaSpring BootAngularTypeScriptTailwind CSSPostgreSQLKafkaDockerStripeMinIOValkeyCaddyOpenTelemetryGrafanaFlutterTestcontainersClaude Code

Terungal est une plateforme de commande de plats sénégalais — thiéboudienne, yassa, maafé… — préparés à la commande et livrés. C'est un projet personnel que je mène avec l'ambition d'en faire un produit professionnel : partie d'une boutique unique, la plateforme est devenue une place de marché multi-restaurants, prête à accueillir des restaurateurs et à facturer un abonnement.

Cette page retrace le projet en trois temps : sa conception (le découpage du domaine et l'architecture microservices), son développement (la structure du code, la sécurité, la qualité et la livraison) puis sa présentation, application par application.

Page d'accueil de la boutique Terungal
Figure 1 — Page d'accueil de la boutique Terungal
  • 18 microservices Spring Boot (Java 21), chacun avec sa base PostgreSQL

  • 4 BFF et 3 applications Angular 22 — boutique, back office, console — plus une application mobile Flutter en préparation

  • Environ 590 tests unitaires et d'intégration, 80 décisions d'architecture consignées dans des ADR

  • Conçu et développé avec Claude Code comme agent de développement

Conception

Point de départ : un monolithe à faire évoluer

Le projet est né d'une première application monolithique Spring Boot : un seul jar redéployé à chaque changement, un modèle de données partagé, un checkout en échec, six failles de sécurité identifiées et un seul test automatisé. Plutôt que de corriger à la marge, j'ai choisi de reconcevoir la plateforme pour qu'elle puisse grandir : plusieurs restaurants, des abonnements, une console d'administration et, à terme, une application mobile.

Découper le domaine (Domain-Driven Design)

La première étape a été un inventaire complet du monolithe, puis un découpage en contextes délimités (bounded contexts). Chaque contexte devient un service autonome qui possède ses données. Ils sont classés selon leur valeur : le cœur de métier reçoit le plus de soin, les contextes génériques reposent sur des solutions éprouvées.

La plateforme est multi-tenant : le locataire est l'organisation, le périmètre le restaurant. Chaque donnée et chaque événement des contextes métier portent l'identifiant de l'organisation et du restaurant.

Architecture cible

Les applications ne parlent qu'à leur BFF (Backend for Frontend), seul point d'entrée exposé derrière Caddy. Les services sont privés, ne partagent aucune base et collaborent par événements Kafka.

  • Une base par service : aucune jointure entre services, migrations Flyway versionnées.

  • Pas d'appel direct entre services : la collaboration passe uniquement par des événements.

  • BFF par application : chaque front-end a une API taillée pour ses écrans et ne voit jamais les jetons.

Des événements fiables : outbox et idempotence

Un événement ne doit jamais être perdu ni appliqué deux fois. Chaque service écrit l'agrégat et le message dans la même transaction (transactional outbox) ; un relais publie ensuite dans l'ordre. Côté consommateur, chaque message déjà traité est ignoré.

La commande : une saga

Le checkout, en échec dans le monolithe, a été reconstruit comme une saga orchestrée par le service des commandes : paiement, réservation du stock et vidage du panier s'enchaînent par événements, avec des compensations (annulation, remboursement) en cas d'échec.

Migrer sans tout arrêter

La migration suit le motif strangler : le BFF route chaque route soit vers le monolithe, soit vers le service déjà migré, et les données du monolithe sont répliquées vers les services (Debezium et Kafka). Les contextes ont été extraits par vagues, du moins risqué au plus central.

Chaque choix structurant — données par service, messagerie, saga, sécurité, multi-tenancy, déploiement — est consigné dans un ADR (Architecture Decision Record) : 80 décisions documentées à ce jour.

Développement

Un service, trois modules : architecture hexagonale

Chaque microservice suit la même structure, inspirée de l'architecture hexagonale et de la Clean Architecture : trois modules Maven domain, application et infrastructure. Les dépendances pointent toujours vers le domaine, écrit en Java pur, sans framework.

  • Règles vérifiées automatiquement (ArchUnit) : un contrôleur n'appelle que des ports d'entrée, le domaine ne dépend de rien.

  • Conventions communes : nommage, erreurs REST au format RFC 9457, clé d'idempotence sur les créations sensibles.

  • Modules partagés pour la messagerie (contrats d'événements versionnés, outbox, consommateurs idempotents).

Sécurité

L'identité est centralisée dans identity-service (OAuth2 / OIDC). Les jetons ne quittent jamais les BFF : le navigateur ne reçoit qu'un cookie de session, et chaque service revérifie le JWT et les droits sur la ressource demandée.

  • Contrôle d'accès par rôles et par périmètre (organisation, restaurant).

  • Journal d'audit chaîné : chaque action sensible est scellée avec l'empreinte de la précédente.

  • Documents légaux versionnés : la version acceptée est enregistrée avec chaque commande.

Front-ends

Trois applications Angular 22 partagent une bibliothèque commune : la boutique des clients, le back office des restaurants et la console de la plateforme. L'état est géré avec les signals (NgRx Signals) et l'interface avec Tailwind CSS 4. Une application mobile Flutter, avec son propre BFF, est en préparation.

Qualité, livraison et exploitation

  • Tests : environ 590 tests unitaires et d'intégration (Testcontainers) et 76 tests de caractérisation du monolithe.

  • Livraison : une image Docker et un pipeline par application ; chaque service se déploie indépendamment.

  • Environnements : démarrage léger (infrastructure dans Docker) ou complet, par profils Docker Compose.

  • Observabilité : traces de bout en bout (OpenTelemetry), journaux JSON corrélés, métriques métier et alertes dans Grafana.

Développé avec Claude Code

Terungal a été conçu et développé avec Claude Code comme agent de développement, de l'inventaire du monolithe jusqu'aux applications Angular. Chaque étape de la migration est guidée par un prompt versionné dans le dépôt, les conventions sont fixées dans des fichiers CLAUDE.md et chaque choix structurant fait l'objet d'un ADR. Le code produit est relu, testé et validé avant intégration.

Présentation

La boutique

La boutique accompagne le client du choix du plat jusqu'à la commande, et s'adapte à lui une fois connecté.

Collections et « plats habituels » du client connecté
Figure 10 — Collections et « plats habituels » du client connecté
Catalogue : plats les plus commandés, notes, prix et commandes du mois
Figure 11 — Catalogue : plats les plus commandés, notes, prix et commandes du mois
Fiche d'un plat : note, avis et favoris
Figure 12 — Fiche d'un plat : note, avis et favoris
Fiche plat : bloc de commande — aucun débit avant la validation du paiement
Figure 13 — Fiche plat : bloc de commande — aucun débit avant la validation du paiement
Recette publiée par le restaurant : préparation, cuisson, portions, difficulté
Figure 14 — Recette publiée par le restaurant : préparation, cuisson, portions, difficulté
Place de marché : restaurants proches et ouverts maintenant
Figure 15 — Place de marché : restaurants proches et ouverts maintenant
Espace client : favoris dans tous les restaurants
Figure 16 — Espace client : favoris dans tous les restaurants
Espace client : préférences alimentaires (régimes et allergènes)
Figure 17 — Espace client : préférences alimentaires (régimes et allergènes)

Le back office des restaurants

Chaque restaurant pilote son activité depuis son back office : service du jour, catalogue, offres, horaires et vitrine de sa boutique.

Back office : l'activité du jour et l'état du stock
Figure 18 — Back office : l'activité du jour et l'état du stock
Back office : catalogue des plats, prix et stocks
Figure 19 — Back office : catalogue des plats, prix et stocks
Back office : offres, remises et codes promo
Figure 20 — Back office : offres, remises et codes promo
Back office : horaires, jours fériés et fermetures
Figure 21 — Back office : horaires, jours fériés et fermetures
Back office : collections affichées sur la boutique
Figure 22 — Back office : collections affichées sur la boutique
Back office : paramétrage de la page d'accueil avec aperçu en direct
Figure 23 — Back office : paramétrage de la page d'accueil avec aperçu en direct

La console de la plateforme

La console, réservée aux administrateurs, pilote la place de marché dans son ensemble : activité, onboarding des restaurateurs, modèle économique, conformité et traçabilité.

Console : tableau de bord — volume d'affaires, commissions, revenu récurrent
Figure 24 — Console : tableau de bord — volume d'affaires, commissions, revenu récurrent
Console : formules d'abonnement versionnées
Figure 25 — Console : formules d'abonnement versionnées
Console : documents légaux versionnés de la plateforme
Figure 26 — Console : documents légaux versionnés de la plateforme
Console : référentiels communs à tous les restaurants
Figure 27 — Console : référentiels communs à tous les restaurants
Console : journal d'audit chaîné et vérifiable
Figure 28 — Console : journal d'audit chaîné et vérifiable

Bilan et perspectives

  • Du monolithe à la plateforme : une application déployable devenue 18 services, 4 BFF et 3 front-ends, chacun livré indépendamment.

  • Commande fiabilisée : le checkout passe par une saga commande, paiement et stock.

  • Sécurité : les six failles du monolithe sont corrigées et vérifiées.

  • Nouvelles capacités : multi-restaurants, abonnements, offres, console de la plateforme.

Prochaines étapes vers un produit professionnel : la mise en production et l'arrêt du monolithe, le suivi des livraisons en temps réel et l'application mobile cliente.