<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Muhammad Abdullah</title>
    <description>The latest articles on DEV Community by Muhammad Abdullah (@aboodi679).</description>
    <link>https://dev.to/aboodi679</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4025568%2F240db28f-cd45-46a1-83bc-09fd0d22b794.jpg</url>
      <title>DEV Community: Muhammad Abdullah</title>
      <link>https://dev.to/aboodi679</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aboodi679"/>
    <language>en</language>
    <item>
      <title>How I Built a Production Multi-Tenant SaaS on AWS for $94/month - And Almost Gave Up</title>
      <dc:creator>Muhammad Abdullah</dc:creator>
      <pubDate>Sat, 11 Jul 2026 23:26:22 +0000</pubDate>
      <link>https://dev.to/aboodi679/how-i-built-a-production-multi-tenant-saas-on-aws-for-94month-and-almost-gave-up-42d5</link>
      <guid>https://dev.to/aboodi679/how-i-built-a-production-multi-tenant-saas-on-aws-for-94month-and-almost-gave-up-42d5</guid>
      <description>&lt;h1&gt;
  
  
  I Almost Quit This Project at 2am. I'm Glad I Didn't.
&lt;/h1&gt;

&lt;p&gt;After OrderFlow I thought I understood AWS.&lt;/p&gt;

&lt;p&gt;I understood enough to be dangerous.&lt;/p&gt;

&lt;p&gt;StatusNest was supposed to be the next step up - a real multi-tenant SaaS platform. Not a learning project. Not a portfolio checkbox. Something that actually demonstrated architecture-level thinking. Production grade. Built from scratch.&lt;/p&gt;

&lt;p&gt;One week later I was staring at a screen at 2am watching my third consecutive deployment fail, wondering if I should just stop.&lt;/p&gt;

&lt;p&gt;This is that story.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why StatusNest
&lt;/h2&gt;

&lt;p&gt;OrderFlow taught me event-driven architecture. Three microservices, EventBridge, SQS, SNS, clean Terraform modules. I was proud of it.&lt;/p&gt;

&lt;p&gt;But it had no users. No tenants. No authentication. No real-world complexity beyond the messaging patterns.&lt;/p&gt;

&lt;p&gt;I wanted to build something where the hard problems weren't just infrastructure - where multi-tenancy, security, cost optimization, and real application logic all had to work together simultaneously.&lt;/p&gt;

&lt;p&gt;A status page platform made sense. Every SaaS company needs one. It has natural multi-tenancy - each customer gets their own page, their own monitors, their own incident history. The monitoring pipeline is genuinely event-driven. The public status pages need CDN. The auth layer needs to be real.&lt;/p&gt;

&lt;p&gt;It touched every AWS service I wanted to prove I could use properly.&lt;/p&gt;

&lt;p&gt;I gave myself one week.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture I Was Aiming For
&lt;/h2&gt;

&lt;p&gt;Three FastAPI microservices on ECS Fargate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Auth Service&lt;/strong&gt; (port 8000) - registration, login, JWT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor Service&lt;/strong&gt; (port 8001) - monitor CRUD, check scheduling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status Service&lt;/strong&gt; (port 8002) - public status page data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behind an ALB with path-based routing. RDS PostgreSQL for persistent storage. ElastiCache Redis for caching and rate limiting. An EventBridge → Lambda → SQS monitoring pipeline. CloudFront with WAF in front of everything. GitHub Actions OIDC for CI/CD. Full Terraform IaC. CloudWatch and X-Ray for observability.&lt;/p&gt;

&lt;p&gt;On paper it was clear. In practice it was the hardest thing I had built.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day One: The Port Problem That Wasn't Simple
&lt;/h2&gt;

&lt;p&gt;The first thing I hit was the ECS services showing Running=0.&lt;/p&gt;

&lt;p&gt;Tasks were registering. Services were active. Nothing was actually running. ALB health checks failing across all three services.&lt;/p&gt;

&lt;p&gt;I spent hours checking the Terraform - security groups, task definitions, ALB target groups. Everything looked right on paper.&lt;/p&gt;

&lt;p&gt;The actual problem: port mismatch in the Dockerfiles. The containers were exposing different ports than what the ECS task definitions were mapping. The fix sounds simple written out like that. Finding it was not simple at all. CloudWatch logs showed the containers starting and immediately stopping. No useful error message. Just an exit code.&lt;/p&gt;

