Commit Graph

155 Commits

Author SHA1 Message Date
you ca4aa72574 fix: region filter nodes by ADVERT observers, not data packets
The previous approach matched nodes via data packet hashes seen by
regional observers — but mesh packets propagate everywhere, so nearly
every node matched every region (550/558).

New approach: _advertByObserver index tracks which observers saw each
node's ADVERT packets. ADVERTs are local broadcasts that indicate
physical presence, so they're the correct signal for geographic filtering.

Also fixes role counts to reflect filtered results, not global totals.
2026-03-21 08:31:55 +00:00
you 63a525ecc1 fix: stack overflow in /analytics/rf — replace Math.min/max spread
Math.min(...arr) and Math.max(...arr) blow the call stack when arr
has tens of thousands of elements. Replaced with simple for-loop
arrMin/arrMax helpers.
2026-03-21 08:26:34 +00:00
you 4ffeb8204e fix: analytics RF stats respect region filter
- Separate region filtering from SNR filtering in /api/analytics/rf
- totalAllPackets now shows regional observation count (was global)
- Add totalTransmissions (unique hashes in regional set)
- Payload types and packet sizes use all regional data, not just SNR-filtered
- Signal stats (SNR, RSSI, scatter) use SNR-filtered subset
- Handle empty SNR/RSSI arrays gracefully (no Infinity/-Infinity)
2026-03-21 08:01:30 +00:00
you c2acf40951 fix: revert broken SQL region filtering for nodes — use in-memory index
The subagent used a non-existent column (sender_key) in the SQL join.
Reverted to the same byObserver + _nodeHashIndex approach used by
bulk-health and network-status endpoints.
2026-03-21 07:15:22 +00:00
you 80b6e1cac1 fix: use SQL for region filtering on nodes page
The previous approach used pktStore._nodeHashIndex which only tracks
nodes appearing as sender/dest in decoded packet JSON. Most nodes only
send ADVERTs, so they had no entries in _nodeHashIndex and were filtered
out when a region was selected (showing 0 results).

Now uses a direct SQL join between observations and transmissions to find
all sender_keys observed by regional observers, which correctly includes
ADVERT-only nodes.
2026-03-21 07:10:56 +00:00
you 0ac7687313 Fix region filtering in Route Patterns, Nodes, and Network Status tabs
- Add RegionFilter.regionQueryString() to all API calls in renderSubpaths and renderNodesTab
- Add region filtering to /api/analytics/subpaths (filter packets by regional observer hashes)
- Add region filtering to /api/nodes/bulk-health (filter nodes by regional presence)
- Add region filtering to /api/nodes/network-status (filter node counts by region)
- Add region param to nodes lookup in hash collision tab
- Update cache keys to include region param for proper cache separation
2026-03-21 07:10:38 +00:00
you 94854c8d40 channels: only show decrypted messages, hide encrypted garbage
- Filter on decoded.type === 'CHAN' (successful decryption) only
- Skip GRP_TXT packets (failed decryption) entirely
- Channel key = decoded channel name instead of hash byte
- Remove channelHashNames lookup, encrypted field, isCollision logic
- Remove encrypted UI badges/indicators from frontend
- Channels with 0 decrypted messages no longer appear
2026-03-21 06:45:45 +00:00
you 7ac051d2a9 Add rainbow table of pre-computed channel keys for common MeshCore channels
- channel-rainbow.json: 592 pre-computed SHA256-derived keys for common
  channel names (cities, topics, ham radio, emergency, etc.)
- server.js: Load rainbow table at startup as lowest-priority key source
- config.example.json: Add #LongFast to hashChannels list

Key derivation verified against MeshCore source: SHA256('#name')[:16bytes].
Rainbow table boosted decryption from ~48% to ~88% in testing.
2026-03-21 06:35:14 +00:00
you 8ad2348a16 fix: simplify channel key scheme + add CHAN packet detail renderer
- Remove composite key scheme (ch_/unk_ prefixes) that broke URL routing
  due to # in channel names. Use plain numeric channelHash as key instead.
