feat: add web playground for interactive bus testing (SSE + vanilla UI, all-in-one server)

This commit is contained in:
agent
2026-06-03 21:18:27 +02:00
parent 888ff75236
commit 22d6106e32
3 changed files with 1139 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
# 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:
```bash
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.