&lt;p&gt;That was day one.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Lambda Deployment Timeout
&lt;/h2&gt;

&lt;p&gt;The monitoring pipeline uses Lambda to execute health checks. When I first deployed the Lambda functions the deployments kept timing out.&lt;/p&gt;

&lt;p&gt;The function zip was too large - I was packaging all dependencies directly into the deployment package. AWS has a 50MB compressed zip limit for direct uploads and I was hitting it.&lt;/p&gt;

&lt;p&gt;The fix was Lambda Layers - extract the heavy dependencies into a separate layer, keep the function code itself small. But figuring that out, restructuring the packaging, updating the Terraform Lambda resources, and redeploying took most of a day.&lt;/p&gt;

&lt;p&gt;Every time I thought I had it the deployment would run for 16 minutes and then fail. Then I'd fix something and try again. 12 minutes. Fail. 12 minutes. Fail.&lt;/p&gt;




&lt;h2&gt;
  
  
  2am on July 2nd
&lt;/h2&gt;

&lt;p&gt;Look at this GitHub Actions history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Jul 2, 01:42 AM  — Deploy Auth Service #4      ❌  27m 51s
Jul 2, 02:16 AM  — fix: remove duplicate redis_url line in config
                 — Deploy Auth Service #5      ✅  17m 50s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That 27-minute failed deployment at 1:42am. I was trying to get the auth service running with Redis. The config had a duplicate &lt;code&gt;redis_url&lt;/code&gt; line that was causing a startup crash. The container would start, hit the config parsing error, and die. The ALB would keep retrying health checks. The deployment would wait the full timeout period before marking as failed.&lt;/p&gt;

&lt;p&gt;27 minutes of watching a progress bar, knowing something was wrong, not knowing what.&lt;/p&gt;

&lt;p&gt;Fixed it at 2:16am with a one-line change.&lt;/p&gt;




&lt;h2&gt;
  
  
  July 3rd: The CI/CD Failures
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Jul 3, 01:59 AM  — chore: remove scratch files     ✅
Jul 3, 14:07 PM  — Add CI/CD workflows             ❌  16m 20s  (Monitor Service)
Jul 3, 14:07 PM  — Add CI/CD workflows             ❌  12m 01s  (Auth Service)
Jul 3, 14:07 PM  — Add CI/CD workflows             ❌  12m 57s  (Status Service)
Jul 3, 14:08 PM  — Remove sensitive files           ✅  11m 52s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three services. Three simultaneous CI/CD workflow failures. Same commit. 14:07pm.&lt;/p&gt;

&lt;p&gt;I had pushed the GitHub Actions workflows for all three services at once. All three failed. The OIDC configuration, the ECR push permissions, the ECS deploy step - all of it needed to be debugged across three separate workflows simultaneously.&lt;/p&gt;

&lt;p&gt;And before that - 1:59am again the night before. Still going past midnight.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Free Tier Problem
&lt;/h2&gt;

&lt;p&gt;I had planned to use Aurora Serverless v2 for the database. Scales to zero when idle. Perfect for a dev environment.&lt;/p&gt;

&lt;p&gt;Not on free tier. The minimum Aurora Serverless v2 capacity costs more than a standard RDS instance running 24/7 at t3.micro.&lt;/p&gt;

&lt;p&gt;So I switched to standard RDS PostgreSQL. Changed the Terraform, updated connection strings across three services, redeployed everything. Half a day gone.&lt;/p&gt;

&lt;p&gt;This is the kind of decision that doesn't show up in architecture diagrams but defines what you actually ship. Real cloud engineering is full of these tradeoffs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Moment I Almost Stopped
&lt;/h2&gt;

&lt;p&gt;It was somewhere in the middle of that week.&lt;/p&gt;

&lt;p&gt;Deployments were failing. The Lambda timeouts weren't resolved yet. The API was returning errors I didn't fully understand. I had been debugging for hours and the list of open issues wasn't getting shorter.&lt;/p&gt;

&lt;p&gt;I remember thinking: this is too much. I could just leave it at OrderFlow. That's already a solid portfolio project. Nobody is forcing me to finish this.&lt;/p&gt;

&lt;p&gt;I sat there for a while.&lt;/p&gt;

