mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
208 lines
5.5 KiB
Markdown
208 lines
5.5 KiB
Markdown
# 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
|
|
|
|
```text
|
|
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
|
|
├── 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
|
|
└── ws.py
|
|
```
|
|
|
|
## Core Runtime Flows
|
|
|
|
### Incoming data
|
|
|
|
1. Radio emits events.
|
|
2. `on_rx_log_data` stores raw packet and tries decrypt/pipeline handling.
|
|
3. Decrypted messages are inserted into `messages` and broadcast over WS.
|
|
4. `CONTACT_MSG_RECV` is a fallback DM path when packet pipeline cannot decrypt.
|
|
|
|
### Outgoing messages
|
|
|
|
1. Send endpoints in `routers/messages.py` call MeshCore commands.
|
|
2. Message is persisted as outgoing.
|
|
3. Endpoint broadcasts WS `message` event so all live clients update.
|
|
4. ACK/repeat updates arrive later as `message_acked` events.
|
|
|
|
### Connection lifecycle
|
|
|
|
- `RadioManager.start_connection_monitor()` checks health every 5s.
|
|
- On reconnect, monitor runs `post_connect_setup()` before broadcasting healthy state.
|
|
- 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/unreads` returns counts, mention flags, and `last_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.
|
|
|
|
### Periodic advertisement
|
|
|
|
- Controlled by `app_settings.advert_interval` (seconds).
|
|
- `0` means disabled.
|
|
- Last send time tracked in `app_settings.last_advert_time`.
|
|
|
|
## API Surface (all under `/api`)
|
|
|
|
### Health
|
|
- `GET /health`
|
|
|
|
### Radio
|
|
- `GET /radio/config`
|
|
- `PATCH /radio/config`
|
|
- `PUT /radio/private-key`
|
|
- `POST /radio/advertise`
|
|
- `POST /radio/reboot`
|
|
- `POST /radio/reconnect`
|
|
|
|
### Contacts
|
|
- `GET /contacts`
|
|
- `GET /contacts/{public_key}`
|
|
- `POST /contacts`
|
|
- `DELETE /contacts/{public_key}`
|
|
- `POST /contacts/sync`
|
|
- `POST /contacts/{public_key}/add-to-radio`
|
|
- `POST /contacts/{public_key}/remove-from-radio`
|
|
- `POST /contacts/{public_key}/mark-read`
|
|
- `POST /contacts/{public_key}/telemetry`
|
|
- `POST /contacts/{public_key}/command`
|
|
- `POST /contacts/{public_key}/trace`
|
|
|
|
### Channels
|
|
- `GET /channels`
|
|
- `GET /channels/{key}`
|
|
- `POST /channels`
|
|
- `DELETE /channels/{key}`
|
|
- `POST /channels/sync`
|
|
- `POST /channels/{key}/mark-read`
|
|
|
|
### Messages
|
|
- `GET /messages`
|
|
- `POST /messages/direct`
|
|
- `POST /messages/channel`
|
|
|
|
### Packets
|
|
- `GET /packets/undecrypted/count`
|
|
- `POST /packets/decrypt/historical`
|
|
- `POST /packets/maintenance`
|
|
|
|
### Read state
|
|
- `GET /read-state/unreads`
|
|
- `POST /read-state/mark-all-read`
|
|
|
|
### Settings
|
|
- `GET /settings`
|
|
- `PATCH /settings`
|
|
- `POST /settings/favorites/toggle`
|
|
- `POST /settings/migrate`
|
|
|
|
### WebSocket
|
|
- `WS /ws`
|
|
|
|
## WebSocket Events
|
|
|
|
- `health`
|
|
- `contacts`
|
|
- `channels`
|
|
- `contact`
|
|
- `message`
|
|
- `message_acked`
|
|
- `raw_packet`
|
|
- `error`
|
|
- `success`
|
|
|
|
Initial WS connect sends `health` only. Contacts/channels are loaded by REST.
|
|
|
|
## Data Model Notes
|
|
|
|
Main tables:
|
|
- `contacts`
|
|
- `channels`
|
|
- `messages`
|
|
- `raw_packets`
|
|
- `app_settings`
|
|
|
|
`app_settings` fields in active model:
|
|
- `max_radio_contacts`
|
|
- `experimental_channel_double_send`
|
|
- `favorites`
|
|
- `auto_decrypt_dm_on_advert`
|
|
- `sidebar_sort_order`
|
|
- `last_message_times`
|
|
- `preferences_migrated`
|
|
- `advert_interval`
|
|
- `last_advert_time`
|
|
- `bots`
|
|
|
|
## 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:
|
|
|
|
```bash
|
|
PYTHONPATH=. uv run pytest tests/ -v
|
|
```
|
|
|
|
High-signal suites:
|
|
- `tests/test_packet_pipeline.py`
|
|
- `tests/test_event_handlers.py`
|
|
- `tests/test_send_messages.py`
|
|
- `tests/test_radio.py`
|
|
- `tests/test_api.py`
|
|
- `tests/test_migrations.py`
|
|
|
|
## Editing Checklist
|
|
|
|
When changing backend behavior:
|
|
1. Update/add router and repository tests.
|
|
2. Confirm WS event contracts when payload shape changes.
|
|
3. Run `PYTHONPATH=. uv run pytest tests/ -v`.
|
|
4. If API contract changed, update frontend types and AGENTS docs.
|