diff --git a/docs/user-guide/analytics.md b/docs/user-guide/analytics.md new file mode 100644 index 00000000..eb2f99b8 --- /dev/null +++ b/docs/user-guide/analytics.md @@ -0,0 +1,88 @@ +# Analytics + +The Analytics page provides deep-dive charts and tables about your mesh network. Select a tab to explore different aspects. + +[Screenshot: analytics page with tab bar] + +## Overview + +Summary dashboard with key network metrics at a glance. Quick sparklines and counts across all data dimensions. + +## RF / Signal + +Radio frequency analysis: + +- **SNR distribution** — histogram of signal-to-noise ratios across all packets +- **RSSI distribution** — histogram of received signal strength +- **SNR by observer** — which observers are getting the best signals +- **Signal trends** — how signal quality changes over time + +Use this to identify weak links or noisy observers. + +## Topology + +Network structure analysis: + +- **Hop count distribution** — how many relay hops packets typically take +- **Top relay nodes** — which repeaters handle the most traffic +- **Node connectivity** — how well-connected each node is + +## Channels + +Channel message statistics: + +- **Messages per channel** — which channels are most active +- **Channel activity over time** — traffic trends by channel +- **Top senders** — most active nodes per channel + +## Hash Stats + +Mesh hash size analysis: + +- **Hash size distribution** — how many bytes nodes use for addressing +- **Hash sizes by role** — do repeaters use different hash sizes than companions? + +## Hash Issues + +Potential hash collision detection: + +- **Collision pairs** — nodes whose short hash prefixes overlap +- **Risk assessment** — how likely collisions are at current hash sizes + +Hash collisions can cause packet misrouting. If you see collisions here, consider increasing hash sizes on affected nodes. + +## Route Patterns (Subpaths) + +Common routing paths through the mesh: + +- **Frequent subpaths** — which relay chains appear most often +- **Path reliability** — how consistently each path is used +- **Path detail** — click a subpath to see every packet that used it + +## Nodes + +Per-node analytics with sortable metrics across the fleet. + +## Distance + +Estimated distances between nodes based on GPS coordinates, correlated with signal quality. + +## Neighbor Graph + +Interactive visualization of which nodes can directly hear each other. Shows the mesh topology as a network graph. + +## RF Health + +Per-observer signal health over time. Identifies observers with degrading reception. + +## Prefix Tool + +Test hash prefix lengths to see how many collisions different sizes would produce. Useful for deciding on hash_size settings. + +## Region filter + +All analytics tabs respect the **region filter** at the top. Select a region to scope the data to observers in that area. + +## Deep linking + +Each tab is deep-linkable. Share a URL like `#/analytics?tab=collisions` to point someone directly at hash issues. diff --git a/docs/user-guide/channels.md b/docs/user-guide/channels.md new file mode 100644 index 00000000..a518463e --- /dev/null +++ b/docs/user-guide/channels.md @@ -0,0 +1,68 @@ +# Channels + +The Channels page shows decrypted MeshCore channel messages — like a group chat viewer for your mesh. + +[Screenshot: channels page with message list] + +## What are channels? + +MeshCore nodes can send messages on named channels (like `#LongFast` or `#test`). These are group messages broadcast through the mesh. Any observer that hears the packet captures it. + +CoreScope can decrypt and display these messages if you provide the channel encryption key. + +## How it works + +1. Observers capture encrypted channel packets from the mesh +2. CoreScope matches the packet's channel hash to a known channel name +3. If a decryption key is configured, the message content is decrypted and displayed +4. Without a key, you'll see the packet metadata but not the message text + +## Viewing messages + +Select a channel from the list on the left. Messages appear in chronological order on the right. + +Each message shows: +- **Sender** — node name or hash +- **Text** — decrypted message content +- **Observer** — which observer captured it +- **Time** — when it was received + +The message list auto-scrolls to show new messages as they arrive via WebSocket. + +## Channel keys + +To decrypt messages, add channel keys to your `config.json`: + +```json +{ + "channelKeys": { + "public": "8b3387e9c5cdea6ac9e5edbaa115cd72" + } +} +``` + +The key name (e.g., `"public"`) is a label for your reference. The value is the 16-byte hex encryption key for that channel. + +See [Configuration](configuration.md) for details on `channelKeys` and `hashChannels`. + +## Hash channels + +The `hashChannels` config lists channel names that CoreScope should try to match by hash: + +```json +{ + "hashChannels": ["#LongFast", "#test", "#sf"] +} +``` + +CoreScope computes the hash of each name and matches incoming packets to identify which channel they belong to. + +## Region filter + +Channels respect the region filter. Select a region to see only messages captured by observers in that area. + +## Tips + +- The default MeshCore "public" channel key is well-known — most community meshes use it +- If messages appear but show garbled text, your key may be wrong +- Not all packets are channel messages — only type "Channel Msg" (GRP_TXT) appears here diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md new file mode 100644 index 00000000..e9da7656 --- /dev/null +++ b/docs/user-guide/configuration.md @@ -0,0 +1,181 @@ +# Configuration + +CoreScope is configured via `config.json` in the server's working directory. Copy `config.example.json` to get started. + +## Core settings + +| Field | Default | Description | +|-------|---------|-------------| +| `port` | `3000` | HTTP server port | +| `apiKey` | — | Secret key for admin API endpoints (POST/PUT routes) | +| `dbPath` | — | Path to SQLite database file (optional, defaults to `meshcore.db`) | + +## MQTT + +```json +"mqtt": { + "broker": "mqtt://localhost:1883", + "topic": "meshcore/+/+/packets" +} +``` + +The ingestor connects to this MQTT broker and subscribes to the topic pattern. + +### Multiple MQTT sources + +Use `mqttSources` for multiple brokers: + +```json +"mqttSources": [ + { + "name": "local", + "broker": "mqtt://localhost:1883", + "topics": ["meshcore/#"] + }, + { + "name": "remote", + "broker": "mqtts://mqtt.example.com:8883", + "username": "user", + "password": "pass", + "topics": ["meshcore/SJC/#"] + } +] +``` + +## Branding + +| Field | Description | +|-------|-------------| +| `branding.siteName` | Site title shown in the nav bar | +| `branding.tagline` | Subtitle on the home page | +| `branding.logoUrl` | URL to a custom logo image | +| `branding.faviconUrl` | URL to a custom favicon | + +## Theme + +Colors used throughout the UI. All values are hex color codes. + +| Field | Description | +|-------|-------------| +| `theme.accent` | Primary accent color (links, buttons) | +| `theme.navBg` | Navigation bar background | +| `theme.navBg2` | Secondary nav background | +| `theme.statusGreen` | Healthy status color | +| `theme.statusYellow` | Degraded status color | +| `theme.statusRed` | Silent/error status color | + +See [Customization](customization.md) for the full list — the theme customizer exposes every color. + +## Node colors + +Default marker colors by role: + +```json +"nodeColors": { + "repeater": "#dc2626", + "companion": "#2563eb", + "room": "#16a34a", + "sensor": "#d97706", + "observer": "#8b5cf6" +} +``` + +## Health thresholds + +How long (in hours) before a node is marked degraded or silent: + +| Field | Default | Description | +|-------|---------|-------------| +| `healthThresholds.infraDegradedHours` | `24` | Repeaters/rooms → degraded after this many hours | +| `healthThresholds.infraSilentHours` | `72` | Repeaters/rooms → silent after this many hours | +| `healthThresholds.nodeDegradedHours` | `1` | Companions/others → degraded | +| `healthThresholds.nodeSilentHours` | `24` | Companions/others → silent | + +## Retention + +| Field | Default | Description | +|-------|---------|-------------| +| `retention.nodeDays` | `7` | Nodes not seen in N days move to inactive | +| `retention.packetDays` | `30` | Packets older than N days are deleted daily | + +## Channel decryption + +| Field | Description | +|-------|-------------| +| `channelKeys` | Object of `"label": "hex-key"` pairs for decrypting channel messages | +| `hashChannels` | Array of channel names (e.g., `"#LongFast"`) to match by hash | + +See [Channels](channels.md) for details. + +## Map defaults + +```json +"mapDefaults": { + "center": [37.45, -122.0], + "zoom": 9 +} +``` + +Initial map center and zoom level. + +## Regions + +```json +"regions": { + "SJC": "San Jose, US", + "SFO": "San Francisco, US" +} +``` + +Named regions for the region filter dropdown. The `defaultRegion` field sets which region is selected by default. + +## Cache TTL + +All values in seconds. Controls how long the server caches API responses: + +```json +"cacheTTL": { + "stats": 10, + "nodeList": 90, + "nodeDetail": 300, + "analyticsRF": 1800 +} +``` + +Lower values = fresher data but more server load. + +## Packet store + +| Field | Default | Description | +|-------|---------|-------------| +| `packetStore.maxMemoryMB` | `1024` | Maximum RAM for in-memory packet store | +| `packetStore.estimatedPacketBytes` | `450` | Estimated bytes per packet (for memory budgeting) | + +## Timestamps + +| Field | Default | Description | +|-------|---------|-------------| +| `timestamps.defaultMode` | `"ago"` | Display mode: `"ago"` (relative) or `"absolute"` | +| `timestamps.timezone` | `"local"` | `"local"` or `"utc"` | +| `timestamps.formatPreset` | `"iso"` | Date format preset | + +## Live map + +| Field | Default | Description | +|-------|---------|-------------| +| `liveMap.propagationBufferMs` | `5000` | How long to buffer observations before animating | + +## HTTPS + +```json +"https": { + "cert": "/path/to/cert.pem", + "key": "/path/to/key.pem" +} +``` + +Provide cert and key paths to enable HTTPS. + +## Home page + +The `home` section customizes the onboarding experience. See `config.example.json` for the full structure including `steps`, `checklist`, and `footerLinks`. diff --git a/docs/user-guide/customization.md b/docs/user-guide/customization.md new file mode 100644 index 00000000..2f41c971 --- /dev/null +++ b/docs/user-guide/customization.md @@ -0,0 +1,78 @@ +# Customization + +CoreScope includes a built-in theme customizer. Access it from **Tools → Customization** in the navigation menu. + +[Screenshot: theme customizer panel with color pickers] + +## What you can customize + +### Branding + +- **Site name** — displayed in the nav bar and browser tab +- **Tagline** — shown on the home page +- **Logo URL** — replace the default logo +- **Favicon URL** — custom browser tab icon + +### Theme colors (Light & Dark) + +Every color in the UI is customizable: + +- **Accent** — primary color for links, buttons, highlights +- **Navigation** — nav bar background, text, and muted text colors +- **Background** — page background and content area +- **Surfaces** — cards, panels, input fields, detail panes +- **Status** — green (healthy), yellow (degraded), red (silent) +- **Text** — primary text, muted text, borders +- **Tables** — row stripe, hover, and selected row colors + +Both light and dark themes are independently configurable. + +### Node colors + +Set the color for each role: repeater, companion, room, sensor, observer. These colors appear on the map, in node badges, and throughout the UI. + +### Packet type colors + +Customize the color for each packet type: Advert, Channel Msg, Direct Msg, ACK, Request, Response, Trace, Path. + +### Home page + +Customize the onboarding experience: + +- Hero title and subtitle +- Getting-started steps (emoji, title, description for each) +- FAQ items +- Footer links + +### Timestamps + +- **Display mode** — relative ("5 min ago") or absolute +- **Timezone** — local or UTC +- **Format preset** — ISO or other presets + +## Live preview + +Changes apply instantly as you edit. You see the result in real time without saving. + +## Exporting a theme + +Click **Export JSON** to download your customizations as a JSON file. This produces a config-compatible block you can paste into your `config.json`. + +## Importing a theme + +Click **Import JSON** and paste a previously exported theme. The customizer loads all values and applies them immediately. + +## Resetting + +Click **Reset to Defaults** to restore all settings to the built-in defaults. + +## How it works + +The customizer writes CSS custom properties (variables) to override the defaults. Exported JSON maps directly to the `theme`, `nodeColors`, `branding`, and `home` sections of [config.json](configuration.md). + +## Tips + +- Start with the accent color — it cascades through buttons, links, and highlights +- Dark mode has its own color set (`themeDark`), independent of light mode +- Node colors affect the [Map](map.md), [Live](live.md) page, and node badges everywhere +- Export your theme before upgrading CoreScope, then re-import it after diff --git a/docs/user-guide/faq.md b/docs/user-guide/faq.md new file mode 100644 index 00000000..47c22170 --- /dev/null +++ b/docs/user-guide/faq.md @@ -0,0 +1,54 @@ +# FAQ + +## 1. How do I add my node to CoreScope? + +Go to the **Home** page, search for your node by name or public key, and click **+ Claim**. Your node appears on the dashboard with live status. + +## 2. Why does my node show as "Silent"? + +Your node hasn't been heard by any observer within the configured threshold. For companions, the default is 24 hours. For repeaters, it's 72 hours. Check that your node is advertising and within range of an observer. See [Configuration](configuration.md) for threshold settings. + +## 3. What's the difference between "Last seen" and "Last heard"? + +**Last seen** updates only when a node sends an advertisement. **Last heard** updates on *any* traffic from that node. CoreScope uses whichever is more recent for status calculations. + +## 4. Why can't I read channel messages? + +You need the channel encryption key in your `config.json`. See [Channels](channels.md) for how to configure `channelKeys`. + +## 5. What do the packet types mean? + +| Type | Meaning | +|------|---------| +| Advert | Node announcing itself to the mesh | +| Channel Msg | Group message on a named channel | +| Direct Msg | Private message between two nodes | +| ACK | Acknowledgment of a received packet | +| Request | Query sent to the mesh | +| Response | Reply to a request | +| Trace | Route tracing packet | +| Path | Path discovery/announcement | + +## 6. How do I filter packets by a specific node? + +On the [Packets](packets.md) page, use the filter bar and type `from:NodeName` or click a node's name anywhere in the UI to jump to its packets. + +## 7. Why do some nodes appear faded on the map? + +Faded markers indicate **stale** nodes — they haven't been heard recently. The threshold depends on the node's role. + +## 8. Can I run CoreScope without MQTT? + +Yes. You can POST packets directly to the `/api/packets` endpoint using the API key. However, MQTT is the standard way to ingest data from mesh observers. + +## 9. How do I change the map's default location? + +Set `mapDefaults.center` and `mapDefaults.zoom` in your `config.json`. See [Configuration](configuration.md). + +## 10. How do I share a link to a specific packet or view? + +CoreScope uses URL hashes for deep linking. Copy the URL from your browser — it includes the current page, filters, and selected items. Examples: + +- `#/packets/abc123` — a specific packet +- `#/analytics?tab=collisions` — the hash issues tab +- `#/nodes/pubkey123` — a specific node's detail page diff --git a/docs/user-guide/getting-started.md b/docs/user-guide/getting-started.md new file mode 100644 index 00000000..64af59b9 --- /dev/null +++ b/docs/user-guide/getting-started.md @@ -0,0 +1,70 @@ +# Getting Started + +## What is CoreScope? + +CoreScope is a web-based analyzer for **MeshCore LoRa mesh networks**. It shows you every node, packet, and signal path in your mesh — in real time. + +Use it to monitor node health, debug connectivity, view decrypted channel messages, and understand how your mesh is performing. + +## What you need + +- A running CoreScope server (Go binary + SQLite database) +- An MQTT broker feeding mesh packets into the CoreScope ingestor +- A modern web browser + +## Quick start + +### 1. Configure + +Copy `config.example.json` to `config.json` and edit it: + +```json +{ + "port": 3000, + "apiKey": "pick-a-secret-key", + "mqtt": { + "broker": "mqtt://your-broker:1883", + "topic": "meshcore/+/+/packets" + } +} +``` + +See [Configuration](configuration.md) for all options. + +### 2. Run + +Start both the ingestor (reads MQTT → writes to SQLite) and the server (serves the UI + API): + +```bash +./corescope-ingestor & +./corescope-server +``` + +### 3. Open the UI + +Go to `http://localhost:3000`. You'll see the **Home** page. + +- **New to MeshCore?** Choose "I'm new" for setup guides and tips. +- **Already set up?** Choose "I know what I'm doing" to jump straight in. + +Search for your node by name or public key, then click **+ Claim** to add it to your personal dashboard. + +## What's on each page + +| Page | What it does | +|------|-------------| +| [Home](getting-started.md) | Your personal mesh dashboard — claimed nodes, health, stats | +| [Nodes](nodes.md) | Browse all nodes with status, role, and filters | +| [Packets](packets.md) | Inspect every packet — grouped or raw, with hex breakdown | +| [Map](map.md) | See node locations on a live map | +| [Live](live.md) | Watch packets flow in real time with map animations | +| [Analytics](analytics.md) | Deep-dive charts: RF, topology, routes, hash stats | +| [Channels](channels.md) | Read decrypted channel messages | + +## Home page features + +- **Claim nodes** — search and add nodes to "My Mesh" for at-a-glance status cards +- **Node cards** — show status (🟢 Active / 🟡 Degraded / 🔴 Silent), SNR, hops, packet count, and 24h sparkline +- **Health detail** — click a card to see full health: observers, recent packets, mini map +- **Packet journey** — click a recent packet to see sender → observer flow +- **Network stats** — total transmissions, nodes, observers, and 24h activity diff --git a/docs/user-guide/live.md b/docs/user-guide/live.md new file mode 100644 index 00000000..e6701e0f --- /dev/null +++ b/docs/user-guide/live.md @@ -0,0 +1,76 @@ +# Live + +The Live page shows packets flowing through your mesh in real time, with animated map visualizations. + +[Screenshot: live page with map animations and packet feed] + +## Real-time feed + +Packets appear as they arrive via WebSocket. Each entry shows: + +- Packet type icon and color +- Sender name +- Observer that captured it +- SNR and hop count +- Timestamp + +The feed scrolls automatically. New packets appear at the top. + +## Map animations + +When a packet arrives, the Live map animates the signal path: + +- A pulse appears at the sender's location +- Lines animate from sender to each observer that heard the packet +- Observer markers flash briefly on reception + +### Realistic propagation + +Enable **Realistic Propagation** in the controls to buffer observations of the same packet and animate them simultaneously — showing how a single transmission ripples through the mesh. + +### Ghost hops + +When enabled, intermediate relay hops are shown as faded markers even if they don't have known locations. Disable to show only nodes with GPS coordinates. + +## VCR mode + +The Live page has a built-in VCR (video cassette recorder) for packet replay. + +| Button | Action | +|--------|--------| +| ⏸ Pause | Freeze the feed. New packets are buffered but not displayed. | +| ▶ Play | Resume live feed or start replay. | +| ⏪ Rewind | Step backward through packet history. | +| ⏩ Fast-forward | Replay at 2×, 4×, or 8× speed. | + +While paused, a badge shows how many packets arrived that you haven't seen yet. + +## Timeline + +The timeline bar at the bottom shows packet activity over the selected time scope (default: 1 hour). Click anywhere on the timeline to jump to that point in time. + +## Packet type legend + +Each packet type has a color and icon: + +| Type | Icon | Color | +|------|------|-------| +| Advert | 📡 | Green | +| Channel Msg | 💬 | Blue | +| Direct Msg | ✉️ | Amber | +| ACK | ✓ | Gray | +| Request | ❓ | Purple | +| Response | 📨 | Cyan | +| Trace | 🔍 | Pink | +| Path | 🛤️ | Teal | + +## Controls + +- **Favorites only** — show only packets from your claimed nodes +- **Matrix mode** — visual effect overlay (just for fun) + +## Tips + +- Use VCR pause when you spot something interesting — then step through packet by packet +- Realistic propagation mode is best for understanding multi-path reception +- The timeline sparkline shows traffic patterns — useful for spotting quiet periods or bursts diff --git a/docs/user-guide/map.md b/docs/user-guide/map.md new file mode 100644 index 00000000..f880deb2 --- /dev/null +++ b/docs/user-guide/map.md @@ -0,0 +1,71 @@ +# Map + +The Map page shows all nodes on an interactive map, color-coded by role. + +[Screenshot: map with colored markers and controls panel] + +## Marker shapes and colors + +Each node role has a distinct shape and color: + +| Role | Shape | Default Color | +|------|-------|---------------| +| Repeater | Diamond | Red | +| Companion | Circle | Blue | +| Room | Square | Green | +| Sensor | Triangle | Orange | +| Observer | Star | Purple | + +Stale nodes (not heard recently) appear faded. + +## Hash labels + +Repeaters can display their short mesh hash ID instead of a plain marker. Toggle **Hash Labels** in the map controls to switch between icon markers and hash-labeled markers. + +## Map controls + +Open the controls panel with the ⚙️ button (top-right corner). + +### Node types + +Check or uncheck roles to show/hide them on the map. All roles are visible by default. + +### Byte size filter + +Filter nodes by packet size category: All, Small, Medium, Large. + +### Status filter + +Show only active, degraded, or silent nodes. + +### Last heard filter + +Limit the map to nodes heard within a time window (e.g., 24h, 7d, 30d). + +### Clustering + +Enable clustering to group nearby nodes into cluster bubbles. Zoom in to expand clusters. + +### Neighbor filter + +Select a reference node to highlight only its direct neighbors. + +## Show Route + +Click a node marker, then click **Show Route** in the popup to see the paths packets take to reach that node. Routes are drawn as lines between nodes. + +## Popups + +Click any marker to see: + +- Node name and role +- Public key +- Last seen timestamp +- Link to the full node detail page + +## Tips + +- Zoom in on dense areas to see individual nodes +- Use the role checkboxes to isolate repeaters and understand coverage +- The neighbor filter is great for seeing which nodes can directly hear each other +- Node colors are [customizable](customization.md) in the theme settings diff --git a/docs/user-guide/nodes.md b/docs/user-guide/nodes.md new file mode 100644 index 00000000..f0697c9a --- /dev/null +++ b/docs/user-guide/nodes.md @@ -0,0 +1,70 @@ +# Nodes + +The Nodes page lists every node your mesh has seen — repeaters, companions, rooms, and sensors. + +[Screenshot: nodes list with status indicators] + +## What you see + +Each row shows: + +- **Name** — the node's advertised name (or public key if unnamed) +- **Role** — Repeater, Companion, Room, or Sensor +- **Status** — color-coded health indicator +- **Last seen** — when the node was last heard +- **Advert count** — how many advertisements this node has sent + +## Status indicators + +| Indicator | Meaning | +|-----------|---------| +| 🟢 Active | Heard recently (within threshold for its role) | +| 🟡 Degraded | Not heard for a while but not yet silent | +| 🔴 Silent | Not heard for an extended period | + +Thresholds differ by role. Infrastructure nodes (repeaters, rooms) have longer grace periods than companions. See [Configuration](configuration.md) for `healthThresholds`. + +## Filtering + +### Role tabs + +Click **All**, **Repeaters**, **Rooms**, **Companions**, or **Sensors** to filter by role. + +### Search + +Type in the search box to filter by name or public key. The filter applies instantly. + +### Status filter + +Filter to show only active, degraded, or silent nodes. + +### Last heard filter + +Filter nodes by how recently they were heard (e.g., last hour, last 24h). + +## Sorting + +Click any column header to sort. Click again to reverse the order. Your sort preference is saved across sessions. + +## Node detail + +Click a node row to open the **detail pane** on the right. It shows: + +- Full public key +- Role and status explanation +- Location (if known) +- Recent packets involving this node +- Neighbor nodes +- Signal statistics + +Click the node name in the detail pane to open the **full node page** with complete history, analytics, and health data. + +## Favorites + +Nodes you've claimed on the Home page appear as favorites. You can also star nodes directly from the Nodes page. + +## Tips + +- Use the search box for quick lookups — it matches partial names and keys +- Sort by "Last seen" descending to find the most active nodes +- The status explanation tells you exactly why a node is marked degraded or silent diff --git a/docs/user-guide/packets.md b/docs/user-guide/packets.md new file mode 100644 index 00000000..2763f027 --- /dev/null +++ b/docs/user-guide/packets.md @@ -0,0 +1,78 @@ +# Packets + +The Packets page shows every transmission captured by your mesh observers. + +[Screenshot: packets table with grouped view] + +## Grouped vs ungrouped view + +By default, packets are **grouped by hash**. Each row represents one unique transmission, with a count of how many observers heard it. + +Click **Ungroup** to see every individual observation as its own row. + +Click the **▶** arrow on a grouped row to expand it and see all observations of that packet. + +## What each row shows + +- **Time** — when the packet was received +- **From** — sender node name or hash prefix +- **Type** — packet type (Advert, Channel Msg, Direct Msg, ACK, Request, Response, Trace, Path) +- **Observer** — which observer captured the packet +- **SNR** — signal-to-noise ratio in dB +- **RSSI** — received signal strength +- **Hops** — how many relay hops the packet took + +## Filters + +### Observer filter + +Select a specific observer to see only packets it captured. Saved across sessions. + +### Type filter + +Filter by packet type (e.g., show only Adverts or Channel Messages). + +### Time window + +Choose how far back to look: 15 minutes, 1 hour, 6 hours, 24 hours, etc. On mobile, the window is capped at 3 hours for performance. + +### Wireshark-style filter bar + +Type filter expressions for advanced filtering: + +``` +type:advert snr>5 hops<3 +from:MyNode observer:SJC +``` + +See the filter bar's help tooltip for all supported fields and operators. + +## Packet detail + +Click any row to open the **detail pane** on the right showing: + +- Full packet metadata (hash, type, size, timestamp) +- Decoded payload fields +- Hop path with resolved node names +- All observers that heard this packet, sorted by SNR + +### Hex breakdown + +The detail pane includes a hex dump of the raw packet bytes with field boundaries highlighted. + +## Observation sorting + +When viewing a grouped packet's observations, they're sorted by SNR (best signal first). This helps you see which observer had the clearest reception. + +## Display options + +- **Hex hashes** — toggle to show packet hashes in hex format +- **Panel resize** — drag the detail pane border to resize it +- **Keyboard shortcuts** — press `Esc` to close the detail pane + +## Tips + +- Grouped view is best for understanding what's happening on the mesh +- Ungrouped view is best for debugging signal paths and comparing observers +- The time window filter is your best friend for managing large datasets +- Packet hashes in the URL are deep-linkable — share a link to a specific packet