Management Panel#
The CaptureGraph server ships with a web management panel for operating a
deployment without SSH: managing targets, browsing captured data, and
editing procedure code with version history. It lives at /management
on the server (for example https://capture-graph.org/management).
Enabling the panel#
The panel is disabled by default. On first launch the server creates a
commented config.toml next to your capture targets (abridged here):
# CaptureGraph server configuration
#
# Set a password to enable the web management panel at /management.
# The panel (and its API) stays disabled while this is blank.
management_password = ""
[server]
host = "0.0.0.0"
port = 4433
no_delete = true # disable client (app) delete endpoints; the
# management panel can always delete
upnp = true # attempt UPnP port forwarding on startup
target_refresh = 30 # seconds between disk re-scans for targets
worker_threads = 64 # thread pool size for filesystem work
behind_tls_proxy = false
[management]
history_limit = 100 # max snapshots kept per target in .history/
validation_timeout = 20 # seconds before a procedure validation is killed
Set management_password to a strong passphrase and restart the server.
While the password is blank, every management endpoint answers 403 and the
panel shows an explanatory message. See
Running a Server for the full
configuration reference.
Explicitly passed CLI flags (--port, --no-delete, …) override the file.
A .session_secret file is generated alongside config.toml so logins
survive server restarts; failed logins are rate-limited per IP.
Building the panel#
The panel is a Vite app in capturegraph-server/panel/:
The server serves the resulting dist/ automatically at /management.
What you can do#
Targets#
The sidebar is a Finder-style column browser: groups open vertical panels, and every panel has its own + New target that creates a Python target directly in that location. Rename and move targets from the header. The target registry updates live — no restart. Avoid moving a target while a study participant is mid-capture.
Files#
A browser that understands the CaptureGraph layout: the captured data is
rendered against the target's schema (read from definition),
iOS-style at every level — session directories with hex ids and file counts,
nested targets, and hidden bookkeeping files. Drag files onto the page to
upload, download single files or whole directories as zips, copy/move/create/
delete. __capture_target__.py is deliberately excluded from raw file
operations — it changes only through the validated code editor.
Files placed by hand are not part of the schema-defined layout; they sit on disk but the schema-driven views do not show them as captures.
Configure overlay#
Opening a target shows its files immediately. Press ⚙ Configure to open a near-fullscreen overlay (the dimmed margin keeps the files view visible) containing the code editor and version history.
Code editor#
Edit __capture_target__.py in the browser (Monaco). Save & go live
runs the candidate in an isolated subprocess first — it must declare a schema
and mark one @cgserver.target procedure over @cg.procedure(Schema) that
builds and serializes cleanly, and any @cgserver.intercept(...)
interceptors must have servable signatures and unique field paths (see
Targets and Interceptors). Failures come back as structured
errors (syntax, import, build, serialize, interceptors, timeout, crash) and
the live target is untouched. Buttons insert stub interceptor functions.
Because the server re-executes the target module on every definition request, a successful save is served to phones immediately — a study participant pulling to refresh sees the new procedure within seconds.
Version history#
Every successful save snapshots the previous version into the target's
.history/ directory (pruned to history_limit per kind). The History
section diffs any snapshot against the current version and restores it
through the same validation pipeline; a restore snapshots first, so it is
itself undoable.
Node editor#
A visual node editor — build a procedure on a canvas instead of writing Python — is planned but not currently available. Its backend routes are unregistered and the panel exposes only the code editor while the graph importer is rebuilt against the Path/schema model, so every target today is authored in Python and the + New target dialog offers no visual option.
When it returns, a node-mode target will keep its graph in a
procedure_nodes.json file beside a fixed __capture_target__.py stub, so
hand-written interceptors coexist with visual editing. The canvas divides
into Global (results saved to the target root), Session (results
saved to a fresh session directory per capture), and Not Saved (scratch
values) areas plus nested, optionally looped folders, where a node's
placement decides whether — and where — its result is saved. The palette,
settings forms, and edge type-checking are all derived at runtime from the
installed capturegraph-lib, so the editor never re-implements procedure
semantics and new node classes appear without frontend changes.
Deploying at a domain#
The panel works behind any path-preserving reverse proxy. Recommended: TLS terminated by Caddy or nginx.
Caddy (Caddyfile):
nginx:
server {
listen 443 ssl;
server_name capture-graph.org;
# ssl_certificate ...; ssl_certificate_key ...;
location / {
proxy_pass http://127.0.0.1:4433;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 2g; # large capture uploads
}
}
Set behind_tls_proxy = true in config.toml so the session cookie is
marked Secure. For direct TLS without a proxy, set ssl_certfile /
ssl_keyfile instead.
Threat model
The management panel executes Python on the server by design — that's what a procedure is. The password is the entire trust boundary. Never expose the panel over plain HTTP on an untrusted network, and treat the management password like an SSH credential.