A web UI for managing and monitoring OpenRiak clusters. Built with Phoenix LiveView.
The dashboard connects to a Riak node's Admin API over HTTP and (optionally) its WebSocket event stream. It gives you:
Cluster monitoring -- consolidated cluster dashboard with summary cards, ring partition distribution bar, per-node stat cards (memory, processes, gets, puts), interactive area chart with 7 switchable metrics, AAE exchange and handoff counters. Updates in real time over WebSocket; without a WebSocket URL configured, pages show a "Not Connected" indicator and wait for data.
Data browser -- list buckets (with optional bucket type), browse keys, read/write/delete objects, inspect and edit bucket properties and bucket type properties.
Data types -- read and increment counters, inspect and update CRDTs (counters, sets, maps).
Query tools -- run MapReduce jobs, secondary index (2i) queries (exact match and range), and complex queries against buckets.
- Elixir 1.18+ and Erlang/OTP 26+ (install guide)
- A running Riak node with the Admin API enabled. Standalone nodes default to port 8099; quickstart devrel clusters use 10015/10025/10035/... The dashboard works without one, but most pages will show errors or empty state.
# Clone and install dependencies
git clone <repo-url> && cd dashboard
mix setup
# Start the dev server
mix phx.serverOpen localhost:4000. Log in with admin / password.
If your Riak node isn't at localhost:8099, point the dashboard at it:
RIAK_ADMIN_URL=http://my-riak-node:8099 \
RIAK_WS_URL=ws://my-riak-node:8099/api/stream/events \
mix phx.serverFor local quickstart clusters where Riak nodes run as dev1, dev2, etc., the admin API binds to 10015, 10025, 10035, ... (devN -> 100N5).
Copy and source the sample, then uncomment the quickstart or standalone profile:
cp example.local.env local.env
# Edit local.env — uncomment the profile matching your setup
source local.env # bash/zsh
# source local.env # fish (use set -x instead of export)
mix phx.serverOr use the quickstart helper directly:
RIAK_DIR=/path/to/riak RIAK_DASHBOARD_DIR=/path/to/riak_dashboard \
/path/to/riak_quickstart/06_start_dashboard.shlocal.env probes for the first responsive admin port and sets:
RIAK_ADMIN_URLRIAK_WS_URLRIAK_DASHBOARD_USERRIAK_DASHBOARD_PASS
All configuration comes from environment variables, read at startup in config/runtime.exs.
| Variable | What it does | Default |
|---|---|---|
RIAK_ADMIN_URL |
Riak Admin HTTP API base URL | http://localhost:8099 |
RIAK_WS_URL |
Riak WebSocket event stream URL | ws://localhost:8099/api/stream/events |
RIAK_DASHBOARD_USER |
Basic auth username | admin |
RIAK_DASHBOARD_PASS |
Basic auth password | password |
SECRET_KEY_BASE |
Cookie signing key (required in prod) | set in dev/test configs |
PHX_SERVER |
Set to true to start the HTTP server |
not set (use mix phx.server in dev) |
PHX_HOST |
Hostname for generated URLs | localhost |
PORT |
HTTP listen port | 4000 |
DNS_CLUSTER_QUERY |
DNS query for Erlang clustering | not set |
For a deeper walkthrough of each variable and deployment scenarios, see docs/configuration.md.
Browser
|
|-- HTTP ---------> Phoenix Endpoint (Bandit, port 4000)
| |
| BasicAuth plug
| |
| LiveView (12 pages)
| |
| Client behaviour -- HttpClient (Req) --> Riak Admin API (:8099)
|
|-- WebSocket -----> Riak WS stream (:8099/api/stream/events)
(JS hook) |
pushes events back to LiveView
Most of the dashboard is stateless -- pages call the Riak Admin API on demand (bucket operations, queries) or receive real-time updates over WebSocket (cluster status, ring, handoff, AAE). The one exception is the MetricStore GenServer, which persists per-node metric history to a DETS file at priv/data/metric_store.dets. It stores four tiers of downsampled data (recent 5 min, hourly, daily, weekly) so the metric chart survives restarts.
Client behaviour: RiakDashboard.Cluster.Client defines callbacks for every Riak API endpoint. HttpClient is the real implementation using the Req HTTP library with a 5-second timeout and no retries. In tests, Mox stubs the behaviour so nothing hits the network.
Real-time updates: The cluster dashboard and node detail pages mount a RiakEvents JavaScript hook that opens a WebSocket to Riak's event stream. The hook subscribes to topics (cluster, node_stats, ring, aae, handoff) and pushes incoming events into the LiveView as handle_event calls. If no RIAK_WS_URL is configured, these pages show a "Not Connected" badge. Ring, AAE, and handoff data that previously had standalone pages is now consolidated into the cluster dashboard.
A full architecture diagram is at docs/architecture/system-overview.excalidraw (open with excalidraw.com or the VS Code extension).
| Path | Page | What it shows |
|---|---|---|
/ |
Cluster dashboard | Summary cards, ring distribution bar, per-node stat cards, interactive metric chart, AAE/handoff counters |
/nodes/:node |
Node detail | Erlang VM stats (memory, processes, run queue), KV metrics (gets, puts, latency) |
/buckets |
Bucket browser | List all buckets, link to keys and properties |
/buckets/:b/keys |
Key browser | List keys in a bucket, create new objects |
/buckets/:b/keys/:k |
Object detail | View/edit/delete an object, see metadata (vclock, etag, content-type) |
/buckets/:b/props |
Bucket properties | View and edit n_val, allow_mult, quorum settings, reset to defaults |
/counters |
Counter lookup | Open a counter by bucket + key |
/buckets/:b/counters/:k |
Counter detail | Current value, increment/decrement with custom delta |
/datatypes |
CRDT lookup | Open or create CRDTs by type/bucket/key |
/types/:t/buckets/:b/datatypes/:k |
CRDT detail | Current value, context, update operations |
/mapred |
MapReduce | JSON query editor, formatted results |
/query |
Query | Complex queries with timeout and max_results |
/query/index |
2i query | Secondary index exact match and range queries |
/types |
Bucket types | List known types, edit type properties |
All bucket routes also work with typed buckets: /types/:type/buckets/:bucket/...
Tests use Mox to stub the Client behaviour. No Riak connection needed.
mix test # run all tests
mix test --cover # with coverage
mix credo --strict # code quality
mix sobelow # security scan
mix format --check-formatted # formatting checkThe ConnCase test helper automatically stubs all Client callbacks with realistic fixture data via RiakDashboard.Test.RiakStubs.stub_all/0, so most tests work without any per-test setup. Override specific stubs with Mox.expect/4 when you need to test error paths or specific responses.
# Build a release
MIX_ENV=prod mix deps.get
MIX_ENV=prod mix assets.deploy
MIX_ENV=prod mix release
# Run it
SECRET_KEY_BASE=$(mix phx.gen.secret) \
PHX_SERVER=true \
RIAK_ADMIN_URL=http://riak-node:8099 \
RIAK_WS_URL=ws://riak-node:8099/api/stream/events \
RIAK_DASHBOARD_USER=ops \
RIAK_DASHBOARD_PASS=<something-strong> \
PORT=4000 \
_build/prod/rel/riak_dashboard/bin/riak_dashboard startThe release is a self-contained binary. No Elixir or Erlang installation needed on the target machine.
mix setup # install deps + build assets
mix phx.server # start with file watching
iex -S mix phx.server # start with IEx shell attachedThe dev server live-reloads Elixir code and rebuilds CSS/JS on file changes. Tailwind CSS 4 with daisyUI handles styling. esbuild bundles JavaScript.
lib/
riak_dashboard/
application.ex # supervision tree
metric_store.ex # per-node metric history (DETS-backed)
cluster/
client.ex # behaviour (API contract)
http_client.ex # Req-based implementation
riak_dashboard_web/
router.ex # all routes
endpoint.ex # HTTP server config
plugs/basic_auth.ex # authentication
live/ # 12 LiveView modules
components/dashboard/ # reusable UI components
formatters.ex # value display helpers
assets/
js/hooks/
riak_events.js # WebSocket client hook
metric_chart.js # interactive chart tooltip/crosshair
choices_select.js # enhanced select dropdown
css/app.css # Tailwind 4 + daisyUI
test/
support/
mocks.ex # Mox.defmock
riak_stubs.ex # default stub data
conn_case.ex # test setup with auto-stubs
MIT