case study · AWS platform · 2026

Microservices platform infrastructure

Terraform infrastructure and a working local environment for a .NET microservices platform. Eight services and two workers share a synchronous API path and an asynchronous S3 and SQS path.

problem

Run a complete product platform within a strict cost limit

The platform needed an admin frontend, eight APIs, two background workers, PostgreSQL, Redis, OpenSearch and queue-based processing. The infrastructure also had to remain small enough for a personal AWS account and reproducible enough to remove when it was not being tested.

The application runs locally as the same set of services used by the AWS design. LocalStack provides S3 and SQS, while real PostgreSQL, Redis and OpenSearch containers avoid replacing cloud dependencies with simpler substitutes.

architecture

Separate request traffic from background processing

AppStack architecture: ALB in front of ECS on EC2, with RDS Postgres, Redis, OpenSearch and SQS workers inside one VPC
CloudFront serves the frontend and forwards API traffic to an ALB. ECS services use PostgreSQL, Redis and OpenSearch; S3 events and SQS queues feed the PDF-ingest and search-sync workers.

Requests follow CloudFront → ALB → ECS → data services. File imports and search updates use S3 and SQS so bursts of background work do not block API requests. Each queue has a dead-letter queue for messages that cannot be processed successfully.

decisions and tradeoffs

Key design decisions

ECS on EC2 instead of Fargate
Ten workloads share one small instance. This lowers compute cost but gives the platform less isolation and capacity than separate Fargate tasks.
No NAT gateway
ECS runs in a security-group-restricted public subnet, while databases remain private. S3 and DynamoDB gateway endpoints cover those service paths. The design saves the fixed NAT cost but requires tighter control of the compute subnet.
SQS workers instead of synchronous jobs
PDF imports and search updates can retry independently and cannot hold open an API request. The tradeoff is eventual consistency and additional failure handling.
One CloudFront origin for frontend and API paths
CloudFront serves S3 content and forwards API paths to the ALB under one hostname, removing the need for browser CORS configuration.

what broke

Local services used the wrong SQS region

LocalStack created queues in its default region while the application requested them from ap-south-1. The queue names were correct, but every worker reported that its queue did not exist. Creating the local queues in the same configured region fixed the mismatch.

A second container failure came from the worker image. The Prometheus ASP.NET package required the ASP.NET shared framework, but the workers used the smaller .NET runtime image. They exited at startup until their Dockerfiles switched to the ASP.NET runtime base.

numbers

Current scope

The local application is complete and the infrastructure modules were applied and removed once. The current 121-resource cloud deployment plan is complete; a full application deployment to AWS remains pending.