Orange County public data platform — interactive infographic maps, community-supported and open source.
An interactive BI infographic platform that visualizes Orange County, CA demographics through choropleth maps, city-level comparisons, correlation analysis, and time-series trends — community-supported and open source.
Live: oc.techcloudup.com
| Before (Chatbot) | After (Infographic Map) |
|---|---|
| LLM response: 15–30 sec | Map load: < 1 sec |
| 1 OCPU saturated | Static + CDN-ready |
| Text-only answers | Visual, color-coded, interactive |
Internet
│
Cloudflare (proxy + DNS)
SSL Termination
│
┌──────────────────┼──────────────────┐
│ │
┌─────▼─────┐ ┌──────▼──────┐
│ oc-a1 │ ← Production │ oc-monitor │ ← Monitoring
│ A1.Flex │ │ E2.1.Micro │
│ 1 OCPU │ │ 1 OCPU │
│ 6 GB RAM │ │ 1 GB RAM │
│ ARM │ │ Ubuntu 24 │
│ │ │ │
│ Nginx │ │ Uptime Kuma │
│ :80/:443 │ │ :3001 │
│ static │ │ Nginx :80 │
│ files │ │ │
└────────────┘ └──────────────┘
CI/CD: GitHub Actions → build → rsync → oc-a1
IaC: Terraform (infra) + Ansible (config)
SSL: Let's Encrypt via certbot (auto-renew)
Standby: Cloudflare Pages (warm) — 3 min failover
- Choropleth Map — 34 OC cities with 7 color-coded metric layers
- Multi-City Comparison — Shift+Click to select up to 3 cities, side-by-side comparison table
- County Overview — OC-wide stats, top/bottom cities, best value insight on initial load
- Sortable City Table — Filter, search, sort by any metric across all cities
- Metric Correlation — Scatter plot with dual-axis selectors + linear regression trend line
- Time-Series Trends — 5-year trend chart per city with OC average reference line
- City Detail Panel — Click any city for full stats + OC ranking comparison
- City Search — Autocomplete dropdown with instant filtering
- Comparison Bar — Visual city-vs-OC-average for any metric
- Mobile First — Bottom sheet panel, horizontal scroll metric pills, 100dvh height
- i18n — English / Spanish toggle with dynamic
<html lang> - Sharable URLs —
#metric=population&city=Irvinedeep links
| Resource | Spec | Role |
|---|---|---|
| oc-a1 | Ampere A1.Flex (1 OCPU, 6 GB RAM, 30 GB) | Production — Nginx, static files |
| oc-monitor | E2.1.Micro (1 OCPU, 1 GB RAM, 50 GB) | Uptime Kuma monitoring + Nginx |
| VCN | Public subnet | — |
| DNS | Cloudflare (proxy) | SSL termination, CDN, DDoS protection |
| CI/CD | GitHub Actions | Auto-deploy on push to main |
| IaC | Terraform + Ansible | Infrastructure provisioning + config management |
| Layer | Technology | Why |
|---|---|---|
| Frontend | Next.js 16, React 19, TypeScript 5 | Static export, zero JS server needed |
| Styling | Tailwind CSS 4 | Utility-first, < 3 KB CSS |
| Maps | Leaflet + react-leaflet v5 | Lightweight (42 KB), no API key needed |
| Charts | Chart.js + react-chartjs-2 | Comparison bars, scatter plots, trend lines |
| State | Zustand | Tiny (1 KB) global state for i18n |
| Web Server | Nginx | Static files, gzip, security headers, SSL |
| SSL | Let's Encrypt via certbot | Auto-renew, trusted by all browsers |
| i18n | Custom React context | EN / ES toggle, 2 locales, localStorage persistence |
| Data | Static JSON (oc-cities.json, 26 KB) |
No database, client-side processing |
leaflet, react-leaflet # Interactive choropleth maps
chart.js, react-chartjs-2 # Comparison bars, scatter, trend charts
zustand # i18n state management
tailwindcss # Utility CSS framework
- Node.js 20+
cd frontend
npm install
npm run dev # http://localhost:3000Deployment is automated via GitHub Actions on push to main. To deploy manually:
cd frontend && npm run build # outputs to frontend/out/
# Manual deploy
scp -r frontend/out/* deploy@<a1-ip>:/tmp/oc-platform/
ssh deploy@<a1-ip> "sudo cp -r /tmp/oc-platform/* /var/www/oc-platform/ && sudo chown -R nginx:nginx /var/www/oc-platform && sudo systemctl reload nginx"All data is sourced from the U.S. Census Bureau ACS 2019–2023 5-Year estimates and packaged as a static GeoJSON file (frontend/public/oc-cities.json, 26 KB).
Data sources:
- U.S. Census Bureau ACS 5-Year — Demographics, income, housing
- OC Cities GeoJSON — Static boundary data
The platform has evolved through several phases:
| Phase | Date | Change |
|---|---|---|
| Chatbot | Early 2026 | FastAPI + Ollama + Open WebUI + ATP Database + Load Balancer |
| Static Pivot | July 2026 | Removed all backend services, static JSON + Nginx on A1 |
| Production Migration | July 2026 | Production moved from vm2 (E2.1.Micro) to oc-a1 (A1.Flex, 6 GB) — 6x more RAM headroom |
| IaC + DR | July 2026 | Terraform, Ansible, Docker configs added — full infrastructure as code + disaster recovery plan |
Previously removed services:
- ✗ Ollama + Open WebUI — Chatbot discontinued
- ✗ FastAPI backend — Frontend uses static JSON
- ✗ ATP Database — Data in static JSON
- ✗ Load Balancer — Cloudflare handles DNS + SSL
- ✗ Redis — No caching layer needed
- ✗ n8n pipeline — Data compiled at build time
- ✗ oc-platform-vm2 — Decommissioned, replaced by oc-a1
All infrastructure is defined as code. Recovery from any failure is automated via Terraform + Ansible.
| Scenario | RTO | Procedure |
|---|---|---|
| Instance failure (oc-a1) | ~16 min | terraform apply → ansible-playbook web.yml → git push |
| Instance failure (oc-monitor) | ~20 min | terraform apply → ansible-playbook monitoring.yml |
| OCI Phoenix region outage | ~3 min | Switch DNS to Cloudflare Pages standby |
| Full OCI account loss | ~70 min | New account → terraform apply → ansible-playbook site.yml |
| DNS / SSL expiry | ~2 min | certbot renew or update Cloudflare DNS |
Standby: Cloudflare Pages connected to this repo — auto-builds on push, ready to take over with a DNS switch.
IaC stack: Terraform (terraform/) for infrastructure, Ansible (ansible/) for configuration, Docker (frontend/Dockerfile) for containerized deployment.
Full plan: docs/DR.md
OC Infographics is independently built and maintained as a public resource. If you find it valuable, consider supporting its continued operation:
Every contribution helps cover infrastructure, domain, and development time — keeping the platform fast, free, and growing.
MIT — see LICENSE for details.
