mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
6.9 KiB
6.9 KiB
Backend AGENTS.md
This document is the backend working guide for agents and developers.
Keep it aligned with app/ source files and router behavior.
Stack
- FastAPI
- aiosqlite
- Pydantic
- MeshCore Python library (
references/meshcore_py) - PyCryptodome
Backend Map
app/
├── main.py # App startup/lifespan, router registration, static frontend mounting
├── config.py # Env-driven runtime settings
├── database.py # SQLite connection + base schema + migration runner
├── migrations.py # Schema migrations (SQLite user_version)
├── models.py # Pydantic request/response models
├── repository.py # Data access layer
├── radio.py # RadioManager + auto-reconnect monitor
├── radio_sync.py # Polling, sync, periodic advertisement loop
├── decoder.py # Packet parsing/decryption
├── packet_processor.py # Raw packet pipeline, dedup, path handling
├── event_handlers.py # MeshCore event subscriptions and ACK tracking
├── websocket.py # WS manager + broadcast helpers
├── bot.py # Bot execution and outbound bot sends
├── dependencies.py # Shared FastAPI dependency providers
├── keystore.py # Ephemeral private/public key storage for DM decryption
├── frontend_static.py # Mount/serve built frontend (production)
└── routers/
├── health.py
├── radio.py
├── contacts.py
├── channels.py
├── messages.py
├── packets.py
├── read_state.py
├── settings.py
├── statistics.py
└── ws.py
Core Runtime Flows
Incoming data
- Radio emits events.
on_rx_log_datastores raw packet and tries decrypt/pipeline handling.- Decrypted messages are inserted into
messagesand broadcast over WS. CONTACT_MSG_RECVis a fallback DM path when packet pipeline cannot decrypt.
Outgoing messages
- Send endpoints in
routers/messages.pycall MeshCore commands. - Message is persisted as outgoing.
- Endpoint broadcasts WS
messageevent so all live clients update. - ACK/repeat updates arrive later as
message_ackedevents.
Connection lifecycle
RadioManager.start_connection_monitor()checks health every 5s.- Monitor reconnect path runs
post_connect_setup()before broadcasting healthy state. - Manual reconnect/reboot endpoints call
reconnect()thenpost_connect_setup(). - Setup includes handler registration, key export, time sync, contact/channel sync, polling/advert tasks.
Important Behaviors
Read/unread state
- Server is source of truth (
contacts.last_read_at,channels.last_read_at). GET /api/read-state/unreadsreturns counts, mention flags, andlast_message_times.
Echo/repeat dedup
- Message uniqueness:
(type, conversation_key, text, sender_timestamp). - Duplicate insert is treated as an echo/repeat; ACK count/path list is updated.
Raw packet dedup policy
- Raw packet storage deduplicates by payload hash (
RawPacketRepository.create), excluding routing/path bytes. - Stored packet
idis therefore a payload identity, not a per-arrival identity. - Realtime raw-packet WS broadcasts include
observation_id(unique per RF arrival) in addition toid. - Frontend packet-feed features should key/dedupe by
observation_id; useidonly as the storage reference. - Message-layer repeat handling (
_handle_duplicate_message+MessageRepository.add_path) is separate from raw-packet storage dedup.
Periodic advertisement
- Controlled by
app_settings.advert_interval(seconds). 0means disabled.- Last send time tracked in
app_settings.last_advert_time.
API Surface (all under /api)
Health
GET /health
Radio
GET /radio/configPATCH /radio/configPUT /radio/private-keyPOST /radio/advertisePOST /radio/rebootPOST /radio/reconnect
Contacts
GET /contactsGET /contacts/{public_key}POST /contactsDELETE /contacts/{public_key}POST /contacts/syncPOST /contacts/{public_key}/add-to-radioPOST /contacts/{public_key}/remove-from-radioPOST /contacts/{public_key}/mark-readPOST /contacts/{public_key}/telemetryPOST /contacts/{public_key}/commandPOST /contacts/{public_key}/trace
Channels
GET /channelsGET /channels/{key}POST /channelsDELETE /channels/{key}POST /channels/syncPOST /channels/{key}/mark-read
Messages
GET /messagesPOST /messages/directPOST /messages/channelPOST /messages/channel/{message_id}/resend
Packets
GET /packets/undecrypted/countPOST /packets/decrypt/historicalPOST /packets/maintenance
Read state
GET /read-state/unreadsPOST /read-state/mark-all-read
Settings
GET /settingsPATCH /settingsPOST /settings/favorites/togglePOST /settings/migrate
Statistics
GET /statistics— aggregated mesh network stats (entity counts, message/packet splits, activity windows, busiest channels)
WebSocket
WS /ws
WebSocket Events
health— radio connection status (broadcast on change, personal on connect)contact— single contact upsert (from advertisements and radio sync)message— new message (channel or DM, from packet processor or send endpoints)message_acked— ACK/echo update for existing message (ack count + paths)raw_packet— every incoming RF packet (for real-time packet feed UI)error— toast notification (reconnect failure, missing private key, etc.)success— toast notification (historical decrypt complete, etc.)
Initial WS connect sends health only. Contacts/channels are loaded by REST.
Client sends "ping" text; server replies {"type":"pong"}.
Data Model Notes
Main tables:
contactschannelsmessagesraw_packetsapp_settings
app_settings fields in active model:
max_radio_contactsfavoritesauto_decrypt_dm_on_advertsidebar_sort_orderlast_message_timespreferences_migratedadvert_intervallast_advert_timebots
Security Posture (intentional)
- No authn/authz.
- No CORS restriction (
*). - Bot code executes user-provided Python via
exec().
These are product decisions for trusted-network deployments; do not flag as accidental vulnerabilities.
Testing
Run backend tests:
PYTHONPATH=. uv run pytest tests/ -v
High-signal suites:
tests/test_packet_pipeline.pytests/test_event_handlers.pytests/test_send_messages.pytests/test_radio.pytests/test_api.pytests/test_migrations.py
Editing Checklist
When changing backend behavior:
- Update/add router and repository tests.
- Confirm WS event contracts when payload shape changes.
- Run
PYTHONPATH=. uv run pytest tests/ -v. - If API contract changed, update frontend types and AGENTS docs.