Implemented new "Discover Nodes" feature in Network Commands menu:
- Added .node_discover command to meshcli wrapper (cli.py)
- Created interactive modal with sortable table showing nearby repeaters
- Displays SNR, RSSI, path length, and signal quality indicators
- Added refresh functionality to rescan for nodes
Fixed advert notification to show clean "Advert sent" message
instead of full meshcli output.
Technical changes:
- app/meshcore/cli.py: Added node_discover() function with JSON parsing
- app/routes/api.py: Updated SPECIAL_COMMANDS and execute_special_command()
to handle node_discover return type and clean advert message
- app/templates/base.html: Added "Discover Nodes" menu button and modal
- app/static/js/app.js: Added discoverNodes() and displayNodeDiscoveryResults()
- README.md: Added documentation for Discover Nodes feature
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed viewport fix approach to be less invasive:
- Removed document.body.style.height modification
- Use document.documentElement.offsetHeight instead
- Trigger resize event instead of modifying DOM
- Increased delay from 100ms to 150ms for better stability
This should prevent potential conflicts with channel loading and
other page initialization code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Two critical fixes:
1. DM Badge Sync Issue:
- After closing DM modal, badge showed correct count for 10 seconds
- Then auto-refresh (running every 10s) used stale dmLastSeenTimestamps
- Solution: Call loadDmLastSeenTimestampsFromServer() before updating badge
- This ensures app.js auto-refresh uses current server state
2. Android PWA Viewport Corruption:
- Viewport corrupted on F5 refresh in Android PWA mode
- Status bar content hidden under system UI
- Solution: Force viewport recalculation on page load
- Scrolls to top and forces reflow after 100ms delay
Testing needed on Android PWA to verify both fixes work correctly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implement modal dialogs to resolve PWA viewport corruption issues on Android.
When navigating between pages using window.location.href, the viewport height
calculation becomes corrupted, causing the status bar to be hidden under system UI.
Changes:
- Add fullscreen modals for Direct Messages and Contact Management in index.html
- Configure FAB buttons to open modals instead of navigating to new pages
- Add JavaScript to reload iframe content when modals are opened (ensures fresh data)
- Remove DM and Contact Management from offcanvas menu to avoid duplication
- Both modals use iframes to embed existing /dm and /contacts/manage pages
- Modal headers styled with appropriate colors (green for DM, blue for Contacts)
This approach bypasses the viewport corruption issue since modals don't trigger
the problematic navigation flow that occurs with page changes in PWA mode.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Root cause: Bootstrap offcanvas leaves backdrop/body classes in DOM
when navigating via window.location.href, causing viewport issues.
Changes:
- Remove hamburger menu button from DM navbar (caused overflow)
- Reduce menu button icon size on channels (remove font-size override)
- Add global navigateTo() function in app.js and contacts.js
- Function closes offcanvas, removes backdrops, clears body classes
- Replace all window.location.href calls with navigateTo()
- Updated navigation in: base.html, contacts*.html templates
- Add 100ms delay before navigation to ensure cleanup completes
This fixes the issue where:
1. Opening offcanvas menu on main page
2. Navigating to DM or Contact Management
3. Returning to main page
Results in corrupted viewport with hidden status bar
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implemented comprehensive message content enhancements for both channel messages and DMs:
- **Mention badges**: @[Username] mentions now display as styled badges similar to Android Meshcore app
- **Clickable URLs**: http:// and https:// URLs are automatically converted to clickable links that open in new tabs
- **Image thumbnails**: URLs ending in .jpg, .jpeg, .png, .gif, .webp display as thumbnails with click-to-expand modal preview
- **Mobile responsive**: Image thumbnails adapt size for mobile screens
- **Security**: Proper XSS protection with HTML escaping and attribute sanitization
Technical implementation:
- Created shared message-utils.js module for content processing
- Added CSS styles for badges, links, images, and modal preview
- Updated both app.js and dm.js to use new content processor
- Used event delegation for image click handlers to support dynamic content
- Responsive design with mobile-optimized image sizes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Move toast container from bottom-right to top-left corner
- Reduce notification display time from 3-5s to 1.5s
- Prevents notifications from blocking message input area
- Applied consistently across all pages (main, DM, contacts)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Change DM menu link from <a> to <button> with onclick for better
mobile compatibility (fixes link not working on some devices)
- Use identical HTML structure as index.html for proper layout
- Remove conflicting inline styles that caused viewport overflow
- Rely on existing style.css rules for body/main flexbox layout
🤖 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>
Add new menu section "Network Commands" with two special commands:
- Send Advert: sends single advertisement (recommended for normal use)
- Flood Advert: floods network with advertisement (for recovery only)
Changes:
- cli.py: Add advert() and floodadv() functions
- api.py: Add POST /api/device/command and GET /api/device/commands endpoints
- base.html: Add Network Commands section to slide-out menu
- app.js: Add JavaScript handlers with confirmation for floodadv
- README.md: Document new Network Commands feature
🤖 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>
- Change message byte limit from 200 to 140 bytes
- Remove keyboard hint text to save space
- Simplify navbar to show only notification bell and channel selector
- Add slide-out offcanvas menu for less-used options:
* Refresh Messages
* Manage Channels
* Message History (archive selector)
* Settings
- Increase font sizes in dropdowns and menu for better readability
- Add icons and text labels to all menu items
- Auto-close menu after selecting options
- Update clipboard API to modern navigator.clipboard with fallback
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replaces the blind 60-second refresh with a smart polling system that only updates the UI when new messages actually arrive.
Key improvements:
- Lightweight update checks every 10 seconds (vs full refresh every 60s)
- Chat view refreshes only when new messages appear on active channel
- Notification bell with global unread count across all channels
- Per-channel unread badges in channel selector (e.g., "Malopolska (3)")
- Last-seen timestamp tracking per channel with localStorage persistence
- Bell ring animation when new messages arrive
Backend changes:
- New /api/messages/updates endpoint for efficient update polling
- Returns per-channel update status and unread counts
Frontend changes:
- Smart auto-refresh mechanism with conditional UI updates
- Unread message tracking system with localStorage
- Notification bell UI component with badge
- Channel selector badges for unread messages
- CSS animations for bell ring effect
This dramatically reduces network traffic and server load while providing better UX through instant notifications about activity on other channels.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Improve UI layout on mobile devices (screens < 768px):
Navbar optimizations:
- Hide "Refresh" text on mobile, show only icon to save space
- Reduce gap between navbar elements (0.25rem instead of 0.5rem)
- Decrease min-width for channel/date selectors (80px vs 120px/150px)
- Smaller font-size (0.75rem) and padding for select elements
- Compact button sizes (0.25rem padding)
Modal optimizations:
- Reduce modal margins (0.5rem) for better mobile fit
- Smaller modal-body padding (0.75rem)
- Compact channel keys with smaller font (0.65rem) and word-break
- Reduce list-group-item padding (0.5rem)
- Stack "Add New" and "Join Existing" buttons vertically on very small screens (<400px)
Files changed:
- app/static/css/style.css: Added mobile-specific CSS rules in @media query
- app/templates/base.html: Wrapped "Refresh" text in <span class="btn-text">
Testing: Verified on mobile viewport (iPhone, Android simulators)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added favicon support with multiple sizes for different platforms (16x16, 32x32, 180x180 for Apple, 192x192 and 512x512 for Android). Includes PWA manifest.json for standalone app display with Bootstrap primary theme color.
🤖 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>
Fixed mobile browser viewport height issues where status bar and hint text were hidden:
CSS changes:
- Use 'height: 100dvh' (dynamic viewport height) for mobile browsers
- Fallback to '100vh' for older browsers
- Added 'min-height: 0' to main flex container (critical for flex children)
HTML changes:
- Added 'viewport-fit=cover' to meta tag (notched displays)
- Improved flexbox structure in index.html
- Added inline 'min-height: 0' on flex-grow-1 row (prevents overflow)
The 'dvh' unit dynamically adjusts to browser chrome (URL bar) visibility,
preventing layout shifts when scrolling on mobile. The min-height: 0 fix
ensures flex children properly shrink when needed.
This should fix the issue where bottom status bar disappears on mobile
and top navbar disappears after sending a message.
🤖 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>