&lt;p&gt;Then I thought about why I started. I wanted to prove I could build something at architecture level - not just follow patterns but make real decisions under real constraints. Quitting with a half-built system proved nothing except that I quit when it got hard.&lt;/p&gt;

&lt;p&gt;So I made chai, opened CloudWatch logs, and kept going.&lt;/p&gt;




&lt;h2&gt;
  
  
  When It Finally Worked
&lt;/h2&gt;

&lt;p&gt;The moment the StatusNest dashboard loaded for the first time - auth working, monitors creating, status page serving data through CloudFront - was one of the best feelings I've had building anything.&lt;/p&gt;

&lt;p&gt;Not because it was perfect. It wasn't. There were still bugs. There are always still bugs.&lt;/p&gt;

&lt;p&gt;But the architecture was running. Every component I had designed on paper was live on AWS. The EventBridge rules were firing. Lambda was executing health checks. SQS was buffering. Redis was caching. CloudFront was serving. X-Ray was tracing the full request path.&lt;/p&gt;

&lt;p&gt;$94/month. Built from scratch. Zero manual console interaction after the initial setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  What StatusNest Actually Is
&lt;/h2&gt;

&lt;p&gt;A production-grade multi-tenant SaaS status page platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;3 FastAPI microservices&lt;/strong&gt; on ECS Fargate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RDS PostgreSQL&lt;/strong&gt; - primary data store&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ElastiCache Redis&lt;/strong&gt; - caching and rate limiting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EventBridge → Lambda → SQS&lt;/strong&gt; - monitoring pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront + WAF&lt;/strong&gt; - CDN and DDoS protection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions OIDC&lt;/strong&gt; - zero stored credentials&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform&lt;/strong&gt; - every resource as code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudWatch + X-Ray&lt;/strong&gt; - full observability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full architecture documented in an 8-ADR Solution Architecture Document in the repo.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Taught Me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Errors are information.&lt;/strong&gt; Every failed deployment told me something specific if I read the logs carefully enough. The ones that cost me the most time were the ones where I guessed the fix instead of reading the actual error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2am debugging is a skill.&lt;/strong&gt; Not a fun one. But learning to stay methodical when you're tired and frustrated and nothing is working - that's what separates someone who ships from someone who has half-finished projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture decisions have real costs.&lt;/strong&gt; Aurora vs RDS. Lambda Layers vs direct packaging. Every choice has a tradeoff that tutorial projects never show you because tutorial projects never have real constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finishing matters more than perfect.&lt;/strong&gt; The bugs I didn't fix before shipping taught me more than the ones I did, because I had to understand the system well enough to know which ones were safe to leave for later.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/aboodi679" rel="noopener noreferrer"&gt;github.com/aboodi679&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The architecture diagram, full Terraform modules, and 8-ADR Solution Architecture Document are all in the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you're hitting any of these same issues - ECS Running=0, Lambda deployment timeouts, OIDC failures, Windows clock drift breaking AWS signatures - drop a comment.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3lq83hnls6hh6ozynxli.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3lq83hnls6hh6ozynxli.png" alt=" " width="799" height="523"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fektp245yciq6gg0yuxhi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fektp245yciq6gg0yuxhi.png" alt=" " width="799" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>saas</category>
      <category>devops</category>
      <category>architecture</category>
    </item>
    <item>
      <title>From FYP to Production AWS: How I Built My First Real Cloud Project (And How Many Times It Broke)</title>
      <dc:creator>Muhammad Abdullah</dc:creator>
      <pubDate>Sat, 11 Jul 2026 23:09:18 +0000</pubDate>
      <link>https://dev.to/aboodi679/how-i-built-a-production-multi-tenant-saas-on-aws-for-94month-and-almost-gave-up-1707</link>
      <guid>https://dev.to/aboodi679/how-i-built-a-production-multi-tenant-saas-on-aws-for-94month-and-almost-gave-up-1707</guid>
      <description>&lt;p&gt;My final year project was done.&lt;/p&gt;

&lt;p&gt;90/100. Top 8 at the exhibition. Supervisor happy. Committee happy.&lt;/p&gt;

&lt;p&gt;And I had absolutely no idea if I could actually get a job.&lt;/p&gt;

