fix(config): persist & surface local node isUnmessagable/isLicensed (#3684)#3688
Conversation
…3684) The Config tab "Unmessageable" checkbox always rendered unchecked for the local node because User.is_unmessagable / is_licensed were never ingested or persisted — the /admin/get-owner local branch hardcoded both to false. Bug 1 (data plumbing) end to end: - Schema: add isUnmessagable/isLicensed boolean columns to the nodes table for all three backends (SQLite 0/1, PG/MySQL boolean). - Migration 101 (add_node_unmessagable): idempotent ALTER for SQLite/PG/MySQL, both columns default false/0. Registered + count test bumped 100->101. - Repository: upsertNode now reads/writes both columns on the insert, upsert, and update paths; getNode already selects all columns so they round-trip. DbNode types (src/db/types.ts, src/services/database.ts, src/types/device.ts) gain the two fields. - Ingest: meshtasticManager NodeInfo handler stores nodeData.isUnmessagable/isLicensed (?? false) from nodeInfo.user. - localNodeInfo: the in-memory local node cache now carries both flags and is updated from the local NodeInfo, so getCurrentConfig().localNodeInfo (read by ConfigurationTab) reflects the real setting. - get-owner: the local-node branch returns the persisted DB values instead of hardcoded false, guarded for when nodeNum is absent. - Tests: nodes repository round-trip test for both flags (insert default, stored true, update path); DDL for PG/MySQL test backends extended. Bug 2 (map indicator) is intentionally deferred. Full vitest suite: 14680 passed, 0 failed. tsc: no new errors in touched files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VBLhGGNh35oMwTL53va1Y5
|
Claude finished @Yeraze's task —— View job PR Review: fix(config): persist & surface local node isUnmessagable/isLicensed (#3684)
SummaryThis is a well-structured, minimal-footprint fix that follows existing codebase patterns closely. The root cause diagnosis is correct: the local-node branch of ObservationsSchema & Migration ( Schema changes are consistent across all three backends (SQLite Repository ( Fields are correctly added to all three paths (update, insert, upsert conflict-set). The update path uses Minor observation: Ingest ( Both the initial NodeInfo processing path and the local-node update path now populate the flags. The PR correctly moves the get-owner ( The local-node branch now queries the DB for the persisted flags instead of hardcoding Types ( All three type definitions are updated consistently. No breaking changes to existing fields. Test coverage ( The repository test covers the three key scenarios for the new columns: default-false on insert, stored-true round-trip, and update path. The migration count test is properly bumped to 101. PG and MySQL DDL strings in the test include the new columns. Issues to Consider
VerdictLGTM. The fix is correct, well-scoped, and follows codebase conventions throughout. The |
Summary
Closes #3684 (and resolves the duplicate #3683). Fixes Bug 1: the Configuration tab's Unmessageable checkbox always rendered unchecked for the local node, because the flag was never ingested or persisted and
/admin/get-owner's local branch hardcoded it tofalse. (Bug 2 — a map indicator for unmessageable nodes — is intentionally deferred as a separate enhancement.)The Meshtastic
Userprotobuf carriesis_unmessagable(optional bool) andis_licensed(bool), which decode toisUnmessagable/isLicensedonnodeInfo.user. These were dropped on ingest, so the frontend (already wired toconfig.localNodeInfo.isUnmessagable) had nothing to show.Changes
src/db/schema/nodes.ts): newisUnmessagable/isLicensedboolean columns across SQLite / PostgreSQL / MySQL (default false).src/server/migrations/101_add_node_unmessagable.ts): idempotent across all three backends (SQLite try/catch duplicate-column, PGIF NOT EXISTS, MySQLinformation_schema). Registered insrc/db/migrations.ts; count test bumped 100→101. (Note: the CLAUDE.md brief said "next is 100," butorigin/mainalready shipped migration 100meshcore_channel_scope, so this is 101.)src/db/repositories/nodes.ts): read/write both columns on the update (preserves prior value via?? existing), insert, and upsert paths.src/server/meshtasticManager.ts): storenodeInfo.user.isUnmessagable/isLicensed ?? false; extend thelocalNodeInfotype and populate it from the local NodeInfo (outside the name-change guard, since the flag can change without a name change).src/server/server.ts): the local-node branch now returns the persisted DB values (guarded for an absent nodeNum) instead of hardcodedfalse. The remote branch already did this.DbNode(src/db/types.ts), the service-facingDbNode(src/services/database.ts), andDeviceInfo(src/types/device.ts).Testing
src/db/repositories/nodes.test.ts(default false on insert, stored true round-trips, update path) plus extended PG/MySQL DDL.tsc --noEmit: 0 errors in any touched file.Frontend
No frontend change needed —
ConfigurationTab.tsxalready readsconfig.localNodeInfo.isUnmessagable, andgetCurrentConfig()returnslocalNodeInfodirectly, so the now-populated flags surface to the checkbox.🤖 Generated with Claude Code