AWS Database Modernization Lab
Benchmark Aurora, DynamoDB+DAX, and MemoryDB under a 10x energy spike.
Introduction
30 Second Summary
When energy prices spike because of geopolitical events, trading platforms need to handle 10x traffic instantly or traders lose millions. Most legacy databases crash under this kind of pressure because they were never designed for unpredictable bursts.
In this project, you will deploy three AWS managed database engines side by side, benchmark them under a simulated market spike, and produce an executive report proving $20M in savings for a fictional energy trading company.
What You'll Build
You will build a complete database modernization lab on AWS using Terraform and Cursor IDE parallel agents, then benchmark Aurora Serverless v2, DynamoDB with DAX, and MemoryDB under realistic energy-market spike load.
By the end of this project, you'll have:
- A Project Requirement Package with architecture decision records, Mermaid diagrams, an implementation plan, a risk register, and SAP-C02 domain alignment.
- A working benchmark lab with three AWS database engines deployed via Terraform within Free Tier, proving performance under a simulated 10x traffic spike.
- An executive HTML report with KPI cards, latency charts, cost projections, an implementation roadmap, and a new revenue stream recommendation that division leaders present to the CTO.
- Secret Mission: Deploy Aurora I/O-Optimized for comparison, demonstrate Babelfish T-SQL compatibility, and build a real-time price API proof-of-concept.
Are there any prerequisites?
You need an AWS account (free tier eligible, under 12 months old or with remaining credits), Cursor IDE installed, and basic familiarity with SQL and Terraform. This project is rated hard and takes approximately 90 minutes.
Before We Start
Before We Start...
Produce the Requirement Package
In a high-pressure organization, the architect who starts building before aligning with leadership gets fired. Your first deliverable is not infrastructure. It is a requirement package that proves you understand the problem, the solution, and the risks.
In this step, you will document your architecture decisions, create diagrams, plan the implementation phases, and align everything to SAP-C02 domains. This is the work that earns trust with the CTO before you touch any AWS resources.
In this step, get ready to:
- Document 5 Architecture Decision Records covering engine selection, caching, and migration strategy.
- Create current-state and future-state architecture diagrams.
- Build the implementation plan, risk register, RACI matrix, and SAP-C02 domain alignment.
Set up the project folder and write the ADRs
You need a dedicated folder to hold your requirement package documents. Everything lives in one place so the CTO can review it as a single deliverable.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and the requirement package directory by running these commands:
mkdir meridian-db-lab
cd meridian-db-lab
mkdir requirement-package
- Confirm the folders exist by running:
ls
You should see requirement-package in the output.
Don't see the folder?
Make sure you ran cd ~/Desktop first. If you are on Windows and mkdir does not recognize the path, run each mkdir command separately without -p.
help me find my project folder on the Desktop
Now open this folder in Cursor so you can create your documentation files.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Cursor and press Enter to open it.
- In Cursor, click File in the top menu bar.
- Click Open Folder.
- Select the meridian-db-lab folder on your Desktop, then click Open.
Architecture Decision Records document the choices you made and the alternatives you rejected. These are what division leaders review to understand your reasoning.
- In the Explorer sidebar, right-click the requirement-package folder and select New File.
- Name the file ADRs.md and press Enter.
- Paste the following content into ADRs.md:
ADR-001: DynamoDB + DAX for trade lookups (rejected Aurora read replicas). ADR-002: RDS Proxy for Aurora (rejected PgBouncer). ADR-003: MemoryDB for price feed (rejected ElastiCache). ADR-004: DMS Serverless for migration. ADR-005: Aurora Serverless v2 on-demand scaling.
What do these ADRs mean?
- ADR-001: DynamoDB on-demand scales instantly to 2x previous peak with zero pre-warming. DAX adds microsecond caching for repeated hot-key reads during flash events. Aurora read replicas have replication lag (up to 100ms) and take minutes to add during a spike.
- ADR-002: RDS Proxy pools 20,000 client connections on a 187-connection-limited instance. It reduces failover time by up to 66%. PgBouncer is self-managed and single-AZ.
- ADR-003: MemoryDB provides sub-millisecond reads WITH Multi-AZ durability via a transaction log. ElastiCache loses data on node failure.
- ADR-004: DMS Serverless handles heterogeneous migration (SQL Server to PostgreSQL) and auto-scales capacity.
- ADR-005: Aurora Serverless v2 scales from 0.5 to 256 ACUs in 0.5 ACU increments per second. Provisioned instances waste money 16 hours/day during off-peak.
Next, create the architecture diagrams file that shows the before-and-after of Meridian's database layer.
- Right-click the requirement-package folder and select New File.
- Name the file architecture-diagrams.md and press Enter.
- Paste the following content into architecture-diagrams.md:
Current-state Mermaid: EC2 r5.4xlarge SQL Server -> 200+ microservices, no cache, single AZ. Future-state Mermaid: DynamoDB+DAX (trade lookups), Aurora Serverless v2+RDS Proxy (analytics), MemoryDB (price feed), DMS (migration path), 2 AZs.
Why two diagrams?
The current-state diagram shows the CTO exactly what is failing today. A single EC2 instance running SQL Server with 200+ direct connections, no caching layer, and a single Availability Zone.
The future-state diagram shows the target: three purpose-built engines, each handling the access pattern it was designed for, spread across 2 AZs for high availability.
- Save both files with Cmd+S (macOS) or Ctrl+S (Windows).
- In the Explorer sidebar, expand the requirement-package folder. You should see ADRs.md and architecture-diagrams.md listed.
Files not showing in the sidebar?
Make sure you created the files inside the requirement-package folder, not in the project root. If they ended up in the wrong place, drag them into the correct folder in the Explorer sidebar.
help me organize my requirement package files in the correct folder
Document the implementation plan and risk register
The implementation plan shows division leaders that you have a phased approach with clear ROI at each stage. The risk register shows you have already anticipated what could go wrong.
- Right-click the requirement-package folder and select New File.
- Name the file implementation-plan.md and press Enter.
- Paste the following content into implementation-plan.md:
Phase 1 (0-3mo): DynamoDB+DAX, $9.2M/yr saved. Phase 2 (3-9mo): Aurora Serverless v2+RDS Proxy, $5M/yr saved. Phase 3 (9-18mo): MemoryDB price API, $600K/yr new revenue.
Why three phases?
Phase 1 targets the highest-pain problem first: failed trades during spikes cost $9.2M/year. DynamoDB + DAX eliminates this immediately.
Phase 2 kills the SQL Server license ($5M/year) by migrating analytics to Aurora Serverless v2. Phase 3 turns the database investment into a revenue product with a real-time price API powered by MemoryDB.
- Create another new file in the requirement-package folder named risk-register.md.
- Paste the following content into risk-register.md:
Risk 1: DMS data loss (mitigation: CDC validation). Risk 2: DAX cold-cache miss (mitigation: pre-warm). Risk 3: Aurora ACU scale-up lag (mitigation: min ACU=2). Risk 4: DBA team resistance (mitigation: Babelfish demo). Risk 5: Budget overrun (mitigation: auto-destroy, cost alerts).
What do these risks cover?
- Risk 1: DMS uses Change Data Capture (CDC) to verify zero rows are lost during migration.
- Risk 2: A cold DAX cache during the first spike after deployment means all requests hit DynamoDB directly. Pre-warming with a batch read prevents this.
- Risk 3: Setting minimum ACU to 2 means Aurora never starts from zero during a sudden spike.
- Risk 4: Babelfish lets T-SQL stored procedures run on Aurora PostgreSQL without rewriting them. This kills the DBA team's top objection.
- Risk 5: Auto-destroy timers and cost alerts prevent forgotten lab resources from burning credits.
- Save both files with Cmd+S (macOS) or Ctrl+S (Windows).
- Confirm implementation-plan.md and risk-register.md appear in the requirement-package folder in the Explorer sidebar.
Seeing unsaved file indicators?
Cursor shows a dot on the file tab when changes are unsaved. Press Cmd+S (macOS) or Ctrl+S (Windows) to save each open file.
help me save all my files in Cursor
Add the RACI matrix and SAP-C02 alignment
The RACI matrix tells leadership exactly who owns each piece of this project. The SAP-C02 alignment maps your architecture decisions to certified AWS competencies.
- Create a new file in the requirement-package folder named raci.md.
- Paste the following content into raci.md:
Responsible: Principal SA. Accountable: CTO. Consulted: DBA team, Finance, Security. Informed: CEO, division leaders, trading desk heads.
What is a RACI matrix?
RACI stands for Responsible, Accountable, Consulted, and Informed. It clarifies who does the work (you), who signs off (CTO), who provides input (DBA team, Finance, Security), and who needs updates (CEO, division leaders).
Without a RACI, stakeholders argue about ownership during crises. With one, everyone knows their lane from Day 1.
- Create a new file in the requirement-package folder named sap-c02-alignment.md.
- Paste the following content into sap-c02-alignment.md:
D2.5: ADR-001, ADR-003, ADR-005. D3.3: ADR-002, DAX caching, Aurora ACU scaling. D4.3: ADR-004, Babelfish, polyglot persistence.
How do these map to the SAP-C02 exam?
- Domain 2.5 (Performance Objectives): Engine selection under load. Key-value access goes to DynamoDB. Relational queries go to Aurora. Ultra-low latency with durability goes to MemoryDB.
- Domain 3.3 (Improve Performance): RDS Proxy for connection pooling. DAX for 10x read acceleration. Aurora per-second ACU scaling.
- Domain 4.3 (New Architecture for Existing Workloads): DMS for heterogeneous migration. Babelfish for T-SQL compatibility. Polyglot persistence decomposing the monolith into purpose-built engines.
- Save both files with Cmd+S (macOS) or Ctrl+S (Windows).
- In the Explorer sidebar, expand requirement-package. You should see all 6 files: ADRs.md, architecture-diagrams.md, implementation-plan.md, raci.md, risk-register.md, and sap-c02-alignment.md.
Missing a file?
Check that you created each file inside the requirement-package folder, not in the meridian-db-lab root. If a file is in the wrong location, drag it into requirement-package using the Explorer sidebar.
help me check that all my requirement package files are in the right place
✔️ Awesome, I've got everything!
Great. Double check you have saved all 6 files in the requirement-package folder.
ⓧ I'd like to double check the full code
Here is the content of each file in your requirement-package folder. Compare yours against these:
ADR-001: DynamoDB + DAX for trade lookups (rejected Aurora read replicas). ADR-002: RDS Proxy for Aurora (rejected PgBouncer). ADR-003: MemoryDB for price feed (rejected ElastiCache). ADR-004: DMS Serverless for migration. ADR-005: Aurora Serverless v2 on-demand scaling.
Current-state Mermaid: EC2 r5.4xlarge SQL Server -> 200+ microservices, no cache, single AZ. Future-state Mermaid: DynamoDB+DAX (trade lookups), Aurora Serverless v2+RDS Proxy (analytics), MemoryDB (price feed), DMS (migration path), 2 AZs.
Phase 1 (0-3mo): DynamoDB+DAX, $9.2M/yr saved. Phase 2 (3-9mo): Aurora Serverless v2+RDS Proxy, $5M/yr saved. Phase 3 (9-18mo): MemoryDB price API, $600K/yr new revenue.
Responsible: Principal SA. Accountable: CTO. Consulted: DBA team, Finance, Security. Informed: CEO, division leaders, trading desk heads.
Risk 1: DMS data loss (mitigation: CDC validation). Risk 2: DAX cold-cache miss (mitigation: pre-warm). Risk 3: Aurora ACU scale-up lag (mitigation: min ACU=2). Risk 4: DBA team resistance (mitigation: Babelfish demo). Risk 5: Budget overrun (mitigation: auto-destroy, cost alerts).
D2.5: ADR-001, ADR-003, ADR-005. D3.3: ADR-002, DAX caching, Aurora ACU scaling. D4.3: ADR-004, Babelfish, polyglot persistence.
Your requirement package is complete. You have not written a single line of infrastructure code, but you have something far more powerful: a documented plan that the CTO can review, challenge, and approve. Next up, you will set up your workstation with Terraform, k6, and the AWS CLI so you can turn this plan into real infrastructure.
Set Up Your Workstation
Your requirement package is complete. The CTO has seen your ADRs, your risk register, and your implementation plan. Now you need to prove it works.
This step installs the three tools you need to build the lab: Terraform for infrastructure-as-code, k6 for load testing, and the AWS CLI for verifying resources. You will also set up your Cursor workspace with module directories ready for parallel agents.
In this step, get ready to:
- Install Terraform and k6 on your machine.
- Configure the AWS CLI with a named profile for the lab.
- Create your Cursor workspace with 4 module directories for parallel agents.
Install Terraform and k6
Terraform provisions all your AWS infrastructure from code. k6 generates the load that simulates an OPEC-announcement spike against your databases.
Both tools are version-pinned for this lab. Terraform must be 1.15.3 or higher. k6 must be 1.7.1 or higher.
- Open your terminal. Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
- Check if Terraform is already installed by running this command:
terraform --version
✔️ I see version 1.15 or higher
Terraform is ready. Move on to the k6 check below.
ⓧ I see an older version
You have Terraform installed, but it is below 1.15.3. Upgrade to the latest version.
macOS
- Upgrade Terraform via Homebrew by running these commands:
brew tap hashicorp/tap
brew upgrade hashicorp/tap/terraform
- Verify the new version by running:
terraform --version
You should see 1.15.3 or higher in the output.
Windows
- Download the latest Terraform binary (AMD64) from the official install page:
developer.hashicorp.com/terraform/install
- Extract the zip file.
- Replace your existing terraform.exe with the new binary.
- Open a new PowerShell window and verify:
terraform --version
You should see 1.15.3 or higher in the output.
ⓧ Command not found
Terraform is not installed yet. Install it now.
macOS
- Install Terraform via Homebrew by running these commands:
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
- Verify the installation by running:
terraform --version
You should see Terraform v1.15.3 in the output.
Windows
- Download the Terraform binary (AMD64) from the official install page:
developer.hashicorp.com/terraform/install
- Extract the zip file.
- Move terraform.exe to a folder that is in your system PATH (for example, C:\terraform).
- Add that folder to your PATH environment variable if it is not already there.
- Open a new PowerShell window and verify:
terraform --version
You should see Terraform v1.15.3 in the output.
Terraform not recognized after install?
Make sure the folder containing terraform.exe (or terraform on macOS) is in your system PATH. On Windows, you must open a new PowerShell window after changing PATH.
Help me troubleshoot this
Now check k6.
- Check if k6 is already installed by running this command:
k6 version
✔️ I see version 1.7 or higher
k6 is ready. Move on to configuring the AWS CLI.
ⓧ I see an older version
You have k6 installed, but it is below 1.7.1. Upgrade to the latest version.
macOS
- Upgrade k6 by running:
brew upgrade k6
- Verify by running:
k6 version
You should see v1.7.1 or higher.
Windows
- Upgrade k6 by running:
winget install Grafana.k6
- Close and reopen PowerShell, then verify:
k6 version
You should see v1.7.1 or higher.
ⓧ Command not found
k6 is not installed yet. Install it now.
macOS
- Install k6 via Homebrew by running:
brew install k6
- Verify the installation:
k6 version
You should see k6 v1.7.1 in the output.
Windows
- Install k6 via the Windows Package Manager by running:
winget install Grafana.k6
- Close and reopen PowerShell, then verify:
k6 version
You should see k6 v1.7.1 in the output.
k6 not recognized after install?
On Windows, close your current PowerShell window and open a new one. Winget installs update the PATH but only take effect in new sessions.
On macOS, if Homebrew itself is not installed, install it first from brew.sh and try again.
Help me fix my k6 installation
💡 Why Terraform and k6?
Terraform lets you define all five infrastructure components (VPC, Aurora, DynamoDB, DAX, MemoryDB) as code and deploy them in parallel. Without it, you would spend hours clicking through the AWS console.
k6 generates realistic load patterns that simulate the 10x traffic spike when OPEC makes an announcement. The benchmark data it produces is what makes your executive report credible. Without measured latency numbers, your recommendation is just an opinion.
Configure the AWS CLI with the meridian-prod profile
The AWS CLI lets you interact with every AWS service from your terminal. You will use a named profile called meridian-prod so all commands target the correct account.
- Check that the AWS CLI is installed by running:
aws --version
✔️ I see a version number
The AWS CLI is installed. Continue with the profile configuration below.
ⓧ Command not found
The AWS CLI is not installed. Follow the official installation guide for your operating system:
docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
After installation, open a new terminal window and run aws --version again to confirm.
- Configure your named profile by running this command:
aws configure --profile meridian-prod
What does this command ask?
The CLI prompts you for four values:
- AWS Access Key ID and Secret Access Key: your IAM credentials. Find these in the AWS Console under IAM > Users > your user > Security credentials > Create access key.
- Default region name: enter us-east-1.
- Default output format: enter json.
- Verify the profile works and confirm your free-tier status by running:
aws sts get-caller-identity --profile meridian-prod
You should see a JSON response with your account ID, user ARN, and user ID. This confirms the CLI can authenticate to your AWS account.
How do I know I'm on free tier?
If your AWS account is less than 12 months old, you are eligible for the free tier. You can confirm this in the AWS Console under Billing > Free Tier. This lab uses only free-tier-eligible services with mandatory teardown at the end.
🙋♀️ Seeing InvalidClientTokenId?
This means your access key or secret key is incorrect. Run aws configure --profile meridian-prod again and re-enter your credentials carefully. Make sure you copy the secret key from the moment it was created (it is only shown once).
Help me troubleshoot my AWS credentials
Create your Cursor workspace and module directories
Each Cursor agent will work inside its own module directory. Keeping the modules isolated means agents can write code in parallel without merge conflicts.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir meridian-db-lab
cd meridian-db-lab
- Create the 4 module directories by running:
macOS
mkdir -p modules/networking modules/aurora modules/dynamodb modules/memorydb
Windows
mkdir modules/networking, modules/aurora, modules/dynamodb, modules/memorydb
- Confirm the directories exist by running:
ls modules/
You should see aurora, dynamodb, memorydb, and networking listed in the output.
What is each module for?
- modules/networking: Agent-A builds the VPC, subnets, EC2 source database, and DMS instance here.
- modules/aurora: Agent-B builds Aurora Serverless v2, RDS Proxy, and Secrets Manager here.
- modules/dynamodb: Agent-C builds the DynamoDB table and DAX cluster here.
- modules/memorydb: Agent-D builds the MemoryDB cluster, k6 test scripts, and CloudWatch dashboard here.
- Open Cursor. Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Cursor and press Enter to open it.
- In Cursor, click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop and select the meridian-db-lab folder, then click Open.
You should see the modules folder in the Explorer sidebar with all four subdirectories visible.
What are agent prompts?
In the next step, you will launch 4 Cursor Composer agents simultaneously. Each agent gets a prompt that tells it which module to build, what free-tier constraints to follow, and which SAP-C02 domain it demonstrates. The module directories you just created give each agent a clean workspace.
🙋♀️ Don't see all four directories in Cursor?
Make sure you opened the meridian-db-lab folder (not a parent folder like Desktop). In the Explorer sidebar, you should see modules/ at the top level containing aurora, dynamodb, memorydb, and networking.
Help me verify my folder structure
Your workstation is armed. Terraform, k6, and the AWS CLI are ready. Your module directories are waiting for agents. Next up, you will launch 4 parallel Cursor agents and deploy the full database stack in under 20 minutes.
Deploy the Full Stack with Parallel Agents
Your requirement package earned the CTO's trust. Your workstation is ready. Now you deploy real infrastructure that proves your architecture works under spike load.
A principal architect does not write every Terraform module by hand. You delegate the implementation to Cursor's parallel agents, each working on an independent module in isolation. You review their output for correctness and free-tier compliance, then deploy everything with a single command.
In this step, get ready to:
- Launch 4 parallel Cursor agents to generate Terraform modules for networking, Aurora, DynamoDB, and MemoryDB.
- Review the generated Terraform plans for security groups, IAM roles, and free-tier compliance.
- Deploy all 4 modules simultaneously with terraform init && terraform apply.
Launch 4 parallel Cursor agents
Each agent gets a dedicated Terraform module to build. Because the modules are independent (networking, Aurora, DynamoDB, MemoryDB), the agents can work in parallel without conflicts.
- In Cursor, open the Agents Window by pressing Cmd+Shift+P (macOS) or Ctrl+Shift+P (Windows) and selecting Open Agents Window.
- Start your first agent. Paste the following prompt for Agent-A (Networking + Source):
Build the Terraform module in modules/networking/main.tf for Meridian Energy Trading.
Context: We are an energy trading platform migrating off a legacy SQL Server monolith. This module provides the foundation networking and the source database for DMS migration.
Requirements:
- VPC with 2 public subnets across 2 AZs (us-east-1a, us-east-1b)
- NO NAT gateway (cost constraint: $0 lab)
- VPC Gateway Endpoints for S3 and DynamoDB
- EC2 t3.micro (free-tier) running PostgreSQL, seeded with 50,000 trade records (crude oil, natural gas, electricity futures, carbon credits)
- DMS Serverless replication instance with source endpoint (EC2 PostgreSQL) and target endpoint (Aurora)
- Security groups allowing internal VPC traffic
- IAM roles for DMS and EC2
- All resources tagged: Project = meridian-gridshift, Environment = lab
Free-tier constraints: t3.micro only (750 hrs/month free), no NAT gateway, public subnets with VPC endpoints instead.
SAP-C02 domain: D4.3 (migration architecture with DMS).
- While Agent-A is running, open a new agent from the sidebar. Paste the following prompt for Agent-B (Aurora + Proxy):
Build the Terraform module in modules/aurora/main.tf for Meridian Energy Trading.
Context: Aurora Serverless v2 handles the analytics and reporting workload. RDS Proxy eliminates connection storms from 200+ microservices.
Requirements:
- Aurora Serverless v2 cluster (PostgreSQL-compatible engine)
- Minimum capacity: 0.5 ACU, maximum capacity: 4 ACU
- Aurora Standard storage (not I/O-Optimized)
- RDS Proxy with connection pooling enabled
- Secrets Manager secret for database credentials (auto-generated password)
- Security groups allowing traffic from VPC CIDR
- Subnet group using the 2 public subnets from the networking module
- Accept VPC ID and subnet IDs as input variables
Free-tier constraints: max 4 ACU, Aurora Serverless v2 free plan covers this for new accounts (12 months).
SAP-C02 domains: D2.5 (engine selection), D3.3 (RDS Proxy connection pooling).
- Open a third agent. Paste the following prompt for Agent-C (DynamoDB + DAX):
Build the Terraform module in modules/dynamodb/main.tf for Meridian Energy Trading.
Context: DynamoDB handles trade lookups during flash market spikes. DAX provides microsecond caching for hot-key reads.
Requirements:
- DynamoDB table named meridian-trades
- Billing mode: PAY_PER_REQUEST (on-demand)
- Partition key: trade_id (String)
- Sort key: commodity_type (String)
- Global Secondary Index on commodity_type + timestamp for range queries
- 1-node DAX cluster (dax.t3.small instance type)
- DAX TTL: 5 minutes (item cache and query cache)
- IAM role for DAX to access the DynamoDB table
- Accept VPC ID and subnet IDs as input variables (DAX is VPC-only)
Free-tier constraints: DynamoDB on-demand has perpetual free tier (25 RCU/WCU). DAX is NOT free-tier but covered by new-account credits. 1 node only.
SAP-C02 domains: D2.5 (DAX vs ElastiCache trap), D3.3 (DAX caching layer).
- Open a fourth agent. Paste the following prompt for Agent-D (MemoryDB + Load Harness):
Build the Terraform module in modules/memorydb/main.tf for Meridian Energy Trading.
Context: MemoryDB powers the real-time price feed with sub-millisecond durable reads. k6 scripts benchmark all 3 database targets under simulated OPEC spike load.
Requirements:
- MemoryDB cluster: db.t4g.small, 1 node, Valkey 7.2 engine, TLS enabled, ACL authentication
- Security group allowing port 6379 from VPC CIDR
- k6 test scripts (JavaScript) for 3 targets:
1. Aurora via RDS Proxy (PostgreSQL queries)
2. DynamoDB via AWS SDK (GetItem and Query)
3. MemoryDB via Redis protocol (GET commands)
- Each k6 script: ramping-vus scenario from 5 to 100 VUs over 60 seconds
- CloudWatch dashboard Terraform resource showing: Aurora ACU capacity, DAX hit/miss ratio, MemoryDB CPU utilization
- Accept VPC ID, subnet IDs, and endpoint outputs from other modules as input variables
Free-tier constraints: MemoryDB covered by $200 new-account credits. 1 node only. Mandatory destroy after benchmark.
SAP-C02 domains: D2.5 (MemoryDB vs ElastiCache trap), D3.3 (sub-ms durable reads).
What is happening with these 4 agents?
Each agent works in an isolated Git worktree, so they cannot overwrite each other's files. Agent-A builds the VPC and source database. Agent-B builds Aurora and RDS Proxy. Agent-C builds DynamoDB and DAX. Agent-D builds MemoryDB and the k6 load test scripts.
This is how a principal architect operates. You define the architecture and constraints. AI agents handle the implementation. You review for quality. The provisioning time (15-20 minutes) is time you spend reviewing plans, not waiting idly.
💡 Why parallel agents instead of writing code yourself?
The SAP-C02 exam (D4.3) tests whether you can design a migration architecture. It does not test whether you can type HCL syntax from memory. Delegating implementation to agents while you focus on architecture decisions, cost guardrails, and security review is the real principal-level operating rhythm.
Review the generated Terraform plans
While the agents generate code (approximately 15-20 minutes), review each module's output. This is your quality gate before deployment.
- As each agent completes, review its output in the Cursor sidebar. Check each module against this list:
- Security groups: Confirm no 0.0.0.0/0 ingress rules on database ports. All DB traffic should be restricted to the VPC CIDR.
- IAM roles: Confirm least-privilege policies. DMS needs dms-vpc-role and dms-cloudwatch-logs-role. DAX needs read access to the meridian-trades table only.
- Free-tier compliance: EC2 is t3.micro (not t3.small). Aurora max ACU is 4 (not higher). No NAT gateway resource exists. DAX is 1 node. MemoryDB is 1 node.
- Module outputs: Each module should export the resource identifiers that downstream modules need (VPC ID, subnet IDs, endpoint URLs, security group IDs).
- Create the root main.tf file in your project root that ties all 4 modules together. The root module passes shared outputs (VPC ID, subnet IDs) from the networking module into the other three:
# Root module - ties all child modules together
# Passes networking outputs (VPC, subnets) to database modules
provider "aws" {
region = "us-east-1"
profile = "meridian-prod"
}
# Module A: VPC, subnets, EC2 source DB, DMS
module "networking" {
source = "./modules/networking"
}
# Module B: Aurora Serverless v2 + RDS Proxy
module "aurora" {
source = "./modules/aurora"
vpc_id = module.networking.vpc_id
subnet_ids = module.networking.subnet_ids
}
# Module C: DynamoDB table + DAX cluster
module "dynamodb" {
source = "./modules/dynamodb"
vpc_id = module.networking.vpc_id
subnet_ids = module.networking.subnet_ids
}
# Module D: MemoryDB + k6 scripts + CloudWatch dashboard
module "memorydb" {
source = "./modules/memorydb"
vpc_id = module.networking.vpc_id
subnet_ids = module.networking.subnet_ids
}
What does this root module do?
The root main.tf declares the AWS provider with your meridian-prod profile, then calls each child module. The networking module deploys first because it has no dependencies. The other three modules receive VPC and subnet outputs as input variables, so Terraform automatically builds them after networking completes.
- Save main.tf in your project root directory (the same folder that contains the modules/ folder).
Agent output doesn't look right?
If an agent produces incomplete or incorrect Terraform, iterate on it. Reply in the same agent thread with what needs fixing (for example: "Remove the NAT gateway resource, use VPC endpoints instead" or "Change instance type to t3.micro for free-tier compliance"). Each agent keeps its context and can correct itself.
If an agent stalls or produces errors repeatedly, help me fix my Terraform module that Cursor generated incorrectly.
Deploy the infrastructure with Terraform
With all 4 modules reviewed and the root main.tf in place, you deploy everything in one command. Terraform resolves the dependency graph and provisions the networking module first, then the three database modules in parallel.
- Initialize and deploy all modules by running this command from your project root:
terraform init && terraform apply
- Terraform will show you a plan listing all resources to be created. Review the resource count. You should see resources for: VPC, subnets, VPC endpoints, EC2 instance, DMS replication instance, Aurora cluster, RDS Proxy, DynamoDB table, DAX cluster, MemoryDB cluster, security groups, IAM roles, and the CloudWatch dashboard.
- Type yes when prompted to confirm the apply.
What happens during terraform apply?
Terraform provisions the networking module first (VPC, subnets, endpoints, EC2, DMS). Once those outputs are available, it launches the Aurora, DynamoDB, and MemoryDB modules in parallel. The full deployment takes approximately 15-20 minutes. Aurora cluster creation and MemoryDB cluster creation are the longest-running operations.
- Wait for the apply to complete. You should see a success message at the end with the total resource count.
- Verify the deployment by running:
terraform output
- You should see outputs including the VPC ID, Aurora cluster endpoint, DynamoDB table name (meridian-trades), DAX cluster endpoint, and MemoryDB cluster endpoint.
Seeing errors during terraform apply?
Common causes:
- "Error: creating Aurora cluster": Your account may not have Aurora Serverless v2 available in us-east-1. Confirm your region is set to us-east-1 in both your AWS CLI profile and the provider block.
- "Error: insufficient IAM permissions": The IAM user in your meridian-prod profile needs broad permissions for this lab. Attach the AdministratorAccess managed policy temporarily.
- "Error: limit exceeded for DAX clusters": New accounts have a default limit of 1 DAX cluster. Confirm your module only provisions 1 node.
If you are stuck, help me troubleshoot this Terraform apply error.
Your full database lab is now running in AWS. The networking layer, three managed database engines, caching clusters, migration infrastructure, and load test scripts are all provisioned and ready. Next up, you will migrate data into all three engines and verify every target with pure CLI commands.
Migrate Data and Verify All Engines
Your infrastructure is deployed. Three empty database engines are running in parallel, waiting for data. The next move is what separates a real migration from a demo.
You need to prove that 50,000 trade records move safely from the legacy source to all three targets. DMS handles the Aurora migration automatically. DynamoDB and MemoryDB get seeded in parallel so no time is wasted. Then you verify every target with pure AWS CLI commands. No console. Scriptable. Repeatable.
In this step, get ready to:
- Start the DMS full-load migration from EC2 PostgreSQL to Aurora.
- Seed DynamoDB and MemoryDB with identical trade data in parallel.
- Verify all five targets via AWS CLI with zero console clicks.
Start the DMS full-load migration
DMS replicates data from your EC2 PostgreSQL source to the Aurora Serverless v2 target. A full-load task copies all 50,000 rows in one pass. This takes roughly 3-5 minutes for this dataset size.
- Retrieve your DMS replication task ARN from Terraform output by running:
terraform output dms_replication_task_arn
- Start the full-load replication task by running this command:
aws dms start-replication-task --replication-task-arn [[DMS_TASK_ARN="your DMS replication task ARN from terraform output"]] --start-replication-task-type start-replication --profile meridian-prod
What does this command do?
The --start-replication-task-type start-replication flag tells DMS to perform a full-load migration. This copies every row from your EC2 PostgreSQL source to the Aurora target in a single pass.
DMS handles schema conversion and data type mapping automatically for this PostgreSQL-to-PostgreSQL path. The task transitions through starting to running to stopped (with stop reason FULL_LOAD_ONLY_FINISHED) when complete.
DMS will take 3-5 minutes for 50,000 rows. While it runs, seed the other two targets in parallel.
Seed DynamoDB and MemoryDB while DMS runs
All three targets need identical trade data for a fair benchmark. Your Cursor agents generated seeding scripts alongside the Terraform modules. Run them now while DMS handles Aurora.
- Seed DynamoDB with the batch-write script by running:
# Batch-write 50,000 trade records to DynamoDB
# Uses 25-item batches (DynamoDB BatchWriteItem limit)
python3 scripts/seed_dynamodb.py --profile meridian-prod
Why batch-write instead of single PutItem calls?
DynamoDB's BatchWriteItem sends up to 25 items per API call. For 50,000 records, that reduces 50,000 network round-trips to 2,000. On-demand billing means you pay per request regardless of batch size, so batching is purely a speed optimization.
- Seed MemoryDB with the Redis MSET bulk load script by running:
# Bulk-load trade records into MemoryDB via MSET
# Connects through TLS with ACL auth
python3 scripts/seed_memorydb.py --profile meridian-prod
What is MSET?
MSET is a Redis command that sets multiple key-value pairs in a single atomic operation. For MemoryDB (which is Valkey/Redis-compatible), this loads thousands of trade records without individual SET round-trips. The TLS connection and ACL auth are handled by the script using credentials from Secrets Manager.
- Wait for both scripts to complete. Each should finish in under 2 minutes.
Script failing with a connection error?
If the DynamoDB script fails, confirm your security group allows outbound HTTPS to the DynamoDB VPC endpoint. If the MemoryDB script fails, check that the security group attached to MemoryDB allows inbound on port 6379 from your EC2 instance's security group.
help me debug my seeding script connection error
Verify all engines via AWS CLI
Every verification uses AWS CLI. No console clicks. This builds the CLI fluency that SAP-C02 Domain 4.3 tests on exam day.
- Verify the Aurora cluster is available by running:
aws rds describe-db-clusters --profile meridian-prod
- Confirm you see "Status": "available" in the output.
- Verify the row count in Aurora through RDS Proxy by running:
# Connect through RDS Proxy endpoint and count rows
psql -h [[RDS_PROXY_ENDPOINT="your RDS Proxy endpoint from terraform output"]] -U postgres -d meridian -c "SELECT count(*) FROM trades;"
- Confirm the output shows 50000.
- Verify the DynamoDB record count by running:
aws dynamodb scan --table-name meridian-trades --select COUNT --profile meridian-prod
- Confirm "Count": 50000 appears in the JSON response.
- Verify the DAX cluster status by running:
aws dax describe-clusters --profile meridian-prod
- Confirm "Status": "available" for your DAX cluster.
- Verify the MemoryDB cluster status by running:
aws memorydb describe-clusters --profile meridian-prod
- Confirm "Status": "available" in the output.
- Verify trade data is present in MemoryDB by running:
# Connect to MemoryDB via redis-cli with TLS
redis-cli -h [[MEMORYDB_ENDPOINT="your MemoryDB cluster endpoint"]] --tls -a [[MEMORYDB_AUTH="your MemoryDB ACL auth token"]] GET trade:crude_oil:00001
- Confirm you see trade record JSON data in the response.
- Verify the DMS task completed successfully by running:
aws dms describe-replication-tasks --profile meridian-prod
- Confirm the task shows "Status": "stopped" with "StopReason": "Stop Reason FULL_LOAD_ONLY_FINISHED". This means DMS loaded all rows and stopped cleanly.
Why does a successful DMS task show 'stopped'?
DMS tasks that use full-load migration type (no ongoing CDC replication) transition to stopped status when they finish. The StopReason field distinguishes between successful completion and failures. FULL_LOAD_ONLY_FINISHED confirms all rows were migrated without errors.
On the SAP-C02 exam, knowing the difference between DMS task states (running, stopped, failed) and stop reasons is tested in Domain 4.3 (new architecture for existing workloads).
🙋♀️ DMS task showing 'failed' status?
Check the LastFailureMessage field in the describe-replication-tasks output. Common causes: the source endpoint security group does not allow outbound to Aurora's security group, or the target Aurora cluster has not finished initializing. Re-run aws rds describe-db-clusters --profile meridian-prod and confirm Aurora status is available before restarting the task.
help me debug my DMS replication task failure
SAP-C02 Domain 4.3 in action
You just completed a heterogeneous database migration using DMS, verified endpoints via CLI, and confirmed data integrity across three managed engines. Domain 4.3 (designing new architectures for existing workloads) tests exactly this: DMS task states, endpoint validation, and migration verification patterns.
When the exam asks about migrating from a self-managed database to managed services, remember: you did not use the console. Every step was a CLI command you could script into a CI/CD pipeline or repeat across environments.
All three engines are loaded with identical data. Your benchmark will be fair and your results will be credible. Next up, you simulate an OPEC announcement and watch these engines perform under a 10x traffic spike.
Run the Benchmark
All three database engines are loaded with identical trade data. Now you need proof that your architecture handles a real spike.
The scenario: It is 14:00 UTC. OPEC announces a surprise production cut. Energy prices spike. Every trader at Meridian hits the platform simultaneously. Read traffic goes from baseline to 10x in 30 seconds. Your k6 scripts simulate exactly this. They ramp from 5 to 100 virtual users over 60 seconds, hammering all three engines with random trade lookups by commodity and date range.
In this step, get ready to:
- Run k6 benchmarks against Aurora, DynamoDB+DAX, and MemoryDB under simulated spike load.
- Monitor CloudWatch metrics while the benchmark runs to watch engines scale in real time.
- Capture final results and calculate production-scale cost projections for 500K reads/minute.
Run k6 against all three database targets
Your Cursor Agent-D already generated the k6 test scripts. Each script uses a ramping-vus scenario that climbs from 5 to 100 virtual users over 60 seconds. Every VU performs random trade lookups by commodity and date range.
- Create the output directory for your benchmark results by running:
mkdir benchmark-results
- Run the k6 benchmark against Aurora Serverless v2 (through RDS Proxy) by running:
k6 run --out json=benchmark-results/aurora.json modules/memorydb/k6-aurora.js
- Run the k6 benchmark against DynamoDB + DAX by running:
k6 run --out json=benchmark-results/dynamodb-dax.json modules/memorydb/k6-dynamodb-dax.js
- Run the k6 benchmark against MemoryDB by running:
k6 run --out json=benchmark-results/memorydb.json modules/memorydb/k6-memorydb.js
What do these commands do?
Each k6 run command executes a load test script that ramps virtual users from 5 to 100 over 60 seconds. The --out json= flag saves all metrics (latency percentiles, throughput, error counts) to a JSON file for your executive report.
Each script simulates traders performing random lookups by commodity (crude oil, natural gas, electricity futures, carbon credits) and date range. This mirrors what happens during an OPEC announcement when every trader refreshes simultaneously.
Each k6 run takes approximately 60 seconds. You should see live output in your terminal showing VUs ramping up and response times for each engine.
Seeing connection errors?
If k6 reports connection timeouts, confirm your security groups allow traffic from your EC2 instance to each database endpoint. Check that the DAX and MemoryDB clusters are in the same VPC as your test runner.
help me debug k6 connection errors to my AWS database targets
Monitor performance with CloudWatch while k6 runs
While k6 runs, you want to see your engines scaling in real time. This is the evidence that proves auto-scaling works under spike conditions.
- Check Aurora Serverless v2 ACU scaling by running:
aws cloudwatch get-metric-data \
--metric-data-queries '[{"Id":"acu","MetricStat":{"Metric":{"Namespace":"AWS/RDS","MetricName":"ServerlessDatabaseCapacity","Dimensions":[{"Name":"DBClusterIdentifier","Value":"meridian-aurora-cluster"}]},"Period":60,"Stat":"Average"},"ReturnData":true}]' \
--start-time $(date -u -d '5 minutes ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--profile meridian-prod
What should I see?
Watch the ServerlessDatabaseCapacity values climb from 0.5 ACU toward 4 ACU as k6 increases load. This proves Aurora Serverless v2 scales per-second without manual intervention. The SAP-C02 exam (D3.3) tests exactly this concept.
- Check DAX cache hit ratio by running:
aws cloudwatch get-metric-data \
--metric-data-queries '[{"Id":"hits","MetricStat":{"Metric":{"Namespace":"AWS/DAX","MetricName":"CacheHitCount","Dimensions":[{"Name":"ClusterId","Value":"meridian-dax-cluster"}]},"Period":60,"Stat":"Sum"},"ReturnData":true},{"Id":"misses","MetricStat":{"Metric":{"Namespace":"AWS/DAX","MetricName":"CacheMissCount","Dimensions":[{"Name":"ClusterId","Value":"meridian-dax-cluster"}]},"Period":60,"Stat":"Sum"},"ReturnData":true}]' \
--start-time $(date -u -d '5 minutes ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--profile meridian-prod
What should I see?
After the first few seconds of warm-up, CacheHitCount should dominate CacheMissCount. Your target is greater than 95% hit ratio. This proves DAX delivers microsecond reads from cache for repeated hot-key lookups during flash events.
- Check MemoryDB resource utilization by running:
aws cloudwatch get-metric-data \
--metric-data-queries '[{"Id":"cpu","MetricStat":{"Metric":{"Namespace":"AWS/MemoryDB","MetricName":"CPUUtilization","Dimensions":[{"Name":"ClusterName","Value":"meridian-memorydb-cluster"}]},"Period":60,"Stat":"Average"},"ReturnData":true},{"Id":"net","MetricStat":{"Metric":{"Namespace":"AWS/MemoryDB","MetricName":"NetworkBytesIn","Dimensions":[{"Name":"ClusterName","Value":"meridian-memorydb-cluster"}]},"Period":60,"Stat":"Sum"},"ReturnData":true}]' \
--start-time $(date -u -d '5 minutes ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--profile meridian-prod
Why MemoryDB stays cool under load
MemoryDB delivers sub-millisecond reads with up to 160 million transactions per second per cluster. Even at 100 VUs, your single-node cluster barely breaks a sweat. The CPUUtilization and NetworkBytesIn metrics confirm capacity headroom for production scale.
🙋♀️ CloudWatch returning empty data?
CloudWatch metrics take 1-2 minutes to appear after activity starts. If you see empty arrays, wait 2 minutes after running k6 and query again. Also confirm your cluster identifiers match exactly what Terraform created. Run terraform output to check the actual resource names.
help me troubleshoot empty CloudWatch metric data for my Aurora, DAX, and MemoryDB clusters
Capture results and calculate production cost projections
Your k6 runs are complete. Now you extract the numbers that go into the executive report and calculate what these engines cost at Meridian's production scale of 500,000 reads per minute during peak events.
- Review the final benchmark results from your k6 JSON output. Your results should show:
- Aurora Serverless v2 + RDS Proxy: p50 = 4.2ms, p95 = 8.1ms, p99 = 12.8ms, throughput = 8,500 req/s, error rate = 0%.
- DynamoDB + DAX: p50 = 0.4ms, p95 = 0.9ms, p99 = 1.2ms, throughput = 45,000 req/s, DAX cache hit ratio > 95%, error rate = 0%.
- Amazon MemoryDB: p50 = 0.6ms, p95 = 1.4ms, p99 = 1.8ms, throughput = 38,000 req/s, error rate = 0%.
Why DAX wins for trade lookups
DAX delivers 0.4ms p50 latency. That is a 10x improvement over Aurora for key-value lookups. The reason is architectural: DAX sits in-memory, API-compatible with DynamoDB, requiring zero code changes. The SAP-C02 exam (D2.5) tests this exact comparison.
Aurora wins for relational analytics (joins, aggregations, reporting). MemoryDB wins for durable real-time feeds where you need both sub-millisecond speed AND a Multi-AZ transaction log. Each engine has a purpose.
- Calculate production-scale cost projections for Meridian's actual peak load of 500,000 reads per minute. Use published pricing to extrapolate your free-tier benchmark numbers:
- Aurora Serverless v2: $0.0014 per 1,000 reads at production scale (ACU-hour billing at $0.12/ACU-hour).
- DynamoDB + DAX: $0.0008 per 1,000 reads at production scale (on-demand RCU pricing + DAX node-hour).
- MemoryDB: $0.0019 per 1,000 reads at production scale (node-hour billing).
How to answer the SAP-C02 performance question
The SAP-C02 exam (D3.3) asks: how do you improve read performance for a bursty workload? Your answer, backed by real data: DAX for key-value (microsecond), Aurora Serverless v2 for relational (auto-scale ACUs per-second), MemoryDB for durable real-time (sub-ms with transaction log).
You have the benchmark numbers to prove it. That is the difference between guessing on the exam and knowing.
Your benchmark data is captured and your cost projections are calculated. Next up, you will build the executive HTML report that the CTO walks into the CEO meeting with.
Build the Executive Report
Your benchmark data is captured. DAX proved microsecond reads under 10x spike load. Aurora auto-scaled ACUs per-second without dropping a request. MemoryDB delivered sub-millisecond durable reads.
Now you need to turn those numbers into something the CTO walks into the CEO meeting with. A single HTML file that answers the only question leadership cares about: does this architecture save $20M, and what does the roadmap look like?
In this step, get ready to:
- Create an executive HTML report with KPIs, benchmark charts, and strategic recommendations.
- Create a decision matrix for the internal engineering wiki.
- Destroy all AWS resources immediately to keep your lab cost at $0.
Create the executive HTML report
The report is a single self-contained HTML file with no external dependencies beyond a CDN-loaded Chart.js library. It can be emailed, projected in a boardroom, or shared on Slack.
- In Cursor, create a new file called report.html in your project root directory (the same folder that contains main.tf).
- Paste the following code into report.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project GRIDSHIFT - Executive KPI Report</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0f172a; color: #e2e8f0; line-height: 1.6; }
.container { max-width: 1200px; margin: 0 auto; padding: 2rem; }
.header { text-align: center; padding: 3rem 0; border-bottom: 1px solid #334155; }
.header h1 { font-size: 2.5rem; color: #38bdf8; margin-bottom: 0.5rem; }
.header .subtitle { font-size: 1.2rem; color: #94a3b8; }
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; margin: 2rem 0; }
.kpi-card { background: #1e293b; border-radius: 12px; padding: 1.5rem; border: 1px solid #334155; }
.kpi-card .label { font-size: 0.875rem; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em; }
.kpi-card .value { font-size: 2.5rem; font-weight: 700; color: #4ade80; margin: 0.5rem 0; }
.kpi-card .value.cost { color: #f87171; }
.kpi-card .value.neutral { color: #38bdf8; }
.kpi-card .detail { font-size: 0.875rem; color: #64748b; }
.section { margin: 3rem 0; }
.section h2 { font-size: 1.5rem; color: #f8fafc; margin-bottom: 1rem; padding-bottom: 0.5rem; border-bottom: 1px solid #334155; }
.chart-container { background: #1e293b; border-radius: 12px; padding: 2rem; margin: 1rem 0; }
table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
th, td { padding: 0.75rem 1rem; text-align: left; border-bottom: 1px solid #334155; }
th { color: #94a3b8; font-weight: 600; font-size: 0.875rem; text-transform: uppercase; }
td { color: #e2e8f0; }
.highlight { color: #4ade80; font-weight: 600; }
.recommendation { background: linear-gradient(135deg, #1e3a5f, #1e293b); border: 1px solid #38bdf8; border-radius: 12px; padding: 2rem; margin: 2rem 0; }
.recommendation h3 { color: #38bdf8; margin-bottom: 1rem; }
.revenue { background: linear-gradient(135deg, #1a2e1a, #1e293b); border: 1px solid #4ade80; border-radius: 12px; padding: 2rem; margin: 2rem 0; }
.revenue h3 { color: #4ade80; margin-bottom: 1rem; }
.free-tier-badge { display: inline-block; background: #065f46; color: #6ee7b7; padding: 0.25rem 0.75rem; border-radius: 9999px; font-size: 0.75rem; font-weight: 600; margin-left: 0.5rem; }
.domain-card { background: #1e293b; border-radius: 12px; padding: 1.5rem; border-left: 4px solid #f59e0b; margin: 1rem 0; }
.domain-card h4 { color: #f59e0b; margin-bottom: 0.5rem; }
.trap { background: #2d1b1b; border: 1px solid #dc2626; border-radius: 8px; padding: 1rem; margin: 0.5rem 0; }
.trap strong { color: #fca5a5; }
.adr { background: #1e293b; border-left: 4px solid #a78bfa; border-radius: 8px; padding: 1rem; margin: 0.75rem 0; }
.adr h4 { color: #a78bfa; margin-bottom: 0.25rem; font-size: 0.9rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Project GRIDSHIFT</h1>
<p class="subtitle">AWS Database Modernization | Meridian Energy Trading</p>
<p class="subtitle" style="margin-top: 0.5rem; font-size: 0.9rem;">Principal Solutions Architect | Lab Cost: $0 <span class="free-tier-badge">AWS FREE TIER</span></p>
</div>
<div class="kpi-grid">
<div class="kpi-card">
<div class="label">Legacy Annual Cost</div>
<div class="value cost">$20M</div>
<div class="detail">SQL Server licensing + hardware + failed trades</div>
</div>
<div class="kpi-card">
<div class="label">New Architecture (18mo)</div>
<div class="value neutral">$9M</div>
<div class="detail">$5M migration + $4M run-rate</div>
</div>
<div class="kpi-card">
<div class="label">Net Savings (18mo)</div>
<div class="value">$20.5M</div>
<div class="detail">Direct + avoided losses + licensing</div>
</div>
<div class="kpi-card">
<div class="label">New Revenue</div>
<div class="value">$600K/yr</div>
<div class="detail">Real-time price API (50M calls/mo)</div>
</div>
</div>
<div class="section">
<h2>Architecture Decision Records</h2>
<div class="adr"><h4>ADR-001: DynamoDB + DAX for trade lookups</h4><p>On-demand scales instantly. DAX adds microsecond cache. Rejected: Aurora read replicas (replication lag + slow scaling).</p></div>
<div class="adr"><h4>ADR-002: RDS Proxy for Aurora connections</h4><p>Pools 20,000 connections on 187-limit instance. 66% faster failover. Rejected: PgBouncer (self-managed, single-AZ).</p></div>
<div class="adr"><h4>ADR-003: MemoryDB for price feed (not ElastiCache)</h4><p>Sub-ms reads WITH Multi-AZ durability. ElastiCache loses data on node failure.</p></div>
<div class="adr"><h4>ADR-004: DMS Serverless for migration</h4><p>Auto-scales, supports SQL Server to PostgreSQL heterogeneous migration. Zero data loss.</p></div>
<div class="adr"><h4>ADR-005: Aurora Serverless v2 (not provisioned)</h4><p>Scales 0.5 to 16 ACUs per-second. Provisioned wastes money 16 hours/day during off-peak.</p></div>
</div>
<div class="section">
<h2>Latency: 10x Market-Spike Benchmark</h2>
<div class="chart-container">
<canvas id="latencyChart" height="100"></canvas>
</div>
</div>
<div class="section">
<h2>Engine Comparison (Production Scale)</h2>
<table>
<thead>
<tr><th>Engine</th><th>p50</th><th>p99</th><th>Throughput</th><th>$/1000 Reads</th><th>Best For</th></tr>
</thead>
<tbody>
<tr><td>Aurora Serverless v2 + RDS Proxy</td><td>4.2ms</td><td>12.8ms</td><td>8,500/s</td><td>$0.0014</td><td>Joins, reporting, analytics</td></tr>
<tr><td>DynamoDB + DAX</td><td class="highlight">0.4ms</td><td class="highlight">1.2ms</td><td class="highlight">45,000/s</td><td>$0.0008</td><td class="highlight">Trade lookups, flash spikes</td></tr>
<tr><td>Amazon MemoryDB</td><td>0.6ms</td><td>1.8ms</td><td>38,000/s</td><td>$0.0019</td><td>Durable real-time feed, sessions</td></tr>
</tbody>
</table>
</div>
<div class="recommendation">
<h3>Architecture Recommendation</h3>
<p><strong>Trade lookups:</strong> DynamoDB + DAX. Microsecond reads. Zero failed trades.</p>
<p style="margin-top: 0.5rem;"><strong>Analytics:</strong> Aurora Serverless v2 + RDS Proxy. Auto-scales. Absorbs connection storms.</p>
<p style="margin-top: 0.5rem;"><strong>Price feed (revenue):</strong> MemoryDB. Sub-ms durable reads. Powers partner API.</p>
</div>
<div class="revenue">
<h3>New Revenue: Real-Time Price API</h3>
<p>MemoryDB sub-ms reads power a paid API for partner energy firms.</p>
<p style="margin-top: 0.5rem;"><strong>$0.001/call x 50M/month = $600K/year.</strong> Margin: 85%.</p>
</div>
<div class="section">
<h2>Implementation Roadmap</h2>
<table>
<thead><tr><th>Phase</th><th>Timeline</th><th>Action</th><th>ROI</th></tr></thead>
<tbody>
<tr><td>1</td><td>0-3 months</td><td>DynamoDB + DAX for trade lookups</td><td>Eliminate failed trades ($9.2M/yr)</td></tr>
<tr><td>2</td><td>3-9 months</td><td>Aurora Serverless v2 + RDS Proxy</td><td>Kill SQL Server license ($5M/yr)</td></tr>
<tr><td>3</td><td>9-18 months</td><td>MemoryDB real-time price API</td><td>New revenue ($600K/yr)</td></tr>
</tbody>
</table>
</div>
<div class="section">
<h2>SAP-C02 Domain Alignment</h2>
<div class="domain-card"><h4>D2.5: Performance Objectives</h4><p>Engine selection by access pattern. Key-value = DynamoDB. Relational = Aurora. Ultra-low + durable = MemoryDB. Capacity: on-demand for spikes.</p></div>
<div class="domain-card"><h4>D3.3: Improve Performance</h4><p>DAX 10x caching. RDS Proxy pooling (20K connections). Aurora per-second ACU scaling. No cold start.</p></div>
<div class="domain-card"><h4>D4.3: New Architecture for Existing Workloads</h4><p>DMS migration. Polyglot persistence. Babelfish T-SQL compatibility. Decompose monolith.</p></div>
</div>
<div class="section">
<h2>Exam Trap Patterns (Proven)</h2>
<div class="trap"><strong>Trap 1:</strong> DynamoDB caching? DAX (not ElastiCache). API-compatible. Zero code changes.</div>
<div class="trap"><strong>Trap 2:</strong> Serverless Aurora? v2 (not v1). v1 has cold-start pauses. v2 scales per-second.</div>
<div class="trap"><strong>Trap 3:</strong> Unpredictable spikes? On-demand (not provisioned). Handles 2x previous peak instantly.</div>
<div class="trap"><strong>Trap 4:</strong> Connection storms? RDS Proxy. Managed, multi-AZ, 66% faster failover.</div>
<div class="trap"><strong>Trap 5:</strong> In-memory + durable? MemoryDB (not ElastiCache). Multi-AZ transaction log.</div>
</div>
</div>
<script>
const ctx = document.getElementById('latencyChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['Aurora Serverless v2', 'DynamoDB + DAX', 'MemoryDB'],
datasets: [
{ label: 'p50 (ms)', data: [4.2, 0.4, 0.6], backgroundColor: '#38bdf8' },
{ label: 'p95 (ms)', data: [8.1, 0.9, 1.4], backgroundColor: '#818cf8' },
{ label: 'p99 (ms)', data: [12.8, 1.2, 1.8], backgroundColor: '#f472b6' }
]
},
options: {
responsive: true,
plugins: { legend: { labels: { color: '#94a3b8' } } },
scales: {
x: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' } },
y: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' }, title: { display: true, text: 'Latency (ms)', color: '#94a3b8' } }
}
}
});
</script>
</body>
</html>
What does this report contain?
This single HTML file delivers everything a CTO needs for a board-level decision:
- 4 KPI cards showing legacy cost ($20M/yr), new architecture cost ($9M/18mo), net savings ($20.5M), and new revenue ($600K/yr).
- A Chart.js bar chart visualizing p50, p95, and p99 latency across all three engines from your benchmark data.
- An engine comparison table with throughput and cost-per-1000-reads at production scale (500K reads/minute).
- ADR summaries, a 3-phase implementation roadmap, SAP-C02 domain alignment cards, and 5 exam trap patterns.
- A new revenue section projecting the MemoryDB-backed price API at $600K/year with 85% margin.
- Save report.html.
- Open report.html in your browser (double-click the file or drag it into a browser tab). You should see a dark-themed dashboard with 4 green/blue/red KPI cards at the top and a bar chart showing DynamoDB+DAX with the lowest latency bars.
Chart not rendering?
- The Chart.js library loads from a CDN. Make sure you have an internet connection when opening the file.
- Check that the <script> tag at the bottom references latencyChart which must match the id on the <canvas> element.
- If you see a blank page, open your browser's DevTools console (F12) and look for JavaScript errors.
Why is my report.html not rendering the chart or showing a blank page?
Create the decision matrix for the internal wiki
Division leaders want a quick reference comparing the three engines side by side. A Markdown table works for internal wikis, Confluence pages, or GitHub repos.
- Create a new file called decision-matrix.md in your project root by running:
touch decision-matrix.md
- Open decision-matrix.md in Cursor and paste the following content:
# Decision Matrix: AWS Database Engine Comparison
## Meridian Energy Trading - Project GRIDSHIFT
| Dimension | Aurora Serverless v2 + RDS Proxy | DynamoDB + DAX | Amazon MemoryDB |
|-----------|----------------------------------|----------------|------------------|
| **p50 Latency** | 4.2ms | 0.4ms | 0.6ms |
| **p99 Latency** | 12.8ms | 1.2ms | 1.8ms |
| **Throughput** | 8,500 req/s | 45,000 req/s | 38,000 req/s |
| **Cost per 1000 reads** | $0.0014 | $0.0008 | $0.0019 |
| **Operational Complexity** | Medium (RDS Proxy manages connections) | Low (fully managed, on-demand) | Medium (ACL auth, TLS config) |
| **Durability** | Multi-AZ, 6 storage copies | On-demand replication across 3 AZs | Multi-AZ transaction log |
| **Best Access Pattern** | Relational joins, reporting, analytics | Key-value lookups, unpredictable spikes | Durable real-time feeds, sessions |
## Recommendation
- **Trade lookups (hot path):** DynamoDB + DAX. Microsecond cache hits eliminate failed trades during spikes.
- **Analytics and reporting:** Aurora Serverless v2 + RDS Proxy. SQL joins with per-second ACU scaling.
- **Real-time price feed (new revenue):** MemoryDB. Sub-ms reads with durability for partner API.
Why a separate decision matrix?
The HTML report is for the CTO and CEO. The Markdown decision matrix is for the engineering team. Engineers want a scannable comparison they can reference during implementation without opening a formatted report.
- Save decision-matrix.md.
- Confirm both new files exist by running:
ls report.html decision-matrix.md
- You should see both filenames listed in the output.
Destroy all infrastructure immediately
This is not optional. DAX is billed per node-hour. MemoryDB burns through your $200 new-account credits. Your lab bill stays at $0 only if you destroy right now.
Destroy now, not later
Every minute you delay costs money. DAX and DMS Serverless are NOT covered by the always-free tier. MemoryDB is covered by promotional credits but burns them fast. Run the destroy command immediately after confirming your report renders correctly.
- Destroy all AWS resources by running:
terraform destroy -auto-approve
What does this command do?
The -auto-approve flag skips the interactive confirmation prompt. Terraform reads your state file, identifies every resource it created (VPC, subnets, EC2, Aurora cluster, RDS Proxy, DynamoDB table, DAX cluster, MemoryDB cluster, DMS instance, security groups, IAM roles), and deletes them all in dependency order.
Your Terraform files and benchmark results stay on your local machine. Only the AWS resources are removed.
- Wait for Terraform to finish (typically 5-10 minutes as it tears down resources in order).
- You should see Destroy complete! followed by a count of resources destroyed.
- Verify nothing remains by running:
aws rds describe-db-clusters --profile meridian-prod
- You should see an empty DBClusters array, confirming Aurora is gone.
Destroy failed or timed out?
- If Terraform reports a dependency error, run terraform destroy -auto-approve again. Some resources (like DAX clusters) take longer to delete, and a second run picks up where the first left off.
- If a specific resource is stuck, check the AWS Console for that service and delete it manually. Then run terraform destroy -auto-approve once more to clean up the state.
- If you see an IAM role deletion error, it usually means a service is still using it. Wait 2 minutes and retry.
Why is terraform destroy failing or timing out on my resources?
Cost discipline is a principal-level skill. You just proved a $20M savings architecture for $0.
✔️ Awesome, I've got everything!
Great. Double check you have saved both report.html and decision-matrix.md, and that terraform destroy completed successfully.
ⓧ I'd like to double check the full code
Here is the complete report.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project GRIDSHIFT - Executive KPI Report</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0f172a; color: #e2e8f0; line-height: 1.6; }
.container { max-width: 1200px; margin: 0 auto; padding: 2rem; }
.header { text-align: center; padding: 3rem 0; border-bottom: 1px solid #334155; }
.header h1 { font-size: 2.5rem; color: #38bdf8; margin-bottom: 0.5rem; }
.header .subtitle { font-size: 1.2rem; color: #94a3b8; }
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; margin: 2rem 0; }
.kpi-card { background: #1e293b; border-radius: 12px; padding: 1.5rem; border: 1px solid #334155; }
.kpi-card .label { font-size: 0.875rem; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em; }
.kpi-card .value { font-size: 2.5rem; font-weight: 700; color: #4ade80; margin: 0.5rem 0; }
.kpi-card .value.cost { color: #f87171; }
.kpi-card .value.neutral { color: #38bdf8; }
.kpi-card .detail { font-size: 0.875rem; color: #64748b; }
.section { margin: 3rem 0; }
.section h2 { font-size: 1.5rem; color: #f8fafc; margin-bottom: 1rem; padding-bottom: 0.5rem; border-bottom: 1px solid #334155; }
.chart-container { background: #1e293b; border-radius: 12px; padding: 2rem; margin: 1rem 0; }
table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
th, td { padding: 0.75rem 1rem; text-align: left; border-bottom: 1px solid #334155; }
th { color: #94a3b8; font-weight: 600; font-size: 0.875rem; text-transform: uppercase; }
td { color: #e2e8f0; }
.highlight { color: #4ade80; font-weight: 600; }
.recommendation { background: linear-gradient(135deg, #1e3a5f, #1e293b); border: 1px solid #38bdf8; border-radius: 12px; padding: 2rem; margin: 2rem 0; }
.recommendation h3 { color: #38bdf8; margin-bottom: 1rem; }
.revenue { background: linear-gradient(135deg, #1a2e1a, #1e293b); border: 1px solid #4ade80; border-radius: 12px; padding: 2rem; margin: 2rem 0; }
.revenue h3 { color: #4ade80; margin-bottom: 1rem; }
.free-tier-badge { display: inline-block; background: #065f46; color: #6ee7b7; padding: 0.25rem 0.75rem; border-radius: 9999px; font-size: 0.75rem; font-weight: 600; margin-left: 0.5rem; }
.domain-card { background: #1e293b; border-radius: 12px; padding: 1.5rem; border-left: 4px solid #f59e0b; margin: 1rem 0; }
.domain-card h4 { color: #f59e0b; margin-bottom: 0.5rem; }
.trap { background: #2d1b1b; border: 1px solid #dc2626; border-radius: 8px; padding: 1rem; margin: 0.5rem 0; }
.trap strong { color: #fca5a5; }
.adr { background: #1e293b; border-left: 4px solid #a78bfa; border-radius: 8px; padding: 1rem; margin: 0.75rem 0; }
.adr h4 { color: #a78bfa; margin-bottom: 0.25rem; font-size: 0.9rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Project GRIDSHIFT</h1>
<p class="subtitle">AWS Database Modernization | Meridian Energy Trading</p>
<p class="subtitle" style="margin-top: 0.5rem; font-size: 0.9rem;">Principal Solutions Architect | Lab Cost: $0 <span class="free-tier-badge">AWS FREE TIER</span></p>
</div>
<div class="kpi-grid">
<div class="kpi-card">
<div class="label">Legacy Annual Cost</div>
<div class="value cost">$20M</div>
<div class="detail">SQL Server licensing + hardware + failed trades</div>
</div>
<div class="kpi-card">
<div class="label">New Architecture (18mo)</div>
<div class="value neutral">$9M</div>
<div class="detail">$5M migration + $4M run-rate</div>
</div>
<div class="kpi-card">
<div class="label">Net Savings (18mo)</div>
<div class="value">$20.5M</div>
<div class="detail">Direct + avoided losses + licensing</div>
</div>
<div class="kpi-card">
<div class="label">New Revenue</div>
<div class="value">$600K/yr</div>
<div class="detail">Real-time price API (50M calls/mo)</div>
</div>
</div>
<div class="section">
<h2>Architecture Decision Records</h2>
<div class="adr"><h4>ADR-001: DynamoDB + DAX for trade lookups</h4><p>On-demand scales instantly. DAX adds microsecond cache. Rejected: Aurora read replicas (replication lag + slow scaling).</p></div>
<div class="adr"><h4>ADR-002: RDS Proxy for Aurora connections</h4><p>Pools 20,000 connections on 187-limit instance. 66% faster failover. Rejected: PgBouncer (self-managed, single-AZ).</p></div>
<div class="adr"><h4>ADR-003: MemoryDB for price feed (not ElastiCache)</h4><p>Sub-ms reads WITH Multi-AZ durability. ElastiCache loses data on node failure.</p></div>
<div class="adr"><h4>ADR-004: DMS Serverless for migration</h4><p>Auto-scales, supports SQL Server to PostgreSQL heterogeneous migration. Zero data loss.</p></div>
<div class="adr"><h4>ADR-005: Aurora Serverless v2 (not provisioned)</h4><p>Scales 0.5 to 16 ACUs per-second. Provisioned wastes money 16 hours/day during off-peak.</p></div>
</div>
<div class="section">
<h2>Latency: 10x Market-Spike Benchmark</h2>
<div class="chart-container">
<canvas id="latencyChart" height="100"></canvas>
</div>
</div>
<div class="section">
<h2>Engine Comparison (Production Scale)</h2>
<table>
<thead>
<tr><th>Engine</th><th>p50</th><th>p99</th><th>Throughput</th><th>$/1000 Reads</th><th>Best For</th></tr>
</thead>
<tbody>
<tr><td>Aurora Serverless v2 + RDS Proxy</td><td>4.2ms</td><td>12.8ms</td><td>8,500/s</td><td>$0.0014</td><td>Joins, reporting, analytics</td></tr>
<tr><td>DynamoDB + DAX</td><td class="highlight">0.4ms</td><td class="highlight">1.2ms</td><td class="highlight">45,000/s</td><td>$0.0008</td><td class="highlight">Trade lookups, flash spikes</td></tr>
<tr><td>Amazon MemoryDB</td><td>0.6ms</td><td>1.8ms</td><td>38,000/s</td><td>$0.0019</td><td>Durable real-time feed, sessions</td></tr>
</tbody>
</table>
</div>
<div class="recommendation">
<h3>Architecture Recommendation</h3>
<p><strong>Trade lookups:</strong> DynamoDB + DAX. Microsecond reads. Zero failed trades.</p>
<p style="margin-top: 0.5rem;"><strong>Analytics:</strong> Aurora Serverless v2 + RDS Proxy. Auto-scales. Absorbs connection storms.</p>
<p style="margin-top: 0.5rem;"><strong>Price feed (revenue):</strong> MemoryDB. Sub-ms durable reads. Powers partner API.</p>
</div>
<div class="revenue">
<h3>New Revenue: Real-Time Price API</h3>
<p>MemoryDB sub-ms reads power a paid API for partner energy firms.</p>
<p style="margin-top: 0.5rem;"><strong>$0.001/call x 50M/month = $600K/year.</strong> Margin: 85%.</p>
</div>
<div class="section">
<h2>Implementation Roadmap</h2>
<table>
<thead><tr><th>Phase</th><th>Timeline</th><th>Action</th><th>ROI</th></tr></thead>
<tbody>
<tr><td>1</td><td>0-3 months</td><td>DynamoDB + DAX for trade lookups</td><td>Eliminate failed trades ($9.2M/yr)</td></tr>
<tr><td>2</td><td>3-9 months</td><td>Aurora Serverless v2 + RDS Proxy</td><td>Kill SQL Server license ($5M/yr)</td></tr>
<tr><td>3</td><td>9-18 months</td><td>MemoryDB real-time price API</td><td>New revenue ($600K/yr)</td></tr>
</tbody>
</table>
</div>
<div class="section">
<h2>SAP-C02 Domain Alignment</h2>
<div class="domain-card"><h4>D2.5: Performance Objectives</h4><p>Engine selection by access pattern. Key-value = DynamoDB. Relational = Aurora. Ultra-low + durable = MemoryDB. Capacity: on-demand for spikes.</p></div>
<div class="domain-card"><h4>D3.3: Improve Performance</h4><p>DAX 10x caching. RDS Proxy pooling (20K connections). Aurora per-second ACU scaling. No cold start.</p></div>
<div class="domain-card"><h4>D4.3: New Architecture for Existing Workloads</h4><p>DMS migration. Polyglot persistence. Babelfish T-SQL compatibility. Decompose monolith.</p></div>
</div>
<div class="section">
<h2>Exam Trap Patterns (Proven)</h2>
<div class="trap"><strong>Trap 1:</strong> DynamoDB caching? DAX (not ElastiCache). API-compatible. Zero code changes.</div>
<div class="trap"><strong>Trap 2:</strong> Serverless Aurora? v2 (not v1). v1 has cold-start pauses. v2 scales per-second.</div>
<div class="trap"><strong>Trap 3:</strong> Unpredictable spikes? On-demand (not provisioned). Handles 2x previous peak instantly.</div>
<div class="trap"><strong>Trap 4:</strong> Connection storms? RDS Proxy. Managed, multi-AZ, 66% faster failover.</div>
<div class="trap"><strong>Trap 5:</strong> In-memory + durable? MemoryDB (not ElastiCache). Multi-AZ transaction log.</div>
</div>
</div>
<script>
const ctx = document.getElementById('latencyChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['Aurora Serverless v2', 'DynamoDB + DAX', 'MemoryDB'],
datasets: [
{ label: 'p50 (ms)', data: [4.2, 0.4, 0.6], backgroundColor: '#38bdf8' },
{ label: 'p95 (ms)', data: [8.1, 0.9, 1.4], backgroundColor: '#818cf8' },
{ label: 'p99 (ms)', data: [12.8, 1.2, 1.8], backgroundColor: '#f472b6' }
]
},
options: {
responsive: true,
plugins: { legend: { labels: { color: '#94a3b8' } } },
scales: {
x: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' } },
y: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' }, title: { display: true, text: 'Latency (ms)', color: '#94a3b8' } }
}
}
});
</script>
</body>
</html>
And here is the complete decision-matrix.md:
# Decision Matrix: AWS Database Engine Comparison
## Meridian Energy Trading - Project GRIDSHIFT
| Dimension | Aurora Serverless v2 + RDS Proxy | DynamoDB + DAX | Amazon MemoryDB |
|-----------|----------------------------------|----------------|------------------|
| **p50 Latency** | 4.2ms | 0.4ms | 0.6ms |
| **p99 Latency** | 12.8ms | 1.2ms | 1.8ms |
| **Throughput** | 8,500 req/s | 45,000 req/s | 38,000 req/s |
| **Cost per 1000 reads** | $0.0014 | $0.0008 | $0.0019 |
| **Operational Complexity** | Medium (RDS Proxy manages connections) | Low (fully managed, on-demand) | Medium (ACL auth, TLS config) |
| **Durability** | Multi-AZ, 6 storage copies | On-demand replication across 3 AZs | Multi-AZ transaction log |
| **Best Access Pattern** | Relational joins, reporting, analytics | Key-value lookups, unpredictable spikes | Durable real-time feeds, sessions |
## Recommendation
- **Trade lookups (hot path):** DynamoDB + DAX. Microsecond cache hits eliminate failed trades during spikes.
- **Analytics and reporting:** Aurora Serverless v2 + RDS Proxy. SQL joins with per-second ACU scaling.
- **Real-time price feed (new revenue):** MemoryDB. Sub-ms reads with durability for partner API.
Secret mission
I/O-Optimized + Babelfish + Revenue API Proof-of-Concept
You proved the 3-engine architecture saves $20M. Now go further. Deploy Aurora I/O-Optimized to prove the analytics workload saves even more. Enable Babelfish to kill the DBA team's migration objection. Build the real-time price API that turns this cost project into a profit center.
Clean Up Your Resources
Clean Up Your Resources
Your lab should already be destroyed. Step 6 includes terraform destroy as a mandatory action before you finish the project.
If resources are still running, DAX and DMS Serverless bill per hour and are NOT covered by free tier. Confirm everything is torn down before you close your terminal.
Cost warning
DAX charges ~$0.04/node-hour regardless of account age. DMS Serverless bills per DCU-hour. MemoryDB burns through your $200 promotional credits quickly.
If you skipped the destroy command in Step 6, run it now. Every hour you wait costs money.
Resources you used:
- Aurora Serverless v2 cluster and RDS Proxy (free tier up to 4 ACUs for 12 months).
- DynamoDB table (perpetual free tier: 25 RCU/WCU).
- DAX cluster (NOT free tier, billed per node-hour).
- MemoryDB cluster (covered by promotional credits, burns them fast).
- EC2 t3.micro source database (free tier: 750 hours/month).
- DMS Serverless replication instance (billed per DCU-hour).
- VPC, subnets, security groups, VPC endpoints, Secrets Manager secret, CloudWatch dashboard.
- Local Terraform project files and report.html.
Keep everything running
No action needed. Choose this only if you are actively running additional benchmarks right now.
- Aurora Serverless v2 and DynamoDB are covered by free tier.
- DAX (~$0.04/node-hour), DMS Serverless, and MemoryDB are actively billing your account or burning credits.
- EC2 t3.micro is free-tier eligible (750 hours/month for new accounts).
- Your Terraform state files remain in your project folder for future runs.
Pause - I'll come back to this later
Destroy all AWS resources to stop billing, but keep your local project files so you can redeploy later with a single command.
- Open your terminal and navigate to your Terraform project root directory.
- Run the destroy command:
terraform destroy -auto-approve
- Wait for Terraform to confirm all resources have been destroyed.
- Keep your local project folder (Terraform modules, k6 scripts, report.html). When you want to redeploy, run terraform apply from the same directory.
Delete - I don't want to use this again
Remove all AWS resources and delete your local project files permanently.
- Open your terminal and navigate to your Terraform project root directory.
- Destroy all AWS resources by running:
terraform destroy -auto-approve
- Wait for Terraform to confirm all resources have been destroyed.
- Verify with the AWS CLI that no resources remain:
aws rds describe-db-clusters --profile meridian-prod
aws dynamodb list-tables --profile meridian-prod
aws dax describe-clusters --profile meridian-prod
aws memorydb describe-clusters --profile meridian-prod
- Each command should return an empty list. If any resources remain, run terraform destroy -auto-approve again.
- Delete your local project folder. On macOS/Linux:
rm -rf ~/Desktop/meridian-db-lab
- On Windows (PowerShell):
Remove-Item -Recurse -Force ~\Desktop\meridian-db-lab
- Optionally, uninstall k6 if you no longer need it:
winget uninstall --name k6
- Optionally, delete the Terraform binary. Find where it is installed (check your system PATH), then delete terraform.exe from that directory. Remove the directory from your system PATH environment variable.
That's a Wrap!
That's a Wrap!
Nice work! You walked into Meridian Energy Trading on Day 1 and delivered what the last architect could not. A full requirement package, a working multi-engine benchmark lab, and an executive report proving $20.5M in savings.
You've learned how to:
- Deploy 3 managed AWS database engines (Aurora Serverless v2, DynamoDB + DAX, MemoryDB) in parallel using Cursor AI agents and Terraform, all within AWS Free Tier.
- Migrate data via DMS, run a realistic k6 benchmark simulating a 10x energy-market spike, and prove each engine's performance with real latency data.
- Build an executive HTML report with KPI cards, latency charts, a 3-phase implementation roadmap, and SAP-C02 domain alignment that the CTO presents to the CEO.
- Secret Mission: Prove Aurora I/O-Optimized wins for heavy-read analytics, demonstrate Babelfish T-SQL compatibility to eliminate migration objections, and build a real-time price API as a net-new revenue product.
Ready to quiz yourself?