Files
unibus/playground/README.md
T

3.6 KiB

unibus playground

An all-in-one, web-based sandbox for the unibus message bus. One command brings up the entire stack embedded — no NATS to install, no services to wire — and a browser UI lets you exercise the bus visually: create peers, create and join rooms (cleartext or end-to-end encrypted), invite, publish, watch messages arrive live, and kick members (forward secrecy).

This is a playground (see .claude/rules/playgrounds.md): it lives inside the unibus app, reuses the parent Go module (no separate go.mod), is not indexed, and keeps all runtime state under playground/local_files/ (ephemeral, safe to delete).

Run

From the unibus app directory:

cd /home/enmanuel/fn_registry/projects/message_bus/apps/unibus
go run ./playground

Then open http://localhost:7700 in your browser.

Stop with Ctrl-C — the server tears down the web UI, every bus client, the control plane, and the embedded NATS cleanly (no orphaned processes).

Architecture

The browser never speaks NATS. The Go server is the actual bus peer:

browser ──fetch/SSE──▶ playground server (:7700)
                            │  holds one unibus client per named peer
                            ├──HTTP──▶ membership control plane (127.0.0.1:8480)
                            └──NATS──▶ embedded NATS + JetStream (:4260)
  • :7700 — web UI (the only browser-facing port).
  • 127.0.0.1:8480 — membership control plane (rooms, members, sealed keys, rekey, blobs). Internal only.
  • :4260 — embedded NATS + JetStream (the data plane). Internal only.

Each named peer gets its own long-term identity, persisted to playground/local_files/<name>.id, so a peer keeps the same endpoint across restarts. When a peer creates or joins a room, the server subscribes on its behalf and streams every received frame to that peer's open browser tabs over Server-Sent Events.

The playground only orchestrates the public unibus client API (CreateRoom, Join, Subscribe, Publish, Invite, Kick); it never reimplements bus or crypto logic.

Try it: 2 peers + encryption + kick

  1. Open two browser tabs on http://localhost:7700.
  2. Tab A: type alice, click Connect.
  3. Tab B: type bob, click Connect.
  4. Tab A (alice): type a subject like room.general, tick 🔒 encrypted (E2E), click Create room. Copy the resulting room_id.
  5. Tab A (alice): in the Action panel, pick bob as the target peer (use the ↻ button to refresh the peer list if needed) and click Invite to this room.
  6. Tab B (bob): paste the room_id into the join field and click Join.
  7. Type messages in both tabs and hit Send — each message appears live in both tabs, tagged with subject, sender, time, and 🔒 (encrypted) or clear.
  8. Tab A (alice): click Kick from this room with bob selected. The room key rotates to a new epoch. New messages alice sends are no longer visible to bob — forward secrecy: bob no longer holds the current key.

Cleartext rooms (leave the checkbox unticked) behave like plain NATS fan-out: fast, ephemeral, unsigned. Encrypted rooms are the Matrix-like mode: E2E encrypted, persisted, and per-message signed.

State / cleanup

All writable state lives under playground/local_files/:

  • <name>.id — per-peer identity (private keys; treat like an SSH key).
  • play.db — membership store (rooms, members, sealed keys).
  • blobs/ — media blob store.
  • js/ — embedded JetStream store.

Delete the whole playground/local_files/ directory to reset to a clean slate. It is gitignored and never distributed.