A grocery delivery platform backend built as independent microservices, each with its own database, deployed as separate containers.
I built this as three separate services instead of one monolith to learn and demonstrate real production patterns: independent deployability, service isolation, and stateless authentication across service boundaries.
| Service | Responsibility | Repo |
|---|---|---|
| AuthService | User registration, login, JWT issuance, role-based claims | AuthService |
| CatalogService | Categories, products, inventory management | CatalogService |
| GlossaryService | Product tags, search keyword/synonym mapping | GlossaryService |
AuthService is the only service that knows about users and passwords. It issues a signed JWT containing the user's role as a claim.
CatalogService and GlossaryService never call AuthService to check a token. Instead, they independently verify the JWT's signature using a shared signing key, issuer, and audience — this is stateless verification, the core reason JWT is used in a microservices architecture rather than a shared session store.
Endpoints are protected at two levels:
[Authorize]— requires any valid, logged-in user[Authorize(Roles = "Admin")]— requires the Admin role specifically (e.g. deleting a product or category)
- Clean Architecture (Models → Repository → Service → Controller)
- Soft delete (
DeletedAttimestamp, never hardDELETE) - Global exception middleware with consistent error responses
- API versioning (v1)
- Rate limiting (stricter limits on auth endpoints to prevent brute force)
- EF Core transactions for multi-table writes (e.g. creating a Product also creates its Inventory record atomically)
- Docker + docker-compose per service
While testing rate limiting on AuthService, I discovered the limiter was
registered in DI but never activated in the middleware pipeline
(missing app.UseRateLimiter()) — meaning the configuration existed but
had zero effect. I also found and fixed plaintext password storage,
replacing it with BCrypt hashing, and caught AWS RDS credentials
accidentally committed to a public repo, which I rotated and purged
from git history.
.NET, ASP.NET Core, Entity Framework Core, SQL Server, Docker, JWT Bearer Authentication, xUnit, Moq
