A .NET e-commerce reference platform covering authentication, catalog, basket, checkout and asynchronous order fulfillment. Run the APIs, workers and observability stack locally with Docker Compose.
Stack: .NET 10 · YARP · RabbitMQ / MassTransit · PostgreSQL · Redis · JWT · Serilog / Seq · Prometheus / Grafana.
Quick start · Checkout flow · Architecture · Tests · Trade-offs
This repository is a portfolio / open-source reference project, not a turnkey commercial platform. Payments and notifications are simulated; the database, broker and cache run as real local services. Use it to explore service ownership, eventual consistency and failure handling before adapting the design to another system.
flowchart TB
Client[Client]
GW[ApiGateway]
Id[IdentityService]
Cat[CatalogService]
Bas[BasketService]
Ord[OrderingService]
Pay[Payment.Worker]
Inv[InventoryService]
Not[Notification.Worker]
RMQ[(RabbitMQ)]
Redis[(Redis)]
PG[(PostgreSQL)]
Seq[Seq]
Client --> GW
GW --> Id
GW --> Cat
GW --> Bas
GW --> Ord
GW --> Inv
Bas -->|checkout + JWT| Ord
Id --> PG
Cat --> PG
Ord --> PG
Pay --> PG
Inv --> PG
Not --> PG
Bas --> Redis
Ord --> RMQ
RMQ --> Pay
RMQ --> Inv
RMQ --> Ord
RMQ --> Not
Ord -.-> Seq
Full technical documentation: docs/architecture.md
| Service | Type | Responsibility | Persistence |
|---|---|---|---|
| ApiGateway | API | YARP reverse proxy, JWT at the edge | — |
| IdentityService | API | Register / login / JWT issuance | PostgreSQL identity_db |
| CatalogService | API | Product catalog | PostgreSQL catalog_db |
| BasketService | API | Shopping cart + HTTP checkout | Redis |
| OrderingService | API | Order lifecycle + integration events | PostgreSQL ordering_db + outbox |
| Payment.Worker | Worker | Simulated payment processing | PostgreSQL payment_db + outbox |
| InventoryService | API | Stock and reservation | PostgreSQL inventory_db + outbox |
| Notification.Worker | Worker | Simulated notifications | PostgreSQL notification_db |
- ApiGateway (
http://localhost:5000) is the single external HTTP entry point. - IdentityService issues JWTs consumed by the gateway and downstream services.
- PostgreSQL — one database per stateful service (
identity_db,catalog_db,ordering_db,inventory_db,payment_db,notification_db). - Redis — ephemeral basket state.
- RabbitMQ + MassTransit — async integration between Ordering, Payment, Inventory, and Notification.
- Seq, Prometheus, Grafana — local observability stack.
- Customer browses the public catalog.
- Customer authenticates via Identity and receives a JWT.
- Customer adds items to the basket (Redis).
- Checkout creates an order in Ordering (HTTP +
Idempotency-Key). - Ordering publishes
OrderCreatedEventvia the transactional outbox. - Payment.Worker approves or rejects payment.
- InventoryService reserves stock.
- Ordering completes the order and publishes
OrderCompletedEvent. - Notification.Worker logs a simulated notification.
POST /identity/auth/login→accessToken+customerIdGET /catalog/products(public)POST /basket/baskets/{customerId}/itemswithAuthorization: BearerPOST /basket/baskets/{customerId}/checkout- Poll
GET /ordering/orders/{orderId}until status isCompleted
Detailed walkthrough: docs/smoke-tests.md · curl examples: docs/examples/http-requests.md
| Pattern | Where |
|---|---|
| Transactional Outbox | Ordering, Payment, Inventory |
| Idempotency-Key | Basket → Ordering checkout |
| Idempotent consumers | (EventId, ConsumerName) in the same DB transaction |
Retry + _error queues |
MassTransit — manual replay |
ADRs: docs/decisions/ · Communication details: docs/service-communication.md
- IdentityService — register, login,
/me - JWT claims:
sub,email,customer_id,role - Gateway — basket and ordering routes require JWT; catalog GET is public; catalog write requires Admin
- Basket and Ordering validate URL
customerIdagainst the token
Details: docs/security.md
| Signal | Tool | Endpoint |
|---|---|---|
| Logs | Serilog → Seq | http://localhost:5341 |
| Metrics | Prometheus + Grafana | /metrics on each service; Grafana http://localhost:3000 |
| Health | ASP.NET Core | /health/live, /health/ready |
Guides: docs/observability.md · Seq · Prometheus/Grafana · Runbooks: docs/runbooks/
| Suite | Project | Docker required |
|---|---|---|
| Unit | Catalog.UnitTests, Basket.UnitTests, Ordering.UnitTests |
No |
| Integration | IntegrationTests |
Yes (Testcontainers) |
| Security | Security.IntegrationTests |
Yes (Testcontainers) |
Run from the repository root with the .NET 10 SDK:
# Unit tests: one project per invocation
dotnet test tests/Catalog.UnitTests/Catalog.UnitTests.csproj
dotnet test tests/Basket.UnitTests/Basket.UnitTests.csproj
dotnet test tests/Ordering.UnitTests/Ordering.UnitTests.csproj
# Integration and security tests: Docker must be running
dotnet test tests/IntegrationTests/IntegrationTests.csproj
dotnet test tests/Security.IntegrationTests/Security.IntegrationTests.csprojCI runs build and unit tests on every push/PR. Integration and security tests are available locally with Docker — see docs/testing.md.
Prerequisites: Docker Desktop (or Docker Engine + Compose v2). .NET 10 SDK is optional for running containers only.
git clone https://github.com/luismpenholato/Microservices.Ecommerce.git
cd Microservices.Ecommerce
docker compose up -d --build| Service | URL |
|---|---|
| ApiGateway | http://localhost:5000 |
| Identity | http://localhost:5005 |
| Grafana | http://localhost:3000 (admin/admin) |
| Seq | http://localhost:5341 |
| RabbitMQ UI | http://localhost:15672 (guest/guest) |
| Prometheus | http://localhost:9090 |
Public catalog: http://localhost:5000/catalog/products
Keep these services local. The Compose stack exposes service and infrastructure ports directly and includes demo credentials; it is not a hardened public deployment.
After docker compose up -d --build, wait for healthchecks (docker compose ps) and follow the manual checklist in docs/smoke-tests.md. Quick checks:
curl -s http://localhost:5000/health/ready
curl -s http://localhost:5000/catalog/productsFor the full checkout flow, see docs/examples/http-requests.md.
Local demo only. Do not use these credentials outside a local environment.
| Role | Password | |
|---|---|---|
| Customer | demo@ecommerce.local |
Demo123! |
| Admin | admin@ecommerce.local |
Admin123! |
curl -s -X POST http://localhost:5000/identity/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"demo@ecommerce.local","password":"Demo123!"}'| Service | Host port | Database / store |
|---|---|---|
| ApiGateway | 5000 | — |
| Catalog | 5001 | catalog_db |
| Basket | 5002 | Redis |
| Ordering | 5003 | ordering_db |
| Inventory | 5004 | inventory_db |
| Identity | 5005 | identity_db |
| Payment.Worker | 5010 | payment_db |
| Notification.Worker | 5011 | notification_db |
| PostgreSQL | 5432 | all databases |
| Redis | 6379 | basket |
| RabbitMQ | 5672 / 15672 (UI) | — |
| Seq | 5341 | — |
| Prometheus | 9090 | — |
| Grafana | 3000 | — |
src/
ApiGateway/
BuildingBlocks/ # Contracts, Domain, Messaging, Observability, Web
Services/ # Catalog, Basket, Ordering, Identity, Payment, Inventory, Notification
tests/
*UnitTests, IntegrationTests, Security.IntegrationTests
infra/ # Prometheus, Grafana, Postgres init
docs/ # Architecture, security, testing, runbooks, ADRs
docker-compose.yml
GitHub Actions workflow .github/workflows/ci.yml:
- build — restore and build the solution
- unit-tests —
Catalog,Basket,Orderingunit tests
Integration and security tests are not run in CI (require Docker locally). Run them manually when needed.
| Document | Content |
|---|---|
| architecture.md | Technical overview and diagrams |
| service-communication.md | HTTP vs events, outbox, retry |
| security.md | JWT, roles, demo credentials |
| testing.md | Test strategy and CI |
| operations.md | Health, metrics, validation |
| smoke-tests.md | Manual end-to-end flow |
| deployment.md | Deployment notes (local/demo scope) |
| Benefit | Cost |
|---|---|
| Independent services and bounded contexts | Operational complexity and distributed debugging |
| Robust outbox + idempotency | Visible intermediate states and latency |
| Full local observability stack | More containers in docker compose |
| Simple HMAC JWT for portfolio demos | Shared secret across services — see ROADMAP for JWKS |
Implemented features are documented above. Planned items (refresh tokens, asymmetric JWT, Alertmanager, contract tests, Kubernetes/Aspire, and more) are tracked in ROADMAP.md.
MIT — Copyright (c) 2026 Luis Penholato