This document provides a comprehensive overview of the Satellite TLE Tracker & AI Orbital Discovery platform architecture, data flows, components, and security mechanisms.
The application is a modular Flask 3 app. Persistence is SQLAlchemy 2 against either SQLite or PostgreSQL (psycopg 3, URI scheme postgresql+psycopg://). Engine choice is stored in instance/datastore.json so it can survive database wipes and be changed from Admin. Orbit math runs in Python (sgp4) and in the browser (satellite.js). Admin access uses Google OAuth2 with a fail-closed local bypass. Text-to-SQL runs in-process via llama-cpp-python and Qwen2.5-Coder-1.5B.
+-----------------------------------------------------------------------------------+
| User Interface |
| Keyword Search (default) | Country Proximity + prefixes | Offline AI | Tracker |
| First-launch /setup | Admin datastore + SQL explorer | Fullscreen maps |
+-----------------------------------------------------------------------------------+
|
HTTP / JSON API
v
+-----------------------------------------------------------------------------------+
| Flask Application |
| setup_bp upload_bp report_bp admin_bp auth_bp |
| - wizard - GET form - keyword - reset - OAuth |
| - bind - ingest - proximity - SQL - is_local_dev() fail-closed |
| - Text-to-SQL - datastore switch |
| Geo / LLM / sql_console / datastore / overlay (EONET, USGS, Open-Meteo, CNBC, OpenSky, GDACS, Digitraffic) |
+-----------------------------------------------------------------------------------+
|
SQLAlchemy ORM (rebind on datastore.json change)
v
+-----------------------------------------------------------------------------------+
| SQLite (instance/*.db) or PostgreSQL 18.6 |
| uploads | satellites | tle_elements | saved_queries | system_settings |
+-----------------------------------------------------------------------------------+
| instance/datastore.json (engine + URI; not stored inside the satellite tables) |
+-----------------------------------------------------------------------------------+
app/services/tle_parser.py)GET /upload renders the form; POST /upload ingests. HEAD /upload is treated as GET so probes do not hit the POST branch.app/services/datastore.py, app/services/db_service.py)DATABASE_URL / DB_ENGINE redirects to /setup.ensure_database_schema() runs create_all after bind and after engine switch so tables such as uploads exist before routes query them.instance/.uploads, satellites, tle_elements, and saved_queries when the admin switches engines.${SATTRACK_UID}:${SATTRACK_GID} (from run.sh) so bind-mounted instance/ files are not root:root mode 600.data/kaggle_tle_data.txt is missing, app/services/demo_tle.py seeds a small labelled demo catalogue.app/routes/report.py)q lists all satellites; a non-empty term ILIKEs name, int_designator, classification, cast NORAD ID, and raw TLE lines.GET /api/proximity/options returns countries that have both bounding box and center (list_available_countries) plus catalogue prefixes (satellite_name_prefix: first word, drop parentheticals and hyphen suffixes).app/services/geo_query_service.py): SGP4 propagation, Haversine sort, decayed-orbit filter.app/routes/report.py)llama-cpp-python. No external web calls required.Qwen2.5-Coder-1.5B-Instruct-Q4_K_M.gguf.validate_sql_safety / cache validator — only SELECT. Blocklist includes DROP, DELETE, UPDATE, INSERT, ALTER, ATTACH, PRAGMA.app/static/js/basemap.js)CARTO_API_KEY is set, templates expose window.SATTRACK_CARTO_KEY and CARTO dark_all is used with ?key=.#orbit-map-card) and tracker (#tracker-map-shell) toggle a CSS fullscreen overlay and call Leaflet invalidateSize. Escape exits.app/services/overlay_cache.py) with per-feed TTLs (about 25s for live flights, 60–90s for quotes and cloud pings, minutes for news, up to an hour for daily city temperatures). Expired entries are served immediately while a background refresh runs. HTTP calls go through app/services/overlay_http.py, which honors 429 / Retry-After and backs off that host so a throttle does not hammer every overlay. The map renders partial data as it arrives (city pins before Open-Meteo trends, GDACS before RSS headlines, cloud-DC pins before p50/p95/p99). The map credit strip and popups attribute each source:
GET /api/world-events — NASA EONET weather/climate events plus USGS earthquakes (app/services/world_events.py) and million-city temperature trends (app/services/city_temperature.py, Open-Meteo ERA5). Response includes events and temperatures (7d / 30d / 90d / 1y °C change). Quake markers include magnitude; the map scales bubble size and color by severity.GET /api/market-indices — major world indexes, CNBC last + 1d %, plus 7d / 30d / 1q / 6m / 1y / 2y / 5y / 10y % computed from Yahoo Finance daily closes (app/services/market_indices.py).GET /api/currencies — local units to buy 1 USD / EUR / yen / oz gold / barrel of WTI / Big Mac, plus 1d / 7d / 30d / 90d / 6m / 1y / 5y FX/gold % (app/services/currency_overlay.py; Frankfurter, CNBC, The Economist).GET /api/flights — OpenSky Network airborne states plus adsbdb origin/destination and estimated on-time; optional lamin/lomin/lamax/lomax (app/services/flight_overlay.py).GET /api/geo-news — last-24h GDACS alerts plus UN News, Global Voices, The Conversation, and Deutsche Welle RSS; gazetteer geocode when the feed has no lat/lng (app/services/news_overlay.py).GET /api/shipping — schematic world sea lanes plus Fintraffic Digitraffic AIS (app/services/shipping_overlay.py). Live ships are Finland/Baltic only (CC BY 4.0).GET /api/webcams — official public webcam pages worldwide plus OpenStreetMap webcam:url via Overpass (world hubs at global scale, current bbox when zoomed in) (app/services/webcam_overlay.py).GET /api/cloud-datacenters — AWS / Azure / GCP region pins with HTTPS ping p50 / p95 / p99 from this server (app/services/cloud_datacenters.py).app/templates/_posthog.html, included from base.html.POSTHOG_PROJECT_API_KEY is set and the app is not in TESTING.https://us.i.posthog.com (POSTHOG_HOST for EU or self-hosted).person_profiles: identified_only so Web analytics stays on anonymous events. Session replay is off unless POSTHOG_SESSION_REPLAY=true.app/routes/admin.py, app/routes/auth.py)@admin_required plus optional ADMIN_ALLOWED_EMAILS.prompt=select_account. An existing admin session is reused (SESSION_PERMANENT, 14-day PERMANENT_SESSION_LIFETIME, refreshed on activity). Sign out still clears it.is_local_dev() is false when FLASK_ENV=production. Docker / RUNNING_IN_DOCKER is not treated as local by itself. /auth/dev-bypass is only offered on localhost/dev./admin/database): table counts, read-only SELECT / WITH / EXPLAIN, row cap 1–10 000 (default 200), CSV/Excel export, saved_queries rows with last-run count and p50/p95/p99/p100 latency (app/services/sql_console.py).erDiagram
Uploads ||--o{ TLEElements : contains
Satellites ||--o{ TLEElements : owns
Uploads {
int id PK
string filename
datetime upload_time
int total_records_in_file
int new_satellites
int updated_satellites
int duplicate_epochs
string source
boolean is_seed
string label
}
Satellites {
int id PK
int norad_cat_id UK
string name
string classification
string int_designator
datetime first_seen
datetime last_updated
}
TLEElements {
int id PK
int satellite_id FK
int upload_id FK
int epoch_year
float epoch_day
datetime epoch_datetime
float mean_motion_dot
float mean_motion_ddot
float bstar_drag
float inclination_deg
float raan_deg
float eccentricity
float arg_of_perigee_deg
float mean_anomaly_deg
float mean_motion_rev_day
int rev_number
string raw_line1
string raw_line2
}
SavedQueries {
int id PK
string name
string sql
int row_limit
datetime created_at
datetime last_run_at
float last_run_ms
int last_run_row_count
int run_count
float latency_p50_ms
float latency_p95_ms
float latency_p99_ms
float latency_p100_ms
string latency_samples_json
}
saved_queries lives in the active datastore so saved SQL and latency percentiles survive process restarts and migrate with an engine switch.
SELECT only; mutation keywords blocked.;, SELECT / WITH / EXPLAIN only, same mutation blocklist.ADMIN_ALLOWED_EMAILS. Production images set FLASK_ENV=production so the local bypass cannot be reached on advertised 1-click/cloud deploys..env. instance/datastore.json is host-owned (0o600). Unreadable files are DATASTORE_UNREADABLE, not treated as first-launch.MAX_CONTENT_LENGTH 16 MB; TLE checksum and line-length checks.