What You'll Produce
In this exercise you will translate the capstone requirements into a concrete architecture — a network diagram with all components placed in their correct tier and AZ, a component interaction diagram showing data flows, and an Architecture Decision Record documenting why you made each major technology choice. This document becomes the technical specification that guides all subsequent implementation work and serves as the reference for on-call engineers who need to understand the system they are operating.
Prerequisites
- Completed M6 Lesson 1: Capstone Brief — understand all functional and non-functional requirements
- Reviewed M3 Lesson 2 (VPC design) and M4 Lessons 1-5 (IAM, EC2, S3, VPC, RDS/DynamoDB)
- A diagramming tool: draw.io (free, browser-based), Lucidchart, or text editor for ASCII diagrams
- A text editor for writing the Architecture Decision Record in Markdown
Step 1 — Network Architecture: VPC and Subnet Design
Start with the network foundation. Design a VPC with three tiers (public, application, data) across three availability zones. Choose CIDR ranges that do not overlap with typical on-premises ranges (avoid 192.168.0.0/16 which is common in home networks) and that leave room for future growth and VPC peering. Document your reasoning for each choice.
# Network design worksheet — fill in your decisions
cat << 'NETWORK_DESIGN'
=== Cricket Analytics Platform Network Design ===
VPC CIDR: ____________ (Reasoning: ____________________________)
Subnet Allocation:
Tier | AZ-A CIDR | AZ-B CIDR | AZ-C CIDR | Size | Usable
-----------|------------------|------------------|------------------|------|-------
Public | ____________ | ____________ | ____________ | ____ | _____
Application| ____________ | ____________ | ____________ | ____ | _____
Data | ____________ | ____________ | ____________ | ____ | _____
Decisions to justify:
1. Why /22 for application subnets and not /24?
Answer: ____________________________________________
2. How many NAT Gateways will you deploy and why?
Answer: ____________________________________________
3. Which VPC endpoints will you create?
Answer: ____________________________________________
Reference answer (for self-check):
VPC: 10.0.0.0/16 (65,531 usable, room for future subnets)
Public /24 per AZ: sufficient for 251 ALB + NAT Gateway IPs
App /22 per AZ: 1,019 usable — needed for EKS pods if added later
Data /24 per AZ: 251 usable — sufficient for RDS replicas + ElastiCache
3 NAT Gateways (one per AZ): eliminates cross-AZ charges, provides AZ-level resilience
Endpoints: S3 (gateway, free) and DynamoDB (gateway, free) — eliminate NAT Gateway S3/DDB traffic
EANSWER
CATEND
COMPLETE_THE_WORKSHEET_ABOVE_BEFORE_CONTINUING
NETWORK_DESIGNStep 2 — Component Architecture: Services and Data Flows
Place each required service in the correct subnet tier and document the data flows between components. Use the security group chain pattern from M4: internet → ALB SG → application SG → data SG. Map each functional requirement to specific AWS services and document the data path from ingestion to API response.
# Component placement and data flow documentation
cat << 'COMPONENT_DESIGN'
=== Component Architecture Worksheet ===
PUBLIC SUBNET resources:
[ ] Route 53 (global DNS)
[ ] ALB (internet-facing Application Load Balancer)
[ ] NAT Gateway (one per AZ)
[ ] Bastion Host (optional, prefer SSM Session Manager)
APPLICATION SUBNET resources:
[ ] EC2 Auto Scaling Group (API servers)
[ ] Lambda VPC-connected functions (optional)
DATA SUBNET resources:
[ ] RDS PostgreSQL (Multi-AZ, primary + standby)
[ ] DynamoDB VPC Endpoint (traffic stays in AWS network)
[ ] ElastiCache Redis (optional: session/query cache)
OUTSIDE VPC (AWS Managed Services):
[ ] DynamoDB (regional service, accessed via VPC endpoint)
[ ] S3 (regional service, accessed via VPC gateway endpoint)
[ ] Lambda (VPC-attached for data access, or outside VPC for S3 trigger)
[ ] CloudWatch (regional service, no VPC attachment needed)
[ ] SQS/SNS (if used for async processing)
DATA FLOWS — document each:
1. Ingest flow: External system → [_____] → [_____] → [_____] → DynamoDB + RDS
2. API read flow: Fan app → Route 53 → ALB → [_____] → [_____] → fan app
3. Analytics flow: CloudWatch Events → [_____] → [_____] → S3 → dashboard
4. Failover flow: Mumbai unhealthy → Route 53 detects → DNS → [_____]
SECURITY GROUP CHAIN:
SG-ALB: inbound 443 from 0.0.0.0/0
SG-APP: inbound 8080 from SG-ALB only
SG-DB: inbound 5432 from SG-APP only
COMPONENT_DESIGNStep 3 — Architecture Decision Record
Write an Architecture Decision Record (ADR) for each of the five most significant technology choices. An ADR has four sections: Context (what is the problem?), Decision (what did you choose?), Alternatives Considered (what else could you have chosen?), and Consequences (what are the trade-offs?). ADRs create a record of why decisions were made, preventing future engineers from second-guessing choices without understanding the original constraints.
# ADR Template — write one for each major decision
cat << 'ADR_TEMPLATE'
# ADR-001: Database Strategy — DynamoDB + RDS vs Single Database
## Status: Accepted
## Date: 2024-04-01
## Context
The cricket analytics platform has two distinct data access patterns:
1. Real-time score lookups during IPL matches: millions of reads/minute,
fixed access pattern (get score by match_id), sub-10ms latency required
2. Historical analytics: complex SQL queries joining players, matches and
deliveries, ad-hoc access patterns, acceptable 500ms-5s query time
## Decision
Use DynamoDB for real-time operational queries and RDS PostgreSQL for
historical analytics queries. Both databases write the same delivery data.
## Alternatives Considered
1. DynamoDB-only: Would require GSIs for analytics queries. DynamoDB Scan
operations on large tables are expensive and slow. Complex joins impossible.
2. RDS-only: PostgreSQL can handle real-time queries but connection pooling
becomes critical at 10,000 req/sec. Each connection consumes ~5MB RAM.
Maximum 500 connections on db.r5.2xlarge. RDS Proxy partially mitigates
but adds latency.
3. Aurora Serverless: Scales compute automatically. Cold start latency (5-30s)
when scaling from zero is unacceptable for real-time score API.
## Consequences
+ DynamoDB provides consistent single-digit ms at any scale for key lookups
+ PostgreSQL enables any SQL analytics query without data modelling constraints
- Dual-write complexity: Lambda must write to both databases atomically
- Risk: if DynamoDB write succeeds but RDS write fails, data is inconsistent
- Mitigation: Use SQS queue for RDS writes (eventual consistency acceptable
for analytics, which queries the previous day's data)
- Additional cost: ~$30/month DynamoDB on-demand + $50/month RDS t3.medium
ADR_TEMPLATE
echo
echo 'Write ADRs for these additional decisions:'
echo ' ADR-002: EC2 ASG vs ECS Fargate for API serving'
echo ' ADR-003: Lambda vs EC2 for data ingestion processor'
echo ' ADR-004: Single-region vs multi-region deployment'
echo ' ADR-005: CloudWatch vs third-party observability (Datadog, Grafana)'Step 4 — Cost Estimate
Produce a monthly cost estimate for the platform at baseline load (3 EC2 instances, normal traffic) and at IPL match peak (10 EC2 instances, 10x traffic). Use ap-south-1 pricing from the AWS pricing calculator. Document which components are the largest cost drivers and identify opportunities for optimisation.
#!/usr/bin/env python3
# Cricket Analytics Platform cost estimator — ap-south-1 pricing
# Pricing (ap-south-1, USD/month unless noted)
PRICING = {
'ec2_t3_medium_od': 0.0416 * 24 * 30, # $29.95/month on-demand
'ec2_t3_medium_ri_1yr': 0.0249 * 24 * 30, # $17.93/month 1yr RI
'alb_per_hour': 0.008 * 24 * 30, # $5.76/month
'alb_per_lcu': 0.008, # per LCU-hour
'rds_t3_medium_multi_az':0.136 * 24 * 30, # $97.92/month Multi-AZ
'nat_gateway_per_hour': 0.045 * 24 * 30, # $32.40/month per NAT GW
'nat_gateway_per_gb': 0.045,
's3_standard_per_gb': 0.023,
'dynamodb_on_demand_write': 1.25, # per million WCU
'dynamodb_on_demand_read': 0.25, # per million RCU
'lambda_per_million': 0.20,
'lambda_per_gb_second': 0.0000166667,
'cloudwatch_custom_metric': 0.30,
'route53_per_zone': 0.50,
'route53_health_check': 0.50,
}
def estimate(scenario):
ec2_count = scenario['ec2_instances']
monthly = {
'EC2 (t3.medium RI)': ec2_count * PRICING['ec2_t3_medium_ri_1yr'],
'ALB': PRICING['alb_per_hour'],
'RDS Multi-AZ (t3.medium)': PRICING['rds_t3_medium_multi_az'],
'NAT Gateways (3)': 3 * PRICING['nat_gateway_per_hour'],
'NAT Gateway data (100GB)': 100 * PRICING['nat_gateway_per_gb'],
'S3 storage (50GB)': 50 * PRICING['s3_standard_per_gb'],
'DynamoDB (5M WCU, 20M RCU)': 5 * PRICING['dynamodb_on_demand_write'] + 20 * PRICING['dynamodb_on_demand_read'],
'Lambda (1M invocations)': PRICING['lambda_per_million'],
'CloudWatch (15 metrics)': 15 * PRICING['cloudwatch_custom_metric'],
'Route 53': PRICING['route53_per_zone'] + 2 * PRICING['route53_health_check'],
}
total = sum(monthly.values())
return monthly, total
for scenario_name, scenario in [
('Baseline (3 EC2 instances)', {'ec2_instances': 3}),
('IPL Peak (10 EC2 instances)', {'ec2_instances': 10}),
]:
monthly, total = estimate(scenario)
print(f'\n=== {scenario_name} ===')
for service, cost in sorted(monthly.items(), key=lambda x: -x[1]):
print(f' {service:<40} ${cost:>8.2f}')
print(f' {"TOTAL":<40} ${total:>8.2f}')
print(f' Top cost driver: {max(monthly, key=monthly.get)}')Warning: Architecture decisions made at this stage are expensive to reverse later. The most common costly mistakes are: choosing a VPC CIDR that overlaps with future peering targets (cannot be changed after VPC creation), choosing RDS Multi-AZ on a large instance for a workload that could run on Aurora Serverless (pays for idle capacity), and choosing a single-region deployment for a service that requires 99.99% availability (single region provides only ~99.95% historically). Spend time on the design — the implementation follows the design, and a poor design results in hours of refactoring.
Extension Challenge: Use the AWS Well-Architected Tool (free in the AWS console) to evaluate your architecture design against the six pillars: Operational Excellence, Security, Reliability, Performance Efficiency, Cost Optimisation and Sustainability. The tool asks a series of questions based on your architecture and produces a report identifying high-risk items and recommended improvements. Run this review before building — catching architectural issues at design time costs minutes; catching them after implementation costs days.
- Architecture Decision Records document why decisions were made, not just what was decided — future engineers reading ADRs can understand the original constraints and avoid repeating past analysis.
- Place components in the correct subnet tier based on their network exposure needs: public-facing (ALB, NAT), application logic (EC2 ASG), data stores (RDS, DynamoDB endpoint).
- Cost estimation at design time reveals the largest cost drivers and enables architectural changes that save money before any infrastructure is built — RDS instance size and NAT Gateway data costs are frequently underestimated.
- The security group chain (internet → ALB SG → App SG → DB SG) must be designed before implementation because security groups reference each other by ID, requiring creation in the correct dependency order.
- Multi-region requirements (latency routing, failover) must be in the design from the start — adding multi-region capability retroactively requires re-architecting DNS, data replication and IAM across two regions.
- The AWS Well-Architected Framework six pillars are the evaluation rubric for production architectures — design explicitly against each pillar before building.