Files
uopi/docs/WORK_PLAN.md
T
Martino Ferrari 9aa89cc0cf Initial commit
2026-04-24 15:09:14 +02:00

255 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Work Plan — uopi
## Phases Overview
| Phase | Name | Focus | Milestone |
| ----- | --------------------- | ---------------------------------------------------------- | ----------------------------------------- |
| 0 | Scaffold | Repo structure, build toolchain, CI | Empty binary serves embedded index page |
| 1 | Core Backend | Broker, WebSocket protocol, REST skeleton | Live signal fan-out working end-to-end |
| 2 | EPICS Data Source | CA connect, monitor, metadata, write | Real EPICS PVs visible in browser console |
| 3 | Synthetic Data Source | DSP engine, Lua sandbox, signal composition | Synthetic signals computed and streamed |
| 4 | Frontend Foundation | Svelte skeleton, WS client, signal stores, view mode shell | Subscribed values rendered in browser |
| 5 | View Mode Widgets | All widget types rendered in view mode | Full interactive HMI panel |
| 6 | Edit Mode | Konva canvas, drag-and-drop, resize, properties pane | Can build and save a panel |
| 7 | Edit Mode — Advanced | Multi-select, align/distribute, undo/redo | Complete editor UX |
| 8 | Historical Data | Archive integration, time navigation UI | Replay past data in widgets |
| 9 | Signal Discovery | Signal tree, CSV import, EPICS Channel Finder | Usable without manual PV entry |
| 10 | Hardening | Docs, packaging, integration tests, performance | Production-ready binary |
---
## Phase 0 — Scaffold
**Goal:** working build pipeline, empty binary that serves a placeholder page.
- [ ] Initialise Go module (`go mod init github.com/org/uopi`)
- [ ] Create directory layout: `cmd/uopi/`, `internal/`, `web/`
- [ ] Svelte + Vite + TypeScript project in `web/`
- [ ] `//go:embed web/dist` in backend; `Makefile` builds frontend then backend
- [ ] HTTP server on configurable port; serves embedded frontend
- [ ] TOML config loading (`BurntSushi/toml` or `pelletier/go-toml`)
- [ ] GitHub Actions CI: `make test` on push
- [ ] `README.md` with quick-start instructions
**Done when:** `./dist/uopi` starts and serves an "under construction" page.
---
## Phase 1 — Core Backend
**Goal:** signal broker and WebSocket protocol working with a stub data source.
- [ ] Define `DataSource` interface (`internal/datasource/iface.go`)
- [ ] Implement in-memory stub data source (sine wave emitter) for development
- [ ] Implement `Broker` (`internal/broker/`):
- Subscribe / unsubscribe with reference counting
- Fan-out goroutine per signal
- Clean teardown when last subscriber leaves
- [ ] WebSocket handler (`internal/server/ws.go`):
- `subscribe` / `unsubscribe` / `write` / `history` messages
- Pushes `update` and `meta` messages to client
- Graceful close on disconnect
- [ ] REST API skeleton (`internal/api/`): datasources, signals, interfaces endpoints (stub responses)
- [ ] Unit tests: broker fan-out, subscribe/unsubscribe lifecycle
**Done when:** a `wscat` client can subscribe to the stub source and receive timed updates.
---
## Phase 2 — EPICS Data Source
**Goal:** real EPICS PVs readable and writable through the broker.
- [ ] CGo wrapper for EPICS `libca` (`internal/datasource/epics/`):
- Context init and cleanup
- `ca_create_channel` with connection callback
- `ca_add_event` monitor with value callback
- `ca_put` for writes
- DBR_CTRL get for metadata (units, limits, enum strings)
- [ ] Map CA DBR types to internal `DataType` enum
- [ ] Implement `DataSource` interface for EPICS
- [ ] Config: `ca_addr_list`, reconnect interval
- [ ] Handle disconnected/reconnected channels gracefully (quality = Bad/Uncertain)
- [ ] Integration test with SoftIOC (gated on `EPICS_BASE` env var)
**Done when:** a PV subscription round-trips from IOC → broker → WebSocket client with correct timestamp and units.
---
## Phase 3 — Synthetic Data Source
**Goal:** users can define computed signals from existing signals.
- [ ] Define synthetic signal definition schema (JSON)
- [ ] Implement DAG evaluator: nodes re-evaluated on upstream change
- [ ] Built-in node types (`internal/dsp/`):
- Arithmetic: gain, offset, add, subtract, multiply, divide
- Statistics: moving average (by count, by time), RMS
- Filters: IIR lowpass/highpass/bandpass (via gonum or biquad)
- Calculus: finite-difference derivative, cumulative integral
- FFT / inverse FFT (gonum/dft)
- Threshold / clamp
- Custom expression (simple formula parser)
- [ ] Lua node: sandboxed `gopher-lua` state per signal; inputs as globals
- [ ] Load synthetic definitions from `synthetic.json` at startup
- [ ] REST endpoint to CRUD synthetic signal definitions (persists to JSON file)
- [ ] Unit tests for each DSP node type
**Done when:** a synthetic moving-average of an EPICS PV is visible in the WebSocket stream.
---
## Phase 4 — Frontend Foundation
**Goal:** Svelte app connects to WebSocket and reactively displays values.
- [ ] Svelte project structure: routes for view (`/`) and edit (`/edit`)
- [ ] WebSocket client (`ws.ts`): connect, reconnect, message dispatch
- [ ] Signal store factory (`stores.ts`): `getStore(signalName)` returns reactive store
- [ ] Subscription manager: reference counting mirrors broker's
- [ ] View mode shell: collapsible interface list pane + empty canvas area
- [ ] Fetch and list interfaces from REST API
- [ ] Load interface XML; parse widget definitions
- [ ] Render a minimal text-view widget reactively from signal store
- [ ] Basic responsive layout; DPI adaptation for canvas
**Done when:** loading a manually crafted XML interface displays live PV values.
---
## Phase 5 — View Mode Widgets
**Goal:** all widget types rendered and interactive in view mode.
- [ ] Text view widget
- [ ] Gauge widget (SVG arc, configurable range/thresholds)
- [ ] Vertical / horizontal bar widget
- [ ] LED widget (condition evaluator, configurable colours)
- [ ] Multi-LED widget (bitset, per-bit labels)
- [ ] Set-value widget (input + Set button; sends `write` over WS)
- [ ] Button widget (sends fixed value on click)
- [ ] Plot widget:
- Time-series (uPlot, streaming buffer of N points)
- FFT, waterfall, histogram, bar chart, logic analyser (ECharts)
- Multi-signal support; legend
- [ ] Text label (static)
- [ ] Image widget (base64 or server URL)
- [ ] Link widget (navigates to another interface)
- [ ] Right-click context menu: signal info dialog, copy name, export CSV
- [ ] Svelte component tests for each widget type (mock store)
**Done when:** a complete HMI panel with multiple widget types runs smoothly at 60 fps.
---
## Phase 6 — Edit Mode (Core)
**Goal:** users can build and save an interface from scratch.
- [ ] Konva stage setup in edit mode; `devicePixelRatio` scaling
- [ ] Widget renderer adapter: same widget components rendered on Konva layer
- [ ] Signal tree pane: fetch signal list, tree display, filter/search
- [ ] Drag signal from tree → drop on canvas → widget type picker
- [ ] Place widget at drop coordinates with default size
- [ ] Single selection: bounding box + resize handles via Konva `Transformer`
- [ ] Move widget by dragging body
- [ ] Delete widget (× button or Del key)
- [ ] Properties pane: common options (label, position, size)
- [ ] Per-widget property editors (range, colour, plot type, etc.)
- [ ] Save interface to server (POST/PUT XML)
- [ ] Load interface from server (GET XML, populate canvas)
- [ ] Export / import local XML file
**Done when:** an engineer can create a panel with 5+ widgets, save it, reload it, and see live data.
---
## Phase 7 — Edit Mode (Advanced)
**Goal:** complete editing UX matching the functional spec.
- [ ] Multi-select: Ctrl+click toggle; rubber-band area select
- [ ] Group move: drag any selected widget to move all
- [ ] Group delete: Del key on selection
- [ ] Align toolbar: left / center-H / right / top / center-V / bottom
- [ ] Distribute toolbar: evenly by center / by gap (H and V)
- [ ] Undo / redo: command pattern, Ctrl+Z / Ctrl+Shift+Z
- [ ] Snap-to-grid (optional, toggle in toolbar)
- [ ] Add text label tool
- [ ] Add image tool (upload to server or embed base64)
- [ ] Add link tool
- [ ] Collapsible signal tree pane and properties pane (toggle buttons)
- [ ] Right-click on interface in list: Edit / Clone / Delete
**Done when:** the editor feels complete and the undo stack works reliably.
---
## Phase 8 — Historical Data
**Goal:** users can navigate to past timestamps using archive data.
- [ ] EPICS Archive Appliance HTTP API client (`internal/datasource/epics/archive.go`)
- [ ] Broker `History()` dispatch: route to correct data source's `History()` impl
- [ ] WebSocket `history` request / response handling
- [ ] Frontend: time range picker in view mode toolbar
- [ ] "Live" button: flushes history state, re-subscribes to live updates
- [ ] Plot widget: switch between streaming and historical range mode
- [ ] Point-value widgets: show value at selected timestamp
**Done when:** a plot can display 24 hours of archived data with a time slider.
---
## Phase 9 — Signal Discovery
**Goal:** users can find signals without knowing their names in advance.
- [ ] EPICS: attempt Channel Finder or `cainfo` enumeration; fall back to manual entry
- [ ] Signal tree: lazy-load children on expand
- [ ] Manual add custom PV (EPICS): text input in signal tree
- [ ] New synthetic signal wizard: name, inputs, node graph UI
- [ ] CSV import: parse `NAME, DataSource, DS_PARAMETERS`; add to tree
**Done when:** a new user can find and subscribe to a PV without prior knowledge.
---
## Phase 10 — Hardening
**Goal:** production-quality binary, docs, performance validation.
- [ ] End-to-end integration tests (real SoftIOC, headless browser via Playwright)
- [ ] Benchmark: 20 clients × 100 signals; verify < 5 ms fan-out latency
- [ ] Benchmark: frontend at 10 Hz update rate; verify 60 fps
- [ ] Static binary validation: run on RHEL 7 (Docker image `centos:7`)
- [ ] Security: Lua sandbox audit; XML XXE protection; write-permission guard
- [ ] Graceful shutdown: drain WS connections, flush pending writes
- [ ] Structured logging (`log/slog`)
- [ ] `/metrics` endpoint (Prometheus format) for server monitoring
- [ ] Complete `README.md` and operator docs
- [ ] Release: `goreleaser` config for Linux amd64 + arm64 binaries
**Done when:** binary passes integration tests on CentOS 7 container with a SoftIOC.
---
## Estimated Effort
These are rough single-developer estimates. Parallel work across backend and frontend where possible will reduce calendar time.
| Phase | Effort |
| --------- | ---------------- |
| 0 | 12 days |
| 1 | 35 days |
| 2 | 12 weeks |
| 3 | 12 weeks |
| 4 | 35 days |
| 5 | 23 weeks |
| 6 | 23 weeks |
| 7 | 12 weeks |
| 8 | 1 week |
| 9 | 1 week |
| 10 | 12 weeks |
| **Total** | **~1420 weeks** |