&lt;p&gt;The FYP had AWS in it  Lambda, DynamoDB, API Gateway. But let's be honest. Zappa does most of the heavy lifting. You're not really doing cloud engineering when a library handles your entire deployment. I knew how to follow a tutorial. I didn't know if I could build something real from scratch.&lt;/p&gt;

&lt;p&gt;That gap bothered me.&lt;/p&gt;

&lt;p&gt;So I opened an empty folder and decided to find out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Event-Driven
&lt;/h2&gt;

&lt;p&gt;I spent a week just researching what to build before writing a single line of code.&lt;/p&gt;

&lt;p&gt;Every job description I read - cloud engineer, DevOps engineer, backend engineer - kept mentioning the same things. Microservices. Event-driven architecture. Decoupled systems. SQS. SNS. EventBridge.&lt;/p&gt;

&lt;p&gt;Not because it's trendy. Because it's how real production systems are actually built. Direct service-to-service API calls don't scale. They create tight coupling. One service goes down and it takes everything with it.&lt;/p&gt;

&lt;p&gt;Event-driven architecture solves that. Services don't talk to each other directly - they fire events and let the messaging layer handle delivery. The order service doesn't care whether inventory or notifications are running. It fires an event and moves on.&lt;/p&gt;

&lt;p&gt;That was the pattern I wanted to learn properly. So I built around it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What OrderFlow Does
&lt;/h2&gt;

&lt;p&gt;OrderFlow is an order management platform with three microservices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Order Service&lt;/strong&gt; - accepts incoming orders, fires an &lt;code&gt;order.created&lt;/code&gt; event&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory Service&lt;/strong&gt; - consumes that event, updates stock&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification Service&lt;/strong&gt; - consumes that event, sends confirmation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple domain. Complex plumbing.&lt;/p&gt;

&lt;p&gt;The entire event flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client Request
      │
      ▼
Application Load Balancer
      │
      ▼
ECS Fargate Cluster
      │
order.created event fired
      │
      ▼
Amazon EventBridge
      │
      ├──► SQS inventory-queue (direct)
      │
      └──► SNS orders-topic
                  │
                  └──► SQS notification-queue (fan-out)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Order service fires one event. EventBridge routes it. SNS fans it out. Both downstream services get what they need without knowing anything about each other.&lt;/p&gt;

&lt;p&gt;That's the theory. The reality was messier.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Part Nobody Puts in Their README
&lt;/h2&gt;

&lt;p&gt;I want to be honest about what building this actually looked like.&lt;/p&gt;

&lt;p&gt;This was my first time building something at this level of complexity without a tutorial holding my hand. No template. No starter repo. Just AWS documentation, Stack Overflow, and a lot of CloudWatch logs telling me things were broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Terraform errors came first.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I had used Terraform before on smaller projects but never with a modular structure across networking, ECS, messaging, and observability layers all wired together. The dependency graph alone took me two days to get right. Terraform would plan successfully and then fail mid-apply because a security group wasn't ready before the ECS task definition tried to reference it. I learned more about &lt;code&gt;depends_on&lt;/code&gt; in those two days than in any course.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then ECS refused to run anything.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Services registered as ACTIVE but tasks immediately stopped. No obvious error in the console. I dug into CloudWatch logs and found the container was crashing on startup - environment variables weren't being injected correctly into the task definition. The container was starting, hitting a missing config value, and dying before it could even serve a health check. The ALB kept marking targets unhealthy. The fix was straightforward once I found it, but finding it took hours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then EventBridge events were disappearing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd fire an &lt;code&gt;order.created&lt;/code&gt; event and nothing would show up in the SQS queue. No error. No DLQ message. Just silence. Turns out my EventBridge rule pattern wasn't matching the event structure I was sending - a JSON field name mismatch between what I was publishing and what the rule was filtering on. One character difference. Two hours of debugging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then GitHub Actions kept failing on ECR push.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OIDC setup between GitHub and AWS is genuinely fiddly. The trust policy on the IAM role has to exactly match the GitHub repository path and branch conditions. I had the role ARN right but the trust relationship was slightly wrong - it was accepting tokens from the right GitHub org but not scoping to the right repo. Every push was failing at the assume-role step with a cryptic access denied. Fixed it by reading the IAM trust policy documentation more carefully than I've ever read any documentation.&lt;/p&gt;

&lt;p&gt;Each one of these felt like a wall when I hit it. In hindsight they were the whole point.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Final Architecture Looks Like
&lt;/h2&gt;

