← Back to Home

Capstone Experience

How Cloud Cost Autopilot was designed, built, and evolved over the quarter, from early architecture decisions to debugging live AWS data.

Architecture

Cloud Cost Autopilot is a full stack application built in three layers. The React frontend handles the user interface, the Node.js and Express backend manages all business logic and AWS communication, and PostgreSQL stores account data, EC2 instance records, and generated recommendations.

React Node.js Express PostgreSQL AWS SDK v3 STS EC2 API CloudWatch

The decision to use IAM role assumption rather than storing AWS access keys was a deliberate security choice. Instead of holding long-term credentials, the system calls STS AssumeRole to get temporary credentials valid for one hour. This follows the principle of least privilege and means the application never has persistent access to any AWS account.

AWS Integration

Getting the AWS integration working with real credentials was the most challenging part of the project. The flow looks simple on paper: assume a role, list instances, pull metrics. In practice it required a deep understanding of how IAM trust relationships work at the JSON policy level before anything would connect.

The initial errors were frustrating because AWS doesn't tell you exactly what's wrong. Every failed attempt returned a generic Access Denied message without pointing to which specific permission was missing. The fix ended up being a correction to the trust policy on the IAM role, adding my specific IAM user as a trusted principal. Once that was in place the entire connection worked on the first try.

Artifact — CPU Metrics Function

This function pulls 7 days of CloudWatch CPU data for a single EC2 instance and averages the daily datapoints into one number used by the recommendation engine.

async function getCPUUtilization(credentials, instanceId, region) { const endTime = new Date(); const startTime = new Date(endTime - 7 * 24 * 60 * 60 * 1000); // Pull daily averages over 7 days from CloudWatch const command = new GetMetricStatisticsCommand({ Namespace: 'AWS/EC2', MetricName: 'CPUUtilization', Period: 86400, // 1 day in seconds Statistics: ['Average'], Dimensions: [{ Name: 'InstanceId', Value: instanceId }], StartTime: startTime, EndTime: endTime, }); const response = await cloudwatch.send(command); const avgCPU = response.Datapoints .reduce((sum, dp) => sum + dp.Average, 0) / response.Datapoints.length; return { averageCPU: avgCPU }; }

Recommendation Engine

The recommendation engine is the core of the project. It queries the database for all running instances with less than 5% average CPU over the past 7 days, then calculates estimated monthly savings using a pricing table built from real AWS on-demand rates for us-east-2.

Early versions of the engine just flagged idle instances without attaching a dollar amount. After meeting with stakeholder and hearing his feedback to show savings in dollars rather than percentages, the output was redesigned to lead with the monthly savings figure rather than the raw CPU number.

Artifact — Savings Calculation

The calculateMonthlySavings function takes an instance type, looks it up in the pricing table, and multiplies the hourly rate by 730 hours per month. A t2.micro at $0.0116 per hour costs $8.47 per month, which is the savings realized if the instance is stopped.

const EC2_PRICING = { 't2.micro': 0.0116, 't2.small': 0.0230, 't3.micro': 0.0104, 'm5.large': 0.0960, // ... more instance types }; function calculateMonthlySavings(instanceType) { const hourlyRate = EC2_PRICING[instanceType] || 0.05; return parseFloat((hourlyRate * 730).toFixed(2)); }

Database Design

PostgreSQL stores four core tables: users, aws_accounts, ec2_instances, and recommendations. The ec2_instances table captures the instance ID, type, state, region, and the averaged CloudWatch CPU metric. The recommendations table links back to the account and tracks the resource name, potential savings, and current status which can be pending, applied, or dismissed.

One significant bug during development came from account ID mismatches. Instances were being saved under old account IDs from previous sessions while new scans were querying against a freshly created account ID. Adding a debug endpoint to inspect raw database rows helped trace exactly where the data flow was breaking and resolved the issue.

Frontend Dashboard

The React frontend went through two major iterations. The first version used a dark theme with animations and a collapsible sidebar. After reviewing it, I decided it looked too complex for the scope of the project and rebuilt it with a cleaner white layout that matched the original login screen style. The redesign kept the focus on the dollar savings number rather than letting the interface compete with the data.

Artifact — Dashboard (Final Version)

The final dashboard shows potential monthly savings, pending and applied recommendation counts, and a table with instance IDs, 7-day CPU averages, estimated savings, and action buttons. All data is live from the PostgreSQL database populated by real AWS scans.

Stakeholder Feedback

I met with my stakeholder, a founder running a startup on AWS, to gather feedback on the project direction. His most important comment was that the interface should lead with dollar amounts rather than technical metrics. He explained that his team doesn't think in terms of CPU percentages. They think in terms of how much their AWS bill costs each month and whether that number makes sense. That conversation shaped everything from the recommendation engine output to the layout of the dashboard.