A real-time map, chat client, and packet-analysis tool for MeshCore mesh
networks. This repository ships the whole stack so it can be brought up with a
single docker compose up:
| Component | Path | Description |
|---|---|---|
| Web app | meshexplorer/ |
Next.js UI + API (map, chat, stats, packet analysis) |
| Ingest + DB | ingest/ |
Go MeshCore MQTT→ClickHouse ingest, ClickHouse image, and SQL migrations |
| Discord relay | meshexplorer/ (Dockerfile.bot) |
Optional bot that relays MeshCore channel messages to Discord |
| Grafana | grafana/ |
Dashboards with a pre-provisioned ClickHouse datasource (read-only user), on 127.0.0.1:3000 |
MQTT brokers (you configure)
│
▼
┌──────────────┐ ┌──────────────┐
│ meshcoreingest│──▶│ ClickHouse │◀── migrate (one-shot, applies schema)
└──────────────┘ └──────┬───────┘
│ (readonly user)
┌──────────┴──────────┐
▼ ▼ ▼
meshexplorer discord-bot grafana
(web UI :3001) (--profile bot) (:3000)
Requirements: Docker + Docker Compose.
cp .env.example .env
# Edit .env — at minimum set:
# CLICKHOUSE_PASSWORD (read/write user, used by ingest + migrations)
# MQTT_BROKERS (JSON array of meshcore MQTT brokers to ingest from)
# Optional, for the Discord relay: DISCORD_WEBHOOK_URL (+ run with --profile bot)
docker compose up --buildThen open http://localhost:3001.
Startup order is handled automatically: ClickHouse becomes healthy → migrate
applies the schema and exits → meshcoreingest and meshexplorer start.
To also run the Discord relay:
docker compose --profile bot up --buildAll configuration is via environment variables in .env (see
.env.example for the full list and defaults). Highlights:
- ClickHouse — two accounts. The read/write
defaultuser (CLICKHOUSE_PASSWORD) is used by the ingest daemon and the migration runner; thereadonlyuser (CLICKHOUSE_READONLY_PASSWORD) is used by the web app and the Discord bot. ClickHouse is only published to127.0.0.1for debugging and is otherwise reachable only on the internalmeshnetnetwork. - MQTT_BROKERS — a JSON array; each entry is
{ "url", "username", "password", "topics" }(topicsdefaults to["meshcore/#"]). The ingest daemon exits with a clear error if this is unset, so configure at least one broker.
Each component can be run on its own:
- Web app: see
meshexplorer/README.md(npm install && npm run dev). - Ingest: see
ingest/README.md(go build ./...).
.envis gitignored — keep real credentials out of version control.- If you previously used the bundled defaults, rotate any secrets before going to production.