diff --git a/AGENTS.md b/AGENTS.md index c7b3537..0c39f32 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -380,6 +380,7 @@ All endpoints are prefixed with `/api` (e.g., `/api/health`). | POST | `/api/settings/blocked-names/toggle` | Toggle blocked name | | POST | `/api/settings/tracked-telemetry/toggle` | Toggle tracked telemetry repeater | | GET | `/api/settings/tracked-telemetry/schedule` | Current telemetry scheduling derivation and next-run-at timestamp | +| POST | `/api/settings/muted-channels/toggle` | Toggle muted status for a channel | | GET | `/api/fanout` | List all fanout configs | | POST | `/api/fanout` | Create new fanout config | | PATCH | `/api/fanout/{id}` | Update fanout config (triggers module reload) | diff --git a/app/AGENTS.md b/app/AGENTS.md index 2c64a5a..31b6d62 100644 --- a/app/AGENTS.md +++ b/app/AGENTS.md @@ -196,6 +196,7 @@ Web Push is a standalone subsystem in `app/push/`, separate from the fanout modu ### Radio - `GET /radio/config` — includes `path_hash_mode`, `path_hash_mode_supported`, advert-location on/off, and `multi_acks_enabled` - `PATCH /radio/config` — may update `path_hash_mode` (`0..2`) when firmware supports it, and `multi_acks_enabled` +- `GET /radio/private-key` — export in-memory private key as hex (requires `MESHCORE_ENABLE_LOCAL_PRIVATE_KEY_EXPORT=true`) - `PUT /radio/private-key` - `POST /radio/advertise` — manual advert send; request body may set `mode` to `flood` or `zero_hop` (defaults to `flood`) - `POST /radio/discover` — short mesh discovery sweep for nearby repeaters/sensors @@ -266,6 +267,7 @@ Web Push is a standalone subsystem in `app/push/`, separate from the fanout modu - `POST /settings/blocked-names/toggle` - `POST /settings/tracked-telemetry/toggle` - `GET /settings/tracked-telemetry/schedule` — current telemetry scheduling derivation, interval options, and next-run-at timestamp +- `POST /settings/muted-channels/toggle` ### Fanout - `GET /fanout` — list all fanout configs @@ -396,7 +398,7 @@ tests/ ├── test_message_prefix_claim.py # Message prefix claim logic ├── test_mqtt.py # MQTT publisher topic routing and lifecycle ├── test_messages_search.py # Message search, around, forward pagination -├── test_migrations.py # Schema migration system +├── test_mqtt_ha.py # MQTT HA (high-availability) behavior ├── test_packet_pipeline.py # End-to-end packet processing ├── test_packets_router.py # Packets router endpoints (decrypt, maintenance) ├── test_path_utils.py # Path hex rendering helpers @@ -415,7 +417,13 @@ tests/ ├── test_security.py # Optional Basic Auth middleware / config behavior ├── test_send_messages.py # Outgoing messages, bot triggers, concurrent sends ├── test_settings_router.py # Settings endpoints, advert validation +├── test_push_send.py # Web Push send/dispatch +├── test_radio_stats.py # Radio stats sampling and noise-floor history +├── test_repeater_telemetry.py # Repeater telemetry history recording +├── test_service_installer.py # Service installer script behavior +├── test_sqs_fanout.py # SQS fanout module ├── test_statistics.py # Statistics aggregation +├── test_telemetry_interval.py # Telemetry interval scheduling math ├── test_version_info.py # Version/build metadata resolution ├── test_websocket.py # WS manager broadcast/cleanup └── test_websocket_route.py # WS endpoint lifecycle diff --git a/app/database.py b/app/database.py index 197664e..9d0c7ae 100644 --- a/app/database.py +++ b/app/database.py @@ -42,7 +42,8 @@ CREATE TABLE IF NOT EXISTS channels ( flood_scope_override TEXT, path_hash_mode_override INTEGER, last_read_at INTEGER, - favorite INTEGER DEFAULT 0 + favorite INTEGER DEFAULT 0, + muted INTEGER DEFAULT 0 ); CREATE TABLE IF NOT EXISTS messages ( @@ -112,7 +113,10 @@ CREATE TABLE IF NOT EXISTS app_settings ( discovery_blocked_types TEXT DEFAULT '[]', tracked_telemetry_repeaters TEXT DEFAULT '[]', auto_resend_channel INTEGER DEFAULT 0, - telemetry_interval_hours INTEGER DEFAULT 8 + telemetry_interval_hours INTEGER DEFAULT 8, + vapid_private_key TEXT DEFAULT '', + vapid_public_key TEXT DEFAULT '', + push_conversations TEXT DEFAULT '[]' ); INSERT OR IGNORE INTO app_settings (id) VALUES (1); @@ -134,6 +138,18 @@ CREATE TABLE IF NOT EXISTS repeater_telemetry_history ( data TEXT NOT NULL, FOREIGN KEY (public_key) REFERENCES contacts(public_key) ON DELETE CASCADE ); + +CREATE TABLE IF NOT EXISTS push_subscriptions ( + id TEXT PRIMARY KEY, + endpoint TEXT NOT NULL, + p256dh TEXT NOT NULL, + auth TEXT NOT NULL, + label TEXT NOT NULL DEFAULT '', + created_at INTEGER NOT NULL, + last_success_at INTEGER, + failure_count INTEGER DEFAULT 0, + UNIQUE(endpoint) +); """ # Indexes are created after migrations so that legacy databases have all diff --git a/app/services/message_send.py b/app/services/message_send.py index 0789600..d5e09f5 100644 --- a/app/services/message_send.py +++ b/app/services/message_send.py @@ -862,7 +862,7 @@ async def send_channel_message_to_channel( ) ) except Exception: - pass # Never let watchdog setup failure break the send + logger.error("Echo watchdog setup failed", exc_info=True) return outgoing_message diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md index 002b849..038f59f 100644 --- a/frontend/AGENTS.md +++ b/frontend/AGENTS.md @@ -75,7 +75,6 @@ frontend/src/ ├── utils/ │ ├── urlHash.ts # Hash parsing and encoding │ ├── conversationState.ts # State keys, in-memory + localStorage helpers -│ ├── favorites.ts # LocalStorage migration for favorites │ ├── messageParser.ts # Message text → rendered segments │ ├── pathUtils.ts # Distance/validation helpers for paths + map │ ├── pubkey.ts # getContactDisplayName (12-char prefix fallback) @@ -132,6 +131,9 @@ frontend/src/ │ ├── ServerLoginStatusBanner.tsx # Shared repeater/room login state banner │ ├── ChannelInfoPane.tsx # Channel detail sheet (stats, top senders) │ ├── ChannelFloodScopeOverrideModal.tsx # Per-channel flood-scope override editor +│ ├── ChannelPathHashModeOverrideModal.tsx # Per-channel path hash mode override editor +│ ├── BulkAddChannelResultModal.tsx # Results dialog for bulk channel creation +│ ├── CommandPalette.tsx # Command palette overlay │ ├── DirectTraceIcon.tsx # Shared direct-trace glyph used in header/dashboard │ ├── NeighborsMiniMap.tsx # Leaflet mini-map for repeater neighbor locations │ ├── settings/ @@ -178,7 +180,6 @@ frontend/src/ ├── prefetch.test.ts ├── rawPacketDetailModal.test.tsx ├── rawPacketFeedView.test.tsx - ├── radioPresets.test.ts ├── rawPacketIdentity.test.ts ├── repeaterDashboard.test.tsx ├── repeaterFormatters.test.ts @@ -350,10 +351,6 @@ It falls back to a 12-char prefix when `name` is missing. Distance/validation helpers used by path + map UI. -### `utils/favorites.ts` - -LocalStorage migration helpers for favorites; canonical favorites are server-side. - ## Types and Contracts (`types.ts`) `AppSettings` currently includes: