1. Technology Stack
Backend (Go)
| Layer | Choice | Rationale |
|---|---|---|
| HTTP router | github.com/go-chi/chi/v5 |
Lightweight, idiomatic, net/http compatible. Matches the existing style (stdlib + cobra/viper). |
| WebSocket | github.com/coder/websocket (ex nhooyr/websocket) |
Context-aware, simpler API than gorilla/websocket, actively maintained. |
| Database | modernc.org/sqlite |
Already in use. Pure Go, keeps cross-compile and CGO_ENABLED=0 working. |
| ORM | REL (github.com/go-rel/rel) with the SQLite3 adapter (github.com/go-rel/sqlite3) |
Data Mapper style ORM (separates domain structs from persistence – fits the existing LocoApp controller layout), database-agnostic, supports transactions, eager loading, query composition and a reltest package for mocking the repository in unit tests. |
| Migrations | github.com/go-rel/rel/cmd/rel (REL's own migration tool) |
Migrations live in Go code, compile-time checked, embed-friendly. Used for the schema described in §3a. |
| Cache / Bus | github.com/redis/go-redis/v9 |
Cache + Pub/Sub for cross-process fan-out of locomotive state events. |
| MCP server | github.com/mark3labs/mcp-go |
Idiomatic Go SDK for the Model Context Protocol. Exposes the same LocoService as MCP tools alongside the REST + WS APIs. Supports both stdio (local) and Streamable HTTP / SSE (remote) transports so it can be mounted under /mcp next to chi. |
| Embedded JS engine | github.com/dop251/goja |
Pure-Go ECMAScript 5.1 engine (with most of ES6). Used by the sibling scripts-executor process to run user-authored throttle scripts in a sandbox. No cgo, keeps CGO_ENABLED=0. Each running script owns one *goja.Runtime on one goroutine (Goja VMs are not goroutine-safe). vm.Interrupt(...) provides a clean way for the executor to stop runaway scripts on deadline, user request or dead-man's switch. |
| Logger | logrus |
Already in use. |
| Config | viper |
Already in use. |
| CLI | cobra |
Already in use; expose loco server and loco worker subcommands. |
Frontend (React)
| Layer | Choice | Rationale |
|---|---|---|
| Bundler / dev | Vite + TypeScript | Fast dev server, HMR, simple production builds. All runtime assets are resolved at npm run build and served from web/dist — no CDN (§7b). |
| Server state | TanStack Query (React Query) | REST caching, retries, deduplication. |
| Client state | Zustand | Tiny, easy to integrate with the WebSocket layer. Redux Toolkit would be overkill. |
| WebSocket | react-use-websocket or a custom useSocket hook |
Reconnect, lifecycle, simple API. |
| UI | Material UI (MUI v9, @mui/material) |
Production-ready React component library implementing Material Design. Comprehensive set of accessible components (sliders, buttons, app bar, drawer, dialogs), built-in theming, responsive breakpoints suitable for both mobile and desktop. See MUI Getting Started. |
| Fonts | @fontsource/roboto |
Roboto is bundled into web/dist at build time — never loaded from Google Fonts at runtime (§7b). |
| Icons | @mui/icons-material |
Official Material Symbols / Material Icons packaged as React components – matches the locomotive control surface (play, stop, lightbulb, horn, etc.). |
| Routing | React Router | Standard. |
| Codegen | tygo (Go → TypeScript types) |
Keep the WS protocol types in sync between Go and TS automatically. |
| Script editor | Monaco editor (@monaco-editor/react) |
Embedded VS-Code-style editor used on the Scripts page for JavaScript source editing (syntax highlighting, basic IntelliSense). Must be vendored via npm and Vite — no cdn.jsdelivr loader at runtime (§7b). The frontend never executes JS – it only edits and submits it to the backend. |