{
  "id": "meshcore-beacon",
  "name": "MeshCore Beacon",
  "short_name": "Beacon",
  "kind": "monitoring",
  "status": "active",
  "maturity": "beta",
  "description": "Real-time LoRa mesh network observation stack: a Go backend subscribes to MeshCore MQTT brokers, decodes and deduplicates packets, stores nodes, routes, traces and channel messages in PostgreSQL, and streams live events via WebSocket and REST API — paired with a React web frontend for packet inspection, node tracking, channel messages, stats and mesh maps.",
  "image": "beacon.png",
  "maintainers": [
    {
      "name": "MeshCore-Beacon",
      "url": "https://github.com/MeshCore-Beacon"
    }
  ],
  "repository": "https://github.com/MeshCore-Beacon/beacon-server",
  "documentation": "https://github.com/MeshCore-Beacon/beacon-docs",
  "license": "AGPL-3.0",
  "languages": [
    "go",
    "typescript"
  ],
  "platforms": [
    "docker",
    "linux",
    "web"
  ],
  "interfaces": [
    "web",
    "api"
  ],
  "connections": [
    "mqtt",
    "websocket",
    "http"
  ],
  "capabilities": [
    "monitoring",
    "telemetry",
    "packet-analysis",
    "mapping",
    "bridging"
  ],
  "install": [
    {
      "type": "docker-compose",
      "url": "https://github.com/MeshCore-Beacon/beacon-docs"
    },
    {
      "type": "docker",
      "package": "ghcr.io/meshcore-beacon/beacon-server",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/pkgs/container/beacon-server"
    },
    {
      "type": "docker",
      "package": "ghcr.io/meshcore-beacon/beacon-web",
      "url": "https://github.com/MeshCore-Beacon/beacon-web/pkgs/container/beacon-web"
    },
    {
      "type": "source",
      "url": "https://github.com/MeshCore-Beacon/beacon-server"
    },
    {
      "type": "source",
      "url": "https://github.com/MeshCore-Beacon/beacon-web"
    }
  ],
  "popularity": {
    "githubStars": 7,
    "githubForks": 2,
    "githubWatchers": 1,
    "githubOpenIssues": 16,
    "githubContributors": 4,
    "releaseDownloads": 3,
    "lastChecked": "2026-07-21",
    "latestReleaseDownloads": 1
  },
  "verification": {
    "sourceAvailable": true,
    "releasesAvailable": true,
    "signedReleases": false,
    "ciBuilds": true,
    "hasDocumentation": true,
    "lastChecked": "2026-07-21",
    "notes": [
      "API authentication is not yet implemented; intended for trusted internal or reverse-proxy deployments.",
      "Full-stack Docker Compose configs (server + web + PostgreSQL + Redis + Caddy TLS) are in the beacon-docs repo.",
      "Swagger UI available at /swagger/index.html on a running instance."
    ]
  },
  "tags": [
    "self-hosted",
    "postgresql",
    "redis",
    "rest-api",
    "websocket-api",
    "react"
  ],
  "last_reviewed": "2026-06-29",
  "source": {
    "path": "data/software/meshcore-beacon/software.yaml",
    "updatedAt": "2026-07-21T08:04:18Z"
  },
  "latest_version": "1.5.4",
  "released": "2026-06-24",
  "releases": [
    {
      "version": "v1.5.4",
      "name": "v1.5.4",
      "datetime": "2026-06-24T15:11:33Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.5.4",
      "prerelease": false,
      "notes": "## Fixes\r\n\r\n- **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.\r\n\r\n**Full Changelog**: https://github.com/MeshCore-Beacon/beacon-server/compare/v1.5.3...v1.5.4",
      "notesHtml": "<h2>Fixes</h2>\n<ul>\n<li><strong>Packet Observation Duplication</strong> - 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.</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/MeshCore-Beacon/beacon-server/compare/v1.5.3...v1.5.4\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/MeshCore-Beacon/beacon-server/compare/v1.5.3...v1.5.4</a></p>\n"
    },
    {
      "version": "v1.5.3",
      "name": "v1.5.3",
      "datetime": "2026-06-20T17:41:42Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.5.3",
      "prerelease": false,
      "notes": "## Features\r\n\r\n- **Discovery request/response parsing** — Beacon now parses `DISCOVER_REQ`/`DISCOVER_RESP` control payloads from the mesh, feeding directly into neighbor data.\r\n- **Neighbor SNR tracking** — a new optional `snr` column on `node_neighbors`, now populated from three independent sources:\r\n  - discovery responses observed by Beacon\r\n  - zero-hop adverts seen directly by observers\r\n  - hop pairs derived from TRACE packets\r\n- **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.\r\n\r\n## Fixes\r\n\r\n- **Node summary neighbor counts** — deduplicated neighbor counts in node summaries that were previously inflated by duplicate rows.\r\n- **Release image publishing** — fixed the GitHub Actions release workflow so built images are pushed to the public registry correctly. (Thanks, @MrAlders0n!)\r\n\r\n## Maintenance\r\n\r\n- Bumped `meshcore-go` to v1.0.8.\r\n- SECURITY: Bumped `github.com/go-chi/chi/v5` from v5.2.2 to v5.2.4 (dependabot).\r\n- Documented the remaining parsed ingest payload structs.\r\n- Added the new neighbor `snr` field to the swagger docs.\r\n\r\n**Full Changelog**: https://github.com/MeshCore-Beacon/beacon-server/compare/v1.5.2...v1.5.3",
      "notesHtml": "<h2>Features</h2>\n<ul>\n<li><strong>Discovery request/response parsing</strong> — Beacon now parses <code>DISCOVER_REQ</code>/<code>DISCOVER_RESP</code> control payloads from the mesh, feeding directly into neighbor data.</li>\n<li><strong>Neighbor SNR tracking</strong> — a new optional <code>snr</code> column on <code>node_neighbors</code>, now populated from three independent sources:<ul>\n<li>discovery responses observed by Beacon</li>\n<li>zero-hop adverts seen directly by observers</li>\n<li>hop pairs derived from TRACE packets</li>\n</ul>\n</li>\n<li><strong>Observer online check uses last seen</strong> — ingest now factors in an observer's last-seen timestamp when determining online status, rather than relying solely on connection state.</li>\n</ul>\n<h2>Fixes</h2>\n<ul>\n<li><strong>Node summary neighbor counts</strong> — deduplicated neighbor counts in node summaries that were previously inflated by duplicate rows.</li>\n<li><strong>Release image publishing</strong> — fixed the GitHub Actions release workflow so built images are pushed to the public registry correctly. (Thanks, @MrAlders0n!)</li>\n</ul>\n<h2>Maintenance</h2>\n<ul>\n<li>Bumped <code>meshcore-go</code> to v1.0.8.</li>\n<li>SECURITY: Bumped <code>github.com/go-chi/chi/v5</code> from v5.2.2 to v5.2.4 (dependabot).</li>\n<li>Documented the remaining parsed ingest payload structs.</li>\n<li>Added the new neighbor <code>snr</code> field to the swagger docs.</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/MeshCore-Beacon/beacon-server/compare/v1.5.2...v1.5.3\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/MeshCore-Beacon/beacon-server/compare/v1.5.2...v1.5.3</a></p>\n"
    },
    {
      "version": "v1.5.0",
      "name": "v1.5.0",
      "datetime": "2026-06-15T22:28:20Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.5.0",
      "prerelease": false,
      "notes": "## Testing\r\n\r\nThis release is primarily a testing overhaul, bringing project coverage from minimal to ~46% with a solid foundation across all major layers.\r\n\r\n### Infrastructure\r\n\r\n- Introduced `sqlc.Querier` interface in `db.Store`, enabling mock-based testing of the database layer without a real PostgreSQL connection\r\n- Added `gomock`-generated mock for `sqlc.Querier` at `db/sqlc/mock`\r\n- Converted `stubReader` in handlers tests to a configurable struct with function fields, eliminating the need for a separate `funcReader` type\r\n- CI coverage filtering now correctly excludes generated code (`db/sqlc`, `docs`, `iatadb/gen`) for accurate badge reporting\r\n\r\n### Coverage by package\r\n\r\n- `db` — store mapping logic, pagination, nil pointer handling, conditional field mapping, type conversions across channels, observers, nodes, packets, traces, routes, scopes, stats, and IATAs\r\n- `internal/api/handlers` — validation paths and happy paths across all handlers including messages, packets, observers, nodes, stats, routes, scopes, and traces\r\n- `internal/cache` — `getOrSet` cache hit/miss/error/corrupt-entry behaviour, TTL resolution fallback chain, node and observer invalidation\r\n- `internal/config` — YAML loading, config seeding, default resolution extracted into testable `Resolve` function\r\n- `internal/hub` — full runtime behaviour including broadcast, subscription lifecycle, lagged notification, OR-scope semantics\r\n- `internal/ingest` — pure function coverage for payload parsing, transport code derivation, capability detection, observer type normalisation\r\n- `internal/keystore` — key derivation, fingerprinting, store lookup, `EntryExists` (moved from `main`)\r\n- `internal/scopestore` — load, replace, copy-on-read semantics\r\n- `internal/background` — scheduler task execution and context cancellation\r\n- `internal/ws` — IP limiter acquire/release/cleanup logic\r\n\r\n## Refactoring\r\n\r\n- `config.Resolve()` extracted from `main.go` to derive runtime defaults with fallback chain — now tested and used at startup\r\n- `keystore.EntryExists()` moved from `main.go` into the keystore package where it belongs\r\n\r\n**Full Changelog**: https://github.com/MeshCore-Beacon/beacon-server/compare/v1.4.1...v1.5.0",
      "notesHtml": "<h2>Testing</h2>\n<p>This release is primarily a testing overhaul, bringing project coverage from minimal to ~46% with a solid foundation across all major layers.</p>\n<h3>Infrastructure</h3>\n<ul>\n<li>Introduced <code>sqlc.Querier</code> interface in <code>db.Store</code>, enabling mock-based testing of the database layer without a real PostgreSQL connection</li>\n<li>Added <code>gomock</code>-generated mock for <code>sqlc.Querier</code> at <code>db/sqlc/mock</code></li>\n<li>Converted <code>stubReader</code> in handlers tests to a configurable struct with function fields, eliminating the need for a separate <code>funcReader</code> type</li>\n<li>CI coverage filtering now correctly excludes generated code (<code>db/sqlc</code>, <code>docs</code>, <code>iatadb/gen</code>) for accurate badge reporting</li>\n</ul>\n<h3>Coverage by package</h3>\n<ul>\n<li><code>db</code> — store mapping logic, pagination, nil pointer handling, conditional field mapping, type conversions across channels, observers, nodes, packets, traces, routes, scopes, stats, and IATAs</li>\n<li><code>internal/api/handlers</code> — validation paths and happy paths across all handlers including messages, packets, observers, nodes, stats, routes, scopes, and traces</li>\n<li><code>internal/cache</code> — <code>getOrSet</code> cache hit/miss/error/corrupt-entry behaviour, TTL resolution fallback chain, node and observer invalidation</li>\n<li><code>internal/config</code> — YAML loading, config seeding, default resolution extracted into testable <code>Resolve</code> function</li>\n<li><code>internal/hub</code> — full runtime behaviour including broadcast, subscription lifecycle, lagged notification, OR-scope semantics</li>\n<li><code>internal/ingest</code> — pure function coverage for payload parsing, transport code derivation, capability detection, observer type normalisation</li>\n<li><code>internal/keystore</code> — key derivation, fingerprinting, store lookup, <code>EntryExists</code> (moved from <code>main</code>)</li>\n<li><code>internal/scopestore</code> — load, replace, copy-on-read semantics</li>\n<li><code>internal/background</code> — scheduler task execution and context cancellation</li>\n<li><code>internal/ws</code> — IP limiter acquire/release/cleanup logic</li>\n</ul>\n<h2>Refactoring</h2>\n<ul>\n<li><code>config.Resolve()</code> extracted from <code>main.go</code> to derive runtime defaults with fallback chain — now tested and used at startup</li>\n<li><code>keystore.EntryExists()</code> moved from <code>main.go</code> into the keystore package where it belongs</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/MeshCore-Beacon/beacon-server/compare/v1.4.1...v1.5.0\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/MeshCore-Beacon/beacon-server/compare/v1.4.1...v1.5.0</a></p>\n"
    },
    {
      "version": "v1.4.1",
      "name": "v1.4.1 assets only",
      "datetime": "2026-06-12T18:29:36Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.4.1",
      "prerelease": false,
      "notes": "Most recent release with code changes was https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.4.0",
      "notesHtml": "<p>Most recent release with code changes was <a href=\"https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.4.0\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.4.0</a></p>\n"
    },
    {
      "version": "v1.4.0",
      "name": "v1.4.0",
      "datetime": "2026-06-12T18:00:53Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.4.0",
      "prerelease": false,
      "notes": "### Features\r\n\r\n- **Background task scheduler** — periodic maintenance tasks now run on independent configurable intervals via a new `internal/background` package. Intervals are set per-task under the `background:` config key; all default to `1h`.\r\n- **Route and neighbor reconfirmation** — a new background task periodically prunes `known_routes` and `node_neighbors` rows that have become stale or ambiguous: routes where any hop has departed `node_short_ids` or whose prefix now resolves to multiple nodes, and neighbors under the same conditions.\r\n\r\n### Fixes\r\n\r\n- **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.\r\n- **IATA seeding** — `UpsertIATADetails` is now a true upsert, correctly updating existing records rather than silently doing nothing on conflict. Contributed by @gadgethd .\r\n- **Graceful shutdown** — added a timeout to the shutdown sequence to prevent possible hangs on exit.\r\n\r\n### Maintenance\r\n\r\n- Switched to dedicated CodeQL action.\r\n- Corrected route list handler cursor documentation.\r\n- Fixed broken README API reference chart.\r\n- Minor code cleanup: renamed `mustEnv` → `getEnv`, fixed view refresh comment, added note on node type helper.\r\n\r\n### Contributors\r\n\r\nWelcome and thank you to @gadgethd  — first contribution to Beacon!",
      "notesHtml": "<h3>Features</h3>\n<ul>\n<li><strong>Background task scheduler</strong> — periodic maintenance tasks now run on independent configurable intervals via a new <code>internal/background</code> package. Intervals are set per-task under the <code>background:</code> config key; all default to <code>1h</code>.</li>\n<li><strong>Route and neighbor reconfirmation</strong> — a new background task periodically prunes <code>known_routes</code> and <code>node_neighbors</code> rows that have become stale or ambiguous: routes where any hop has departed <code>node_short_ids</code> or whose prefix now resolves to multiple nodes, and neighbors under the same conditions.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li><strong>Neighbor recording</strong> — 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.</li>\n<li><strong>IATA seeding</strong> — <code>UpsertIATADetails</code> is now a true upsert, correctly updating existing records rather than silently doing nothing on conflict. Contributed by @gadgethd .</li>\n<li><strong>Graceful shutdown</strong> — added a timeout to the shutdown sequence to prevent possible hangs on exit.</li>\n</ul>\n<h3>Maintenance</h3>\n<ul>\n<li>Switched to dedicated CodeQL action.</li>\n<li>Corrected route list handler cursor documentation.</li>\n<li>Fixed broken README API reference chart.</li>\n<li>Minor code cleanup: renamed <code>mustEnv</code> → <code>getEnv</code>, fixed view refresh comment, added note on node type helper.</li>\n</ul>\n<h3>Contributors</h3>\n<p>Welcome and thank you to @gadgethd  — first contribution to Beacon!</p>\n"
    },
    {
      "version": "v1.3.1",
      "name": "v1.3.1",
      "datetime": "2026-06-11T23:00:29Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.3.1",
      "prerelease": false,
      "notes": "### Traces & Pings\r\nSingle-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`.\r\n\r\n### Routes\r\nSingle-hop routes are no longer stored — direct links are already captured by neighbor relationships, making them redundant.\r\n\r\n### Nodes\r\n`knownNeighborCount` added to node summaries, and `publicKey` added to node neighbor responses.\r\n\r\n### Database Migrations\r\nMigrations 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.\r\n\r\n**Full Changelog**: https://github.com/MeshCore-Beacon/beacon-server/compare/v1.3.0...v1.3.1",
      "notesHtml": "<h3>Traces &amp; Pings</h3>\n<p>Single-hop traces are now classified as pings and tagged accordingly. The <code>/traces</code> 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 <code>type</code> query parameter allows filtering traces by <code>TRACE</code> or <code>PING</code>.</p>\n<h3>Routes</h3>\n<p>Single-hop routes are no longer stored — direct links are already captured by neighbor relationships, making them redundant.</p>\n<h3>Nodes</h3>\n<p><code>knownNeighborCount</code> added to node summaries, and <code>publicKey</code> added to node neighbor responses.</p>\n<h3>Database Migrations</h3>\n<p>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.</p>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/MeshCore-Beacon/beacon-server/compare/v1.3.0...v1.3.1\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/MeshCore-Beacon/beacon-server/compare/v1.3.0...v1.3.1</a></p>\n"
    },
    {
      "version": "v1.2.1",
      "name": "BUGFIX: v1.2.1",
      "datetime": "2026-06-10T20:49:35Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.2.1",
      "prerelease": false,
      "notes": "Just a silly bug in a query for radio preset stats.",
      "notesHtml": "<p>Just a silly bug in a query for radio preset stats.</p>\n"
    },
    {
      "version": "v1.2.0",
      "name": "v1.2.0",
      "datetime": "2026-06-10T20:23:22Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.2.0",
      "prerelease": false,
      "notes": "### New features\r\n\r\n**CORS support**\r\n- Configurable CORS headers for cross-origin frontend deployments\r\n\r\n**Node type breakdown**\r\n- New `GET /api/v1/stats/node-types` endpoint returning node counts by type (companion, repeater, room server, sensor)\r\n- Supports the same multi-IATA and region filtering as all other stats endpoints\r\n\r\n**Multi-IATA and region filtering on stats endpoints**\r\n- All `/stats/*` endpoints now accept `iatas`, `iata`, `regionId`, and `region` query params\r\n- Previously only a single exact-match IATA was supported\r\n- Top nodes chart now returns data correctly in the default all-regions view\r\n\r\n### Bug fixes\r\n\r\n**Observer telemetry**\r\n- Timestamps were being returned in seconds instead of milliseconds — now consistent with the rest of the API\r\n- Bucketed telemetry (`6h`, `24h` intervals) was grouping by hour-of-day rather than by time window, causing incorrect bucket boundaries and near-zero deltas in the 30-day view\r\n- 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\r\n\r\n### Maintenance\r\n\r\n- Removed unused queries\r\n- Updated dependencies (SHOULDERS.md)\r\n- CodeQL security scanning via GitHub integration\r\n\r\n**Full Changelog**: https://github.com/MeshCore-Beacon/beacon-server/compare/v1.1.0...v1.2.0",
      "notesHtml": "<h3>New features</h3>\n<p><strong>CORS support</strong></p>\n<ul>\n<li>Configurable CORS headers for cross-origin frontend deployments</li>\n</ul>\n<p><strong>Node type breakdown</strong></p>\n<ul>\n<li>New <code>GET /api/v1/stats/node-types</code> endpoint returning node counts by type (companion, repeater, room server, sensor)</li>\n<li>Supports the same multi-IATA and region filtering as all other stats endpoints</li>\n</ul>\n<p><strong>Multi-IATA and region filtering on stats endpoints</strong></p>\n<ul>\n<li>All <code>/stats/*</code> endpoints now accept <code>iatas</code>, <code>iata</code>, <code>regionId</code>, and <code>region</code> query params</li>\n<li>Previously only a single exact-match IATA was supported</li>\n<li>Top nodes chart now returns data correctly in the default all-regions view</li>\n</ul>\n<h3>Bug fixes</h3>\n<p><strong>Observer telemetry</strong></p>\n<ul>\n<li>Timestamps were being returned in seconds instead of milliseconds — now consistent with the rest of the API</li>\n<li>Bucketed telemetry (<code>6h</code>, <code>24h</code> intervals) was grouping by hour-of-day rather than by time window, causing incorrect bucket boundaries and near-zero deltas in the 30-day view</li>\n<li>Running total fields (<code>airtime_tx_pct</code>, <code>airtime_rx_pct</code>, <code>receive_errors</code>) were being averaged across buckets instead of computing the delta — now correctly returns increase per bucket</li>\n</ul>\n<h3>Maintenance</h3>\n<ul>\n<li>Removed unused queries</li>\n<li>Updated dependencies (SHOULDERS.md)</li>\n<li>CodeQL security scanning via GitHub integration</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/MeshCore-Beacon/beacon-server/compare/v1.1.0...v1.2.0\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/MeshCore-Beacon/beacon-server/compare/v1.1.0...v1.2.0</a></p>\n"
    },
    {
      "version": "v1.1.0",
      "name": "v1.1.0 Redis!",
      "datetime": "2026-06-09T21:15:15Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.1.0",
      "prerelease": false,
      "notes": "## v1.1.0 — Redis caching layer\r\n\r\nThis release adds an optional Redis-backed caching layer that reduces redundant\r\nPostgreSQL reads for read-heavy, slow-changing endpoints.\r\n\r\n### What's new\r\n\r\n- **Redis cache layer** (`internal/cache`) — a `CachedReader` wraps the database\r\n  store and transparently caches responses using a generic `getOrSet` helper with\r\n  graceful degradation. If Redis is unavailable, all reads fall through to\r\n  PostgreSQL with no impact on availability.\r\n- **Explicit cache invalidation** — node and observer cache entries are\r\n  invalidated immediately on upsert from the ingest path, keeping detail\r\n  responses accurate despite caching.\r\n- **TTL-based expiry** for stats and reference data, with a per-category\r\n  override system and a global fallback. Defaults to 1h, aligned with the\r\n  materialized view refresh cycle.\r\n- **Fully optional** — set `REDIS_ADDR` to enable. Unset, Beacon behaves\r\n  exactly as before.\r\n\r\n### Configuration\r\n\r\nAdd to `.env`:\r\n```env\r\nREDIS_ADDR=localhost:6379\r\nREDIS_PASSWORD=\r\nREDIS_DB=0\r\n```\r\n\r\nAdd to `config.yaml` (all optional, defaults to 1h):\r\n```yaml\r\ncache:\r\n  ttl: \"1h\"\r\n  ttls:\r\n    stats: \"1h\"\r\n    reference: \"1h\"\r\n    nodes: \"1h\"\r\n    observers: \"1h\"\r\n```",
      "notesHtml": "<h2>v1.1.0 — Redis caching layer</h2>\n<p>This release adds an optional Redis-backed caching layer that reduces redundant\nPostgreSQL reads for read-heavy, slow-changing endpoints.</p>\n<h3>What's new</h3>\n<ul>\n<li><strong>Redis cache layer</strong> (<code>internal/cache</code>) — a <code>CachedReader</code> wraps the database\nstore and transparently caches responses using a generic <code>getOrSet</code> helper with\ngraceful degradation. If Redis is unavailable, all reads fall through to\nPostgreSQL with no impact on availability.</li>\n<li><strong>Explicit cache invalidation</strong> — node and observer cache entries are\ninvalidated immediately on upsert from the ingest path, keeping detail\nresponses accurate despite caching.</li>\n<li><strong>TTL-based expiry</strong> for stats and reference data, with a per-category\noverride system and a global fallback. Defaults to 1h, aligned with the\nmaterialized view refresh cycle.</li>\n<li><strong>Fully optional</strong> — set <code>REDIS_ADDR</code> to enable. Unset, Beacon behaves\nexactly as before.</li>\n</ul>\n<h3>Configuration</h3>\n<p>Add to <code>.env</code>:</p>\n<pre><code>REDIS_ADDR=localhost:6379\nREDIS_PASSWORD=\nREDIS_DB=0\n</code></pre>\n<p>Add to <code>config.yaml</code> (all optional, defaults to 1h):</p>\n<pre><code>cache:\n  ttl: \"1h\"\n  ttls:\n    stats: \"1h\"\n    reference: \"1h\"\n    nodes: \"1h\"\n    observers: \"1h\"\n</code></pre>\n"
    },
    {
      "version": "v1.0.4",
      "name": "v1.0.4",
      "datetime": "2026-06-09T16:23:32Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.0.4",
      "prerelease": false,
      "notes": "## [v1.0.4] — 2026-06-09\r\n\r\n### Security\r\nFix no bounds check on region IDs.\r\n\r\n**Full Changelog**: https://github.com/MeshCore-Beacon/beacon-server/compare/v1.0.3...v1.0.4",
      "notesHtml": "<h2>[v1.0.4] — 2026-06-09</h2>\n<h3>Security</h3>\n<p>Fix no bounds check on region IDs.</p>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/MeshCore-Beacon/beacon-server/compare/v1.0.3...v1.0.4\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/MeshCore-Beacon/beacon-server/compare/v1.0.3...v1.0.4</a></p>\n"
    },
    {
      "version": "v1.0.2",
      "name": "v1.0.2",
      "datetime": "2026-06-09T15:42:40Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.0.2",
      "prerelease": false,
      "notes": "## [v1.0.2] — 2026-06-09\r\n\r\n### Features\r\n- **Traces: raw path hashes included in responses** — trace responses now include raw (unresolved) path hashes alongside the resolved node data, giving clients access to the full hop information even when nodes aren't known to the observer.\r\n\r\n### Bug Fixes\r\n- Fixed typo in `subscribeScope` struct that could cause unexpected subscription behaviour.\r\n- Fixed missing Swagger annotation for the traces `rawPath` field.\r\n\r\n### Documentation\r\n- Updated schema migration notes.\r\n\r\n\r\n**Full Changelog**: https://github.com/MeshCore-Beacon/beacon-server/compare/v1.0.1...v1.0.2",
      "notesHtml": "<h2>[v1.0.2] — 2026-06-09</h2>\n<h3>Features</h3>\n<ul>\n<li><strong>Traces: raw path hashes included in responses</strong> — trace responses now include raw (unresolved) path hashes alongside the resolved node data, giving clients access to the full hop information even when nodes aren't known to the observer.</li>\n</ul>\n<h3>Bug Fixes</h3>\n<ul>\n<li>Fixed typo in <code>subscribeScope</code> struct that could cause unexpected subscription behaviour.</li>\n<li>Fixed missing Swagger annotation for the traces <code>rawPath</code> field.</li>\n</ul>\n<h3>Documentation</h3>\n<ul>\n<li>Updated schema migration notes.</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/MeshCore-Beacon/beacon-server/compare/v1.0.1...v1.0.2\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/MeshCore-Beacon/beacon-server/compare/v1.0.1...v1.0.2</a></p>\n"
    },
    {
      "version": "v1.0.0",
      "name": "v1.0.0",
      "datetime": "2026-06-08T23:16:46Z",
      "url": "https://github.com/MeshCore-Beacon/beacon-server/releases/tag/v1.0.0",
      "prerelease": false,
      "notes": "## v1.0.0\r\n\r\nThis is the first public release of Beacon, a MeshCore network observation backend built by [MeshCore Canada](https://meshcore.ca).\r\n\r\n### What is Beacon\r\n\r\nBeacon connects to one or more MeshCore MQTT brokers, ingests LoRa packet traffic in real time, stores it in PostgreSQL, and serves it via a REST API and WebSocket stream. It is designed to be the data backbone for MeshCore network monitoring frontends and tools.\r\n\r\n### Features\r\n\r\n**Packet ingestion and storage**\r\n- Subscribes to multiple MeshCore MQTT brokers simultaneously\r\n- Decodes all MeshCore packet types using meshcore-go\r\n- Deduplicates observations across brokers — the same packet heard by multiple brokers produces one observation per observer\r\n- Stores packets, observations, nodes, observers, traces, known routes, neighbors, and channel messages in PostgreSQL\r\n- Configurable retention for packets and telemetry\r\n\r\n**Node and observer tracking**\r\n- Upserts nodes from advert payloads with name, type, location, and radio settings\r\n- Tracks observers from /status messages including hardware model, firmware version, battery level, uptime, and radio configuration\r\n- Detects multibyte path and trace firmware capability from path hash sizes\r\n- Records node neighbors from forwarded adverts\r\n- Builds and maintains known routes — fully resolved multi-hop paths where all nodes are identified with high confidence\r\n- Observer telemetry snapshots with configurable resolution and bucketed query support (1h, 6h, 24h intervals)\r\n\r\n**Channel messages**\r\n- Decrypts group text messages for configured channel keys\r\n- Supports hashtag-derived PSKs (`SHA256(\"#tag\")[:16]`) and explicit hex keys\r\n- Records channel hash observations even for unknown channels\r\n\r\n**Transport scopes**\r\n- Matches `TRANSPORT_FLOOD` and `TRANSPORT_DIRECT` packets to configured scope keys\r\n- Tags nodes and observers with their default scope\r\n- Scope-filtered queries across packets, nodes, observers, channels, and traces\r\n\r\n**Geographic filtering**\r\n- Optional ingest filter by country or continent using a compiled-in IATA → country/continent database sourced from OurAirports\r\n- Regions group IATAs for display and filtering\r\n\r\n**REST API**\r\n- Full paginated REST API with cursor-based pagination across all resources\r\n- Endpoints for packets, observations, nodes, observers, channels, messages, traces, routes, regions, IATAs, scopes, and stats\r\n- Cross-IATA route search\r\n- Observer telemetry with bucketed aggregation\r\n- Swagger UI at `/swagger/index.html`\r\n\r\n**WebSocket**\r\n- Real-time event stream with per-connection subscription filtering by IATA, region slug, region ID, payload type, channel hash, and event type\r\n- Events: `packetObservation`, `observerStatus`, `nodeUpdate`, `channelMessage`\r\n- Backpressure handling with `lagged` notifications and REST backfill support\r\n- Per-IP connection limits\r\n\r\n**Path resolution**\r\n- Resolves path hash prefixes to node UUIDs using `node_short_ids`\r\n- Confidence levels: `high` (unambiguous), `ambiguous` (hash collision), `none` (unknown)\r\n- Resolved hop nodes included in packet observations, traces, and known routes\r\n\r\n### Project\r\n\r\n- AGPL-3.0-or-later license\r\n- Contributor Covenant code of conduct\r\n- Full contributing guide including database change, API change, and testing requirements\r\n- GitHub Actions CI with build, format, vet, test, and swagger doc checks\r\n- Docker image published to GitHub Container Registry on every push to `main` and `dev`",
      "notesHtml": "<h2>v1.0.0</h2>\n<p>This is the first public release of Beacon, a MeshCore network observation backend built by <a href=\"https://meshcore.ca/\" target=\"_blank\" rel=\"noopener noreferrer\">MeshCore Canada</a>.</p>\n<h3>What is Beacon</h3>\n<p>Beacon connects to one or more MeshCore MQTT brokers, ingests LoRa packet traffic in real time, stores it in PostgreSQL, and serves it via a REST API and WebSocket stream. It is designed to be the data backbone for MeshCore network monitoring frontends and tools.</p>\n<h3>Features</h3>\n<p><strong>Packet ingestion and storage</strong></p>\n<ul>\n<li>Subscribes to multiple MeshCore MQTT brokers simultaneously</li>\n<li>Decodes all MeshCore packet types using meshcore-go</li>\n<li>Deduplicates observations across brokers — the same packet heard by multiple brokers produces one observation per observer</li>\n<li>Stores packets, observations, nodes, observers, traces, known routes, neighbors, and channel messages in PostgreSQL</li>\n<li>Configurable retention for packets and telemetry</li>\n</ul>\n<p><strong>Node and observer tracking</strong></p>\n<ul>\n<li>Upserts nodes from advert payloads with name, type, location, and radio settings</li>\n<li>Tracks observers from /status messages including hardware model, firmware version, battery level, uptime, and radio configuration</li>\n<li>Detects multibyte path and trace firmware capability from path hash sizes</li>\n<li>Records node neighbors from forwarded adverts</li>\n<li>Builds and maintains known routes — fully resolved multi-hop paths where all nodes are identified with high confidence</li>\n<li>Observer telemetry snapshots with configurable resolution and bucketed query support (1h, 6h, 24h intervals)</li>\n</ul>\n<p><strong>Channel messages</strong></p>\n<ul>\n<li>Decrypts group text messages for configured channel keys</li>\n<li>Supports hashtag-derived PSKs (<code>SHA256(\"#tag\")[:16]</code>) and explicit hex keys</li>\n<li>Records channel hash observations even for unknown channels</li>\n</ul>\n<p><strong>Transport scopes</strong></p>\n<ul>\n<li>Matches <code>TRANSPORT_FLOOD</code> and <code>TRANSPORT_DIRECT</code> packets to configured scope keys</li>\n<li>Tags nodes and observers with their default scope</li>\n<li>Scope-filtered queries across packets, nodes, observers, channels, and traces</li>\n</ul>\n<p><strong>Geographic filtering</strong></p>\n<ul>\n<li>Optional ingest filter by country or continent using a compiled-in IATA → country/continent database sourced from OurAirports</li>\n<li>Regions group IATAs for display and filtering</li>\n</ul>\n<p><strong>REST API</strong></p>\n<ul>\n<li>Full paginated REST API with cursor-based pagination across all resources</li>\n<li>Endpoints for packets, observations, nodes, observers, channels, messages, traces, routes, regions, IATAs, scopes, and stats</li>\n<li>Cross-IATA route search</li>\n<li>Observer telemetry with bucketed aggregation</li>\n<li>Swagger UI at <code>/swagger/index.html</code></li>\n</ul>\n<p><strong>WebSocket</strong></p>\n<ul>\n<li>Real-time event stream with per-connection subscription filtering by IATA, region slug, region ID, payload type, channel hash, and event type</li>\n<li>Events: <code>packetObservation</code>, <code>observerStatus</code>, <code>nodeUpdate</code>, <code>channelMessage</code></li>\n<li>Backpressure handling with <code>lagged</code> notifications and REST backfill support</li>\n<li>Per-IP connection limits</li>\n</ul>\n<p><strong>Path resolution</strong></p>\n<ul>\n<li>Resolves path hash prefixes to node UUIDs using <code>node_short_ids</code></li>\n<li>Confidence levels: <code>high</code> (unambiguous), <code>ambiguous</code> (hash collision), <code>none</code> (unknown)</li>\n<li>Resolved hop nodes included in packet observations, traces, and known routes</li>\n</ul>\n<h3>Project</h3>\n<ul>\n<li>AGPL-3.0-or-later license</li>\n<li>Contributor Covenant code of conduct</li>\n<li>Full contributing guide including database change, API change, and testing requirements</li>\n<li>GitHub Actions CI with build, format, vet, test, and swagger doc checks</li>\n<li>Docker image published to GitHub Container Registry on every push to <code>main</code> and <code>dev</code></li>\n</ul>\n"
    }
  ],
  "changelogSource": "github",
  "changelogUpdatedAt": "2026-07-03T22:14:01.076Z"
}