&lt;p&gt;Three Flask microservices running on &lt;strong&gt;ECS Fargate&lt;/strong&gt; behind an &lt;strong&gt;Application Load Balancer&lt;/strong&gt; with path-based routing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;/&lt;span class="n"&gt;orders&lt;/span&gt;/*     → &lt;span class="n"&gt;order&lt;/span&gt;-&lt;span class="n"&gt;service&lt;/span&gt;     (&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;)
/&lt;span class="n"&gt;inventory&lt;/span&gt;/*  → &lt;span class="n"&gt;inventory&lt;/span&gt;-&lt;span class="n"&gt;service&lt;/span&gt; (&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="m"&gt;5001&lt;/span&gt;)
/&lt;span class="n"&gt;notify&lt;/span&gt;/*     → &lt;span class="n"&gt;notification&lt;/span&gt;-&lt;span class="n"&gt;service&lt;/span&gt; (&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="m"&gt;5002&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every AWS resource - VPC, subnets, route tables, security groups, ECS cluster, task definitions, ECR repos, ALB, SQS queues, SNS topic, EventBridge rules, CloudWatch alarms, X-Ray group - provisioned through &lt;strong&gt;modular Terraform&lt;/strong&gt;. Zero manual console clicks after the initial setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI/CD&lt;/strong&gt; via GitHub Actions with OIDC - no AWS access keys stored anywhere. On push, the pipeline assumes an IAM role via web identity token, builds the Docker image, pushes to ECR, and forces a rolling ECS redeployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability&lt;/strong&gt; through CloudWatch dashboards tracking ECS CPU and memory across all three services, ALB request count and response time, and SQS queue depth. Alarms fire if CPU crosses 80% or queue depth crosses 100 messages. X-Ray distributed tracing wired across the full request path.&lt;/p&gt;

&lt;p&gt;The whole thing runs for &lt;strong&gt;~$22-25/month.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Event-Driven Actually Taught Me
&lt;/h2&gt;

&lt;p&gt;Before this project, event-driven architecture was a concept I understood intellectually.&lt;/p&gt;

&lt;p&gt;After this project, I understand it in my hands.&lt;/p&gt;

&lt;p&gt;The difference between calling inventory service directly from order service versus firing an EventBridge event is not just architectural elegance. It's operational resilience. During testing I deliberately stopped the inventory service container while firing order events. The orders kept processing. The events sat in SQS. When inventory came back up it consumed the backlog and caught up. Nothing was lost.&lt;/p&gt;

&lt;p&gt;Try that with a direct REST call. The order fails. The user gets an error. You have a support ticket.&lt;/p&gt;

&lt;p&gt;That moment - watching the system absorb a failure and recover without intervention - was when cloud engineering stopped feeling like infrastructure configuration and started feeling like system design.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built Next
&lt;/h2&gt;

&lt;p&gt;OrderFlow taught me the patterns. But it was missing something real - actual users, actual tenants, actual production concerns like multi-tenancy, authentication, rate limiting, and cost optimization under real traffic.&lt;/p&gt;

&lt;p&gt;So I built StatusNest next. A production multi-tenant SaaS status page platform on AWS, with everything OrderFlow taught me plus the things OrderFlow couldn't teach me.&lt;/p&gt;

&lt;p&gt;That story is in my next post.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;Everything is open source - Terraform modules, GitHub Actions workflows, service code, test events.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; github.com/aboodi679/orderflow-aws&lt;/p&gt;

&lt;h2&gt;
  
  
  If you're building something similar and hitting the same walls I hit - ECS tasks stopping immediately, EventBridge rules not matching, OIDC trust policy rejections - drop a comment.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwyusaewj88ojhj0d3kpi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwyusaewj88ojhj0d3kpi.png" alt=" " width="800" height="965"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>terraform</category>
      <category>devops</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Two Friends, Two Different Domains, One FYP - And a Committee That Changed Everything</title>
      <dc:creator>Muhammad Abdullah</dc:creator>
      <pubDate>Sat, 11 Jul 2026 22:17:07 +0000</pubDate>
      <link>https://dev.to/aboodi679/two-friends-two-different-domains-one-fyp-and-a-committee-that-changed-everything-4ng7</link>
      <guid>https://dev.to/aboodi679/two-friends-two-different-domains-one-fyp-and-a-committee-that-changed-everything-4ng7</guid>
      <description>&lt;p&gt;Final year project selection is stressful enough on its own.&lt;/p&gt;

&lt;p&gt;Now imagine two friends sitting in a class, one laptop between them, trying to pick a single project that would satisfy a supervisor, an examination committee, and two completely different career paths.&lt;/p&gt;

&lt;p&gt;That was me and Hassan in early 2024.&lt;/p&gt;

&lt;p&gt;I was deep into AWS - ECS, Lambda, Terraform, the whole cloud stack. Hassan was into Unity and game development. We needed something that genuinely needed both of us. A game with a cloud backend made sense - Hassan owns the game, I own the infrastructure, we both have something real to show.&lt;/p&gt;

&lt;p&gt;We went to the committee feeling good about it.&lt;/p&gt;

&lt;p&gt;Then they said four words that changed everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  "You Need to Add AI."
&lt;/h2&gt;

&lt;p&gt;Not a suggestion. A requirement.&lt;/p&gt;

&lt;p&gt;We walked out of that room and looked at each other. Hassan said: &lt;em&gt;"Let's just add some pathfinding and call it AI."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I wasn't satisfied with that. If we were going to add AI, I wanted it to actually mean something - something the committee hadn't seen before, something that justified the domain split between a cloud guy and a game dev.&lt;/p&gt;

&lt;p&gt;Hassan had been reading about Reinforcement Learning. The idea was compelling - instead of scripting NPC behavior manually, let the agent learn through trial and error. Reward good behavior, penalize bad, and over time it develops its own strategy.&lt;/p&gt;

&lt;p&gt;He pitched it. It sounded perfect on paper.&lt;/p&gt;

&lt;p&gt;Then we actually tried to implement it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Pure RL Was a Problem
&lt;/h2&gt;

&lt;p&gt;RL has a dirty secret that papers don't emphasize enough: &lt;strong&gt;it needs thousands of training episodes before it does anything useful.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a controlled grid environment with a simple reward function, that's manageable. In a real Unity game with a 3D environment, dynamic player behavior, and a demo deadline four months away - it's a disaster.&lt;/p&gt;

&lt;p&gt;The problems we hit:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RL is unpredictable by nature.&lt;/strong&gt; That's literally the point - it explores. But in a game, "exploration" means your NPC stands in a corner, walks into walls, or runs away from the player for no reason. Not exactly the threatening enemy we were going for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reward shaping is an art, not a science.&lt;/strong&gt; If you reward the NPC for getting close to the player, it learns to get close - then just stands there. Every reward signal has to be carefully designed or the agent learns to game the reward function instead of actually playing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training time.&lt;/strong&gt; We didn't have a GPU cluster. We had Hassan's laptop. Full RL training on a live Unity environment wasn't going to be ready for demo day.&lt;/p&gt;

&lt;p&gt;Hassan was honest about it - the RL implementation was beyond what he could execute in the Unity codebase within the timeline. He built the FSM instead, which worked, but felt incomplete given what the committee was expecting.&lt;/p&gt;

&lt;p&gt;That's when I stepped in.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Research Rabbit Hole
&lt;/h2&gt;

&lt;p&gt;I took ownership of the AI architecture problem. If RL alone was too unstable and FSM alone was too rigid, there had to be a middle ground.&lt;/p&gt;

&lt;p&gt;I spent two weeks reading - research papers, game AI blogs, anything I could find. The pattern that kept appearing in serious game AI literature was a hybrid approach. Not RL or FSM. &lt;strong&gt;RL and FSM together.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The insight was simple once I found it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FSM and RL have exactly opposite weaknesses.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FSM is stable but rigid - it does exactly what you tell it, nothing more. Players figure it out fast. The NPC becomes a puzzle instead of a threat.&lt;/p&gt;

&lt;p&gt;RL is adaptive but unpredictable - it can surprise you, but early in training it's chaotic and unreliable. You can't ship a game where the enemy randomly walks into walls.&lt;/p&gt;

&lt;p&gt;What if FSM handled the high-level structure and RL handled the low-level execution?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture We Landed On
&lt;/h2&gt;

&lt;p&gt;The FSM controls the overall zombie behavior. High-level states - Patrol, Stalk, Engage, Retreat - with deterministic rule-based transitions. This is what Hassan had already built. It was stable, it worked, it demoed reliably.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;within the Engage state&lt;/strong&gt;, instead of scripted attack patterns, the NPC uses an RL policy to control its movement.&lt;/p&gt;

&lt;p&gt;The zombie knows it's in Engage mode because of FSM rules. But &lt;em&gt;how&lt;/em&gt; it moves during engagement - how it positions itself, how it adjusts to the player dodging, how it cuts off escape routes - that comes from the RL model.&lt;/p&gt;

&lt;p&gt;The FSM gives the RL agent guardrails. The RL agent never has to explore the entire state space from scratch - it only makes decisions within a constrained, well-defined context. That solved the unpredictability problem.&lt;/p&gt;

&lt;p&gt;The RL agent gives the FSM emergent behavior. The high-level states are still deterministic, but the execution inside each state adapts to the specific player. That solved the rigidity problem.&lt;/p&gt;

&lt;p&gt;Each one covered the other's weakness. That was the breakthrough.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where the Cloud Came In
&lt;/h2&gt;

&lt;p&gt;This is where my domain actually mattered.&lt;/p&gt;

&lt;p&gt;The RL model needed to be trained on player session data and updated over time. Running that inside Unity wasn't feasible. We needed a backend.&lt;/p&gt;

&lt;p&gt;I built a serverless Flask API deployed to &lt;strong&gt;AWS Lambda via Zappa&lt;/strong&gt;, with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDB&lt;/strong&gt; storing NPC behavior profiles and session data per player&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3&lt;/strong&gt; storing trained model artifacts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway&lt;/strong&gt; exposing endpoints to the Unity client&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The split finally made complete sense. Hassan owned the game engine and FSM implementation in Unity. I owned the AI architecture design, the RL research, and the entire AWS backend.&lt;/p&gt;

&lt;p&gt;Neither of us could have built the other's half.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;90/100 at the university's Project Exhibition.&lt;/p&gt;

&lt;p&gt;Top 8 Runner-Up out of the Final Project Exhibition.&lt;/p&gt;

&lt;p&gt;The viva ran long - not because anything went wrong, but because the committee kept asking questions. The hybrid architecture was something they hadn't seen in a student project before. They pushed hard on why we combined FSM and RL, how we handled the training instability, and why Lambda over EC2 for the backend.&lt;/p&gt;

&lt;p&gt;We had answers for all of it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;On the RL side:&lt;/strong&gt; Train in a headless simulation environment instead of the live game. A simulation running 100x faster than real-time would have produced a significantly better policy by demo day. We were constrained by training in real Unity time which slowed everything down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the cloud side:&lt;/strong&gt; API Gateway WebSockets instead of REST for Unity-to-backend communication. The polling approach added latency that hurt the real-time feel. With my current AWS knowledge I'd redesign that from day one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the project itself:&lt;/strong&gt; Don't wait for the committee to push you. We almost shipped a safe, forgettable project. The "add AI" requirement felt like a burden in that moment. It turned out to be the best thing that happened to us.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Actual Lesson
&lt;/h2&gt;

&lt;p&gt;The hybrid FSM+RL pattern we built isn't just a game AI trick. The same principle - deterministic rules for structure, learned policies for adaptation - shows up in production systems everywhere. Recommendation engines. Fraud detection. Adaptive difficulty in AAA games.&lt;/p&gt;

&lt;p&gt;We didn't invent it. But we found it, understood it deeply enough to implement it under a deadline, and shipped something that surprised the people evaluating it.&lt;/p&gt;

&lt;p&gt;That last part - surprising people who've seen hundreds of student projects - is harder than it sounds.&lt;/p&gt;

&lt;p&gt;And it started with two friends from completely different domains who had no choice but to figure it out together.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Hassan Saleh Hayat handled Unity, game systems, and FSM implementation. I handled AI architecture research, RL integration design, and the AWS backend.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Source
&lt;/h2&gt;

&lt;p&gt;GitHub:github.com/aboodi679/ai-hitman-backend&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqptm5li369eh6wrxjic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqptm5li369eh6wrxjic.png" alt=" " width="800" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6huidsnnw8f1h9xeotti.png" alt=" " width="639" height="301"&gt;
&lt;/h2&gt;

</description>
      <category>ai</category>
      <category>unity3d</category>
      <category>aws</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
