Weather Dashboard

Weather Dashboard — AWS Serverless Architecture

A production-grade serverless weather application that fetches real-time conditions and a 5-day forecast for any city in the world. The API key never touches the browser — Lambda retrieves it from SSM Parameter Store at runtime. Results are cached in DynamoDB for 15 minutes to reduce API calls and cost. The entire stack is defined in CloudFormation, deployed through CodePipeline, and served globally via CloudFront.

Stack: AWS Lambda (Python 3.11) · API Gateway HTTP API · DynamoDB · SSM Parameter Store · CloudFront · S3 · Route 53 · ACM · CodePipeline · CodeBuild · CodeCommit · CloudFormation | Type: Serverless web app — 100% AWS-native, zero third-party CI/CD


How it works

Request flow — cache miss vs cache hit

Cache-first request flow — When a user searches for a city, the browser calls API Gateway, which proxies to Lambda. Lambda checks DynamoDB first. On a cache hit (within 15 minutes), it returns the stored result immediately — no outbound API call, sub-30 ms response. On a miss, it fetches the API key from SSM, calls OpenWeatherMap, writes the result to DynamoDB with a TTL, and returns the response (~150–250 ms).

Secure secret handling — The OpenWeatherMap API key is stored as a SecureString in SSM Parameter Store. Lambda fetches it on cold start and caches it in the execution context. The key never appears in environment variables, source code, or any browser-side resource.

Static frontend — HTML, CSS, and JavaScript are deployed to a private S3 bucket. CloudFront serves them globally using Origin Access Control (OAC) — the bucket has no public access policy and is unreachable directly. A CloudFront Function rewrites directory index paths so /about/ resolves to about/index.html.


Architecture

Weather Dashboard — AWS Architecture

Compute & API

ServiceRole
AWS LambdaPython 3.11 handler — input validation, cache check, OpenWeatherMap call, response mapping
API Gateway HTTP API v2Public HTTPS endpoint with CORS restricted to https://weather.craftingnewtech.com
Lambda Reserved ConcurrencyCapped at 10 concurrent executions — prevents runaway API costs

Frontend hosting

ServiceRole
Amazon S3Private static hosting — HTML, CSS, JS, and 18 custom SVG weather icons
Amazon CloudFrontGlobal CDN — HTTPS termination, security headers policy, directory index function
CloudFront FunctionRewrites /path/ to /path/index.html at the edge

DNS & TLS

ServiceRole
Route 53ALIAS records — weather.craftingnewtech.com and apex craftingnewtech.com pointing to CloudFront
AWS Certificate ManagerTLS certificate provisioned in us-east-1 (required for CloudFront)

Data & secrets

ServiceRole
Amazon DynamoDBWeatherCache table — On-Demand billing, TTL attribute for automatic 15-min expiry
SSM Parameter StoreOpenWeatherMap API key as SecureString — fetched by Lambda, never exposed to the browser

Observability

ServiceRole
Amazon CloudWatchStructured Lambda logs, 5-widget dashboard, 4 alarms (errors, duration, API 4xx, API 5xx)
Amazon SNSAlarm topic — CloudWatch breaches publish to SNS, triggering email alerts

CI/CD pipeline

ServiceRole
AWS CodeCommitGit repository — main branch triggers pipeline on push
AWS CodePipelineTwo-stage pipeline: Source (CodeCommit) → Build (CodeBuild)
AWS CodeBuildRuns cfn-lint, checkov, pip-audit, pytest gates before deploying
EventBridgePush-triggered pipeline — no polling, instant invocation on git push aws main

Security design

No secrets in the browser — The OpenWeatherMap key lives exclusively in SSM Parameter Store. The frontend JavaScript only knows the API Gateway URL. There is no way for a user to extract the key from the browser.

Least-privilege IAM — Five separate IAM roles cover Lambda, CodeBuild, CodePipeline, CloudFormation, and EventBridge. Each role has only the permissions required for its function. No shared credentials, no wildcard resource ARNs.

S3 + OAC — The frontend bucket blocks all public access. CloudFront uses Origin Access Control (OAC) to sign requests to S3 with SigV4. Direct S3 object URLs return 403. The bucket policy permits only the CloudFront distribution’s service principal.

