mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
Update AGENTS.md
This commit is contained in:
@@ -93,6 +93,15 @@ Ancillary AGENTS.md files which should generally not be reviewed unless specific
|
||||
5. **Offline-capable**: Radio operates independently; server syncs when connected
|
||||
6. **Auto-reconnect**: Background monitor detects disconnection and attempts reconnection
|
||||
|
||||
## Code Ethos
|
||||
|
||||
- Prefer fewer, stronger modules over many tiny wrapper files.
|
||||
- Split code only when the new module owns a real invariant, workflow, or contract.
|
||||
- Avoid "enterprise" indirection layers whose main job is forwarding, renaming, or prop bundling.
|
||||
- For this repo, "locally dense but semantically obvious" is better than context scattered across many files.
|
||||
- Use typed contracts at important boundaries such as API payloads, WebSocket events, and repository writes.
|
||||
- Refactors should be behavior-preserving slices with tests around the moved seam, not aesthetic reshuffles.
|
||||
|
||||
## Intentional Security Design Decisions
|
||||
|
||||
The following are **deliberate design choices**, not bugs. They are documented in the README with appropriate warnings. Do not "fix" these or flag them as vulnerabilities.
|
||||
|
||||
@@ -11,6 +11,14 @@ Keep it aligned with `app/` source files and router behavior.
|
||||
- MeshCore Python library (`meshcore` from PyPI)
|
||||
- PyCryptodome
|
||||
|
||||
## Code Ethos
|
||||
|
||||
- Prefer strong domain modules over layers of pass-through helpers.
|
||||
- Split code when the new module owns real policy, not just a nicer name.
|
||||
- Avoid wrapper services around globals unless they materially improve testability or reduce coupling.
|
||||
- Keep workflows locally understandable; do not scatter one reasoning unit across several files without a clear contract.
|
||||
- Typed write/read contracts are preferred over loose dict-shaped repository inputs.
|
||||
|
||||
## Backend Map
|
||||
|
||||
```text
|
||||
@@ -19,7 +27,7 @@ app/
|
||||
├── 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
|
||||
├── models.py # Pydantic request/response models and typed write contracts (for example ContactUpsert)
|
||||
├── repository/ # Data access layer (contacts, channels, messages, raw_packets, settings, fanout)
|
||||
├── services/ # Shared orchestration/domain services
|
||||
│ ├── messages.py # Shared message creation, dedup, ACK application
|
||||
@@ -240,6 +248,8 @@ Main tables:
|
||||
- `contact_name_history` (tracks name changes over time)
|
||||
- `app_settings`
|
||||
|
||||
Repository writes should prefer typed models such as `ContactUpsert` over ad hoc dict payloads when adding or updating schema-coupled data.
|
||||
|
||||
`app_settings` fields in active model:
|
||||
- `max_radio_contacts`
|
||||
- `favorites`
|
||||
|
||||
@@ -16,6 +16,15 @@ Keep it aligned with `frontend/src` source code.
|
||||
- `meshcore-hashtag-cracker` + `nosleep.js` (channel cracker)
|
||||
- Multibyte-aware decoder build published as `meshcore-decoder-multibyte-patch`
|
||||
|
||||
## Code Ethos
|
||||
|
||||
- Prefer fewer, stronger modules over many thin wrappers.
|
||||
- Split code only when the new hook/component owns a real invariant or workflow.
|
||||
- Keep one reasoning unit readable in one place, even if that file is moderately large.
|
||||
- Avoid dedicated files whose main job is pass-through, prop bundling, or renaming.
|
||||
- For this repo, "locally dense but semantically obvious" is better than indirection-heavy "clean architecture".
|
||||
- When refactoring, preserve behavior first and add tests around the seam being moved.
|
||||
|
||||
## Frontend Map
|
||||
|
||||
```text
|
||||
@@ -37,12 +46,10 @@ frontend/src/
|
||||
│ ├── index.ts # Central re-export of all hooks
|
||||
│ ├── useConversationActions.ts # Send/resend/trace/block conversation actions
|
||||
│ ├── useConversationNavigation.ts # Search target, selection reset, and info-pane navigation state
|
||||
│ ├── useConversationMessages.ts # Dedup/update helpers over the conversation timeline
|
||||
│ ├── useConversationTimeline.ts # Fetch, cache restore, jump-target loading, pagination, reconcile
|
||||
│ ├── useConversationMessages.ts # Conversation timeline loading, cache restore, jump-target loading, pagination, dedup, pending ACK buffering
|
||||
│ ├── useUnreadCounts.ts # Unread counters, mentions, recent-sort timestamps
|
||||
│ ├── useRealtimeAppState.ts # WebSocket event application and reconnect recovery
|
||||
│ ├── useAppShell.ts # App-shell view state (settings/sidebar/modals/cracker)
|
||||
│ ├── useAppShellProps.ts # AppShell child prop assembly + cracker create/decrypt flow
|
||||
│ ├── useRepeaterDashboard.ts # Repeater dashboard state (login, panes, console, retries)
|
||||
│ ├── useRadioControl.ts # Radio health/config state, reconnection
|
||||
│ ├── useAppSettings.ts # Settings, favorites, preferences migration
|
||||
@@ -154,7 +161,6 @@ frontend/src/
|
||||
├── useConversationMessages.test.ts
|
||||
├── useConversationMessages.race.test.ts
|
||||
├── useConversationNavigation.test.ts
|
||||
├── useAppShellProps.test.ts
|
||||
├── useAppShell.test.ts
|
||||
├── useRepeaterDashboard.test.ts
|
||||
├── useContactsAndChannels.test.ts
|
||||
@@ -186,13 +192,13 @@ High-level state is delegated to hooks:
|
||||
- `useConversationRouter`: URL hash → active conversation routing
|
||||
- `useConversationNavigation`: search target, conversation selection reset, and info-pane state
|
||||
- `useConversationActions`: send/resend/trace/block handlers and channel override updates
|
||||
- `useAppShellProps`: assembles the prop bundles passed into `AppShell` children, including the cracker-created-channel historical decrypt flow
|
||||
- `useConversationMessages`: dedup/update helpers and pending ACK buffering
|
||||
- `useConversationTimeline`: conversation switch loading, cache restore, jump-target loading, pagination, reconcile
|
||||
- `useConversationMessages`: conversation switch loading, cache restore, jump-target loading, pagination, dedup/update helpers, and pending ACK buffering
|
||||
- `useUnreadCounts`: unread counters, mention tracking, recent-sort timestamps
|
||||
- `useRealtimeAppState`: typed WS event application, reconnect recovery, cache/unread coordination
|
||||
- `useRepeaterDashboard`: repeater dashboard state (login, pane data/retries, console, actions)
|
||||
|
||||
`App.tsx` intentionally still does the final `AppShell` prop assembly. That composition layer is considered acceptable here because it keeps the shell contract visible in one place and avoids a prop-bundling hook with little original logic.
|
||||
|
||||
`ConversationPane.tsx` owns the main active-conversation surface branching:
|
||||
- empty state
|
||||
- map view
|
||||
@@ -359,7 +365,7 @@ The `SearchView` component (`components/SearchView.tsx`) provides full-text sear
|
||||
- **State**: `targetMessageId` is shared between `useConversationNavigation` and `useConversationMessages`. When a search result is clicked, `handleNavigateToMessage` sets the target ID and switches to the target conversation.
|
||||
- **Same-conversation clear**: when `targetMessageId` is cleared after the target is reached, the hook preserves the around-loaded mid-history view instead of replacing it with the latest page.
|
||||
- **Persistence**: `SearchView` stays mounted after first open using the same `hidden` class pattern as `CrackerPanel`, preserving search state when navigating to results.
|
||||
- **Jump-to-message**: `useConversationTimeline` handles optional `targetMessageId` by calling `api.getMessagesAround()` instead of the normal latest-page fetch, loading context around the target message. `MessageList` scrolls to the target via `data-message-id` attribute and applies a `message-highlight` CSS animation.
|
||||
- **Jump-to-message**: `useConversationMessages` handles optional `targetMessageId` by calling `api.getMessagesAround()` instead of the normal latest-page fetch, loading context around the target message. `MessageList` scrolls to the target via `data-message-id` attribute and applies a `message-highlight` CSS animation.
|
||||
- **Bidirectional pagination**: After jumping mid-history, `hasNewerMessages` enables forward pagination via `fetchNewerMessages`. The scroll-to-bottom button calls `jumpToBottom` (re-fetches latest page) instead of just scrolling.
|
||||
- **WS message suppression**: When `hasNewerMessages` is true, incoming WS messages for the active conversation are not added to the message list (the user is viewing historical context, not the latest page).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user