- Create inactive_nodes table with identical schema to nodes
- Add retention.nodeDays config (default 7) in Node.js and Go
- On startup: move nodes not seen in N days to inactive_nodes
- Daily timer (24h setInterval / goroutine ticker) repeats the move
- Log 'Moved X nodes to inactive_nodes (not seen in N days)'
- All existing queries unchanged — they only read nodes table
- Add 14 new tests for moveStaleNodes in test-db.js
- Both Node (db.js/server.js) and Go (ingestor/server) implemented
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
advert_count was incremented on every upsertNode call, meaning each
observation of the same ADVERT packet inflated the count. Node N6NU
showed 4191 'adverts' but only had 77 unique ADVERT transmissions.
Changes:
- db.js: Remove advert_count increment from upsertNode SQL. Add
separate incrementAdvertCount() called only for new transmissions.
insertTransmission() now returns isNew flag.
- server.js: All three ADVERT processing paths (MQTT format 1,
companion bridge, API) now check isNew before incrementing.
- cmd/ingestor/db.go: Same fix in Go — UpsertNode no longer
increments, new IncrementAdvertCount method added.
InsertTransmission returns (bool, error) with isNew flag.
- cmd/ingestor/main.go: Check isNew before calling IncrementAdvertCount.
- One-time startup migration recalculates advert_count from
transmissions table (payload_type=4 matching node public_key).
Fixes#200
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
autoLearnHopNodes was creating stub 'repeater' entries in the nodes table
for every unresolved hop prefix. With hash_size=1, this generated thousands
of phantom nodes (6,638 fake repeaters on a ~300-node mesh).
Root cause fix:
- autoLearnHopNodes no longer calls db.upsertNode() for unresolved hops
- Hop prefixes are still cached to avoid repeated DB lookups
- Unresolved hops display as raw hex via hop-resolver (no behavior change)
Cleanup:
- Added db.removePhantomNodes() — deletes nodes with public_key <= 16 chars
(real MeshCore pubkeys are 64 hex chars / 32 bytes)
- Called at server startup to purge existing phantoms
Tests: 14 new assertions in test-db.js (109 total, all passing)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The /api/stats endpoint returned totalNodes from SELECT COUNT(*) FROM nodes,
which counts every node ever seen. On long-running instances this climbs to
6800+ for a ~200-400 node mesh.
Changes:
- totalNodes now counts only nodes with last_seen within the last 7 days
- Added totalNodesAllTime field for the full historical count
- Role counts (repeaters, rooms, etc.) also filtered to 7-day window
- Added countActiveNodes and countActiveNodesByRole prepared statements
- Added 6 tests verifying active vs all-time node counting
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>