diff --git a/db.js b/db.js
index 0ba06128..6648f7a0 100644
--- a/db.js
+++ b/db.js
@@ -360,47 +360,8 @@ function getStats() {
};
}
-function seed() {
- if (stmts.countPackets.get().count > 0) return false;
- const now = new Date().toISOString();
- const rawHex = '11451000D818206D3AAC152C8A91F89957E6D30CA51F36E28790228971C473B755F244F718754CF5EE4A2FD58D944466E42CDED140C66D0CC590183E32BAF40F112BE8F3F2BDF6012B4B2793C52F1D36F69EE054D9A05593286F78453E56C0EC4A3EB95DDA2A7543FCCC00B939CACC009278603902FC12BCF84B706120526F6F6620536F6C6172';
-
- upsertObserver({ id: 'obs-seed-001', name: 'Seed Observer', iata: 'UNK', last_seen: now, first_seen: now });
-
- insertTransmission({
- raw_hex: rawHex,
- timestamp: now,
- observer_id: 'obs-seed-001',
- observer_name: 'Seed Observer',
- direction: 'rx',
- snr: 10.5,
- rssi: -85,
- score: 42,
- hash: 'seed-test-hash',
- route_type: 1,
- payload_type: 4,
- payload_version: 1,
- path_json: JSON.stringify(['A1B2', 'C3D4']),
- decoded_json: JSON.stringify({ type: 'ADVERT', name: 'Test Repeater', role: 'repeater', lat: 0, lon: 0 }),
- });
-
- upsertNode({
- public_key: 'seed-test-pubkey',
- name: 'Test Repeater',
- role: 'repeater',
- lat: 0,
- lon: 0,
- last_seen: now,
- first_seen: now,
- });
-
- return true;
-}
-
// --- Run directly ---
if (require.main === module) {
- const seeded = seed();
- console.log(seeded ? 'Database seeded with test data.' : 'Database already has data, skipping seed.');
console.log('Stats:', getStats());
}
@@ -631,4 +592,4 @@ function getNodeAnalytics(pubkey, days) {
};
}
-module.exports = { db, insertTransmission, upsertNode, upsertObserver, updateObserverStatus, getPackets, getPacket, getTransmission, getNodes, getNode, getObservers, getStats, seed, searchNodes, getNodeHealth, getNodeAnalytics };
+module.exports = { db, insertTransmission, upsertNode, upsertObserver, updateObserverStatus, getPackets, getPacket, getTransmission, getNodes, getNode, getObservers, getStats, searchNodes, getNodeHealth, getNodeAnalytics };
diff --git a/packet-store.js b/packet-store.js
index 3506a4fa..4277938d 100644
--- a/packet-store.js
+++ b/packet-store.js
@@ -156,19 +156,24 @@ class PacketStore {
}
}
- // Post-load: set each transmission's observer/path to the EARLIEST observation
+ // Post-load: set each transmission's display path to the LONGEST observation path
+ // (most representative of mesh topology — short paths are just nearby observers)
for (const tx of this.packets) {
if (tx.observations.length > 0) {
- let earliest = tx.observations[0];
+ let best = tx.observations[0];
+ let bestLen = 0;
+ try { bestLen = JSON.parse(best.path_json || '[]').length; } catch {}
for (let i = 1; i < tx.observations.length; i++) {
- if (tx.observations[i].timestamp < earliest.timestamp) earliest = tx.observations[i];
+ let len = 0;
+ try { len = JSON.parse(tx.observations[i].path_json || '[]').length; } catch {}
+ if (len > bestLen) { best = tx.observations[i]; bestLen = len; }
}
- tx.observer_id = earliest.observer_id;
- tx.observer_name = earliest.observer_name;
- tx.snr = earliest.snr;
- tx.rssi = earliest.rssi;
- tx.path_json = earliest.path_json;
- tx.direction = earliest.direction;
+ tx.observer_id = best.observer_id;
+ tx.observer_name = best.observer_name;
+ tx.snr = best.snr;
+ tx.rssi = best.rssi;
+ tx.path_json = best.path_json;
+ tx.direction = best.direction;
}
}
@@ -228,6 +233,12 @@ class PacketStore {
if (pkt.timestamp < tx.first_seen) {
tx.first_seen = pkt.timestamp;
tx.timestamp = pkt.timestamp;
+ }
+ // Update display path if new observation has longer path
+ let newPathLen = 0, curPathLen = 0;
+ try { newPathLen = JSON.parse(pkt.path_json || '[]').length; } catch {}
+ try { curPathLen = JSON.parse(tx.path_json || '[]').length; } catch {}
+ if (newPathLen > curPathLen) {
tx.observer_id = pkt.observer_id;
tx.observer_name = pkt.observer_name;
tx.path_json = pkt.path_json;
@@ -377,10 +388,16 @@ class PacketStore {
this.byTxId.set(tx.id, tx);
this._indexByNode(tx);
} else {
- // Update first_seen if earlier — also update observer + path to match
+ // Update first_seen if earlier
if (row.timestamp < tx.first_seen) {
tx.first_seen = row.timestamp;
tx.timestamp = row.timestamp;
+ }
+ // Update display path if new observation has longer path
+ let newPathLen = 0, curPathLen = 0;
+ try { newPathLen = JSON.parse(row.path_json || '[]').length; } catch {}
+ try { curPathLen = JSON.parse(tx.path_json || '[]').length; } catch {}
+ if (newPathLen > curPathLen) {
tx.observer_id = row.observer_id;
tx.observer_name = row.observer_name;
tx.path_json = row.path_json;
@@ -584,6 +601,7 @@ class PacketStore {
// Already grouped by hash — just format for backward compat
const sorted = filtered.map(tx => ({
hash: tx.hash,
+ first_seen: tx.first_seen || tx.timestamp,
count: tx.observation_count,
observer_count: new Set(tx.observations.map(o => o.observer_id).filter(Boolean)).size,
latest: tx.observations.length ? tx.observations.reduce((max, o) => o.timestamp > max ? o.timestamp : max, tx.observations[0].timestamp) : tx.timestamp,
diff --git a/public/index.html b/public/index.html
index 143de56b..649b711f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -22,9 +22,9 @@
-
-
-
+
+
+
@@ -81,27 +81,28 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+