Add control logic engine, panel logic dialogs, logic-edit restriction
Introduce server-side control-logic flow graphs (cron/alarm triggers, Lua blocks) with CRUD endpoints, panel-logic lifecycle triggers and user-interaction dialog nodes, and a synthetic node-graph editor. Add an optional logic-editor allowlist (server.logic_editors) gating who may add/edit panel logic and control logic, surfaced via /api/v1/me and enforced in the API; hide logic affordances in the UI accordingly. Update README, example config, and functional/technical specs to cover all current features (plot panels, panel/control logic, local variables, access control) and refresh the in-app manual and contextual help. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+133
-46
@@ -8,13 +8,23 @@ uopi is a web-based HMI (Human-Machine Interface) for monitoring and controlling
|
||||
|
||||
## 2. Users and Roles
|
||||
|
||||
| Role | Description |
|
||||
|------|-------------|
|
||||
| Operator | Uses interfaces in View mode; can interact with controls but cannot edit layouts |
|
||||
| Engineer | Creates and edits interfaces in Edit mode; manages signal lists |
|
||||
| Administrator | Manages server configuration, data sources, and saved interfaces |
|
||||
User identity is established from a header set by a trusted authenticating reverse
|
||||
proxy (`server.trusted_user_header`), with a configurable `default_user` fallback for
|
||||
unproxied/LAN deployments. There is no login page inside the application.
|
||||
|
||||
In the initial version all users share the same access level. Role-based access control is deferred to a future release.
|
||||
**Global access levels.** Every user is trusted with full **write** access by default. A
|
||||
configuration blacklist can downgrade specific users to **read-only** (view only, no
|
||||
writes) or **no access** (denied). Named **groups** are defined in configuration and
|
||||
referenced by per-panel sharing.
|
||||
|
||||
**Per-panel access.** Panels are owned by their creator and private by default. Owners
|
||||
share a panel with specific users/groups (read or write) or make it public; the owner's
|
||||
global level always caps the per-panel permission. Panels are organised into nested
|
||||
folders whose permissions inherit down the chain. See §9.
|
||||
|
||||
**Logic-edit restriction.** Adding/editing panel logic and server-side control logic can
|
||||
optionally be limited to an allowlist of users/groups (`server.logic_editors`); when
|
||||
unset, any writer may edit logic.
|
||||
|
||||
---
|
||||
|
||||
@@ -30,27 +40,27 @@ The default mode when opening the application.
|
||||
- "New interface" button opens Edit mode with a blank canvas.
|
||||
- The pane width can be adjusted by dragging the resize handle on its right edge.
|
||||
|
||||
**Tabs**
|
||||
- **HMI tab**: the live widget canvas (described below).
|
||||
- **Plot tab**: a dedicated live multi-signal plot panel (see §3.3).
|
||||
- **Info tab**: signal info and metadata display for the last right-clicked signal.
|
||||
|
||||
**HMI canvas (center)**
|
||||
- Renders the selected interface as a live, interactive panel.
|
||||
- Widgets display real-time data; controls (set-value, buttons) are active.
|
||||
- Panel logic (if any) runs while the panel is open (see §6).
|
||||
- No drag, resize, or layout operations are possible in this mode.
|
||||
- Right-clicking any widget opens a context menu:
|
||||
- **Signal info** — switches to the Info tab showing DS name, type, unit, range, current value and timestamp.
|
||||
- **Signal info** — shows DS name, type, unit, range, current value and timestamp.
|
||||
- **Copy signal name** — copies the signal identifier to the clipboard.
|
||||
- **Export data to CSV** — downloads buffered data for the signal(s) used by the widget.
|
||||
- **Plot** — adds the signal(s) to the Plot tab.
|
||||
|
||||
> Dedicated multi-signal plotting is provided by **plot panels** — a special interface
|
||||
> kind whose plots fill the viewport (see §3.3) — rather than a separate live "Plot tab".
|
||||
|
||||
**Top toolbar**
|
||||
- Show/hide interface list pane.
|
||||
- **⏱ History** button: toggle historical time navigation bar.
|
||||
- **⚙ Control logic** button: open the server-side control-logic editor (see §7).
|
||||
Shown only to users permitted to edit logic.
|
||||
- Zoom control (A− / % / A+): adjust the UI scale (see §3.4).
|
||||
- Edit button: switch to Edit mode for the current interface.
|
||||
- Connection status indicator.
|
||||
- Connection status indicator and signed-in user chip.
|
||||
|
||||
**Historical time navigation bar** (shown when History is active)
|
||||
- Date/time range pickers (start and end).
|
||||
@@ -71,9 +81,17 @@ Activated via the "New interface" button or by clicking Edit in the toolbar.
|
||||
- Filter/search box to narrow the list.
|
||||
- Synthetic signals show an edit (✎) button to reopen the wizard.
|
||||
|
||||
**Widget canvas (center)**
|
||||
- Free-form canvas where widgets can be placed at arbitrary pixel positions.
|
||||
- Background grid with snap-to-grid.
|
||||
**Center area — Layout / Logic tabs**
|
||||
- **Layout**: free-form canvas where widgets can be placed at arbitrary pixel positions,
|
||||
over a background grid with snap-to-grid. (For plot panels this is replaced by the
|
||||
split-layout editor; see §3.3.)
|
||||
- **Logic**: a node-graph flow editor for panel behaviour (see §6). Hidden when the user
|
||||
is not permitted to edit logic.
|
||||
|
||||
**Local variables**
|
||||
- A panel may declare panel-scoped variables (data source `local`) with initial values.
|
||||
- They are written by set-value widgets, buttons and logic actions, and referenced
|
||||
anywhere a signal is. Added from the signal tree's *Local* group / the Logic palette.
|
||||
|
||||
**Properties pane (right, resizable and collapsible)**
|
||||
- Appears when one or more widgets are selected.
|
||||
@@ -88,25 +106,27 @@ Activated via the "New interface" button or by clicking Edit in the toolbar.
|
||||
- Close (return to View mode).
|
||||
- Zoom control (A− / % / A+).
|
||||
|
||||
### 3.3 Plot Tab (Live Multi-Signal Plot)
|
||||
### 3.3 Plot Panels (Split Layout)
|
||||
|
||||
A dedicated panel for live time-series plotting of any signals, independent of the interface layout.
|
||||
A **plot panel** is a special interface kind dedicated to charts. Rather than free-form
|
||||
widget boxes, plots **fill the viewport** and the user divides the space between them with
|
||||
a recursive split layout (tmux/IDE-style tiling). Created via **+ Plot** in the interface
|
||||
list, opening with a single full-viewport empty plot.
|
||||
|
||||
**Adding signals:** right-click any widget in the HMI tab → **Plot**. The signal is added to the Plot tab immediately.
|
||||
**Editing (Edit mode):**
|
||||
- Hover a pane and use its split buttons (**⬌** vertical / **⬍** horizontal) to divide it;
|
||||
a new empty plot fills the freed half. Nesting is unlimited.
|
||||
- Drag the divider between two panes to resize them.
|
||||
- Click a pane to select it and configure its plot in the Properties pane (plot sub-type,
|
||||
Y range, time window, legend, per-signal colour). Drag a signal onto a pane to add it.
|
||||
- A pane's **✕** removes it; the layout collapses onto its sibling.
|
||||
|
||||
**Time window selector:** 10s / 30s / 1m / 5m / 15m / 1h buttons control how much history is displayed.
|
||||
**View mode:** the saved split layout fills the screen with live, streaming plots; the
|
||||
per-widget right-click menu (signal info / copy / CSV) and historical time navigation
|
||||
apply as for any time-series plot.
|
||||
|
||||
**Per-signal legend:**
|
||||
- Color swatch and signal name.
|
||||
- Statistics table: Last / Min / Max / Mean over the current window.
|
||||
- ✎ button opens an inline style editor:
|
||||
- **Color**: color picker.
|
||||
- **Width**: line width (none, 1, 1.5, 2, 3 px).
|
||||
- **Line**: solid / dashed / dotted.
|
||||
- **Markers**: none, S (3 px), M (5 px), L (8 px).
|
||||
- ✕ button removes the signal from the plot.
|
||||
|
||||
**Chart area:** rendered with uPlot; auto-scaled Y axis; time axis tracks the rolling window in real time.
|
||||
Per-plot configuration reuses the standard Plot widget (§4.4), so all plot sub-types and
|
||||
options are available within a pane.
|
||||
|
||||
### 3.4 UI Zoom
|
||||
|
||||
@@ -210,16 +230,18 @@ When the signal's metadata reports enum strings (e.g. EPICS mbbi/mbbo records):
|
||||
|
||||
A signal defined by composing one or more input signals through a chain of processing nodes.
|
||||
|
||||
**New Synthetic Signal Wizard:**
|
||||
1. Click "New synthetic signal" in the signal tree.
|
||||
2. Name the signal and optionally set a unit.
|
||||
3. Add processing nodes from the node type dropdown and connect them.
|
||||
4. Configure each node's parameters inline.
|
||||
5. Click Create — the signal appears in the tree and updates live.
|
||||
**Two authoring surfaces:**
|
||||
- **Wizard** — for the common single-input case: name the signal, pick an input and a
|
||||
processing node, set parameters, Create.
|
||||
- **Node-graph editor** — a visual editor that wires one or more inputs through a chain of
|
||||
DSP blocks, for multi-input pipelines. It compiles to the same inputs + pipeline model.
|
||||
|
||||
The wizard dialog is resizable (drag its corner) and defaults to 600 px wide to accommodate the Lua editor.
|
||||
**Visibility scope:** each synthetic signal is scoped as *panel* (visible only to the panel
|
||||
that created it), *user*, or *global* (shared with everyone).
|
||||
|
||||
**Editing an existing synthetic signal:** click the ✎ button next to the signal in the tree to reopen the wizard.
|
||||
The dialogs are resizable and default to a width that accommodates the Lua editor.
|
||||
|
||||
**Editing an existing synthetic signal:** click the ✎ button next to the signal in the tree to reopen the editor.
|
||||
|
||||
**Built-in node types:**
|
||||
|
||||
@@ -237,15 +259,80 @@ The wizard dialog is resizable (drag its corner) and defaults to 600 px wide to
|
||||
|
||||
---
|
||||
|
||||
## 6. Interface Persistence
|
||||
## 6. Panel Logic
|
||||
|
||||
- Interfaces are saved to the server in XML format and are available to all connected clients.
|
||||
- Export/Import allows local file exchange of XML files.
|
||||
- The XML schema records: widget type, position, size, signal bindings, and all property values.
|
||||
The **Logic** tab in the panel editor is a node-graph (Node-RED-style) flow editor that
|
||||
gives a panel interactive behaviour. The flow runs **client-side** while the panel is open
|
||||
in View mode; it is saved as part of the interface XML. The tab and any logic editing are
|
||||
gated by the logic-edit restriction (§2).
|
||||
|
||||
**Authoring:** drag blocks from the palette (or click to add), connect output ports to
|
||||
input ports, and edit the selected node in the inspector. Expression fields reference a
|
||||
signal as `{ds:name}` and a panel-local variable by its bare name, and support arithmetic,
|
||||
comparisons, boolean logic and common math functions. The editor has its own undo/redo and
|
||||
copy/paste.
|
||||
|
||||
**Node categories:**
|
||||
|
||||
| Category | Nodes |
|
||||
|----------|-------|
|
||||
| Triggers | Button press, threshold crossing, value change, timer/interval, panel loop, On-open / On-close lifecycle |
|
||||
| Logic | AND gate, If (then/else), Loop (count or while) |
|
||||
| Actions | Write to signal/variable, Delay, Log; Accumulate / Export-CSV / Clear for in-memory data arrays |
|
||||
| Dialogs | Info and Error pop-ups; Set-point prompt (asks the user for a number and writes it) |
|
||||
|
||||
**System helpers in expressions:** `{sys:time}` (epoch seconds) and `{sys:dt}` (seconds
|
||||
since the firing trigger last fired).
|
||||
|
||||
---
|
||||
|
||||
## 7. Historical Data Navigation
|
||||
## 7. Control Logic
|
||||
|
||||
**Control logic** is server-side automation: flow graphs that run continuously on the
|
||||
server, independent of any connected client (unlike panel logic, which only runs while a
|
||||
panel is open). Opened with the **⚙ Control logic** button in the View-mode toolbar and
|
||||
managed through the REST API.
|
||||
|
||||
- Triggers include *cron* schedules and signal *alarm*/threshold conditions.
|
||||
- A **Lua** block provides custom logic; results are written back to signals.
|
||||
- Each graph can be enabled/disabled independently; saving reloads the engine live.
|
||||
- Editing is gated by the logic-edit restriction (§2).
|
||||
|
||||
---
|
||||
|
||||
## 8. Interface Persistence
|
||||
|
||||
- Interfaces are saved to the server in XML format and are available to all connected clients.
|
||||
- Per-panel access rules and panel-folder placement are stored server-side (sidecar JSON).
|
||||
- Saved versions are retained; a panel's version history can be listed, tagged and promoted.
|
||||
- Export/Import allows local file exchange of XML files.
|
||||
- The XML schema records: interface kind (panel/plot) and split layout, widget type,
|
||||
position, size, signal bindings, all property values, local variables, and panel logic.
|
||||
|
||||
---
|
||||
|
||||
## 9. Access Control, Sharing & Folders
|
||||
|
||||
**Identity** is resolved per request from the trusted proxy header, falling back to
|
||||
`default_user`. The `/api/v1/me` endpoint reports the caller's identity, global level,
|
||||
group memberships and whether they may edit logic; the UI hides affordances accordingly.
|
||||
|
||||
**Global levels** (§2): write (default), read-only, or no-access via the config blacklist.
|
||||
|
||||
**Per-panel sharing:** the **Share** dialog on a panel grants read or write to specific
|
||||
users or groups, or marks the panel public. New panels are private to their owner. The
|
||||
owner's global level caps any per-panel grant.
|
||||
|
||||
**Folders:** panels are organised into nested folders; permissions inherit down the folder
|
||||
chain. Panels can be dragged to reorder or move between folders.
|
||||
|
||||
**Logic-editor allowlist:** when `server.logic_editors` is set, only the listed users/
|
||||
groups may add or change panel logic and control logic; everyone else keeps full access to
|
||||
the rest of the application.
|
||||
|
||||
---
|
||||
|
||||
## 10. Historical Data Navigation
|
||||
|
||||
When the server has archive access configured:
|
||||
- The **⏱ History** button in the View mode toolbar reveals a time range bar.
|
||||
@@ -257,7 +344,7 @@ When the server has archive access configured:
|
||||
|
||||
---
|
||||
|
||||
## 8. Non-functional Requirements
|
||||
## 11. Non-functional Requirements
|
||||
|
||||
| Requirement | Target |
|
||||
|-------------|--------|
|
||||
|
||||
+105
-24
@@ -186,17 +186,35 @@ Framing: JSON messages over a single persistent WebSocket connection per client.
|
||||
|
||||
Base path: `/api/v1`
|
||||
|
||||
| Method | Path | Description |
|
||||
| ------ | ------------------------- | -------------------------------------------- |
|
||||
| GET | `/datasources` | List connected data sources and their status |
|
||||
| GET | `/signals?ds=epics` | List signals for a data source |
|
||||
| GET | `/signals/:ds/:name/meta` | Get full metadata for a signal |
|
||||
| GET | `/interfaces` | List saved interfaces |
|
||||
| POST | `/interfaces` | Create a new interface (body: XML) |
|
||||
| GET | `/interfaces/:id` | Download interface XML |
|
||||
| PUT | `/interfaces/:id` | Update interface XML |
|
||||
| DELETE | `/interfaces/:id` | Delete interface |
|
||||
| POST | `/interfaces/:id/clone` | Clone an interface |
|
||||
| Method | Path | Description |
|
||||
| --------------- | ------------------------------------- | ------------------------------------------------- |
|
||||
| GET | `/me` | Caller identity, global level, groups, `canEditLogic` |
|
||||
| GET | `/datasources` | List connected data sources and their status |
|
||||
| GET | `/signals?ds=epics` | List signals for a data source |
|
||||
| GET | `/signals/search?q=` | Search signals across all sources |
|
||||
| GET | `/channel-finder?q=` | Proxy to EPICS Channel Finder |
|
||||
| GET | `/archiver/search?q=` | Search the EPICS archiver for PV names |
|
||||
| GET, POST | `/interfaces` | List saved interfaces / create one (body: XML) |
|
||||
| POST | `/interfaces/reorder` | Reorder panels / move between folders |
|
||||
| GET, PUT, DELETE| `/interfaces/{id}` | Download, update, or delete an interface |
|
||||
| POST | `/interfaces/{id}/clone` | Clone an interface |
|
||||
| GET | `/interfaces/{id}/versions` | List saved versions; `…/{version}` to fetch one |
|
||||
| PUT | `/interfaces/{id}/versions/{v}/tag` | Tag a version |
|
||||
| POST | `/interfaces/{id}/versions/{v}/promote` | Promote a version to current |
|
||||
| POST | `/interfaces/{id}/versions/{v}/fork` | Fork a version into a new panel |
|
||||
| GET, PUT | `/interfaces/{id}/acl` | Read or set a panel's sharing rules |
|
||||
| GET, POST | `/folders` | List or create panel folders |
|
||||
| PUT, DELETE | `/folders/{id}` | Rename/reparent or delete a folder |
|
||||
| GET | `/usergroups` | List configured users and groups (for sharing) |
|
||||
| GET, PUT | `/groups` | Read or set group definitions |
|
||||
| GET, POST | `/synthetic` | List or create synthetic signal definitions |
|
||||
| GET, PUT, DELETE| `/synthetic/{name}` | Read, update, or delete a synthetic definition |
|
||||
| GET, POST | `/controllogic` | List or create server-side control-logic graphs |
|
||||
| GET, PUT, DELETE| `/controllogic/{id}` | Read, update, or delete a control-logic graph |
|
||||
|
||||
Mutating requests are gated by the access middleware (§8): global level for writes,
|
||||
per-panel ACL for interface endpoints, and the logic-editor allowlist for control-logic
|
||||
endpoints and for any change to a panel's `<logic>` block.
|
||||
|
||||
### 3.5 EPICS Data Source
|
||||
|
||||
@@ -232,7 +250,15 @@ Base path: `/api/v1`
|
||||
|
||||
### 3.7 Interface Storage
|
||||
|
||||
Interfaces are stored as XML files in a configurable directory on the server.
|
||||
Interfaces are stored as XML files in a configurable directory on the server. The
|
||||
`<interface>` element carries an optional `kind` attribute (`panel` default, or `plot`);
|
||||
plot panels add a nested `<layout>` split tree referencing plot widgets by id. Beyond
|
||||
widgets, an interface may also contain panel-local variables and a `<logic>` flow graph
|
||||
(`<node>` + `<param>` + `<wire>`), all round-tripping through the same XML.
|
||||
|
||||
Per-panel access rules and folder placement are kept in a sidecar `acl.json` in the same
|
||||
directory (not in the interface XML), and prior versions of each panel are retained for the
|
||||
version history endpoints.
|
||||
|
||||
```xml
|
||||
<interface name="My Panel" version="1" created="2026-04-24T12:00:00Z">
|
||||
@@ -255,6 +281,39 @@ Interfaces are stored as XML files in a configurable directory on the server.
|
||||
</interface>
|
||||
```
|
||||
|
||||
### 3.8 Panel Logic Engine
|
||||
|
||||
Panel logic is a client-side flow engine (`web/src/lib/logic.ts`, singleton `logicEngine`).
|
||||
The graph is built/edited in the panel editor's Logic tab (`LogicEditor.tsx`) and serialized
|
||||
into the interface XML. In View mode, `Canvas` calls `logicEngine.load(iface.logic)` on
|
||||
mount and `clear()` on unmount. The engine subscribes to every referenced signal into a live
|
||||
cache, then on each trigger activation walks the wired graph (gates, if/loop, actions),
|
||||
evaluating expression fields via a small safe recursive-descent evaluator (no `eval`).
|
||||
Triggers include button/threshold/change/timer/loop and On-open/On-close lifecycle; actions
|
||||
include signal writes, delay, log, in-memory data arrays (accumulate/export-CSV/clear) and
|
||||
user dialogs (info/error/set-point). The engine runs entirely in the browser — no backend
|
||||
component.
|
||||
|
||||
### 3.9 Control Logic Engine
|
||||
|
||||
Control logic is server-side (`internal/controllogic`): always-on flow graphs that run under
|
||||
the root context, independent of any client. The engine subscribes to the broker, fires on
|
||||
cron schedules and signal alarm/threshold conditions, executes a Lua block for custom logic,
|
||||
and writes results back to signals. Graphs are persisted by a store and managed via
|
||||
`/api/v1/controllogic`; each mutation calls `Engine.Reload()` to apply changes live. Graphs
|
||||
can be individually enabled/disabled.
|
||||
|
||||
### 3.10 Access Control
|
||||
|
||||
Identity and global policy live in `internal/access` (`Policy`, `Level`). The user identity
|
||||
is read per request from `server.trusted_user_header` (with a `default_user` fallback) and
|
||||
stored on the request context. `accessMiddleware` gates mutating HTTP methods by the user's
|
||||
global level. Per-panel ownership and ACL evaluation (with folder inheritance) live in
|
||||
`internal/panelacl`, backed by the `acl.json` sidecar. `Policy.CanEditLogic(user)` enforces
|
||||
the optional `server.logic_editors` allowlist over control-logic endpoints and over any
|
||||
change to a panel's `<logic>` block; it is surfaced to the frontend through `/api/v1/me`
|
||||
(`canEditLogic`) so the UI can hide logic-editing affordances.
|
||||
|
||||
---
|
||||
|
||||
## 4. Frontend Architecture
|
||||
@@ -298,16 +357,17 @@ View mode renders widgets as absolutely positioned Preact components on a scroll
|
||||
- Plot widgets maintain a rolling ring buffer of 200,000 samples per signal for smooth long-window display.
|
||||
- Step-hold interpolation: when multiple signals at different update rates share a plot, the most recent value is carried forward to fill the shared time axis correctly.
|
||||
|
||||
### 4.5 Plot Panel (`PlotPanel.tsx`)
|
||||
### 4.5 Plot Panels (`SplitLayout.tsx`, `PlotPanelCanvas.tsx`)
|
||||
|
||||
A live multi-signal plot panel accessible from the "Plot" tab in View mode:
|
||||
Plot panels are interfaces of `kind === 'plot'` whose plots fill the viewport in a recursive
|
||||
split layout (`lib/plotLayout.ts` holds the pure tree helpers; `SplitLayout.tsx` is the
|
||||
shared presentational renderer with draggable dividers):
|
||||
|
||||
- Signals are added by right-clicking any widget and choosing "Plot".
|
||||
- Supports configurable time window (10s to 1h).
|
||||
- Per-signal style editor: color picker, line width (0 = hidden), line dash (solid/dashed/dotted), marker size (none/S/M/L).
|
||||
- Statistics table per signal: last, min, max, mean over the current time window.
|
||||
- Uses a `requestAnimationFrame` loop limited to ≤1 redraw/second when data is not changing.
|
||||
- Chart fills its container; `ResizeObserver` keeps the uPlot canvas sized correctly.
|
||||
- In View mode, `Canvas` renders the saved layout read-only with live `PlotWidget`s.
|
||||
- In Edit mode, `PlotPanelCanvas.tsx` adds per-pane overlays: split (⬌/⬍), close (✕), click
|
||||
to select, and signal-drop to add a signal to that pane's plot.
|
||||
- Each pane reuses the standard `PlotWidget`, so all plot sub-types and options apply.
|
||||
- Layout edits (split/close/resize) participate in the editor's undo/redo.
|
||||
|
||||
### 4.6 Resizable Panels
|
||||
|
||||
@@ -407,17 +467,31 @@ Server is configured via a TOML file (default: `uopi.toml`, overridable via `--c
|
||||
listen = ":8080"
|
||||
storage_dir = "./interfaces"
|
||||
|
||||
# Access control (all optional)
|
||||
trusted_user_header = "" # header carrying the proxy-authenticated user
|
||||
default_user = "" # identity when the header is absent (LAN/dev)
|
||||
logic_editors = [] # users/groups allowed to edit panel & control logic
|
||||
|
||||
# [[server.blacklist]] # downgrade users: level = "readonly" | "noaccess"
|
||||
# user = "guest"
|
||||
# level = "readonly"
|
||||
|
||||
# [[groups]] # named user sets for per-panel sharing
|
||||
# name = "operators"
|
||||
# members = ["alice", "bob"]
|
||||
|
||||
[datasource.epics]
|
||||
enabled = true
|
||||
ca_addr_list = "" # EPICS_CA_ADDR_LIST override
|
||||
archive_url = "" # EPICS Archive Appliance URL
|
||||
channel_finder_url = "" # EPICS Channel Finder URL
|
||||
|
||||
[datasource.synthetic]
|
||||
enabled = true
|
||||
definitions_file = "./synthetic.toml"
|
||||
```
|
||||
|
||||
All settings can also be overridden with `UOPI_*` environment variables (e.g. `UOPI_SERVER_LISTEN`, `UOPI_EPICS_CA_ADDR_LIST`).
|
||||
All settings can also be overridden with `UOPI_*` environment variables (e.g.
|
||||
`UOPI_SERVER_LISTEN`, `UOPI_SERVER_LOGIC_EDITORS`, `UOPI_EPICS_CA_ADDR_LIST`).
|
||||
|
||||
---
|
||||
|
||||
@@ -440,13 +514,20 @@ All settings can also be overridden with `UOPI_*` environment variables (e.g. `U
|
||||
- Lua sandbox: disable `os`, `io`, `package`, `debug` libraries; restrict `math` and `string` to safe subsets.
|
||||
- WebSocket write operations: validate that the target signal is writable before forwarding to the data source.
|
||||
- Interface XML parsing: use strict schema validation to prevent XXE.
|
||||
- No authentication in v1; intended for trusted LAN / SSH-tunnel deployment.
|
||||
- **Identity & access control:** the end-user identity is taken from a header set by a
|
||||
trusted authenticating reverse proxy (`trusted_user_header`), never from client-supplied
|
||||
values — the proxy MUST strip any inbound copy of that header or it can be spoofed. A
|
||||
global blacklist downgrades users (read-only/no-access); per-panel ACLs and the optional
|
||||
`logic_editors` allowlist provide finer control. An unidentified caller (no header, no
|
||||
`default_user`) is treated as a trusted-LAN user with full write access, preserving the
|
||||
unproxied/SSH-tunnel deployment model.
|
||||
|
||||
---
|
||||
|
||||
## 9. Non-goals (v1)
|
||||
|
||||
- User authentication and authorisation.
|
||||
- Built-in user authentication (a login page / credential store) — identity is delegated to
|
||||
the front-end reverse proxy; authorisation (levels, ACLs, logic allowlist) is implemented.
|
||||
- TLS termination (expected to be handled by SSH tunnel or a reverse proxy).
|
||||
- Windows or macOS server binary.
|
||||
- Mobile-optimised frontend layout.
|
||||
|
||||
Reference in New Issue
Block a user