Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
0.5.4 - 2026-04-09¶
Added¶
- dSGP4 batch propagation backend (
director/dsgp4_propagator.py) -- optional PyTorch-based differentiable SGP4 via thedsgp4package (ESA / Politecnico di Torino; arXiv:2402.04830, Acta Astronautica vol 226, 2025). ImplementsPropagatorProtocolwith a newDSGP4Propagatorclass and abatch_calculate_az_el()fast path for computing az/el across many satellites in one call. The module imports cleanly withoutdsgp4ortorchinstalled and gracefully falls back toSkyfieldPropagatoron any exception. Adapter functions convert SkyfieldEarthSatellite+Timetotorch.Tensorat one boundary and back to Python floats at the other, so PyTorch tensors never leak into the rest of the codebase. Thread-safe 1000-entry FIFO TLE cache. Install the optional backend withpip install -e .[director-batch]. (#38) - TimescaleDB-ready telemetry persistence (
core/telemetry_store.py,core/migrations/versions/003_timescale_telemetry.py) -- newTelemetryRecordSQLModel table for tracking-telemetry samples (timestamp, station, campaign, NORAD id, az, el, freq, mode, signal strength). Hand-written Alembic migration003_v054_telemetry(chained off002_v055) creates the table with five indexes including a composite(station_id, ts)index. On Postgres, the migration detects the TimescaleDB extension viapg_extensionand runscreate_hypertableonly if present, otherwise operates as a plain Postgres table. On SQLite the hypertable block is skipped entirely via anop.get_context().dialect.name == "postgresql"guard.insert_telemetry()/query_telemetry()/is_hypertable_available()library helpers included. The module does not yet subscribe to MQTT telemetry topics -- that ingestion wiring is reserved for a follow-up session. (#43)
Testing¶
- Added
tests/test_director/test_dsgp4_propagator.pywith 17 tests: runtimePropagatorProtocolcheck, clean import withoutdsgp4, fallback delegation, cache FIFO eviction, batch fast-path shape/type assertions, and a dSGP4-vs-Skyfield parity test (gated on_DSGP4_AVAILABLE, skipped whendsgp4is not installed). - Added
tests/test_telemetry_store.pywith 10 self-contained tests using an in-memory SQLite engine: model instantiation, optional field defaults, composite index declaration, insert+query roundtrip, time-window filtering, station filtering, limit enforcement, andis_hypertable_availablereturning False on SQLite. - Added
director.dsgp4_propagatorandcore.telemetry_storetotests/test_imports.py-- 34 modules now verified to import cleanly in fresh subprocesses. - Alembic round-trip verified on SQLite:
upgrade head -> downgrade -1 -> upgrade headexits 0 for migration 003. - Total test count: ~375 (up from ~358), one new skip (dSGP4 parity gated on optional dep).
0.5.3 - 2026-04-05¶
Security¶
- Thread safety: Added
threading.Lockto Director globals and stream router UDP socket (#81, #82) - Auth hardening: Removed magic link URL from logs, added startup guard, uniform login response (#83, #91)
- CORS: Restricted
allow_headersfrom wildcard to explicit list (#84) - Session cookie: Added
path="/"attribute (#85) - Rate limiting: Extended to admin (30/min), public API (60/min), campaign creation (20/min) (#86)
- Proxy-aware limiter: Rate limiter now reads
X-Forwarded-Forfirst hop (#87) - Input sanitization: HTML tag stripping on all user-controlled text fields (#88)
- Migration logging: Suppressed migration errors now logged at WARNING (#90)
UI/UX¶
- Magic link expiry page: Expired/invalid tokens now show a styled HTML page with "Request New Link" button instead of raw JSON
Correctness¶
- Admin pagination: List endpoints accept
page/per_pagequery params (#89) - Geo validation: Station lat/lon/alt constrained to valid ranges (#92)
- Director BROKER_PORT: Now reads from environment variable (#93)
- Agent socket cleanup: Sockets closed on connection failure (#94)
- Async deprecation: Replaced
asyncio.get_event_loop()withget_running_loop()(#95) - Agent telemetry: Now publishes to org-scoped topic when
--orgis set (#96)
Testing¶
- Added 29 new tests: auth security (expired/invalid JWT HTML), RBAC violations, input validation (HTML stripping, geo bounds, field lengths), stream router socket lock
- Total test count: 328 (up from 293)
0.5.2 - 2026-04-05¶
Added¶
- Streaming architecture (phasma-operations integration) -- streaming-first data pipeline from edge GNU Radio flowgraphs through TALOS to external YAMCS mission control instances
- Stream router (
core/stream_router.py) -- background MQTT subscriber that forwards decoded frames to YAMCS via UDP, matching the phasma-operations convention (4-byte frame_id prepend) - MissionLink model (
core/database.py) -- maps campaigns to external YAMCS endpoints (host, port, instance, frame_id) with enable/disable toggle - Mission link API (
core/routes/missions.py) -- GET/PUT/PATCH/DELETE at/api/orgs/{slug}/campaigns/{id}/missionfor configuring YAMCS routing per campaign - StreamCommand schema -- Director-to-Agent command for starting/stopping GNU Radio flowgraphs on pass boundaries (AOS/LOS)
- FrameData schema -- Agent-to-Core decoded frame payload with campaign/station/satellite metadata
- MissionEndpoint schema -- YAMCS instance configuration model
- Stream MQTT topics --
cmd/stream(Director->Agent),stream/frames(Agent->Core), wildcard subscriptions - MQTT ACL updates -- agents can write
stream/#, director can readstream/# - FlowgraphManager (
agent/flowgraph.py): GNU Radio flowgraph subprocess lifecycle manager with SIGTERM->SIGKILL fallback (#74) - Research document (
docs/research/06-phasma-integration.md) -- architecture decisions, fork strategy, YAMCS wrapping rationale, 5-phase implementation plan
Streaming Pipeline (Phase 3-5)¶
- Agent handles
cmd/streamtopics: START spawns flowgraph + ZMQ-to-MQTT frame bridge, STOP tears down (#75) - Agent CLI: added
--sdr-deviceand--zmq-portarguments (#76) - Director emits
StreamCommandon AOS (with transmitter params) and LOS (#77, #78) - Full frame pipeline: Director triggers -> Agent spawns flowgraph -> ZMQ frames -> MQTT -> Stream Router -> UDP to YAMCS
Changed¶
- Stream router integrated into FastAPI lifespan (startup/shutdown alongside MQTT notification client)
- Campaign model gains
mission_linkrelationship to MissionLink - ROADMAP.md reorganized: v0.5.2 is now the streaming architecture release with 5 phases
Testing¶
- 23 new tests covering stream schemas, topics, and router routing logic
- Added FlowgraphManager unit tests (start/stop/restart/force-kill)
- Total test count: ~356
0.5.0 - 2026-04-05¶
New Modules¶
- CelesTrak TLE fallback (
shared/tle_sources.py): CelesTrakClient with caching + TLESourceManager priority cascade (SatNOGS -> CelesTrak -> stale cache) (#41) - PropagatorProtocol (
director/propagator.py): Swappable interface for satellite propagation backends with SkyfieldPropagator adapter (#37) - BackgroundPredictor (
director/background_predictor.py): ThreadPoolExecutor-based background computation for pass predictions and ground tracks (#36)
Improvements¶
- Director pass predictions moved to background thread -- protects 2Hz loop at 50+ stations (#36)
- TLE manager uses multi-source fallback (SatNOGS + CelesTrak + cache) instead of SatNOGS-only (#41)
- Public satellite tracker uses TLESourceManager for cached, resilient TLE lookups (#42)
Testing¶
- Added 21 new tests: TLE source fallback cascade, BackgroundPredictor lifecycle, PropagatorProtocol compliance, import checks for 3 new modules
- Total test count: ~349 (up from 328)
0.4.0 - 2026-04-03¶
Added¶
- MQTT authentication and ACLs -- broker enforces
allow_anonymous falsewith password file and per-station topic ACLs - MQTT TLS support -- cert generation script (
ops/scripts/gen_tls_certs.sh), optional TLS on port 8883 for all clients - CORS middleware with configurable origin allowlist (
CORS_ORIGINSenv var) - Rate limiting on
/auth/login(5/min) and/auth/verify(10/min) via slowapi - Prometheus metrics on Core (
/metrics) and Director (:8001/metrics) -- request rate, latency, active campaigns, tick duration - Director HTTP health endpoint (
:8001/health) with tick-age monitoring - Structured JSON logging -- set
TALOS_LOG_FORMAT=jsonfor production (Core, Director, Agent) - Grafana dashboard with pre-built panels for HTTP traffic, Director performance, and MQTT throughput (
ops/grafana/) - Monitoring stack docker-compose overlay (
ops/docker-compose.monitoring.yml) with Prometheus + Grafana - WebSocket MQTT relay preparation -- broker port 9001 can be restricted to internal access
- Deprecation headers on legacy endpoints (
/missions/*,/stations/create) with Sunset date - Docker build caching in CI (
--cache-fromfor faster image builds)
Changed¶
- core/main.py split into package -- 2357-line monolith decomposed into 17 modules:
core/app.py,core/config.py,core/deps.py,core/mqtt_client.py,core/sync.py,core/models.py, and 11 route files undercore/routes/ - Agent rewritten to asyncio -- replaced synchronous paho-mqtt with aiomqtt, global state replaced with dataclass, built-in reconnection
- Agent authenticates to MQTT --
--keyCLI arg now used as MQTT password with station_id as username - Director authenticates to MQTT -- reads
MQTT_USER/MQTT_PASSenv vars (previously ignored) - Inline JavaScript extracted -- ~1261 lines of JS moved from 10 templates into
core/static/js/*.jsES modules - Paho MQTT JS replaced with MQTT.js -- modern, maintained library for browser WebSocket connections
- Auth/org dependency extracted --
require_role(),require_admin(),get_current_user()incore/deps.py
Removed¶
- Legacy Mission code path from Director (
_tick_legacy(),get_active_mission()) - Dead inline JavaScript from all HTML templates (replaced by external modules)
- Direct browser-to-MQTT broker dependency (config prepared for WebSocket relay)
Dependencies Added¶
prometheus-client(metrics),python-json-logger(structured logging),slowapi(rate limiting),aiomqtt(async MQTT)
0.3.1 - 2026-04-03¶
Fixed¶
- Agent
on_messagehandler wrapped in try/except to survive malformed MQTT payloads - Session cookie now sets
secure=Truefor HTTPS enforcement - Removed stale
window_start/window_endfields fromAssignmentCreateandAssignmentResponseschemas (columns were already dropped from DB) - Footprint radius now computed from orbital altitude instead of hardcoded 2,500 km
Changed¶
ADMIN_EMAILandALLOWED_EMAIL_DOMAINSnow configurable via environment variables- Login endpoint uses Pydantic
EmailStrvalidation instead of raw dict - Agent supports
--orgCLI argument for org-scoped MQTT topic subscription alongside legacy topics - All API request models now enforce
max_lengthconstraints on string fields Membership.roleconstrained toowner/operator/viewervia database CHECK constraint- Build stage in CI gated on SAST security scans (optional dependency)
- Added
email-validatorto core dependencies forEmailStrsupport
Removed¶
- Deleted dead
core/tracker.py(161 lines, never imported)
0.3.0 - 2026-04-03¶
Added¶
- System administration dashboard (
/admin) for platform-wide management of users, networks, stations, and join requests (admin-only) - Network discovery page (
/networks) where authenticated users can browse all organizations and request to join - Join request system: users can request to join networks; org owners can approve or deny requests from the settings page or admin dashboard
is_adminfield on User model for system-wide admin privilegesJoinRequestmodel for tracking membership requests with status (pending/approved/denied)descriptionfield on Organization model- Email domain restriction: only
@libre.spaceemails can self-register; other users must be invited - Admin API routes: list all users/orgs/stations, promote/demote admin, delete users
- Member management API: update member roles, remove members from organizations
- Admin nav link (visible only to admins) across all authenticated pages
- Networks nav link across all authenticated pages
- Auto-select first active campaign on dashboard load so telemetry is visible immediately
- Fresh v0.3 research documents: architecture review, security review, operations & scalability, SatNOGS integration, technology roadmap, executive summary
Changed¶
- ADMIN_EMAIL changed from
pierros@papadeas.grtopierros@libre.space - Admin user is auto-created with
is_admin=Trueon first startup - Public satellite tracker now showcases PHASMA-LAMARR, PHASMA-DIRAC, PeakSat, and ISS as quick-select satellites (replacing Hubble, Landsat 8, Fermi, NOAA-18, AO-51)
- Default tracked satellite changed from ISS to PHASMA-LAMARR
- Organization switcher: replaced confusing dropdown with a simple
<select>element and linked org badge to settings (fixes z-index issue where dropdown appeared behind the map) - Archived v0.1-v0.2 research documents to
docs/research/archive/ - Updated DEVELOPMENT.md: Makefile targets, project structure, CI pipeline description, test counts
- Fixed mkdocs edit_uri from
maintomasterbranch - Pinned mkdocs versions in CI to avoid mkdocs 2.0 breaking changes
0.3.0 - 2026-04-03¶
Added¶
- TALOS Design System (Astro UXDS) — unified dark-theme stylesheet (
talos.css) based on U.S. Space Force Astro UXDS patterns, with CSS custom properties for surfaces, status colors, typography, spacing, and components (cards, badges, buttons, data tables, KPIs, form fields) - Visual redesign across all templates (dashboard, members, stations, campaigns, settings, login, home) using the new design system
- GitLab CI/CD pipeline with DAG dependencies, SAST, secret detection, dependency scanning, JUnit/Cobertura reporting, Docker builds, release automation, and Fly.io deployment
- GitLab issue templates (Bug Report, Feature Request, Question, Security Vulnerability) and merge request templates (Default, Hotfix, Release)
- GitLab Pages documentation site via MkDocs Material with full nav (architecture, dev guide, contributing, research docs, changelog)
- CODEOWNERS file for automatic review assignment
.editorconfigwith indent rules for Python, HTML, CSS, JS, YAML, and shell scripts.gitattributesfor line ending normalization and linguist overrides- Expanded Makefile with 16 targets including
test-unit,test-smoke,test-campaign,test-all,docs,docs-serve,logs,clean, and auto-generatedhelp - Logout route (
GET /auth/logout) with session cookie clearing and redirect - Smoke tests for logout (redirect, cookie clearing, unauthenticated access)
- Campaign end-to-end test suite (33 tests covering lifecycle, RBAC, assignments)
- README badges for pipeline status, coverage, release, license, and docs
Changed¶
- Dashboard rebuilt with TALOS design system, replacing Bootstrap CSS while keeping Bootstrap JS for modals/dropdowns
- Navigation bar standardized across all pages using
nav-globalBEM pattern - Campaign visualization palette updated to match design system accent colors
- Migrated from GitHub Actions to GitLab CI/CD
- CI security templates updated to current GitLab paths (
Jobs/prefix)
Fixed¶
- CI/CD pipeline failure caused by non-existent
Security/License-Scanning.gitlab-ci.ymltemplate - CI template include paths:
Security/→Jobs/for SAST, Secret-Detection, and Dependency-Scanning - README badges pointing to
mainbranch instead of actual default branchmaster - GitLab Pages not deploying due to
changes-only trigger restriction and missingdocs/index.md - MkDocs build failures from nav paths referencing files outside
docs/directory - Broken anchor links in research documentation TOC
test-unitCI job referencing empty test directories (test_core/,test_director/)- Login page accessibility: added form label and aria attributes
- Brand links: changed from non-navigable
<span>to<a href="/">across login and public tracking pages - Duplicated
.page-containerCSS extracted to sharedtalos.css
Removed¶
.github/directory (workflows, issue templates, PR template) — replaced by GitLab equivalents- Bootstrap CSS dependency from dashboard (Bootstrap JS retained for modal/dropdown functionality)
0.2.1 - 2026-04-02¶
Added¶
- Management pages for members, stations, campaigns, and organization settings
- End-to-end test coverage: 71 tests covering org, station, campaign, and assignment APIs
- RBAC enforcement tests (viewer receives 403 on operator-only endpoints)
- Magic link email authentication via Resend API
- Dashboard campaign sidebar now displays all campaigns (not just the single active one)
Fixed¶
- Campaign creation: resolve
norad_idfromsatnogs_idwhen not provided by the dashboard - Resilient transmitter linking: campaign is saved even if the SatNOGS transmitter fetch fails
- Fly.io deployment: broker WSS connectivity, CI pipeline Docker image, Dockerfile paths
- Database connection reliability: add
pool_pre_pingand handlepostgres://URL scheme - Dashboard API paths: use correct org-scoped endpoints
- Login page: inform users to check email instead of console logs
Changed¶
- Simplified assignments: removed time windows (
window_start/window_end), assignments are now a direct station-to-campaign link with a unique constraint on(station_id, campaign_id) - Assignment status values changed from
pending/tracking/completed/failedtoactive/paused/completed
0.2.0 - 2026-04-01¶
Added¶
- Organization model with membership and role-based access control
- Campaign system replacing single-mission model
- Per-station campaign assignments with time windows
- Multi-satellite concurrent tracking in Director
- Org-scoped MQTT topics
- Org-scoped API endpoints
- Multi-campaign dashboard visualization
- Alembic database migrations
- Auto-organization creation for new users
- Campaign lifecycle management (draft -> active -> completed)
Changed¶
- Director now processes per-station assignments instead of global mission
- Dashboard supports multi-satellite visualization with color coding
- MQTT topics support org-scoped prefix
- Station ownership moved from email to organization
Deprecated¶
- Mission model (replaced by Campaign)
- Global
is_activeflag (replaced by per-station assignments) - Non-org-scoped MQTT topics (still supported, legacy mode)
0.1.0 - 2026-04-01¶
Added¶
- Monorepo consolidation of talos-core, talos-agent, and talos-ops into a single repository
shared/package with MQTT topic constants (topics.py), Pydantic v2 payload schemas (schemas.py), UTC time utilities (time_utils.py), and SatNOGS API client (satnogs_client.py)- Mission Director extracted as a separate component (
director/) with its own entry point and proper error handling - CI/CD pipeline with GitHub Actions (lint via Ruff, type checking via mypy, unit tests via pytest)
- SatNOGS API client consolidation with response caching to reduce external API calls
- Docker Compose orchestration for full stack deployment (PostgreSQL, Mosquitto, Core API, Director)
- Development Makefile with targets:
dev,up,down,test,lint,format,typecheck pyproject.tomlwith project metadata, optional dependency groups (core, director, agent, dev), and tool configuration- Architecture research documents: six analysis reports covering architecture, operations, security, CCSDS compliance, SatNOGS integration, and technology roadmap
- Executive summary with prioritized five-phase roadmap
- System architecture documentation (
docs/ARCHITECTURE.md) - Development guide (
docs/DEVELOPMENT.md) - Release process documentation (
docs/RELEASING.md) - Contribution guidelines (
CONTRIBUTING.md) - Security policy (
SECURITY.md)
Security¶
- Signed session cookies using
itsdangerousURLSafeTimedSerializer, replacing plaintext cookie authentication SECRET_KEYloaded from environment variable; hardcoded secret removed from source- MQTT broker authentication enabled with username/password (
MQTT_USER/MQTT_PASS) - Anonymous MQTT broker access disabled in Mosquitto configuration
- Database credentials moved to
.envfile (gitignored), no longer hardcoded - PostgreSQL port restricted to internal Docker network (not exposed to host)