Terungal is an ordering platform for Senegalese dishes — thieboudienne, yassa, maafe… — cooked to order and delivered. It is a personal project that I am building with the ambition of turning it into a professional product: it started as a single shop and became a multi-restaurant marketplace, ready to onboard restaurant owners and bill them a subscription.
This page tells the story in three parts: its design (domain split and microservices architecture), its development (code structure, security, quality and delivery) and its presentation, application by application.

18 Spring Boot microservices (Java 21), each with its own PostgreSQL database
4 BFFs and 3 Angular 22 applications — storefront, back office, console — plus a Flutter mobile app in progress
About 590 unit and integration tests, 80 architecture decisions recorded as ADRs
Designed and built with Claude Code as the development agent
Design
Starting point: a monolith that had to evolve
The project grew out of a first Spring Boot monolith: a single jar redeployed on every change, a shared data model, a failing checkout, six identified security flaws and a single automated test. Rather than patching it, I chose to redesign the platform so it could grow: several restaurants, subscriptions, an admin console and, eventually, a mobile app.
Splitting the domain (Domain-Driven Design)
The first step was a full inventory of the monolith, then a split into bounded contexts. Each context becomes an autonomous service that owns its data. They are ranked by value: the core domain gets the most care, while generic contexts rely on proven solutions.
The platform is multi-tenant: the tenant is the organisation, the scope is the restaurant. Every record and event of the business contexts carries the organisation and restaurant identifiers.
Target architecture
Applications only talk to their BFF (Backend for Frontend), the single entry point exposed behind Caddy. Services are private, share no database and collaborate through Kafka events.
One database per service: no cross-service joins, versioned Flyway migrations.
No direct calls between services: collaboration only goes through events.
One BFF per application: each front-end gets an API shaped for its screens and never sees the tokens.
Reliable events: outbox and idempotency
An event must never be lost or applied twice. Each service writes the aggregate and the message in the same transaction (transactional outbox); a relay then publishes them in order. On the consumer side, any message already processed is ignored.
Ordering as a saga
The checkout, broken in the monolith, was rebuilt as a saga orchestrated by the order service: payment, stock reservation and cart clean-up are chained through events, with compensations (cancellation, refund) when something fails.
Migrating without stopping
The migration follows the strangler pattern: the BFF routes each route either to the monolith or to the already migrated service, and the monolith's data is replicated to the services (Debezium and Kafka). Contexts were extracted in waves, from the least risky to the most central.
Every structural choice — data per service, messaging, saga, security, multi-tenancy, deployment — is recorded in an ADR (Architecture Decision Record): 80 decisions documented so far.
Development
One service, three modules: hexagonal architecture
Every microservice follows the same structure, inspired by hexagonal architecture and Clean Architecture: three Maven modules domain, application and infrastructure. Dependencies always point towards the domain, written in plain Java with no framework.
Rules checked automatically (ArchUnit): a controller only calls inbound ports, the domain depends on nothing.
Shared conventions: naming, RFC 9457 REST errors, an idempotency key on sensitive creations.
Shared modules for messaging (versioned event contracts, outbox, idempotent consumers).
Security
Identity is centralised in identity-service (OAuth2 / OIDC). Tokens never leave the BFFs: the browser only gets a session cookie, and every service re-checks the JWT and the rights on the requested resource.
Role- and scope-based access control (organisation, restaurant).
A chained audit log: every sensitive action is sealed with the hash of the previous one.
Versioned legal documents: the accepted version is stored with each order.
Front-ends
Three Angular 22 applications share a common library: the customers' storefront, the restaurants' back office and the platform console. State is managed with signals (NgRx Signals) and the UI is built with Tailwind CSS 4. A Flutter mobile app, with its own BFF, is in progress.
Quality, delivery and operations
Tests: about 590 unit and integration tests (Testcontainers) and 76 characterisation tests of the monolith.
Delivery: one Docker image and one pipeline per application; each service is deployed independently.
Environments: a lightweight setup (infrastructure in Docker) or a full one through Docker Compose profiles.
Observability: end-to-end traces (OpenTelemetry), correlated JSON logs, business metrics and alerts in Grafana.
Built with Claude Code
Terungal was designed and built with Claude Code as its development agent, from the inventory of the monolith to the Angular applications. Each migration step is driven by a prompt versioned in the repository, conventions live in CLAUDE.md files and every structural choice has its ADR. Generated code is reviewed, tested and validated before merging.
Presentation
The storefront
The storefront takes customers from choosing a dish to placing an order, and adapts to them once signed in.








The restaurant back office
Each restaurant runs its business from its back office: today's service, catalogue, offers, opening hours and its shop window.






The platform console
The console, reserved for administrators, runs the marketplace as a whole: activity, restaurant onboarding, business model, compliance and traceability.





Outcomes and next steps
From monolith to platform: one deployable application became 18 services, 4 BFFs and 3 front-ends, each delivered independently.
Reliable ordering: checkout runs through an order, payment and stock saga.
Security: the monolith's six flaws are fixed and verified.
New capabilities: multi-restaurant support, subscriptions, offers, platform console.
Next steps towards a professional product: going live and shutting down the monolith, real-time delivery tracking and the customer mobile app.
