Multi-Tenant POS Platform for Restaurants (MENA).
The platform is a multi-tenant POS SaaS that any restaurant operator can sign up to. Each tenant gets its own SQL Server database, its own Keycloak realm for federated identity, and runs the hierarchy most regional groups actually use: a parent group, one or more restaurant concepts, and stores under each concept.
The backend is a modular monolith on .NET split into eight modules: Sales, Stores, Identity, Members, Menus, Configuration, Communication, and Tenancy. Each module owns its own domain, application, infrastructure, and presentation layers. There are no direct cross-module calls. Modules talk through integration events for state changes and integration commands for request and response. The whole platform follows Clean Architecture and DDD with Result<T> for business failures instead of exceptions, EF projections that have to be SQL-translatable by convention, and architecture tests that block the wrong dependency direction at build time.
The piece I’m proudest of is the tenant onboarding saga. Adding a new tenant kicks off a twelve-step orchestration: provision the custom domain, create the parent group and concept aggregates, loop over every concept’s stores and licenses, create the Keycloak realm and admin role and admin user, create the SQL database, queue a migration job, run EF Core migrations for every module plus a DbUp baseline through a KEDA-scaled container that scales from zero to one only when there’s work to do, then publish a TenantCreatedEvent that fans out to every module so it can seed its own reference data. If any step fails, the message lands in a dead-letter queue. We inspect, fix the root cause, re-publish the trigger event, and the saga resumes from that step. Adding a new tenant went from several days of manual setup to a single automated workflow.
Multi-tenancy is enforced at two layers. Every tenant runs in its own SQL Server database, so backup, restore, and per-tenant compliance is a database-level concern instead of a row-level one. Inside each tenant database, every module owns its schema, and every table also carries a TenantId column with a global query filter applied at the DbContext level as defense in depth. The HTTP request pipeline resolves the tenant from a JWT claim in TenancyMiddleware, picks the right connection string, and any background service explicitly restores tenant context per tenant before doing work. Cross-module data is never queried directly. Modules that need data from another module project a read-only copy into their own database, kept in sync by integration event handlers that translate to internal MediatR commands wrapped in transactions.
Staff verification runs over WhatsApp instead of SMS because that’s what restaurant teams in the region actually use day to day. The Communication module wraps the Meta WhatsApp Business Cloud API behind an integration command, so any module that needs to send an OTP just publishes a message and gets the result back. Order updates and dashboard refreshes flow through tenant-aware SignalR hubs with strongly-typed clients, grouped by store and terminal so no real-time message ever crosses a tenant boundary.
The frontend is a pnpm and Turbo monorepo with three apps (the POS terminal, the back office for restaurant operators, and an internal sysadmin panel) sharing packages for UI, SignalR, auth, layout, theme, routes, shared queries, and tooling configs. The whole thing is React 19 with TypeScript and Vite, with DevExtreme on the data-heavy back office screens. Husky and lint-staged enforce formatting and linting on every commit.
Infrastructure runs on Azure, all of it Terraform-managed. Container Apps for the API, the worker, Keycloak, and the migrations runner. Service Bus for async messaging. Redis for cache and connection tracking. SignalR Service for real-time. Front Door for global routing. Key Vault for secrets, reached over managed identity so no app holds a credential. Seq for structured logs alongside Log Analytics for the resource-level telemetry. Builds run in GitHub Actions across dev, staging, and production environments.
- Backend: .NET, C#, Keycloak, Azure Service Bus, SQL Server (one database per tenant), Redis, SignalR.
- Frontend: React 19, TypeScript, Vite, pnpm, Turbo, DevExtreme.
- Infrastructure and DevOps: Terraform, Azure Container Apps, Azure Front Door, Azure Key Vault, GitHub Actions.
- Quality and ops: xUnit, NSubstitute, AutoFixture, Playwright for end-to-end, k6 for load, Serilog and Seq for logs.