Skip to content

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 the dsgp4 package (ESA / Politecnico di Torino; arXiv:2402.04830, Acta Astronautica vol 226, 2025). Implements PropagatorProtocol with a new DSGP4Propagator class and a batch_calculate_az_el() fast path for computing az/el across many satellites in one call. The module imports cleanly without dsgp4 or torch installed and gracefully falls back to SkyfieldPropagator on any exception. Adapter functions convert Skyfield EarthSatellite + Time to torch.Tensor at 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 with pip install -e .[director-batch]. (#38)
  • TimescaleDB-ready telemetry persistence (core/telemetry_store.py, core/migrations/versions/003_timescale_telemetry.py) -- new TelemetryRecord SQLModel table for tracking-telemetry samples (timestamp, station, campaign, NORAD id, az, el, freq, mode, signal strength). Hand-written Alembic migration 003_v054_telemetry (chained off 002_v055) creates the table with five indexes including a composite (station_id, ts) index. On Postgres, the migration detects the TimescaleDB extension via pg_extension and runs create_hypertable only if present, otherwise operates as a plain Postgres table. On SQLite the hypertable block is skipped entirely via an op.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.py with 17 tests: runtime PropagatorProtocol check, clean import without dsgp4, fallback delegation, cache FIFO eviction, batch fast-path shape/type assertions, and a dSGP4-vs-Skyfield parity test (gated on _DSGP4_AVAILABLE, skipped when dsgp4 is not installed).
  • Added tests/test_telemetry_store.py with 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, and is_hypertable_available returning False on SQLite.
  • Added director.dsgp4_propagator and core.telemetry_store to tests/test_imports.py -- 34 modules now verified to import cleanly in fresh subprocesses.
  • Alembic round-trip verified on SQLite: upgrade head -> downgrade -1 -> upgrade head exits 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.Lock to 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_headers from 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-For first 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_page query 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() with get_running_loop() (#95)
  • Agent telemetry: Now publishes to org-scoped topic when --org is 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}/mission for 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 read stream/#
  • 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/stream topics: START spawns flowgraph + ZMQ-to-MQTT frame bridge, STOP tears down (#75)
  • Agent CLI: added --sdr-device and --zmq-port arguments (#76)
  • Director emits StreamCommand on 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_link relationship 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 false with 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_ORIGINS env 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=json for 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-from for 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 under core/routes/
  • Agent rewritten to asyncio -- replaced synchronous paho-mqtt with aiomqtt, global state replaced with dataclass, built-in reconnection
  • Agent authenticates to MQTT -- --key CLI arg now used as MQTT password with station_id as username
  • Director authenticates to MQTT -- reads MQTT_USER/MQTT_PASS env vars (previously ignored)
  • Inline JavaScript extracted -- ~1261 lines of JS moved from 10 templates into core/static/js/*.js ES 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() in core/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_message handler wrapped in try/except to survive malformed MQTT payloads
  • Session cookie now sets secure=True for HTTPS enforcement
  • Removed stale window_start/window_end fields from AssignmentCreate and AssignmentResponse schemas (columns were already dropped from DB)
  • Footprint radius now computed from orbital altitude instead of hardcoded 2,500 km

Changed

  • ADMIN_EMAIL and ALLOWED_EMAIL_DOMAINS now configurable via environment variables
  • Login endpoint uses Pydantic EmailStr validation instead of raw dict
  • Agent supports --org CLI argument for org-scoped MQTT topic subscription alongside legacy topics
  • All API request models now enforce max_length constraints on string fields
  • Membership.role constrained to owner/operator/viewer via database CHECK constraint
  • Build stage in CI gated on SAST security scans (optional dependency)
  • Added email-validator to core dependencies for EmailStr support

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_admin field on User model for system-wide admin privileges
  • JoinRequest model for tracking membership requests with status (pending/approved/denied)
  • description field on Organization model
  • Email domain restriction: only @libre.space emails 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.gr to pierros@libre.space
  • Admin user is auto-created with is_admin=True on 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 main to master branch
  • 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
  • .editorconfig with indent rules for Python, HTML, CSS, JS, YAML, and shell scripts
  • .gitattributes for 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-generated help
  • 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-global BEM 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.yml template
  • CI template include paths: Security/Jobs/ for SAST, Secret-Detection, and Dependency-Scanning
  • README badges pointing to main branch instead of actual default branch master
  • GitLab Pages not deploying due to changes-only trigger restriction and missing docs/index.md
  • MkDocs build failures from nav paths referencing files outside docs/ directory
  • Broken anchor links in research documentation TOC
  • test-unit CI 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-container CSS extracted to shared talos.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_id from satnogs_id when 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_ping and handle postgres:// 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/failed to active/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_active flag (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.toml with 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 itsdangerous URLSafeTimedSerializer, replacing plaintext cookie authentication
  • SECRET_KEY loaded 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 .env file (gitignored), no longer hardcoded
  • PostgreSQL port restricted to internal Docker network (not exposed to host)