21 KiB
PRD: mc-webui
Product Requirements Document
Version: 1.0
Date: 2025-01-21
Author: Marek / Claude AI
1. Project Overview
1.1 Project Name
mc-webui - A simple web interface for meshcore-cli
1.2 Description
mc-webui is a lightweight web application that provides convenient access to the MeshCore network without requiring terminal/SSH access. The application serves as a wrapper around meshcore-cli, offering a user-friendly interface for viewing messages, sending communications, and basic contact management.
1.3 Problem Statement
Currently, using the MeshCore network via a Heltec V4 device connected to a Debian server requires:
- SSH connection to the virtual machine
- Knowledge of meshcore-cli commands
- Manual command entry in the terminal
mc-webui eliminates these barriers by providing browser-based access from any device on the local network.
1.4 Target Users
- Single user (single-user deployment)
- Access from multiple devices (computer, tablet, phone) via web browser
- Environment: trusted local network (no authentication requirement)
1.5 Existing Solutions
| Project | Assessment | Why It Doesn't Fit |
|---|---|---|
| meshcore-hub | Feature-rich | Requires MQTT, too complex for single-user |
| MeshCore App (Flutter) | Official app | Requires BLE/WiFi, doesn't work with Serial over network |
| MeshTUI | Terminal UI | Still requires SSH |
mc-webui fills the niche of a simple, lightweight web solution for a single device.
2. Goals and Assumptions
2.1 Primary Goals (MVP)
- View messages - display chat history from the Public channel
- Send messages - publish to the Public channel
- Reply to users - using
@[UserName] contentformat - Manage contacts - clean up inactive contacts
2.2 Technical Assumptions
- Backend: Python 3.11+ with Flask
- Frontend: HTML5, Bootstrap 5, vanilla JavaScript
- Deployment: Docker / Docker Compose
- MeshCore communication: subprocess calls to
meshcli - Data source:
~/.config/meshcore/<device_name>.msgsfile - Refresh rate: automatic every 60 seconds + manual button
2.3 Design Assumptions
- Minimalism - only essential features at launch
- Simple configuration - environment variables
- Responsive design - works on phone and desktop
- No authentication - trusted local network
3. Technical Architecture
3.1 Architecture Diagram
┌─────────────────────────────────────────────────────────────────┐
│ Host (Debian VM) │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Docker Container │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Flask │◄────►│ meshcli │ │ │
│ │ │ Backend │ │ (subprocess) │ │
│ │ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Bootstrap │ │ .msgs file │ │ │
│ │ │ Frontend │ │ (mounted) │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Heltec V4 │ │
│ │ (USB Serial) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
▲
│ HTTP :5000
▼
┌─────────────────┐
│ Browser │
│ (LAN/VPN) │
└─────────────────┘
3.2 Components
3.2.1 Backend (Flask)
- HTTP server on port 5000
- REST API for frontend communication
- meshcli wrapper - command execution via subprocess
- Parser for .msgs - reading and parsing JSON Lines file
3.2.2 Frontend (Bootstrap 5)
- Chat view - message list in messenger style
- Send form - text input field + button
- Management panel - contact cleanup
- Auto-refresh - JavaScript polling every 60s
3.2.3 meshcore-cli Integration
Commands executed via subprocess:
# Fetch messages (trigger sync)
meshcli -s <SERIAL_PORT> recv
# Send to Public channel
meshcli -s <SERIAL_PORT> public "message content"
# Reply to user
meshcli -s <SERIAL_PORT> public "@[UserName] content"
# Clean up inactive contacts
meshcli -s <SERIAL_PORT> "apply_to u<48h,t=1 remove_contact"
# Get contact list
meshcli -s <SERIAL_PORT> contacts
3.3 Project File Structure
mc-webui/
├── docker/
│ ├── Dockerfile
│ └── docker-compose.yml
├── app/
│ ├── __init__.py
│ ├── main.py # Flask entry point
│ ├── config.py # Configuration
│ ├── meshcore/
│ │ ├── __init__.py
│ │ ├── cli.py # meshcli wrapper (subprocess)
│ │ └── parser.py # .msgs file parser
│ ├── routes/
│ │ ├── __init__.py
│ │ ├── api.py # API endpoints
│ │ └── views.py # HTML views
│ ├── static/
│ │ ├── css/
│ │ │ └── style.css # Custom styles
│ │ └── js/
│ │ └── app.js # Frontend logic
│ └── templates/
│ ├── base.html # Base template
│ ├── index.html # Main chat view
│ └── components/
│ ├── message.html # Message component
│ └── navbar.html # Navigation
├── requirements.txt
├── .env.example
├── README.md
└── PRD.md
4. Functional Requirements (MVP)
4.1 Module: Message Viewing
| ID | Requirement | Priority |
|---|---|---|
| F1.1 | System displays message list from .msgs file | MUST |
| F1.2 | Messages are sorted chronologically (newest at bottom) | MUST |
| F1.3 | Each message contains: sender, content, timestamp | MUST |
| F1.4 | Own messages are visually distinguished (e.g., different side) | SHOULD |
| F1.5 | Auto-scroll to newest message | SHOULD |
| F1.6 | Display emoji (Unicode) | SHOULD |
Message format in .msgs (JSON Lines):
{"type": "CHAN", "SNR": 10.5, "channel_idx": 0, "text": "UserName: content", "timestamp": 1766300846}
{"type": "SENT_CHAN", "channel_idx": 0, "text": "content", "name": "MarWoj", "timestamp": 1766309413}
4.2 Module: Message Sending
| ID | Requirement | Priority |
|---|---|---|
| F2.1 | Form with text field and "Send" button | MUST |
| F2.2 | Send via Enter (Shift+Enter = new line) | SHOULD |
| F2.3 | Validation - non-empty field | MUST |
| F2.4 | Status feedback (success/error) | MUST |
| F2.5 | Clear field after sending | MUST |
4.3 Module: Replying to Users
| ID | Requirement | Priority |
|---|---|---|
| F3.1 | "Reply" button on each message | MUST |
| F3.2 | Click inserts @[UserName] into text field |
MUST |
| F3.3 | Focus moves to text field | SHOULD |
4.4 Module: Contact Management
| ID | Requirement | Priority |
|---|---|---|
| F4.1 | "Clean inactive contacts" button | MUST |
| F4.2 | Configurable inactivity hours (default 48h) | SHOULD |
| F4.3 | Confirmation before execution (modal) | MUST |
| F4.4 | Feedback on number of removed contacts | SHOULD |
4.5 Module: Data Refresh
| ID | Requirement | Priority |
|---|---|---|
| F5.1 | Automatic refresh every 60 seconds | MUST |
| F5.2 | Manual refresh button | MUST |
| F5.3 | Last refresh indicator | SHOULD |
| F5.4 | Loading indicator during refresh | SHOULD |
5. Non-Functional Requirements
5.1 Performance
| ID | Requirement |
|---|---|
| NF1.1 | API response time < 2 seconds |
| NF1.2 | Handle .msgs file up to 10,000 messages |
| NF1.3 | Minimal resource usage (< 100MB RAM) |
5.2 Usability
| ID | Requirement |
|---|---|
| NF2.1 | Responsive design (mobile-first) |
| NF2.2 | Readable on screens 320px - 2560px |
| NF2.3 | Basic view works without JavaScript (graceful degradation) |
5.3 Reliability
| ID | Requirement |
|---|---|
| NF3.1 | Handle meshcli errors (timeout, device unavailable) |
| NF3.2 | Log errors to stdout/stderr (Docker logs) |
| NF3.3 | Automatic container restart on failure |
5.4 Security
| ID | Requirement |
|---|---|
| NF4.1 | No authentication (trusted network) - deliberate decision |
| NF4.2 | Input sanitization (injection protection) |
| NF4.3 | No sensitive data storage |
6. User Interface
6.1 Wireframe - Main View
┌────────────────────────────────────────────────────────────┐
│ mc-webui [↻ Refresh] [⚙️] │
├────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 12:30 MarioTJE🤖 │ │
│ │ Hey everyone [↩️] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 12:35 BBKr │ │
│ │ @[Mruk-A] no it's ID conflict 01 [↩️] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────┐ │
│ │ 12:40 MarWoj (You) │ │
│ │ Good morning everyone │ │
│ └────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 12:45 Zen │ │
│ │ Good morning everyone, greetings [↩️] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
├────────────────────────────────────────────────────────────┤
│ ┌──────────────────────────────────────────┐ ┌────────┐ │
│ │ Type a message... │ │ Send │ │
│ └──────────────────────────────────────────┘ └────────┘ │
├────────────────────────────────────────────────────────────┤
│ Last refresh: 12:46:30 Next in: 45s │
└────────────────────────────────────────────────────────────┘
6.2 Wireframe - Settings Panel (modal/dropdown)
┌─────────────────────────────────────┐
│ ⚙️ Settings ✕ │
├─────────────────────────────────────┤
│ │
│ Contact Management │
│ ───────────────────────────────── │
│ Remove contacts inactive for: │
│ [ 48 ] hours │
│ │
│ [🗑️ Clean Inactive Contacts] │
│ │
│ ───────────────────────────────── │
│ Device Information │
│ Name: MarWoj │
│ Port: /dev/serial/by-id/usb-... │
│ │
└─────────────────────────────────────┘
6.3 Colors and Style
- Theme: Light (dark mode possibility in future)
- Primary colors:
- Primary: #0d6efd (Bootstrap blue)
- Own messages: light blue background (#e7f1ff)
- Others' messages: white/gray background (#f8f9fa)
- Fonts: System fonts (Bootstrap defaults)
- Icons: Bootstrap Icons
7. Configuration
7.1 Environment Variables
| Variable | Description | Default Value |
|---|---|---|
MC_SERIAL_PORT |
Path to serial device | /dev/ttyUSB0 |
MC_DEVICE_NAME |
Device name (for .msgs file) | MeshCore |
MC_CONFIG_DIR |
meshcore configuration directory | /root/.config/meshcore |
MC_REFRESH_INTERVAL |
Refresh interval (seconds) | 60 |
MC_INACTIVE_HOURS |
Inactivity hours for cleanup | 48 |
FLASK_HOST |
Listen address | 0.0.0.0 |
FLASK_PORT |
Application port | 5000 |
FLASK_DEBUG |
Debug mode | false |
7.2 Example .env File
# MeshCore device configuration
MC_SERIAL_PORT=/dev/serial/by-id/usb-Espressif_Systems_heltec_wifi_lora_32_v4__16_MB_FLASH__2_MB_PSRAM__90706984A000-if00
MC_DEVICE_NAME=MarWoj
MC_CONFIG_DIR=/root/.config/meshcore
# Application settings
MC_REFRESH_INTERVAL=60
MC_INACTIVE_HOURS=48
# Flask
FLASK_HOST=0.0.0.0
FLASK_PORT=5000
FLASK_DEBUG=false
7.3 Docker Compose
version: '3.8'
services:
mc-webui:
build: .
container_name: mc-webui
restart: unless-stopped
ports:
- "5000:5000"
devices:
- "${MC_SERIAL_PORT}:${MC_SERIAL_PORT}"
volumes:
- "${MC_CONFIG_DIR}:/root/.config/meshcore:rw"
environment:
- MC_SERIAL_PORT
- MC_DEVICE_NAME
- MC_REFRESH_INTERVAL
- MC_INACTIVE_HOURS
- FLASK_HOST
- FLASK_PORT
env_file:
- .env
8. Implementation Plan
Phase 0: Environment Setup (0.5 day)
- Create GitHub repository
- Project directory structure
- Docker and docker-compose configuration
- Install meshcore-cli in container
- Verify device connection
Phase 1: Backend - Basics (1 day)
- Flask application skeleton
- Configuration from environment variables
- meshcli wrapper (subprocess)
- .msgs file parser
- Basic API endpoints:
GET /api/messages- message listPOST /api/messages- send messageGET /api/status- connection status
Phase 2: Frontend - Chat View (1 day)
- Base template (Bootstrap 5)
- Message list view
- Distinguish own/others' messages
- Time formatting
- Emoji support
Phase 3: Frontend - Message Sending (0.5 day)
- Send form
- Validation
- Feedback (toast notifications)
- Reply button (@[UserName])
Phase 4: Auto-refresh (0.5 day)
- JavaScript polling
- Last refresh indicator
- Manual refresh button
- Smart scroll (don't jump if user is scrolling)
Phase 5: Contact Management (0.5 day)
- Settings panel (modal)
- Contact cleanup function
- Action confirmation
- Result feedback
Phase 6: Polish & Documentation (0.5 day)
- Manual testing
- Error handling and edge cases
- README with installation instructions
- Docker image optimization
Total estimated time: ~4-5 working days
9. Future Extensions (Backlog)
Features to consider in future versions:
| Priority | Feature | Description |
|---|---|---|
| HIGH | Dark mode | Dark theme interface |
| HIGH | Other channels | Send to channels other than Public |
| MEDIUM | Contact list | Browse and manage contacts |
| MEDIUM | Private messages | Send DMs to contacts |
| MEDIUM | Notifications | Audio/visual notifications for new messages |
| MEDIUM | Map | Display contact locations on map |
| LOW | Statistics | Message count, network activity |
| LOW | Telemetry | Display telemetry data |
| LOW | Authentication | Optional login (for internet access) |
| LOW | Multi-device | Support for multiple devices |
10. Risks and Limitations
10.1 Technical Risks
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| meshcli delays | Medium | Medium | Timeout + async execution |
| Device connection loss | Low | High | Health check + restart |
| Large .msgs file | Low | Medium | Pagination, tail last N |
| Concurrent access conflicts | Low | Low | Command queuing |
10.2 Limitations
- Single-user - no multi-user support
- No authentication - requires trusted network
- meshcli dependency - requires installed meshcore-cli
- Public channel only (MVP) - other channels in future versions
- No persistence - data only in .msgs file
10.3 Assumptions
- Heltec V4 device is always connected and available
- meshcore-cli is properly configured
- .msgs file is regularly updated by meshcore-cli
- Local network is trusted (no authentication needed)
11. Definitions and Abbreviations
| Term | Definition |
|---|---|
| MeshCore | Mesh networking protocol for LoRa radios |
| meshcore-cli | Command-line interface for MeshCore |
| meshcli | Alias for meshcore-cli |
| Heltec V4 | Heltec WiFi LoRa 32 V4 - LoRa device |
| .msgs | JSON Lines file with message history |
| Public | Default public channel (channel 0) |
| SNR | Signal-to-Noise Ratio |
12. Changelog
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2025-01-21 | Marek/Claude | Initial version |
Appendices
A. Example Message Format (.msgs)
{"type": "CHAN", "SNR": 10.5, "channel_idx": 0, "path_len": 5, "txt_type": 0, "sender_timestamp": 1766300840, "text": "MarioTJE🤖: Hey everyone ", "name": "channel 0", "timestamp": 1766300846}
{"type": "SENT_CHAN", "channel_idx": 0, "text": "Good morning everyone", "txt_type": 0, "name": "MarWoj", "timestamp": 1766309432}
B. meshcli Commands Used in Project
# Sync messages
meshcli -s <PORT> recv
# Send to Public
meshcli -s <PORT> public "message"
# Contact list
meshcli -s <PORT> contacts
# Clean inactive contacts (type client, >48h)
meshcli -s <PORT> "apply_to u<48h,t=1 remove_contact"
# Device information
meshcli -s <PORT> infos