1. System Overview
PlaneTrack.ai is a production-grade flight tracking platform that processes real-time ADS-B (Automatic Dependent Surveillance-Broadcast) data from aircraft worldwide. The system ingests data from multiple sources, processes and stores it in PostgreSQL, and serves it through a modern React web application with live map visualization.
Data Sources
2
OpenSky Network & ADSBHub
Live Aircraft
10k+
Tracked simultaneously
Message Rate
50k/s
Peak throughput
Update Frequency
15s
Real-time refresh
Storage
73TB
Total capacity
Services
9
Running systemd units
2. Complete Data Flow
End-to-end journey of ADS-B data from aircraft transponders to user's browser
✈️ Aircraft
ADS-B Transponders
1090 MHz broadcasts
→
📡 Receivers
Ground Stations
RTL-SDR, FlightAware
→
🌐 Networks
OpenSky & ADSBHub
Global aggregation
↓
📨 Redpanda Cluster
Kafka-compatible streaming
3 brokers: 10.0.3.24, 10.0.3.108, 10.0.3.50
↓
⚙️ Aggregator
adsb_snapshot_aggregator.py
Groups aircraft positions
→
📝 Writer
adsb_unified_writer.py
Batch inserts: 2000/batch
↓
🗄️ PostgreSQL 16
adsb_production database
Host: 10.0.3.235:5432
↓
🔌 adsb-api
FastAPI on :3001
Read-only data API
🔐 auth-admin-api
FastAPI on :8080
Auth & admin
🚀 production-api
Flask/Gunicorn on :9003
Main API server
↓
🌐 Nginx
Reverse Proxy & SSL
planetrack.ai:443
↓
⚛️ React Frontend
TypeScript + Vite
MapLibre GL visualization
3. Systemd Services
All background services managed by systemd for automatic startup and recovery
| Service |
Port |
Script |
Purpose |
Status |
| adsb-snapshot-aggregator |
- |
adsb_snapshot_aggregator.py |
Aggregates raw ADS-B from Kafka → adsb_snapshot topic |
Running |
| adsb-unified-writer |
- |
adsb_unified_writer.py |
Writes Kafka snapshots to PostgreSQL tables |
Running |
| adsb-api |
3001 |
adsb_api.py |
FastAPI read-only data API (live aircraft, tracks) |
Running |
| auth-admin-api |
8080 |
main_api.py |
Authentication, admin, Stripe billing |
Running |
| planetrack-api-1 |
9003 |
production_api.py |
Primary Flask API (gunicorn + gevent) |
Running |
| planetrack-api-2 |
9004 |
production_api.py |
Backup Flask API for failover |
Running |
| flight-snapshot |
- |
flight_snapshot_service.py |
5-minute snapshots with flight duration/routes |
Running |
| system-status-api |
9999 |
system_status_api.py |
Health metrics for dashboards |
Running |
4. Data Ingestion Layer
Data Sources
OpenSky Network
Kafka Topic: adsb_snapshot
Format: JSON snapshots
Rate: ~30k messages/min
- Primary data source
- Global coverage from 5000+ receivers
- Position, altitude, velocity, heading
- Aircraft registration & type codes
- Historical data access
ADSBHub.org
Kafka Topic: adsb.raw
Format: BaseStation/SBS CSV
Rate: ~50k messages/sec peak
- Secondary/backup source
- MSG types 1-8 (all message types)
- Real-time raw feed
- Coverage gap filling
- Redundancy & validation
Redpanda Message Queue
Kafka-Compatible Streaming Platform
Cluster: 3 brokers for high availability
Broker 1: 10.0.3.24:9092
Broker 2: 10.0.3.108:9092
Broker 3: 10.0.3.50:9092
Topics:
- adsb_snapshot - Aggregated aircraft positions (1 partition, 3 replicas)
- adsb.raw - Raw BaseStation format from ADSBHub (1 partition, 3 replicas)
Benefits:
- Decoupling: Data sources independent from consumers
- Buffering: Handles traffic spikes & consumer downtime
- Replayability: Can reprocess historical messages
- Durability: 3x replication across brokers
Processing Scripts
adsb_snapshot_aggregator.py
Consumes raw BaseStation messages from adsb.raw topic
- Groups by aircraft (icao24)
- Keeps latest position per aircraft
- Publishes aggregated snapshot every 15 seconds
- Outputs to adsb_snapshot topic
adsb_unified_writer.py
Writes aggregated snapshots to PostgreSQL
- Batch processing: 2000 records per batch
- 800ms batch window
- Writes to adsb_points_partitioned table
- Upserts to aircraft_state for fast lookups
- Automatic partition creation
flight_snapshot_service.py
Creates detailed flight snapshots every 5 minutes
- Captures all ~10,000 live flights
- Calculates flight duration from route progress
- Stores route info (origin/destination)
- Used for "Longest Flight" feature
- Historical flight analysis
5. Database Architecture
PostgreSQL Configuration
Host: 10.0.3.235
Port: 5432
Database: adsb_production
Version: PostgreSQL 16
Users:
- adsb_prod_user (primary application user)
- adsb_writer (write-only for ingestion)
- web_anon (read-only for PostgREST)
Storage Tiers
🔥
Hot Storage (ts_hot)
Location: Local NVMe SSD
Retention: Today + yesterday (2-3 days)
Size: ~50-75 GB
Purpose: Real-time queries, live aircraft tracking
📦
Archive Storage (ts_archive)
Location: Local SATA drives
Retention: Last 30 days
Size: ~700-800 GB
Purpose: Recent history queries, track analysis
❄️
Cold Storage (ts_cold)
Location: NAS at /mnt/nas_pg/planetrackai/pg_ts
Retention: 30+ days (unlimited)
Capacity: 73 TB total
Purpose: Historical data, analytics, compliance
Core Tables
aircraft_state
Current state of each aircraft (fast lookup)
- icao24 (PRIMARY KEY)
- callsign, lat, lon, altitude
- heading, velocity, vertical_rate
- last_seen timestamp
- Updated via UPSERT on each batch
adsb_points_partitioned
Historical position data (partitioned by day)
- received_at, icao24, callsign
- lat, lon, altitude, heading, velocity
- vertical_rate, onground, alert, spi
- Daily partitions: adsb_points_part_YYYYMMDD
- Millions of records per day
flight_snapshots
5-minute flight state snapshots
- snapshot_time, hex_ident, callsign
- lat, lon, altitude, speed, heading
- departure_airport, arrival_airport
- flight_duration_minutes
- distance_total_nm, distance_remaining_nm
- progress_percent, airline, category
active_flights
Currently active flight tracking
- hex_ident, callsign
- departure_time, first_seen, last_updated
- origin_icao, dest_icao
- distance_remaining_nm, progress_percent
- flight_phase (climb/cruise/descent)
route_reference
Known flight routes and airlines
- callsign (lookup key)
- origin_icao, origin_name, origin_city
- dest_icao, dest_name, dest_city
- great_circle_distance_nm
- airline_name
faa_aircraft
FAA registry data for US aircraft
- mode_s_code_hex (ICAO address)
- n_number (registration)
- type_aircraft, manufacturer
- model, serial_number
- owner_name, owner_city
Materialized Views
latest_flight_snapshot
Latest position for each aircraft - used for fast live queries
CREATE MATERIALIZED VIEW latest_flight_snapshot AS
SELECT DISTINCT ON (hex_ident)
hex_ident, callsign, lat, lon, altitude,
speed, heading, received_at
FROM aircraft_state
WHERE received_at > now() - interval '2 minutes'
ORDER BY hex_ident, received_at DESC;
Refreshed automatically by the unified writer after each batch
Partitioning Strategy
Daily Partitions with Auto-Rotation
- Partitioned by received_at (daily boundaries, UTC)
- Auto-creation for yesterday/today/tomorrow via ensure_adsb_points_partition()
- Nightly cron job (00:15) moves 30+ day partitions to cold storage
- Partition pruning enables fast queries within date ranges
-- Partition naming convention
adsb_points_part_20260120 (today - ts_hot)
adsb_points_part_20260119 (yesterday - ts_hot)
adsb_points_part_20251221 (30 days ago - ts_cold)
6. API Layer
Read-Only Data API (adsb_api.py)
Port 3001 - FastAPI with Uvicorn
High-performance read-only API for live aircraft data
GET /rpc/live_aircraft?window_secs=120&max_rows=30000
→ Returns all aircraft with positions in last 120 seconds
→ Response: [{ icao24, callsign, lat, lon, altitude, heading, velocity, last_seen }]
GET /rpc/track?icao24={hex}&minutes=30&max_rows=2000
→ Returns flight track history (breadcrumb trail)
→ Response: [{ icao24, lat, lon, altitude, velocity, received_at }]
GET /rpc/search?q={query}&limit_n=20
→ Search aircraft by hex code or callsign
→ Response: [{ icao24, callsign, last_seen, lat, lon }]
GET /rpc/longest_flight
→ Aircraft with longest current flight duration
→ Response: { hex, callsign, flight_time_minutes, departure_airport, arrival_airport }
GET /rpc/stats
→ System statistics
→ Response: { rows_1m, freshness_ms, live_aircraft }
Production API (production_api.py)
Port 9003 - Flask with Gunicorn + Gevent
Main production API with advanced features
Configuration:
- Workers: 2 gevent workers
- Connections: 1000 per worker
- Max requests: 1000 before worker recycle
Endpoints:
GET /api/rpc/live_aircraft → Live aircraft with oceanic predictions
GET /api/rpc/track → Flight track with stitching
GET /api/rpc/longest_flight → Longest flight from snapshots
GET /api/route/{callsign} → Route information
GET /api/flight/{callsign}/status → Flight status with ETA
GET /api/aircraft_lookup/{hex} → Aircraft photos & registration
Auth & Admin API (main_api.py)
Port 8080 - FastAPI with Authentication
POST /auth/login → User login
POST /auth/register → Create new account
GET /auth/me → Get current user info
POST /stripe/create-checkout-session → Start Stripe payment
POST /stripe/webhook → Handle Stripe webhooks
Admin pages (HTTP Basic Auth protected):
- /admin.html → Dashboard
- /admin-users.html → User management
- /admin-database.html → Database stats
- /admin-data.html → Data management
- /admin-providers.html → Data provider tools
- /admin-system.html → System configuration
Rate Limiting Tiers
Free Tier
1/s
100 requests/day
Starter ($9/mo)
10/s
10,000 requests/day
Professional ($29/mo)
100/s
100,000 requests/day
Enterprise
1000/s
Unlimited requests
7. Frontend Architecture
Technology Stack
React 18
TypeScript
Vite
MapLibre GL
Zustand
React Query
Tailwind CSS
Framer Motion
Lucide Icons
Project Structure
/home/tristanmunday/psql/website/test/src/
├── App.tsx # Root application component
├── main.tsx # Vite entry point
├── index.css # Global styles (Tailwind)
│
├── components/ # React components
│ ├── aircraft/
│ │ └── DetailPanel.tsx # Aircraft details, route, history
│ ├── layout/
│ │ └── Header.tsx # Top navigation bar
│ ├── map/
│ │ ├── FlightMap.tsx # MapLibre GL map with aircraft
│ │ └── MapControls.tsx # Style, 3D, terrain toggles
│ ├── search/
│ │ └── SearchBar.tsx # Aircraft search interface
│ ├── stats/
│ │ └── StatsBar.tsx # Statistics display
│ └── ui/
│ └── Toast.tsx # Notification toasts
│
├── hooks/
│ └── useAircraftData.ts # React Query data fetching hooks
│
├── services/
│ ├── api.ts # API client functions
│ ├── airports.ts # Airport lookup database
│ ├── trackStitching.ts # Multi-leg track handling
│ └── flightLegService.ts # Flight leg detection
│
├── stores/ # Zustand state management
│ ├── aircraftStore.ts # Aircraft state & selection
│ ├── mapStore.ts # Map configuration
│ └── uiStore.ts # UI state (toasts)
│
├── types/
│ ├── api.ts # API response types
│ └── aircraft.ts # Domain types
│
└── utils/
├── formatters.ts # Number/distance formatting
├── geo.ts # Geographic calculations
├── greatCircle.ts # Great circle math
└── antimeridian.ts # International date line
Key Components
FlightMap.tsx
Main map rendering component
- MapLibre GL for WebGL rendering
- Custom SVG aircraft icons with rotation
- Three map styles: Dark, Light, Satellite
- Track visualization (breadcrumb trail)
- Route line with antimeridian handling
- Smooth aircraft interpolation
DetailPanel.tsx
Aircraft information display
- Callsign, hex code, altitude, speed
- Route (origin → destination airports)
- Flight duration and progress bar
- Aircraft photos & registration lookup
- Flight history table
- Track view toggle (current leg / all)
StatsBar.tsx
Live statistics display
- Total aircraft count
- Category breakdown (Commercial, Military, etc.)
- Emergency aircraft alerts
- Fastest aircraft
- Highest altitude aircraft
- Longest flight duration
SearchBar.tsx
Real-time aircraft search
- Search by hex code or callsign
- Instant results as you type
- Click to select and track
- Recent searches history
State Management (Zustand)
aircraftStore
- Aircraft Map (hex → Aircraft object)
- Selected aircraft hex & details
- Track points for selected aircraft
- Statistics (fastest, highest, longest)
- Category filter state
- Track view mode (current leg / all)
- Interpolation data for smooth movement
mapStore
- Map center [longitude, latitude]
- Zoom level
- Map style (dark/light/satellite)
- 3D mode enabled
- Labels visible
- Terrain visible
uiStore
- Toast notifications array
- Search open state
- Detail panel open state
- Stats expanded state
Data Fetching (React Query)
Automatic Background Updates
- Live Aircraft: Fetches every 15 seconds, 60s stale time
- Oceanic Predictions: Fetches every 60 seconds (after live data loaded)
- Track History: Fetches on aircraft selection, 30s stale time
- Aircraft Lookup: Fetches photos/registration, 60s stale time
- Flight Route: Cascading API calls with 5-minute cache
- Longest Flight: Fetches every 30 seconds
Aircraft Category Detection
Hybrid Classification System
- Hex Prefixes: Military ICAO country blocks (ae, af, 43c, etc.)
- Callsign Patterns: Commercial ICAO codes (AAL, UAL, DAL, etc.)
- Military Callsigns: RCH, DUKE, NAVY, ARMY, RAF, etc.
- Cargo Airlines: FDX, UPS, DHL, etc.
- N-Numbers: US private registrations (N12345)
- Emergency: Squawk codes 7700, 7600, 7500
Categories: commercial | private | military | cargo | emergency | unknown
8. Nginx & Infrastructure
Nginx Configuration
Server: planetrack.ai, www.planetrack.ai
Listen: 80 (redirect to HTTPS), 443 (HTTP/2)
SSL/TLS:
- Certificates: Cloudflare Origin (/etc/ssl/cloudflare/)
- Protocols: TLSv1.2, TLSv1.3
- Session caching: 10 minutes
- OCSP Stapling: Enabled
Security Headers:
- Strict-Transport-Security: max-age=31536000
- X-Frame-Options: SAMEORIGIN
- X-Content-Type-Options: nosniff
- X-XSS-Protection: 1; mode=block
- Content-Security-Policy: (comprehensive policy)
Routing:
- /api/* → proxy to 127.0.0.1:9003 (planetrack-api-1)
- /rpc/* → proxy to 127.0.0.1:9003
- /admin*.html → proxy to 127.0.0.1:8080 (auth-admin-api)
- /* → static files from /home/tristanmunday/psql/website/
Real IP:
- Cloudflare CF-Connecting-IP header extraction
Cron Jobs
# Daily ADS-B backup at 1:00 AM
0 1 * * * /usr/local/bin/backup_adsb.sh
# Flight history processing at 1:30 AM
30 1 * * * /home/tristanmunday/psql/website/process_daily_flights.sh
# Flight history monitoring every 15 minutes
*/15 * * * * /home/tristanmunday/psql/website/monitor_flight_history.sh
# System config backup at 3:00 AM
0 3 * * * /home/tristanmunday/psql/website/backup_system_config.sh
File Locations
Configuration:
- Nginx: /etc/nginx/sites-enabled/planetrack.ai
- Systemd: /etc/systemd/system/*.service
- SSL Certs: /etc/ssl/cloudflare/
Application:
- Backend: /home/tristanmunday/psql/
- Frontend: /home/tristanmunday/psql/website/
- React Source: /home/tristanmunday/psql/website/test/src/
- Production API: /home/tristanmunday/planetrack.ai-production/app/
Logs:
- Nginx: /var/log/nginx/
- Flight Snapshot: /home/tristanmunday/psql/logs/
- Systemd: journalctl -u [service-name]
9. Monitoring & Operations
System Status API
Port: 9999
File: system_status_api.py
- Real-time service health checks
- Database connectivity status
- Kafka consumer lag
- Disk usage monitoring
- HTTP Basic Auth protected
Prometheus Metrics
Port: 9090
- Time-series metrics database
- 15-day retention
- 15-second scrape interval
- Custom ADSB metrics exporter
Grafana Dashboards
Port: 3000
- Ingestion rate graphs
- Database size trends
- API response times
- Service health overview
Auto-Recovery
File: monitor_and_recover.py
- Detects service failures
- Automatic restarts
- Ingestion stall detection
- Alert notifications
Critical Alerts
Ingestion Stopped
⚠️
No messages for 5+ min
Database Down
⚠️
Cannot connect to PostgreSQL
Disk Critical
⚠️
Less than 5% free space
API Down
⚠️
Not responding 3+ min
10. Complete Technology Stack
Backend
Python 3.12
FastAPI
Flask
Gunicorn
Uvicorn
Gevent
PostgreSQL 16
psycopg3
Redpanda/Kafka
confluent-kafka
bcrypt
Stripe SDK
Frontend
React 18
TypeScript
Vite
MapLibre GL JS
Zustand
React Query
Tailwind CSS
Framer Motion
Lucide Icons
Infrastructure
Ubuntu Linux
Nginx
systemd
Cloudflare SSL
Prometheus
Grafana
Cron
Data Sources
OpenSky Network
ADSBHub.org
FAA Aircraft Registry
ADSBDB