CORS enforcement — API Gateway allows only https://weather.craftingnewtech.com. Cross-origin calls from other domains or localhost are rejected at the API layer.

Input validation — The city name parameter is validated against a whitelist regex (^[a-zA-Z0-9\s,\-\.]{1,100}$) before any downstream call is made. SQL injection and path traversal patterns are rejected immediately.

Content Security Policy — All pages serve a strict CSP (default-src 'self', no 'unsafe-inline'). All styles are in an external stylesheet — no inline <style> blocks or style= attributes.

Pipeline security gatescfn-lint and checkov validate CloudFormation templates. pip-audit scans Lambda dependencies for CVEs. pytest enforces ≥ 80% test coverage. Any gate failure aborts the build with on-failure: ABORT.


CI/CD pipeline

CI/CD pipeline — build gates and deploy phases

git push aws main
   └─▶ CodeCommit ──▶ EventBridge ──▶ CodePipeline

                                    ┌──────▼──────┐
                                    │  CodeBuild   │
                                    │  pre_build   │
                                    │  cfn-lint    │
                                    │  checkov     │
                                    │  pip-audit   │
                                    │  pytest      │
                                    └──────┬───────┘
                                           │ (all gates pass)
                              ┌────────────▼────────────────┐
                              │  build phase                │
                              │  cfn package (Lambda zip)   │
                              │  cfn deploy (nested stacks) │
                              │  s3 sync (frontend)         │
                              │  cloudfront invalidate /*   │
                              └─────────────────────────────┘

The CloudFront invalidation uses --invalidation-batch with CallerReference=${CODEBUILD_BUILD_ID}, making it idempotent — re-running the same build never creates duplicate invalidations.


Key design decisions

CloudFormation over Terraform — The entire project uses AWS-native IaC only. No third-party state backend, no Terraform Cloud, no external lock table. CloudFormation nested stacks organized by concern (IAM, storage, CDN, database, backend, API, pipeline, monitoring) keep each template focused and independently deployable.

DynamoDB On-Demand — No minimum capacity cost. At portfolio scale, the cache table costs effectively nothing. On-demand scales automatically if traffic spikes without capacity planning.

Lambda reserved concurrency — Capped at 10 concurrent executions. This prevents a sudden traffic spike or misconfigured client from sending thousands of calls to OpenWeatherMap and blowing through the API quota.

Vanilla JS frontend — No React, no build step for the frontend. The HTML, CSS, and JS are deployed directly to S3 as static files. This eliminates a node_modules dependency tree, reduces the attack surface for supply-chain CVEs, and makes the frontend trivially cacheable.

18 custom SVG weather icons — OpenWeatherMap’s raster PNG icons depend on an external CDN call, which the strict CSP blocks. Inline SVG icons built from OpenWeatherMap’s condition codes serve from the same origin with no external dependencies.

DynamoDB TTL for cache expiry — No cron job, no Lambda sweeper. DynamoDB TTL automatically deletes expired records. The 15-minute window balances freshness against API call volume — weather data does not change meaningfully in 15 minutes for most use cases.


Infrastructure layout

infrastructure/cloudformation/
├── 01-iam.yml          # 5 least-privilege roles
├── 02-storage.yml      # WebsiteBucket + ArtifactsBucket
├── 03-cdn.yml          # CloudFront + OAC + CloudFront Function
├── 04-database.yml     # DynamoDB WeatherCache table
├── 05-backend.yml      # Lambda function + log group
├── 06-api.yml          # API Gateway HTTP API + CORS
├── 07-ssm.yml          # SSM parameter placeholder
├── 08-pipeline.yml     # CodeCommit + CodeBuild + CodePipeline + EventBridge
├── 09-monitoring.yml   # CloudWatch alarms + dashboard + SNS topic
└── master.yml          # Root nested stack — deploys all 9 in dependency order

Live application

Weather App — live frontend

The app is deployed at weather.craftingnewtech.com.

Try searching for any city — London, Tokyo, São Paulo, or New York. Use the °C / °F toggle to switch units. The About page documents how the app works and the privacy model.