Extracted dedup_retry_messages() helper (300s window, was 120s which
was too tight) and applied it in three places:
- GET /api/dm/messages - already had inline dedup, now uses helper
- get_dm_conversations() - fixes last_message_timestamp inflation
- GET /api/dm/updates - was missing dedup entirely, counted retries
as unread messages (root cause of persistent unread markers)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Monitor: For .msg commands, keep waiting for expected_ack in response
instead of completing on silence timeout. Waits up to half of cmd_timeout
(5s) for the JSON to arrive before giving up.
Unread: Apply 120s time-window dedup to outgoing messages in conversation
listing, so retry messages don't inflate last_message_timestamp and cause
permanent unread markers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The parser's .strip() was removing trailing whitespace from message
text, but the encrypted radio payload includes those trailing spaces.
This caused pkt_payload mismatches for messages ending with spaces
(e.g., "Dzień dobry "). Use original unstripped text for raw_text.
Also add debug logging for unmatched messages to help diagnose
remaining edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace unreliable timestamp-based heuristic (±10s window) with exact
cryptographic matching for incoming channel message routes. Compute
pkt_payload by reconstructing the AES-128-ECB encrypted packet from
message data (sender_timestamp, txt_type, text) + channel secret, then
match against echo data by exact key lookup.
Also accumulate ALL route paths per message (previously only last path
was kept due to dict overwrite), and display them in a multi-path popup
showing SNR and hops for each route.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bridge captures ACK packets from meshcli stdout (json_log_rx),
persists to .acks.jsonl, and exposes /ack_status endpoint.
Delivery status is merged server-side into DM messages and
displayed as a green checkmark with SNR/route tooltip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bridge now detects device name from meshcli prompt ("DeviceName|*")
and exposes it via /health endpoint. mc-webui fetches this at startup
and uses RuntimeConfig for dynamic device name throughout the app.
Fallback chain: prompt detection → .infos command → MC_DEVICE_NAME env var
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix channel message sender name display. In meshcore-cli 1.3.12, the 'name'
field in SENT_CHAN entries now contains the channel name instead of the
sender's device name. Update parser to use the 'sender' field instead.
Before: Sent messages showed "channel 0" as sender
After: Sent messages correctly show "MarWoj" (actual sender name)
This change is consistent with the SENT_MSG parsing for Direct Messages.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove workaround for meshcore-cli 1.3.11 bug where SENT_MSG contained
sender name instead of recipient. Now using native SENT_MSG entries from
.msgs file with correct recipient and sender fields (requires meshcore-cli >= 1.3.12).
Changes:
- Add _parse_sent_msg() to parse SENT_MSG from .msgs file
- Update read_dm_messages() to process both PRIV and SENT_MSG from .msgs
- Remove save_sent_dm(), _read_sent_dm_log(), _parse_sent_dm_entry()
- Remove dm_sent_log_path property from config
- Add _cleanup_old_dm_sent_log() to remove obsolete log file
- Update comments and documentation
Benefits:
- Single source of truth (.msgs file only)
- Simpler codebase (-95 lines)
- No custom workarounds
- Better data consistency
Related: meshcore-cli update to 1.3.12 (commit ad4a7b3)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Fix duplicate conversations in dropdown by merging pk_ and name_ IDs
- Add intelligent refresh (only reload when new messages arrive)
- Fix message alignment (own messages right, others left)
- Change sent message status from 'timeout' to 'pending'
- Add emoji picker button to DM page
- Change message limit from 200 to 140 bytes (consistent with channels)
- Update README.md with corrected DM documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace DM modal with full-page view at /dm route for better mobile UX
- Add workaround for meshcore-cli bug where SENT_MSG contains sender's
name instead of recipient - now saving sent DMs to separate log file
- Fix DM button styling to match Reply button (btn-outline-secondary)
- Add dm.js for DM page functionality
- Add dm.html template with green navbar for visual distinction
- Update menu link to navigate to /dm instead of opening modal
- Remove unused DM modal functions from app.js
- Update documentation with new DM workflow
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Parse PRIV (incoming) and SENT_MSG (outgoing) message types
- Add DM API endpoints: conversations, messages, updates
- Implement conversation grouping by pubkey_prefix or name
- Add timeout-based delivery status (pending → timeout)
- Add DM modal with conversation list and thread views
- Add dual notification badge (blue=channels, green=DM)
- Add DM button next to Reply on channel messages
- Include message deduplication for both incoming and outgoing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Allow joining public channels (starting with #) without encryption key
- Frontend: Make key field optional with validation for # channels
- Backend: Update API to accept optional key parameter
- CLI wrapper: Build meshcli command dynamically based on key presence
- Implement automatic message cleanup when deleting channels
- Add delete_channel_messages() function to remove channel history
- Integrate cleanup into DELETE /api/channels endpoint
- Prevents message leakage when reusing channel slots
- Update documentation with new features and usage instructions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements automatic daily archiving of messages to improve performance
and enable browsing historical chat by date.
Backend changes:
- Add APScheduler for daily archiving at midnight (00:00 UTC)
- Create app/archiver/manager.py with archive logic and scheduler
- Extend parser.py to read from archive files and filter by days
- Add archive configuration to config.py (MC_ARCHIVE_*)
API changes:
- Extend GET /api/messages with archive_date and days parameters
- Add GET /api/archives endpoint to list available archives
- Add POST /api/archive/trigger for manual archiving
Frontend changes:
- Add date selector dropdown in navbar for archive browsing
- Implement archive list loading and date selection
- Update formatTime() to show full dates in archive view
- Live view now shows only last 7 days (configurable)
Docker & Config:
- Add archive volume mount in docker-compose.yml
- Add MC_ARCHIVE_DIR, MC_ARCHIVE_ENABLED, MC_ARCHIVE_RETENTION_DAYS env vars
- Update .env.example with archive configuration section
Documentation:
- Update README.md with archive feature and usage instructions
- Update .claude/instructions.md with archive endpoints
Key features:
- Automatic daily archiving (midnight UTC)
- Live view filtered to last 7 days for better performance
- Browse historical messages by date via dropdown selector
- Archives stored as dated files: {device}.YYYY-MM-DD.msgs
- Original .msgs file never modified (safe, read-only approach)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implemented core backend functionality:
- Flask application structure with blueprints
- Configuration module loading from environment variables
- MeshCore CLI wrapper with subprocess execution and timeout handling
- Message parser for .msgs JSON Lines file format
- REST API endpoints (messages, status, sync, contacts cleanup)
- HTML views with Bootstrap 5 responsive design
- Frontend JavaScript with auto-refresh and live updates
- Custom CSS styling for chat interface
API Endpoints:
- GET /api/messages - List messages with pagination
- POST /api/messages - Send message with optional reply-to
- GET /api/status - Device connection status
- POST /api/sync - Trigger message sync
- POST /api/contacts/cleanup - Remove inactive contacts
- GET /api/device/info - Device information
Features:
- Auto-refresh every 60s (configurable)
- Reply to messages with @[UserName] format
- Toast notifications for feedback
- Settings modal for contact management
- Responsive design (mobile-friendly)
- Message bubbles with sender, timestamp, SNR, hop count
Ready for testing on production server (192.168.131.80:5000)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>