- All packets with same hash byte go in one bucket; name is set from
  first successful decryption.
- Add packet detail renderer for decoded CHAN type showing channel name,
  sender, and sender timestamp.
- Update cache buster for packets.js.
2026-03-21 06:11:01 +00:00
you 6402d291c1 fix: normalize packet hash case for deeplink lookups 2026-03-21 05:50:29 +00:00
you f303b7a4b9 fix: regional filters — proper indexed queries + frontend integration
Fixes Kpa-clawbot/meshcore-analyzer#111
2026-03-21 05:48:54 +00:00
you 378adc03c9 fix: restore channel message decryption — correct hash matching in API
The /api/channels endpoint was returning simple numeric hash (e.g. '45') while
/api/channels/:hash/messages was using composite keys (e.g. 'ch_#LongFast',
'unk_45') internally. This mismatch meant no channel ever matched, so all
messages appeared encrypted.

Fix: return the composite key as the hash field from /api/channels so the
frontend passes the correct identifier. Also add encodeURIComponent() to
channel API calls in the frontend since composite keys can contain '#'.
2026-03-21 05:47:51 +00:00
you b236b41568 feat: add regional filters to all tabs
Fixes Kpa-clawbot/meshcore-analyzer#111
2026-03-21 05:41:02 +00:00
you 27f4af3f3b fix: validate ADVERT data to prevent corrupted node entries
Fixes Kpa-clawbot/meshcore-analyzer#112
2026-03-21 05:34:57 +00:00
you 81275acff0 Make map default center/zoom configurable via config.json
Adds mapDefaults config option with center and zoom properties.
New /api/config/map endpoint serves the defaults. live.js and map.js
fetch the config with fallback to hardcoded Bay Area defaults.

Fixes Kpa-clawbot/meshcore-analyzer#115
2026-03-21 05:29:05 +00:00
you f9b9a0c07d Fix channel name resolution to use decryption key, not just hash
Channels sharing the same hash prefix but with different keys (e.g. #startrek
and #ai-bot both with hash 2d) now display the correct name by keying on the
actual channel name from decryption rather than just the hash byte.

Fixes Kpa-clawbot/meshcore-analyzer#108
2026-03-21 05:27:02 +00:00
you ac44f7fc2a feat: paths through node section on repeater detail page 2026-03-21 02:22:59 +00:00
you 75a1b8fc98 fix: anchor hop disambiguation from sender origin, not just observer
resolve-hops now accepts originLat/originLon params. Forward pass
starts from sender position so first ambiguous hop resolves to the
nearest node to the sender, not the observer.
2026-03-21 02:19:20 +00:00
you d660c03833 feat: realistic packet propagation mode on live map 2026-03-21 01:41:55 +00:00
lincomatic 11a7e54614 Fix require statement for db module 2026-03-21 01:29:01 +00:00
lincomatic 98294a533c add hashChannels
(cherry picked from commit e35794c4531f3c16ceeb246fbde6912c7d831671)
2026-03-21 01:29:01 +00:00
you 61afedd5f6 remove self-referential hashtag channel key seeding from DB 2026-03-21 01:28:17 +00:00
Kpa-clawbot 56d84ce11e Merge pull request #109 from lincomatic/prgraceful
graceful shutdown
2026-03-21 01:25:17 +00:00
Kpa-clawbot 4a9e69b207 Merge pull request #105 from lincomatic/https
add https support
2026-03-21 01:25:15 +00:00
you e38d1fa8f8 fix: map labels show short hash ID (e.g. 5B, BEEF), better deconfliction with spiral offsets 2026-03-21 00:30:25 +00:00
you b114cd6eb0 Add hash size labels for repeater markers on map
- Compute hash_size from ADVERT packets in /api/nodes response
- Show colored rectangle markers with hash size (e.g. '2B') for repeaters
- Add 'Hash size labels' toggle in map controls (default ON, saved to localStorage)
- Non-repeater markers unchanged
2026-03-21 00:19:15 +00:00
you 85c356448e fix: switch all user-facing URLs to hash-based for stability across restarts
After dedup migration, packet IDs from the legacy 'packets' table differ
from transmission IDs in the 'transmissions' table. URLs using numeric IDs
became invalid after restart when _loadNormalized() assigned different IDs.

Changes:
- All packet URLs now use 16-char hex hashes instead of numeric IDs
  (#/packets/HASH instead of #/packet/ID)
- selectPacket() accepts hash parameter, uses hash-based URLs
- Copy Link generates hash-based URLs
- Search results link to hash-based URLs
- /api/packets/:id endpoint accepts both numeric IDs and 16-char hashes
- insert() now calls insertTransmission() to get stable transmission IDs
- Added db.getTransmission() for direct transmission table lookup
- Removed redundant byTransmission map (identical to byHash)
- All byTransmission references replaced with byHash
2026-03-21 00:18:11 +00:00
you 9d65f041d4 fix: check transmission ID before observation ID in packet lookup 2026-03-20 23:58:23 +00:00
you 8ebce8087b fix: packet detail lookup uses transmission ID index
After dedup, table rows have transmission IDs but getById() maps
observation IDs. Added byTxId index so /api/packets/:id resolves
both observation and transmission IDs correctly.
2026-03-20 23:55:38 +00:00
you 15e80e56f1 fix: packet links use hash instead of observation ID
After dedup migration, transmission IDs != old packet IDs.
Hash-based links (#/packets/HASH) are stable across the migration.
Affected: node detail, channel messages, live page packet cards.
2026-03-20 23:40:30 +00:00
you 9713e972f9 traces: clickable observer names, path graph, remove redundant observer table
- API returns observer_name + path_json per observation
- Timeline shows resolved names with links to #/observers/<id>
- Path Visualization replaced with SVG graph showing all observed paths
- Removed redundant Observer Details table (same data as timeline)
2026-03-20 23:19:37 +00:00
you aa35164252 M4: API response changes for dedup-normalize
- GET /api/packets: returns transmissions with observation_count, strip
  observations[] by default (use ?expand=observations to include)
- GET /api/packets/🆔 includes observation_count and observations[]
- GET /api/nodes/:pubkey/health: stats.totalTransmissions + totalObservations
  (totalPackets kept for backward compat)
- GET /api/nodes/bulk-health: same transmission/observation split
- WebSocket broadcast: includes observation_count
- db.js getStats(): adds totalTransmissions count
- All backward-compatible: old field names preserved alongside new ones
2026-03-20 20:49:34 +00:00
you baa60cac0f M2: Dual-write ingest to transmissions/observations tables
- Add transmissions and observations schema to db.js init
- Add insertTransmission() function: upsert transmission by hash,
  always insert observation row
- All 6 pktStore.insert() call sites in server.js now also call
  db.insertTransmission() with try/catch (non-fatal on error)
- packet-store.js: add byTransmission Map index (hash → transmission
  with observations array) for future M3 query migration
- Existing insertPacket() and all read paths unchanged
2026-03-20 20:29:03 +00:00
lincomatic ac8a6a4dc3 graceful shutdown 2026-03-20 10:58:37 -07:00
you 4f7b02a91c fix: centralize hardcoded values — roles, thresholds, colors, tiles, limits — closes #104
- New public/roles.js shared module: ROLE_COLORS, ROLE_LABELS, ROLE_STYLE,
  ROLE_EMOJI, ROLE_SORT, HEALTH_THRESHOLDS, TILE_DARK/LIGHT, SNR_THRESHOLDS,
  DIST_THRESHOLDS, MAX_HOP_DIST, LIMITS — all configurable via /api/config/roles
- Removed duplicate ROLE_COLORS from map.js, nodes.js, live.js, analytics.js
- Removed duplicate health thresholds from nodes.js, home.js, observer-detail.js
- Deduplicated CartoDB tile URLs (3 copies → 1 in roles.js)
- Removed hardcoded region names from map.js and packets.js
- channels.js uses ROLE_EMOJI/ROLE_LABELS instead of hardcoded emoji chains
- server.js reads healthThresholds from config.json with defaults
- Unknown roles get gray circle fallback instead of crashing
2026-03-20 17:36:41 +00:00
lincomatic 209e17fcd4 add https support 2026-03-20 09:21:02 -07:00
you f0db317051 fix: observer locations case-insensitive match, regions from API not hardcoded
- Observer ID is uppercase, node pubkey is lowercase — added COLLATE NOCASE
- New /api/config/regions endpoint merges config regions + observed IATAs
- map.js and packets.js fetch regions from API instead of hardcoded maps
2026-03-20 16:10:16 +00:00
you 74a08d99b0 fix: observer location from nodes table direct join — observer ID = node pubkey 2026-03-20 15:11:57 +00:00
you 76d63ffe75 feat: observers as map markers (purple stars) with computed locations
- Removed dead 'MQTT Connected Only' checkbox (never worked)
- Added 'observer' role type with purple star marker
- Observer locations computed from average of nodes they've seen
- Observer popup with name, IATA, packets, link to detail page
- Role filter checkbox includes observers with count
2026-03-20 14:56:08 +00:00
you 9ef5c1a809 fix: My Nodes filter uses server-side findPacketsForNode for all packet types
Client was matching field names that only exist on ADVERTs. Now sends
pubkeys to server, which uses findPacketsForNode() (byNode index +
text search) to find ALL packet types referencing those nodes.
2026-03-20 09:30:41 +00:00
you 920eab04c1 fix: sort observer analytics packets newest-first, fix recentPackets slice 2026-03-20 09:10:16 +00:00
you d67b531bf2 fix: pass observer name (msg.origin) to packet insert and observer upsert
Lincomatic MQTT packets include origin field with friendly name but
we were only using it in status handler. Now both packet and observer
records get the name.
2026-03-20 09:07:39 +00:00
you 5a6847bbf4 fix: remove duplicate crypto require that crashed server 2026-03-20 08:54:35 +00:00
you 034c68c154 feat: auto-derive hashtag channel keys from SHA256(name)
Scans DB for known #channel names, derives 16-byte AES keys
algorithmically. No need to manually add hashtag channels to config.
Private channels still need manual config.
2026-03-20 08:53:11 +00:00
you 477dcde82f fix: analytics shows total packets + signal data count separately
RF analytics filtered on snr!=null, showing only 3 packets when most
lincomatic data has no SNR. Now shows total packets prominently and
signal-data count as a separate stat.
2026-03-20 08:42:38 +00:00
you c997318cd2 fix: recentPackets in health endpoint — show 20 newest DESC, not 10 oldest 2026-03-20 08:39:01 +00:00
you 8ce2262813 refactor: single findPacketsForNode() replaces 4 duplicate node lookups
One method resolves name→pubkey, combines byNode index + text search.
Used in: query fast-path, combined-filter path, health endpoint,
analytics endpoint. Bulk-health still uses index-only (perf).
2026-03-20 08:29:45 +00:00
you 90c4c03ac3 fix: node health endpoint searches by name + pubkey, not just byNode index
byNode only has packets where full pubkey appears in decoded_json fields.
Channel messages reference nodes by name, not pubkey. Combined search
finds all 304 packets instead of just 12.
2026-03-20 08:25:06 +00:00
you d8c0e3a156 fix: only backfill observer name if observer already exists
Prevents ADVERT nodes from being created as observers
2026-03-20 07:47:37 +00:00
you f58728118d feat: observer detail page with analytics
- GET /api/observers/:id — observer metadata + packet count
- GET /api/observers/:id/analytics — timeline, type breakdown, nodes heard, SNR distribution
- observer-detail.js — info cards, 4 Chart.js charts, recent packets table
- Observers list rows now clickable to navigate to detail
- Time range selector (24h, 3d, 7d, 30d)
2026-03-20 07:37:36 +00:00