Releases: MeshCore-Beacon/beacon-server
Release list
v1.5.4
Fixes
- Packet Observation Duplication - The packet observations were being constrained as unique on observer, packet hash and the heard at TS. The TS has been removed and a migration is in place to clean up bad data.
Full Changelog: v1.5.3...v1.5.4
v1.5.3
Features
- Discovery request/response parsing — Beacon now parses
DISCOVER_REQ/DISCOVER_RESPcontrol payloads from the mesh, feeding directly into neighbor data. - Neighbor SNR tracking — a new optional
snrcolumn onnode_neighbors, now populated from three independent sources:- discovery responses observed by Beacon
- zero-hop adverts seen directly by observers
- hop pairs derived from TRACE packets
- Observer online check uses last seen — ingest now factors in an observer's last-seen timestamp when determining online status, rather than relying solely on connection state.
Fixes
- Node summary neighbor counts — deduplicated neighbor counts in node summaries that were previously inflated by duplicate rows.
- Release image publishing — fixed the GitHub Actions release workflow so built images are pushed to the public registry correctly. (Thanks, @MrAlders0n!)
Maintenance
- Bumped
meshcore-goto v1.0.8. - SECURITY: Bumped
github.com/go-chi/chi/v5from v5.2.2 to v5.2.4 (dependabot). - Documented the remaining parsed ingest payload structs.
- Added the new neighbor
snrfield to the swagger docs.
Full Changelog: v1.5.2...v1.5.3
v1.5.0
Testing
This release is primarily a testing overhaul, bringing project coverage from minimal to ~46% with a solid foundation across all major layers.
Infrastructure
- Introduced
sqlc.Querierinterface indb.Store, enabling mock-based testing of the database layer without a real PostgreSQL connection - Added
gomock-generated mock forsqlc.Querieratdb/sqlc/mock - Converted
stubReaderin handlers tests to a configurable struct with function fields, eliminating the need for a separatefuncReadertype - CI coverage filtering now correctly excludes generated code (
db/sqlc,docs,iatadb/gen) for accurate badge reporting
Coverage by package
db— store mapping logic, pagination, nil pointer handling, conditional field mapping, type conversions across channels, observers, nodes, packets, traces, routes, scopes, stats, and IATAsinternal/api/handlers— validation paths and happy paths across all handlers including messages, packets, observers, nodes, stats, routes, scopes, and tracesinternal/cache—getOrSetcache hit/miss/error/corrupt-entry behaviour, TTL resolution fallback chain, node and observer invalidationinternal/config— YAML loading, config seeding, default resolution extracted into testableResolvefunctioninternal/hub— full runtime behaviour including broadcast, subscription lifecycle, lagged notification, OR-scope semanticsinternal/ingest— pure function coverage for payload parsing, transport code derivation, capability detection, observer type normalisationinternal/keystore— key derivation, fingerprinting, store lookup,EntryExists(moved frommain)internal/scopestore— load, replace, copy-on-read semanticsinternal/background— scheduler task execution and context cancellationinternal/ws— IP limiter acquire/release/cleanup logic
Refactoring
config.Resolve()extracted frommain.goto derive runtime defaults with fallback chain — now tested and used at startupkeystore.EntryExists()moved frommain.gointo the keystore package where it belongs
Full Changelog: v1.4.1...v1.5.0
v1.4.1 assets only
Most recent release with code changes was https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.4.0
v1.4.0
Features
- Background task scheduler — periodic maintenance tasks now run on independent configurable intervals via a new
internal/backgroundpackage. Intervals are set per-task under thebackground:config key; all default to1h. - Route and neighbor reconfirmation — a new background task periodically prunes
known_routesandnode_neighborsrows that have become stale or ambiguous: routes where any hop has departednode_short_idsor whose prefix now resolves to multiple nodes, and neighbors under the same conditions.
Fixes
- Neighbor recording — neighbors are now only recorded when the resolved first-hop node is a repeater or room. Previously a prefix collision could cause a companion or other non-infrastructure node to be written as a neighbor. Thanks to @gadgethd for the contributing fix to IATA seeding that triggered this investigation.
- IATA seeding —
UpsertIATADetailsis now a true upsert, correctly updating existing records rather than silently doing nothing on conflict. Contributed by @gadgethd . - Graceful shutdown — added a timeout to the shutdown sequence to prevent possible hangs on exit.
Maintenance
- Switched to dedicated CodeQL action.
- Corrected route list handler cursor documentation.
- Fixed broken README API reference chart.
- Minor code cleanup: renamed
mustEnv→getEnv, fixed view refresh comment, added note on node type helper.
Contributors
Welcome and thank you to @gadgethd — first contribution to Beacon!
v1.3.1
Traces & Pings
Single-hop traces are now classified as pings and tagged accordingly. The /traces list response now includes the path and SNR values from the most complete observation of each trace, making it possible to assess signal quality and hop progression at a glance without opening the detail view. A new type query parameter allows filtering traces by TRACE or PING.
Routes
Single-hop routes are no longer stored — direct links are already captured by neighbor relationships, making them redundant.
Nodes
knownNeighborCount added to node summaries, and publicKey added to node neighbor responses.
Database Migrations
Migrations are now embedded in the binary and applied automatically on startup, removing the dependency on external tooling or container entrypoints. Existing deployments will bootstrap cleanly on first run.
Full Changelog: v1.3.0...v1.3.1
BUGFIX: v1.2.1
Just a silly bug in a query for radio preset stats.
v1.2.0
New features
CORS support
- Configurable CORS headers for cross-origin frontend deployments
Node type breakdown
- New
GET /api/v1/stats/node-typesendpoint returning node counts by type (companion, repeater, room server, sensor) - Supports the same multi-IATA and region filtering as all other stats endpoints
Multi-IATA and region filtering on stats endpoints
- All
/stats/*endpoints now acceptiatas,iata,regionId, andregionquery params - Previously only a single exact-match IATA was supported
- Top nodes chart now returns data correctly in the default all-regions view
Bug fixes
Observer telemetry
- Timestamps were being returned in seconds instead of milliseconds — now consistent with the rest of the API
- Bucketed telemetry (
6h,24hintervals) was grouping by hour-of-day rather than by time window, causing incorrect bucket boundaries and near-zero deltas in the 30-day view - Running total fields (
airtime_tx_pct,airtime_rx_pct,receive_errors) were being averaged across buckets instead of computing the delta — now correctly returns increase per bucket
Maintenance
- Removed unused queries
- Updated dependencies (SHOULDERS.md)
- CodeQL security scanning via GitHub integration
Full Changelog: v1.1.0...v1.2.0
v1.1.0 Redis!
v1.1.0 — Redis caching layer
This release adds an optional Redis-backed caching layer that reduces redundant
PostgreSQL reads for read-heavy, slow-changing endpoints.
What's new
- Redis cache layer (
internal/cache) — aCachedReaderwraps the database
store and transparently caches responses using a genericgetOrSethelper with
graceful degradation. If Redis is unavailable, all reads fall through to
PostgreSQL with no impact on availability. - Explicit cache invalidation — node and observer cache entries are
invalidated immediately on upsert from the ingest path, keeping detail
responses accurate despite caching. - TTL-based expiry for stats and reference data, with a per-category
override system and a global fallback. Defaults to 1h, aligned with the
materialized view refresh cycle. - Fully optional — set
REDIS_ADDRto enable. Unset, Beacon behaves
exactly as before.
Configuration
Add to .env:
REDIS_ADDR=localhost:6379
REDIS_PASSWORD=
REDIS_DB=0Add to config.yaml (all optional, defaults to 1h):
cache:
ttl: "1h"
ttls:
stats: "1h"
reference: "1h"
nodes: "1h"
observers: "1h"