From 03afe57a16ad7a6f38c7e2988da59a9a94ed8b2a Mon Sep 17 00:00:00 2001 From: Louis King Date: Fri, 17 Apr 2026 20:41:37 +0100 Subject: [PATCH] Move UPGRADING.md to docs/ with versioned headings, extract LetsMesh decoding to docs/letsmesh.md --- .agents/skills/docs-sync/SKILL.md | 13 +++-- .../references/documentation-checklist.md | 35 ++++++++---- AGENTS.md | 9 ++- README.md | 40 ++++--------- docs/letsmesh.md | 36 ++++++++++++ UPGRADING.md => docs/upgrading.md | 56 ++++++++++--------- 6 files changed, 115 insertions(+), 74 deletions(-) create mode 100644 docs/letsmesh.md rename UPGRADING.md => docs/upgrading.md (92%) diff --git a/.agents/skills/docs-sync/SKILL.md b/.agents/skills/docs-sync/SKILL.md index 31fcd61..c3e137e 100644 --- a/.agents/skills/docs-sync/SKILL.md +++ b/.agents/skills/docs-sync/SKILL.md @@ -1,13 +1,13 @@ --- name: docs-sync -description: "Audits and fixes discrepancies between project source code (Python config, Docker Compose files) and primary documentation files (README.md, AGENTS.md, UPGRADING.md, .env.example, SCHEMAS.md). Extracts environment variables from Pydantic Settings, Click CLI options, and os.getenv calls; parses Docker Compose services, profiles, volumes, and env passthroughs; verifies feature flags, CLI commands, and file paths referenced in documentation. Produces a structured audit report and applies fixes to keep documentation accurate and up-to-date. Invoke after any config change, env var addition/removal, Docker service modification, feature flag change, or when documentation drift is suspected." +description: "Audits and fixes discrepancies between project source code (Python config, Docker Compose files) and primary documentation files (README.md, AGENTS.md, docs/upgrading.md, .env.example, SCHEMAS.md). Extracts environment variables from Pydantic Settings, Click CLI options, and os.getenv calls; parses Docker Compose services, profiles, volumes, and env passthroughs; verifies feature flags, CLI commands, and file paths referenced in documentation. Produces a structured audit report and applies fixes to keep documentation accurate and up-to-date. Invoke after any config change, env var addition/removal, Docker service modification, feature flag change, or when documentation drift is suspected." license: MIT compatibility: opencode metadata: author: https://github.com/agessaman version: "0.1.0" domain: quality - triggers: documentation sync, docs audit, env vars, config drift, .env.example, README, AGENTS.md, UPGRADING.md, SCHEMAS.md, docker compose docs, feature flags, documentation update, keep docs in sync, documentation accuracy + triggers: documentation sync, docs audit, env vars, config drift, .env.example, README, AGENTS.md, docs/upgrading.md, SCHEMAS.md, docker compose docs, feature flags, documentation update, keep docs in sync, documentation accuracy role: specialist scope: review output-format: report @@ -37,7 +37,8 @@ The following files are the documentation targets. All must be kept in sync: |------|------| | `README.md` | User-facing reference: env var tables, Docker instructions, feature list | | `AGENTS.md` | AI agent instructions: env var list, project structure, conventions | -| `UPGRADING.md` | Upgrade guide: deprecated vars, new vars, migration steps | +| `docs/upgrading.md` | Upgrade guide: deprecated vars, new vars, migration steps | +| `docs/letsmesh.md` | LetsMesh packet decoding: normalization, channel keys, message handling | | `.env.example` | Example environment file with comments and defaults | | `SCHEMAS.md` | Event JSON schemas and database column mappings | @@ -144,7 +145,7 @@ Load detailed guidance based on context: - Treat Python source code (`common/config.py`, CLI modules, `os.getenv` calls) as the single source of truth for environment variables - Treat `docker-compose*.yml` files as the source of truth for Docker configuration -- Check ALL five documentation files on every audit +- Check ALL primary documentation files on every audit - Include `.env.example` comment verification - Include `docker-compose*.yml` inline comment verification - Verify default values match exactly (type-aware: `true` vs `"true"`, port numbers as strings vs ints) @@ -159,8 +160,8 @@ Load detailed guidance based on context: - Add documentation for variables that don't exist in source - Remove content from documentation without confirming it's stale in source - Change the formatting style of existing documentation (match surrounding content) -- Modify UPGRADING.md historical content (deprecated var lists, old instructions) -- Skip any of the 5 documentation files +- Modify docs/upgrading.md historical content (deprecated var lists, old instructions) +- Skip any of the primary documentation files - Guess at defaults — always verify against actual source code - Treat test compose files (`tests/e2e/`) as documentation targets (they are test fixtures) diff --git a/.agents/skills/docs-sync/references/documentation-checklist.md b/.agents/skills/docs-sync/references/documentation-checklist.md index 3b9f236..3a4a824 100644 --- a/.agents/skills/docs-sync/references/documentation-checklist.md +++ b/.agents/skills/docs-sync/references/documentation-checklist.md @@ -96,13 +96,14 @@ AGENTS.md has a "Key variables" subsection under "Environment Variables". Verify - [ ] References to `PLAN.md` — should be removed (file deleted) - [ ] References to `TASKS.md` — should be removed (file deleted) - [ ] References to `SCHEMAS.md` — should remain (file exists) -- [ ] References to `UPGRADING.md` — should remain (file exists) +- [ ] References to `docs/upgrading.md` — should remain (file exists) +- [ ] References to `docs/letsmesh.md` — should remain (file exists) -## 3. UPGRADING.md +## 3. docs/upgrading.md ### Deprecated Variables -UPGRADING.md lists variables to remove during upgrade. Verify: +docs/upgrading.md lists variables to remove during upgrade. Verify: - [ ] Each deprecated var truly no longer exists in `config.py` or any CLI module - [ ] Removal instructions are clear @@ -131,6 +132,20 @@ UPGRADING.md lists variables to remove during upgrade. Verify: - [ ] Column renames documented accurately (e.g., `receiver_node_id` → `observer_node_id`) - [ ] Table renames documented accurately (e.g., `event_receivers` → `event_observers`) +## 3b. docs/letsmesh.md + +### Packet Decoding Documentation + +docs/letsmesh.md documents the LetsMesh packet normalization and decoding behavior. Verify: + +- [ ] MQTT subscription topics match `subscriber.py` topic patterns +- [ ] Payload type mappings match `letsmesh_decoder.py` and `letsmesh_normalizer.py` logic +- [ ] Channel key handling documented matches `COLLECTOR_CHANNEL_KEYS` config behavior +- [ ] Known channel indexes (`17 -> Public`, `217 -> #test`) match built-in defaults in decoder +- [ ] Message normalization rules match collector handler implementations +- [ ] GPS/location update behavior documented matches advertisement handler logic +- [ ] No stale decoder behavior documented (e.g., references to Node.js decoder) + ## 4. .env.example ### Section Structure @@ -209,7 +224,7 @@ For each table documented in SCHEMAS.md: ## Cross-File Consistency Checks -These checks ensure all 5 files are consistent with each other: +These checks ensure all primary documentation files are consistent with each other: ### Env Var Coverage Matrix @@ -221,7 +236,7 @@ Every hub-consumed env var should appear in: | `README.md` | Yes | Table row with default + description | | `AGENTS.md` | Yes | Mentioned in env vars section | | `.env.example` | Yes | Entry with default + comment | -| `UPGRADING.md` | Only if new/renamed/deprecated | Migration instruction | +| `docs/upgrading.md` | Only if new/renamed/deprecated | Migration instruction | Every passthrough env var should appear in: @@ -240,13 +255,13 @@ Every passthrough env var should appear in: ### Stale Reference Sweep -Check all 5 files for references to removed items: +Check all primary documentation files for references to removed items: - [ ] `PLAN.md` — removed, references should be deleted from AGENTS.md - [ ] `TASKS.md` — removed, references should be deleted from AGENTS.md -- [ ] Old compose profiles (`receiver`, `sender`, `mock`) — should only exist in UPGRADING.md as deprecated -- [ ] Old service names (`interface-receiver`, `interface-sender`) — should only exist in UPGRADING.md as deprecated -- [ ] Old env var names (`COLLECTOR_LETSMESH_DECODER_*`, `SERIAL_BAUD`, etc.) — should only exist in UPGRADING.md as deprecated +- [ ] Old compose profiles (`receiver`, `sender`, `mock`) — should only exist in docs/upgrading.md as deprecated +- [ ] Old service names (`interface-receiver`, `interface-sender`) — should only exist in docs/upgrading.md as deprecated +- [ ] Old env var names (`COLLECTOR_LETSMESH_DECODER_*`, `SERIAL_BAUD`, etc.) — should only exist in docs/upgrading.md as deprecated ## Applying Fixes @@ -256,5 +271,5 @@ When discrepancies are found: 2. **Determine scope** — which files need updating 3. **Make minimal edits** — only change what's wrong, preserve surrounding formatting 4. **Match existing style** — tables use same column order, comments use same format, sections use same headers -5. **Preserve historical content** — UPGRADING.md deprecated var lists are historical, do not remove them +5. **Preserve historical content** — docs/upgrading.md deprecated var lists are historical, do not remove them 6. **Verify after editing** — re-read the changed section to confirm accuracy diff --git a/AGENTS.md b/AGENTS.md index 3346229..42bad17 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,7 @@ This document provides context and guidelines for AI coding assistants working o - `source .venv/bin/activate` * You MUST install all project dependencies using `pip install -e ".[dev]"` command` * You MUST install `pre-commit` for quality checks -* You MUST keep project documentation in sync with behavior/config/schema changes made in code (at minimum update relevant sections in `README.md`, `SCHEMAS.md`, and/or `UPGRADING.md` when applicable) +* You MUST keep project documentation in sync with behavior/config/schema changes made in code (at minimum update relevant sections in `README.md`, `SCHEMAS.md`, `docs/upgrading.md`, `docs/letsmesh.md` when applicable) * Before commiting: - Run **targeted tests** for the components you changed, not the full suite: - `pytest tests/test_web/` for web-only changes (templates, static JS, web routes) @@ -37,7 +37,8 @@ MeshCore Hub is a Python 3.14+ monorepo for managing and orchestrating MeshCore ## Key Documentation - [SCHEMAS.md](SCHEMAS.md) - MeshCore event JSON schemas and database mappings -- [UPGRADING.md](UPGRADING.md) - Upgrade guide for breaking changes +- [docs/upgrading.md](docs/upgrading.md) - Upgrade guide for breaking changes +- [docs/letsmesh.md](docs/letsmesh.md) - LetsMesh packet decoding details ## Technology Stack @@ -335,6 +336,10 @@ meshcore-hub/ ├── docker-compose.dev.yml # Development overrides (port mappings) ├── docker-compose.prod.yml # Production overrides (proxy network) ├── docker-compose.traefik.yml # Optional Traefik labels +├── docs/ # Documentation +│ ├── images/ # Screenshots and images +│ ├── letsmesh.md # LetsMesh packet decoding details +│ └── upgrading.md # Upgrade guide for breaking changes └── SCHEMAS.md ``` diff --git a/README.md b/README.md index 086e540..c2ca998 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Python 3.14+ platform for managing and orchestrating MeshCore mesh networks. > [!WARNING] -> **BREAKING CHANGES** - The latest release replaces Mosquitto with a JWT-based MQTT broker, removes the proprietary receiver service in favor of [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture), and renames `receiver_node_id` to `observer_node_id` in the database. If upgrading from a previous version, see [UPGRADING.md](UPGRADING.md) for migration steps. +> **BREAKING CHANGES** - The latest release replaces Mosquitto with a JWT-based MQTT broker, removes the proprietary receiver service in favor of [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture), and renames `receiver_node_id` to `observer_node_id` in the database. If upgrading from a previous version, see [docs/upgrading.md](docs/upgrading.md) for migration steps. ![MeshCore Hub Web Dashboard](docs/images/web.png) @@ -354,31 +354,7 @@ All components are configured via environment variables. Create a `.env` file or #### LetsMesh Packet Decoding -The collector subscribes to packets published by [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture): - -- `/+/+/packets` -- `/+/+/status` -- `/+/+/internal` - -Normalization behavior: - -- `status` packets are stored as informational `letsmesh_status` events and are not mapped to `advertisement` rows. -- Decoder payload type `4` is mapped to `advertisement` when node identity metadata is present. -- Decoder payload type `11` (control discover response) is mapped to `contact`. -- Decoder payload type `9` is mapped to `trace_data`. -- Decoder payload type `8` is mapped to informational `path_updated` events. -- Decoder payload type `1` can map to native response events (`telemetry_response`, `battery`, `path_updated`, `status_response`) when decrypted structured content is available. -- `packet_type=5` packets are mapped to `channel_msg_recv`. -- `packet_type=1`, `2`, and `7` packets are mapped to `contact_msg_recv` when decryptable text is available. -- For channel packets, if a channel key is available, a channel label is attached (for example `Public` or `#test`) for UI display. -- In the messages feed and dashboard channel sections, known channel indexes are preferred for labels (`17 -> Public`, `217 -> #test`) to avoid stale channel-name mismatches. -- Additional channel names are loaded from `COLLECTOR_CHANNEL_KEYS` when entries are provided as `label=hex` (for example `bot=`). -- Decoder-advertisement packets with location metadata update node GPS (`lat/lon`) for map display. -- This keeps advertisement listings focused on node advert traffic only, not observer status telemetry. -- Packets without decryptable message text are kept as informational `letsmesh_packet` events and are not shown in the messages feed; when decode succeeds the decoded JSON is attached to those packet log events. -- When decoder output includes a human sender (`payload.decoded.decrypted.sender`), message text is normalized to `Name: Message` before storage; receiver/observer names are never used as sender fallback. -- The collector keeps built-in keys for `Public` and `#test`, and merges any additional keys from `COLLECTOR_CHANNEL_KEYS`. -- Docker runtime uses the native Python `meshcoredecoder` library (no external Node.js dependency). +For details on how the collector normalizes and decodes LetsMesh packets, see [docs/letsmesh.md](docs/letsmesh.md). ### Webhooks @@ -822,15 +798,19 @@ meshcore-hub/ ├── docker-compose.dev.yml # Development overrides (port mappings) ├── docker-compose.prod.yml # Production overrides (proxy network) ├── docker-compose.traefik.yml # Optional Traefik labels -├── SCHEMAS.md # Event schema documentation -├── UPGRADING.md # Upgrade guide for breaking changes -└── AGENTS.md # AI assistant guidelines +├── docs/ # Documentation +│ ├── images/ # Screenshots and images +│ ├── letsmesh.md # LetsMesh packet decoding details +│ └── upgrading.md # Upgrade guide for breaking changes +├── SCHEMAS.md # Event schema documentation +└── AGENTS.md # AI assistant guidelines ``` ## Documentation - [SCHEMAS.md](SCHEMAS.md) - MeshCore event schemas -- [UPGRADING.md](UPGRADING.md) - Upgrade guide for breaking changes +- [docs/upgrading.md](docs/upgrading.md) - Upgrade guide for breaking changes +- [docs/letsmesh.md](docs/letsmesh.md) - LetsMesh packet decoding details - [AGENTS.md](AGENTS.md) - Guidelines for AI coding assistants ## Contributing diff --git a/docs/letsmesh.md b/docs/letsmesh.md new file mode 100644 index 0000000..d08e5ae --- /dev/null +++ b/docs/letsmesh.md @@ -0,0 +1,36 @@ +# LetsMesh Packet Decoding + +The collector subscribes to packets published by [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture): + +- `/+/+/packets` +- `/+/+/status` +- `/+/+/internal` + +## Normalization Behavior + +- `status` packets are stored as informational `letsmesh_status` events and are not mapped to `advertisement` rows. +- Decoder payload type `4` is mapped to `advertisement` when node identity metadata is present. +- Decoder payload type `11` (control discover response) is mapped to `contact`. +- Decoder payload type `9` is mapped to `trace_data`. +- Decoder payload type `8` is mapped to informational `path_updated` events. +- Decoder payload type `1` can map to native response events (`telemetry_response`, `battery`, `path_updated`, `status_response`) when decrypted structured content is available. +- `packet_type=5` packets are mapped to `channel_msg_recv`. +- `packet_type=1`, `2`, and `7` packets are mapped to `contact_msg_recv` when decryptable text is available. + +## Channel Keys + +- For channel packets, if a channel key is available, a channel label is attached (for example `Public` or `#test`) for UI display. +- In the messages feed and dashboard channel sections, known channel indexes are preferred for labels (`17 -> Public`, `217 -> #test`) to avoid stale channel-name mismatches. +- Additional channel names are loaded from `COLLECTOR_CHANNEL_KEYS` when entries are provided as `label=hex` (for example `bot=`). +- The collector keeps built-in keys for `Public` and `#test`, and merges any additional keys from `COLLECTOR_CHANNEL_KEYS`. + +## Location and Messages + +- Decoder-advertisement packets with location metadata update node GPS (`lat/lon`) for map display. +- This keeps advertisement listings focused on node advert traffic only, not observer status telemetry. +- Packets without decryptable message text are kept as informational `letsmesh_packet` events and are not shown in the messages feed; when decode succeeds the decoded JSON is attached to those packet log events. +- When decoder output includes a human sender (`payload.decoded.decrypted.sender`), message text is normalized to `Name: Message` before storage; receiver/observer names are never used as sender fallback. + +## Decoder Runtime + +- Docker runtime uses the native Python `meshcoredecoder` library (no external Node.js dependency). diff --git a/UPGRADING.md b/docs/upgrading.md similarity index 92% rename from UPGRADING.md rename to docs/upgrading.md index 1ca2388..b08e74a 100644 --- a/UPGRADING.md +++ b/docs/upgrading.md @@ -1,8 +1,12 @@ # Upgrading MeshCore Hub -This guide covers upgrading from a previous MeshCore Hub release to the current version. The latest release includes **breaking changes** to the MQTT broker, packet capture service, and data ingestion pipeline. +This guide covers upgrading from a previous MeshCore Hub release to the current version. Check the relevant version section below before upgrading. -## Overview of Changes +## v0.9.0 + +This release includes **breaking changes** to the MQTT broker, packet capture service, and data ingestion pipeline. + +### Overview of Changes | Area | Before | After | |------|--------|-------| @@ -20,7 +24,7 @@ This guide covers upgrading from a previous MeshCore Hub release to the current | Container names | `meshcore-*` | Parameterized via `COMPOSE_PROJECT_NAME` (default: `hub-*`) | | Volume names | `meshcore_*` | Parameterized via `COMPOSE_PROJECT_NAME` (default: `hub_*`) | -## Step 1: Backup +### Step 1: Backup **Do not skip this step.** Back up all data volumes before proceeding. @@ -40,7 +44,7 @@ docker run --rm -v meshcore_hub_data:/data -v $(pwd)/backup:/backup \ alpine sh -c "cd / && tar xzf /backup/meshcore_hub_data-YYYYMMDD-HHMMSS.tar.gz" ``` -## Step 2: Stop and Remove Containers +### Step 2: Stop and Remove Containers Stop all services and remove orphaned containers from the old configuration: @@ -50,7 +54,7 @@ docker compose --profile all down --remove-orphans > **Important:** Do NOT use `--volumes` / `-v`. That would delete your database. The `--remove-orphans` flag cleans up old services (like `interface-receiver`, `interface-sender`) that no longer exist in the new compose file. -## Step 3: Rename Docker Volumes +### Step 3: Rename Docker Volumes Container and volume names are now parameterized via `COMPOSE_PROJECT_NAME`. The default is `hub`, so volumes are renamed from `meshcore_*` to `hub_*`. @@ -60,7 +64,7 @@ First, check which volumes you have: docker volume ls | grep meshcore ``` -### Volumes to migrate +#### Volumes to migrate These volumes always need migrating: @@ -70,7 +74,7 @@ These volumes always need migrating: > **Note:** `observer_data` and `mqtt_data` are new — they are created automatically on first run and do not need migrating. -### Option A: Rename (Docker Engine 23.0+) +#### Option A: Rename (Docker Engine 23.0+) > **Note:** `docker volume rename` is not available in all Docker builds (e.g., Docker Desktop). If the command is not found, use Option B instead. @@ -78,7 +82,7 @@ These volumes always need migrating: docker volume rename meshcore_hub_data hub_data ``` -### Option B: Copy (all Docker versions) +#### Option B: Copy (all Docker versions) If `docker volume rename` is not available in your Docker build: @@ -97,7 +101,7 @@ docker volume rm meshcore_hub_data > **Note:** After migrating volumes, you may see warnings like `volume "hub_data" already exists but was not created by Docker Compose. Use \`external: true\` to use an existing volume`. This is safe to ignore — it appears because the volumes were created manually during migration rather than by Docker Compose. Fresh deployments will not see this warning. -## Step 4: Update Configuration Files +### Step 4: Update Configuration Files Download the latest configuration files: @@ -113,9 +117,9 @@ wget -O .env.example https://raw.githubusercontent.com/ipnet-mesh/meshcore-hub/m Then compare your existing `.env` against the new `.env.example` and update it (see Step 5). -## Step 5: Migrate Your `.env` File +### Step 5: Migrate Your `.env` File -### Variables to Remove +#### Variables to Remove These variables no longer exist and should be removed from your `.env`: @@ -148,7 +152,7 @@ MQTT_EXTERNAL_PORT=1883 MQTT_WS_PORT=9001 ``` -### Variables to Update +#### Variables to Update | Variable | Old Value | New Value | Notes | |----------|-----------|-----------|-------| @@ -159,7 +163,7 @@ MQTT_WS_PORT=9001 > **Note:** The Python-level defaults for `MQTT_TRANSPORT` and `MQTT_WS_PATH` are now `websockets` and `/`, matching the Docker Compose and `.env.example` values. No additional configuration is needed for non-Docker users. -### Variables to Add +#### Variables to Add ```bash # Docker Compose project name (container and volume prefix) @@ -177,7 +181,7 @@ PACKETCAPTURE_IATA=LOC All other `PACKETCAPTURE_*` variables have sensible defaults in `docker-compose.yml` and only need to be set in `.env` if you want to override them. See `.env.example` for the full list. -## Step 6: Run Database Migration +### Step 6: Run Database Migration The migration renames `receiver_node_id` → `observer_node_id` across all event tables, `event_receivers` → `event_observers`, and `received_at` → `observed_at` in the event observers table: @@ -191,9 +195,9 @@ This runs automatically as part of the `core` profile, but can also be run stand docker compose -f docker-compose.yml -f docker-compose.dev.yml --profile migrate run --rm migrate ``` -## Step 7: Start Services +### Step 7: Start Services -### With local MQTT broker (single-host deployment) +#### With local MQTT broker (single-host deployment) ```bash # Start everything including the MQTT broker @@ -203,14 +207,14 @@ docker compose -f docker-compose.yml -f docker-compose.dev.yml --profile mqtt -- docker compose -f docker-compose.yml -f docker-compose.dev.yml --profile mqtt --profile core --profile observer up -d ``` -### With external MQTT broker +#### With external MQTT broker ```bash # Start core services only (broker runs elsewhere) docker compose -f docker-compose.yml -f docker-compose.dev.yml --profile core up -d ``` -### Verify +#### Verify ```bash # Check all containers are running @@ -223,16 +227,16 @@ docker compose -f docker-compose.yml -f docker-compose.dev.yml --profile all log open http://localhost:8080 ``` -## Notes +### Notes -### JWT-Based Packet Capture Authentication +#### JWT-Based Packet Capture Authentication The new packet capture service ([meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture)) uses the LetsMesh Observer model: - **No custom MQTT credentials needed for publishing.** Authentication is handled via JWT tokens signed by the capture device's hardware public key. The MQTT broker validates the JWT and authorizes publishing automatically. - The collector connects as a **subscriber** to read all published events, including `/internal` topics. Configure `MQTT_USERNAME` and `MQTT_PASSWORD` to match the broker's subscriber account. -### Production MQTT Configuration +#### Production MQTT Configuration In production, the MQTT WebSocket server should be hosted behind a TLS/SSL-terminated reverse proxy (e.g., Nginx Proxy Manager, Caddy, Traefik) under the `/mqtt` path. The proxy handles TLS termination and forwards plain WebSocket connections to the broker on port 1883. @@ -254,7 +258,7 @@ MQTT_TLS=true MQTT_TOKEN_AUDIENCE=mqtt.example.com # your public domain ``` -### Existing LetsMesh Observer Installs +#### Existing LetsMesh Observer Installs If you already run [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture) separately, configure **MQTT server #3** to point at your MeshCore Hub MQTT broker. Servers #1 and #2 are reserved for Let's Mesh US (`mqtt-us-v1.letsmesh.net`) and Let's Mesh EU (`mqtt-eu-v1.letsmesh.net`) respectively. @@ -269,7 +273,7 @@ PACKETCAPTURE_MQTT3_USE_AUTH_TOKEN=true PACKETCAPTURE_MQTT3_TOKEN_AUDIENCE=mqtt.localhost ``` -### Removed Services +#### Removed Services The following Docker Compose services have been removed: @@ -281,7 +285,7 @@ The following Docker Compose services have been removed: The `observer` service uses the [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture) image and is included in `docker-compose.yml` under the `observer` profile for an easy transition. -### New Docker Compose File Structure +#### New Docker Compose File Structure The Docker Compose configuration is now split into multiple files: @@ -307,7 +311,7 @@ docker compose -f docker-compose.yml -f docker-compose.prod.yml -f docker-compos Container and volume names are parameterized via `COMPOSE_PROJECT_NAME` in `.env`. This enables multiple instances (e.g., `hub-prod`, `hub-beta`) on the same Docker host. -### Removed API Endpoints +#### Removed API Endpoints The command dispatch API endpoints have been removed: @@ -315,7 +319,7 @@ The command dispatch API endpoints have been removed: - `POST /api/v1/commands/send-channel-message` - `POST /api/v1/commands/send-advertisement` -### Native Python Decoder +#### Native Python Decoder The Node.js `meshcore-decoder` CLI tool has been replaced by the native Python `meshcoredecoder` library. This means: