From 28769d01d02fae0d76067baccb70a1073c6b3719 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 28 Mar 2026 13:08:30 +0000 Subject: [PATCH] [docs](trx-rs): document UI/UX design guidelines Add docs/UX_Guidelines.md covering web frontend patterns (theming, responsive design, accessibility, real-time data), REST API conventions, CLI interface, configuration wizard, error handling, branding, security UX, and inferred design principles. https://claude.ai/code/session_01LC9Yp36ARX47bmKavNPTcB Signed-off-by: Claude --- docs/UX_Guidelines.md | 390 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 docs/UX_Guidelines.md diff --git a/docs/UX_Guidelines.md b/docs/UX_Guidelines.md new file mode 100644 index 0000000..3f34764 --- /dev/null +++ b/docs/UX_Guidelines.md @@ -0,0 +1,390 @@ +# UX Guidelines + +This document captures the UI/UX design patterns, conventions, and principles observed across +the trx-rs application. It covers the web frontend, CLI interfaces, configuration wizard, API +design, and error handling. + +*Last reviewed: 2026-03-28* + +--- + +## 1. Web Frontend (trx-frontend-http) + +### 1.1 Layout and Navigation + +The web UI is a single-page application served from embedded assets (no build step). It uses +a **tab-based** navigation model with six top-level tabs: + +| Tab | Icon | Purpose | +|---|---|---| +| **Main** | House | Primary radio control: spectrum, frequency, mode, PTT, VFO, SDR controls | +| **Bookmarks** | Bookmark | Saved frequency/mode presets with folder organisation | +| **Digital modes** | Bar chart | FT8/FT4/FT2, WSPR, CW, APRS, AIS, VDES decode tables | +| **Map** | Pin | Leaflet map for APRS/AIS/FT8 station plotting | +| **Settings** | Wrench | Scheduler, background decode, history retention | +| **About** | Info circle | Server/client/radio/audio/decoder/integration details | + +Tabs use inline SVG icons with a text label below. On narrow viewports the tab bar wraps and +subtitles collapse to save space. + +The **Settings** and **About** tabs each use a secondary **sub-tab bar** for further grouping +(e.g. Settings > Scheduler | Background Decode | History). + +### 1.2 Theming + +The UI supports **dark mode** (default) and **light mode** toggled via a header button. Theme +preference persists in `localStorage`. + +Additionally, nine **colour styles** are available via a dropdown: + +- Original (default), Arctic, Lime, Contrast, Neon Disco, Donald (golden-rain), Amber, Fire, Phosphor + +Each style provides a full CSS custom-property override set for both dark and light variants. +Styles are applied via `data-style` and `data-theme` attributes on ``. + +All colours reference CSS custom properties (`--bg`, `--card-bg`, `--text`, `--accent-green`, +`--border-light`, etc.) so components never use hard-coded colour values. + +### 1.3 Typography + +- **Body**: `system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif` +- **Frequency display**: `DSEG14 Classic` (14-segment display font, loaded from CDN with `preload`) +- **Labels**: uppercase, 0.68-0.78 rem, `font-weight: 700`, `letter-spacing: 0.04em` +- **Section labels** use pill-shaped badges (`border-radius: 999px`) with muted text + +### 1.4 Responsive Design + +Six breakpoints handle layout adaptation: + +| Breakpoint | Behaviour | +|---|---| +| `> 1100px` | Full width with bookmark side gutters on spectrum | +| `< 1100px` | Side bookmark panels hidden | +| `< 900px` | Card fills viewport width, reduced padding | +| `< 760px` | Tab bar wraps, controls stack vertically, safe-area-inset padding for notched devices | +| `< 640px` | Bottom-fixed tab bar (mobile), subtitles hidden, compact header | +| `< 520px` | Further compact adjustments | + +Touch-specific: `@media (hover: none) and (pointer: coarse)` enlarges hit targets. + +The spectrum panel hints adapt: mouse users see "Scroll to zoom / Ctrl+Scroll to tune / +Drag to pan" while touch users see "Pinch to zoom / Drag to pan". + +### 1.5 Interactive Controls + +- **Jog wheel**: Circular CSS-styled draggable dial for frequency tuning (skeuomorphic radial-gradient, grab cursor, shadow/inset). Plus/minus buttons flank it. +- **Step unit buttons**: Segmented button group (MHz / kHz / Hz) with `.active` highlight +- **Step scale**: 1x / 0.1x multiplier toggle +- **Frequency input**: Monospace DSEG14 font, editable `` with disabled opacity fix +- **Mode selector**: `` dropdown in the top bar for switching between connected rigs +- Per-tab rig binding: each SSE session independently selects a rig via `?remote=` query parameter +- Rig state isolation: only the disconnected rig shows the connection-lost banner +- About tab shows active rig, available rigs list + +--- + +## 2. REST API Design + +### 2.1 Conventions + +- **Read operations** use `GET` (e.g. `/status`, `/events`, `/decode/history`, `/rigs`, `/bookmarks`) +- **Mutations** use `POST` for actions and toggles (e.g. `/set_freq`, `/toggle_power`, `/toggle_ft8_decode`) +- **CRUD resources** use proper verbs: `GET /bookmarks`, `POST /bookmarks`, `PUT /bookmarks/{id}`, + `DELETE /bookmarks/{id}` +- **Batch operations**: `POST /bookmarks/batch_delete`, `POST /bookmarks/batch_move` +- **Nested resources**: `/channels/{remote}/{channel_id}/subscribe`, `/scheduler/{remote}/status` +- Responses are JSON with `Content-Type: application/json` +- SSE stream uses `Content-Type: text/event-stream` with `no-cache` and `keep-alive` headers + +### 2.2 Request Timeout + +All rig command requests have a **15-second timeout** (`REQUEST_TIMEOUT`). If the command +doesn't complete in time, the request returns an error rather than hanging. + +### 2.3 Error Responses + +- `401 Unauthorized`: `{"error": "Invalid credentials"}` or `{"error": "Authentication required"}` +- `429 Too Many Requests`: `{"error": "Too many login attempts, please try again later"}` +- `404 Not Found`: Auth endpoints when auth is disabled +- `500 Internal Server Error`: Serialization failures +- Rate limiting: 10 attempts per 60-second window per IP, counter resets on successful login + +### 2.4 State Enrichment + +API responses merge rig state with **frontend metadata** (`FrontendMeta`) via `serde(flatten)`: + +``` +http_clients, rigctl_clients, audio_clients, rigctl_addr, +active_remote, remotes[], owner_callsign, owner_website_url, +owner_website_name, ais_vessel_url_base, show_sdr_gain_control, +initial_map_zoom, spectrum_coverage_margin_hz, spectrum_usable_span_ratio, +decode_history_retention_min, server_connected +``` + +This single-payload approach avoids extra round trips for UI configuration. + +--- + +## 3. CLI Interface + +### 3.1 Argument Style + +Both `trx-server` and `trx-client` use **clap** for argument parsing with short and long flags: + +``` +-C, --config FILE Path to configuration file +--print-config Print example configuration and exit +-r, --rig NAME Rig backend name +-l, --listen ADDR Listen address +-p, --port NUM Port number +``` + +Positional arguments are used sparingly (e.g. `RIG_ADDR` for serial/TCP address). + +### 3.2 Configuration Resolution + +Config files are searched in priority order: +1. Current directory: `trx-rs.toml` +2. XDG config: `~/.config/trx-rs/trx-rs.toml` +3. System: `/etc/trx-rs/trx-rs.toml` + +The loaded config path is logged: `INFO Loaded configuration from /path/to/config.toml` + +### 3.3 Example Config Generation + +`--print-config` outputs a complete, commented TOML file to stdout with example values +(callsign `N0CALL`, coordinates `52.2297, 21.0122`). Each section has a header comment and +each field has an inline description. + +### 3.4 Startup Log Sequence + +Server: +``` +INFO Loaded configuration from /path/to/config.toml +INFO Starting trx-server with N rig(s): [rig-names] +INFO Callsign: CALL +INFO [rig-id] Starting (rig: ft817, access: serial /dev/ttyUSB0 @ 9600 baud) +INFO Listening on 0.0.0.0:4530 +``` + +Client: +``` +INFO Loaded configuration from /path/to/config.toml +INFO Starting trx-client (remotes: [remote-names], frontends: http,rigctl) +INFO rigctl frontend for rig 'default' on 127.0.0.1:4532 +``` + +--- + +## 4. Configuration Wizard (trx-configurator) + +### 4.1 Interactive Mode + +Uses the **dialoguer** crate for terminal prompts: + +- `Select` menus for enumerated choices (config type, rig model, access type, log level) +- `Input` for free-text with defaults (callsign defaults to `N0CALL`, listen defaults to `127.0.0.1`) +- `Confirm` for yes/no questions (enable auth, set location, etc.) +- Serial port auto-detection with fallback to `/dev/ttyUSB0` + +### 4.2 Non-Interactive Mode + +`--defaults` generates a config file without prompts, using sensible defaults. + +### 4.3 Config Validation + +`--check FILE` validates an existing config file: + +``` +/path/to/config.toml: valid TOML + Detected type: server + warning: [general].log_level 'verbose' is invalid (expected: trace, debug, info, warn, error) + 1 warning(s), 0 error(s) +``` + +Validates: TOML syntax, unknown keys, log levels, coordinate ranges (-90..90 lat, -180..180 lon +with pair requirement), access types, port ranges (0-65535). + +### 4.4 File Write Confirmation + +Prompts before overwriting an existing file. Outputs `Wrote /path/to/file` on success. + +--- + +## 5. Error Handling and User-Facing Messages + +### 5.1 Error Message Conventions + +- **Contextual**: Include file paths, section names, and peer addresses + - `"Failed to parse config file /path: error details"` + - `"Unknown rig model: X (available: ft817, ft450d, soapysdr)"` +- **Actionable**: Suggest alternatives when available + - `"Rig model not specified. Use --rig or set [rig].model in config."` + - `"Unknown frontend: X (available: http, rigctl, httpjson)"` +- **Structured**: Use field=value format in structured logging + +### 5.2 Log Level Guidelines + +| Level | Usage | +|---|---| +| `INFO` | Startup milestones, configuration loaded, listening, client connect/disconnect, decoder state changes | +| `WARN` | Non-fatal issues: command took too long, panel lock blocking, VFO priming failed, initial tune failed | +| `ERROR` | Fatal or significant failures: CAT polling errors, client errors, parse failures | + +Logs suppress module targets (`with_target(false)`) for cleaner output. + +### 5.3 Connection State Communication + +- Server logs: `"Client connected: {peer}"`, `"Client {peer} disconnected"`, `"Client {peer} closing due to shutdown"` +- Rig task: `"[rig-id] Rig backend ready"`, `"Serial: /dev/ttyUSB0 @ 9600 baud"` +- Web UI: Connection-lost banner with reconnect indication, per-rig isolation + +### 5.4 Graceful Degradation + +- Startup continues after non-fatal failures: `"Initial PowerOn failed (continuing)"` +- Stream errors are deduplicated with 60-second summaries to avoid log flooding +- Lock poisoning is recovered from rather than panicking +- Unknown SSE events or lagged broadcast channels are silently skipped + +--- + +## 6. Branding and Customisation + +### 6.1 Owner Branding + +Configurable via TOML and exposed via `FrontendMeta`: + +- `owner_callsign` -- displayed in header subtitle and About tab +- `owner_website_url` / `owner_website_name` -- optional link in header +- `ais_vessel_url_base` -- base URL for linking AIS vessel MMSI numbers + +### 6.2 UI Behaviour Configuration + +- `http_show_sdr_gain_control` -- show/hide RF gain controls +- `http_initial_map_zoom` -- default map zoom level +- `http_spectrum_coverage_margin_hz` -- guard margin for spectrum center retune +- `http_spectrum_usable_span_ratio` -- fraction of spectrum span treated as usable +- `http_decode_history_retention_min` -- default history retention (per-rig overrides supported) + +### 6.3 Embedded Assets + +Logo and favicon are embedded at compile time via `include_bytes!`. The logo image has an +`onerror` handler to hide itself if loading fails (`this.style.display='none'`). + +--- + +## 7. Security UX + +### 7.1 Route Access Classification + +Routes are classified into three tiers: + +| Tier | Examples | Requirement | +|---|---|---| +| **Public** | `/`, `/index.html`, `/map`, `/auth/*`, static assets | None | +| **Read** | `/status`, `/events`, `/audio`, `/decode`, `/spectrum`, `/bookmarks` | Rx or Control role | +| **Control** | `/set_freq`, `/set_mode`, `/set_ptt`, `/toggle_power`, all other POST | Control role only | + +### 7.2 Session Management + +- Sessions are 128-bit random hex tokens stored in HttpOnly cookies +- Configurable TTL (default from TOML config) +- Expired sessions auto-pruned on access +- Constant-time passphrase comparison to mitigate timing attacks + +### 7.3 TX Access Control + +An additional `tx_access_control_enabled` flag can restrict transmit-related actions even +for Control-role users, providing an extra safety layer. + +--- + +## 8. Virtual Channels (SDR) + +Virtual channels allow SDR users to monitor multiple frequencies simultaneously: + +- Channels appear in a picker row below the VFO controls +- CRUD API: `POST /channels/{remote}` to create, `DELETE` to remove, `PUT` to update freq/mode/BW +- Subscribe/unsubscribe audio per channel +- Background decode channels (hidden, no audio stream back) +- Channels auto-destroyed when out-of-bandwidth after center-frequency retune +- Channel-list changes broadcast to SSE clients via `event: channels` + +--- + +## 9. Design Principles (Inferred) + +1. **Server-rendered SPA**: All HTML/CSS/JS embedded in the binary -- zero external build tooling, no CDN dependency for core functionality (CDN used only for fonts and Leaflet maps). + +2. **Progressive disclosure**: Advanced controls (WFM, SAM, SDR settings, spectrum controls) are hidden by default and revealed based on the active mode and backend type. + +3. **Keyboard-first, touch-aware**: Spectrum supports full keyboard navigation alongside mouse and touch gestures. Mobile breakpoints enlarge hit targets and adapt layout. + +4. **Real-time by default**: SSE + WebSocket provide sub-second state updates without polling from the browser. 5-second ping heartbeat detects stale connections. + +5. **Per-tab isolation**: Each browser tab gets its own SSE session UUID and can independently select a rig, preventing cross-tab interference. + +6. **Configuration over code**: UI behaviour knobs (gain visibility, map zoom, history retention, spectrum margins) are exposed as TOML config rather than requiring code changes. + +7. **Graceful degradation**: The UI handles server disconnection gracefully with visible banners, and only the affected rig shows as disconnected in multi-rig setups. + +8. **Defensive security defaults**: Auth disabled by default for ease of setup, but when enabled, provides role-based access, rate limiting, constant-time comparison, and HttpOnly cookies.