
Earthquake Data Platform
A Turborepo-based serverless data platform that ingests USGS earthquake data, stores it in DynamoDB, and exposes dashboard, explorer, and backend-admin views.
Stack
Tags
Why I built it
I built Earthquake Data Platform as a compact version of an operational data product: ingest external events, normalize them, store them for query patterns, expose dashboard views, and keep the system usable in local or offline demo modes.
I chose earthquake data because it is public, time-series-oriented, geographic, and easy to filter by magnitude and date range.
What it does
The platform ingests recent earthquake events from the USGS FDSN Event API, normalizes GeoJSON data, and stores event records in DynamoDB. I exposed API behavior for ingestion, earthquake search, and popular filter analytics.
The live web app presents a dashboard with metrics, a map, recent activity, weekly event charts, magnitude distribution, and top regions. It also includes an Explorer page with start time, end time, minimum magnitude, and result size filters, plus a Backend Admin page for backend endpoint behavior and offline fallback data.
Technical shape
Repository evidence shows a Turborepo monorepo with apps/infra for CDK infrastructure and apps/web for a Next.js 15 dashboard. I used shared packages for domain logic, environment validation, Zod schemas, DynamoDB clients, service code, UI, and utilities.
The infrastructure shape includes API Gateway, Lambda, DynamoDB, and CloudWatch. The data flow is USGS fetch, GeoJSON normalization, idempotent DynamoDB upsert, validated query handling with pagination cursors, analytics over request logs, and a Next.js dashboard consuming API Gateway endpoints or offline fallback data.

The shape I wanted was a small real-world data platform: ingest public events, normalize them, query them by time, and keep the demo usable offline.
The DynamoDB model uses a single-table design with pk and sk, plus a TimeOrderedIndex GSI with a day bucket partition key and timestamp sort key. Request logs include metadata, filter fields, status/latency fields, and TTL.
The access pattern is the product
The more interesting design choice was not “use DynamoDB.” It was deciding which questions the table should answer without turning every query into a scan. Earthquake data is naturally time-heavy, so I shaped the table around day buckets, timestamps, and bounded result sets.

The data model I wanted readers to see: public events become normalized records, and the key design follows the Explorer filters the UI actually exposes.
That is why the Explorer and the storage model belong in the same article. The UI asks for time range, magnitude, and size. The backend should make those requests predictable, validated, and paginated instead of treating them as one-off dashboard needs.
Key implementation decisions
- I used a monorepo so infrastructure, web app, shared schemas, and Lambda services can evolve together.
- I validated boundaries with Zod schemas instead of letting API contracts stay implicit.
- I used a DynamoDB GSI optimized for time-ordered day-bucket queries.
- I kept an offline dataset so the portfolio demo can render without a live backend.
- I used LocalStack to keep cloud-shaped infrastructure reproducible locally.
Current status
The project is active with both a live site and source repository. Live exploration confirmed dashboard, explorer, documentation, and backend admin surfaces.
The public demo showed zero-valued dashboard data in offline or no-data mode, and the Settings route returned 404 during research. I call those out as current surface realities instead of implying the demo is always backed by live production AWS.
What I would improve next
I would refresh the offline dataset regularly so the public demo has meaningful sample data, make “offline demo mode” visually explicit, and either complete or remove the Settings route. I would also add public deployment notes beside the architecture diagram so readers can separate the cloud-shaped implementation from the portfolio demo mode.