plan(kez-chat): add web app design — Svelte SPA served by chat-server
The test UI is a Svelte 5 + TypeScript + Vite + Tailwind single-page
app served as static files by kez-chat-server. The web app uses the
exact same HTTP API a native client would use, so every action in the
UI dogfoods the API contract.
Architecture changes:
- kez-chat-server now serves `/` as the SPA (tower-http ServeDir)
alongside the existing /v1 API
- Web app talks NATS over WebSocket (nats.ws + nats-server's
built-in websocket transport — same auth callout, same nkey auth,
same JetStream durable consumers)
- Web app cannot do Iroh: browsers can't open raw UDP sockets and
Iroh's WebTransport story isn't ready in 2026. Web shows manifests
and prompts "Download requires CLI" for actual file transfer.
- Key storage in browser: passphrase-encrypted IndexedDB (documented
limitation — native clients use OS keychain)
New / updated sections in document.md:
- §1: opening pitch mentions the web app + that it dogfoods the API
- §4.1: responsibilities table adds "serves the test web app"
- §4.4 NEW: full design of the web app — stack, capabilities, what
it can't do in v0, deployment model
- §4.5: endpoint list now includes / (the SPA) and /assets/*
- §4.3: nats.conf snippet enables WebSocket transport alongside the
existing native NATS port; both transports hit the same auth
callout
- §5.4: file-sharing flow notes the web app caveat (visible manifest,
CLI required for actual download)
- §6.1: folder layout adds web/ subdirectory with Svelte/Vite/Tailwind
scaffolding and an updated Dockerfile (multi-stage: build web →
build rust → ship)
- §6.3: dependencies split into Rust server vs Web app sections.
Web app pulls in svelte, typescript, vite, nats.ws, @noble/curves,
@scure/base, canonicalize, svelte-spa-router, tailwindcss,
idb-keyval.
- §7 MVP scope: full Web app checklist added; CLI section renamed
and clarified ("same Rust core powers CLI and future native GUI")
- §8 out-of-scope: "file transfer from the browser" added
- §11 sequenced plan: split into 12 steps; new phases 7-10 are the
web app build (scaffold → account/contacts → chat → manifest);
step 12 deferred native GUI
- §12 summary: rewritten to reflect "two Rust services + a Svelte
web app + a CLI"
- Decisions-locked table: added rows for test UI choice, browser
file transfer, manifest format, frontend framework, in-browser
key storage
This commit is contained in:
parent
055040423e
commit
a1d1aa6983
@ -21,6 +21,9 @@ A real-time chat + file-sharing application with verified identities.
|
||||
downloaded when a recipient actually wants them. No background sync.
|
||||
- Identity is portable: the underlying key + sigchain survives the home
|
||||
server going dark. Handles can be migrated to other servers later.
|
||||
- A **Svelte web app** served directly by `kez-chat-server` is the test
|
||||
UI. It uses the same HTTP API any native client would use, so the
|
||||
web app dogfoods the API. See §4.4.
|
||||
|
||||
This is the Keybase model rebuilt on a decentralized substrate:
|
||||
- **Identity layer** → KEZ (instead of Keybase's central account system)
|
||||
@ -198,6 +201,7 @@ microservices (NATS broker, sigchain server).
|
||||
| **NATS auth callout** | ✅ Yes |
|
||||
| **WebFinger endpoint** | ✅ Yes |
|
||||
| **HTTP API for clients** | ✅ Yes |
|
||||
| **Serves the test web app** (Svelte SPA, built into the binary) | ✅ Yes (§4.4) |
|
||||
| **Sigchain storage** | ❌ No — defer to `kez-sig-server` (separate container) |
|
||||
| **NATS broker** | ❌ No — separate `nats-server` (Go) container |
|
||||
| **Iroh pinning** | ❌ No for v0 — files transfer P2P when both peers are online. Pinning is a future tier. |
|
||||
@ -301,14 +305,22 @@ NATS:
|
||||
2. Set `NATS_URL=nats://your-broker:4222` in the chat-server's env.
|
||||
3. Apply our reference `nats.conf` snippet to their NATS deployment.
|
||||
|
||||
The auth_callout config snippet:
|
||||
The auth_callout config snippet (and WebSocket for browser clients):
|
||||
|
||||
```conf
|
||||
# nats.conf — patched into whichever NATS deployment is used
|
||||
|
||||
# Enable WebSocket transport so the browser SPA can connect.
|
||||
# Native CLI clients use the standard NATS port (4222).
|
||||
websocket {
|
||||
port: 8443
|
||||
no_tls: false # behind a TLS terminator in prod
|
||||
}
|
||||
|
||||
authorization {
|
||||
auth_callout {
|
||||
issuer: "<our auth-callout signing nkey public part>"
|
||||
auth_users: ["AUTHUSER"] # placeholder identity NATS uses
|
||||
auth_users: ["AUTHUSER"] # placeholder identity NATS uses
|
||||
account: "DEFAULT"
|
||||
}
|
||||
}
|
||||
@ -316,12 +328,88 @@ authorization {
|
||||
|
||||
The chat-server signs auth-callout responses with a long-lived nkey
|
||||
that NATS trusts. When a client connects to NATS with their KEZ
|
||||
ed25519 key, NATS forwards the auth request to our chat-server,
|
||||
which checks the handle registry and signs a yes/no response.
|
||||
ed25519 key — whether via native protocol (CLI) or WebSocket
|
||||
(browser) — NATS forwards the auth request to our chat-server,
|
||||
which checks the handle registry and signs a yes/no response. Same
|
||||
auth path for both transports.
|
||||
|
||||
### 4.4 Endpoints
|
||||
### 4.4 The test web app
|
||||
|
||||
The chat-server serves a Svelte single-page app as static files under
|
||||
`/`. The web app is the test UI for the project — and crucially, it
|
||||
**uses the exact same HTTP API a native client would use.** No
|
||||
backend-rendered pages, no server-side state for the SPA. Every action
|
||||
in the web UI goes through the public `/v1/...` API, which means the
|
||||
web app is also a continuous test that the API contract works end to
|
||||
end.
|
||||
|
||||
```
|
||||
Browser hits https://kez.lat/ → SPA HTML+JS+CSS
|
||||
SPA calls https://kez.lat/v1/u/chris → handle lookup (same as CLI)
|
||||
SPA opens wss://kez.lat/nats → NATS broker over WebSocket
|
||||
SPA calls https://sig.kez.lat/v1/sigchains/... → fetch sigchain (same as CLI)
|
||||
```
|
||||
|
||||
#### Stack
|
||||
|
||||
| Layer | Pick |
|
||||
|---|---|
|
||||
| Framework | **Svelte 5 + TypeScript** |
|
||||
| Build | **Vite** (output: static files served by chat-server) |
|
||||
| Routing | **`svelte-spa-router`** (hash routing — works under any subpath) |
|
||||
| NATS client | **`nats.ws`** — the official NATS WebSocket client. nkey auth supported. |
|
||||
| Crypto | **`@noble/curves`** + **`@noble/hashes`** (same primitives our Node port uses) |
|
||||
| Key storage | **passphrase-encrypted IndexedDB.** User enters a passphrase on first launch; seed is encrypted with that key. Documented limitation: browsers don't have an equivalent of OS keychain. Native clients (CLI, future Tauri) get better protection via OS keychain. |
|
||||
| State | **Svelte stores** (built-in; no Redux needed) |
|
||||
| Styling | **Tailwind** (default; trivially swappable) |
|
||||
|
||||
#### What the web app can do (v0)
|
||||
|
||||
- Account creation: generate ed25519 key in-browser, display mnemonic
|
||||
for paper backup, register handle via `POST /v1/register`, upload
|
||||
sigchain endpoint events to `kez-sig-server` via HTTP.
|
||||
- Contacts: look up handles, fetch sigchains, display verified
|
||||
identities (uses the same channel-verification logic via in-browser
|
||||
TypeScript, sharing `@kez/core` and `@kez/channels`).
|
||||
- 1:1 chat: subscribe to NATS inbox over WebSocket, decrypt incoming,
|
||||
encrypt + publish outgoing. Real-time messaging works.
|
||||
- Manifest browse: fetch and decrypt `@chris`'s shared-files manifest;
|
||||
display the list of files; show metadata.
|
||||
- Identity verification view: show the user's sigchain visually (claims,
|
||||
channel proofs, rotations).
|
||||
- Settings: show/re-display the mnemonic, re-verify it, log out
|
||||
(clears IndexedDB).
|
||||
|
||||
#### What the web app can't do (v0)
|
||||
|
||||
- **File download / upload via Iroh.** Browsers can't open raw UDP
|
||||
sockets, and Iroh's WebTransport story isn't ready in 2026. The
|
||||
web app shows the manifest entries and a "Download (requires
|
||||
desktop client)" button that points at the CLI. v0.5 may revisit
|
||||
if Iroh-in-browser matures.
|
||||
- Anything that requires the OS keychain (proper offline crypto).
|
||||
|
||||
#### Deployment
|
||||
|
||||
The web app's static build output (e.g. `kez-chat-server/web/dist/`)
|
||||
is bundled into the chat-server's Docker image at build time and
|
||||
served by axum's `ServeDir`. No separate static host, no separate
|
||||
CDN. `docker compose up` deploys the SPA along with everything else.
|
||||
|
||||
The build pipeline:
|
||||
1. `cd web && npm install && npm run build` → produces `web/dist/`
|
||||
2. Dockerfile copies `web/dist/` into the runtime image
|
||||
3. Rust binary serves it as `GET /*` (with the API mounted at `/v1/...`)
|
||||
|
||||
For dev: `npm run dev` runs Vite's dev server on port 5173, proxying
|
||||
`/v1` requests to the locally-running chat-server. Hot module reload
|
||||
works as normal Svelte dev.
|
||||
|
||||
### 4.5 Endpoints
|
||||
|
||||
```
|
||||
GET / the web app (Svelte SPA)
|
||||
GET /assets/* SPA static assets (CSS, JS, images)
|
||||
GET /v1/healthz
|
||||
GET /v1/u/:handle handle → { primary, sigchain_url, endpoints }
|
||||
POST /v1/register claim a handle (signed body)
|
||||
@ -331,8 +419,8 @@ GET /.well-known/webfinger?resource=acct:tudisco@kez.lat
|
||||
POST /internal/nats/auth verify nkey signature, return permissions
|
||||
```
|
||||
|
||||
Sigchain endpoints are **not** on this server — clients talk directly to
|
||||
`kez-sig-server` for those.
|
||||
Sigchain endpoints are **not** on this server — both web and native
|
||||
clients talk directly to `kez-sig-server` for those.
|
||||
|
||||
---
|
||||
|
||||
@ -427,11 +515,19 @@ The broker sees:
|
||||
the unwrapped content key, verifies BLAKE3 hash. File appears.
|
||||
```
|
||||
|
||||
**v0 limitation:** If tudisco is offline at step 10, chris waits.
|
||||
Iroh will retry; download starts when tudisco's node comes back.
|
||||
Pinning (the server holding a copy) is **not** in v0 — we accept this
|
||||
limitation in exchange for zero server-side storage cost and the
|
||||
simplest possible architecture.
|
||||
**v0 limitations:**
|
||||
|
||||
1. If tudisco is offline at step 10, chris waits. Iroh will retry;
|
||||
download starts when tudisco's node comes back. Pinning (the
|
||||
server holding a copy) is **not** in v0 — we accept this
|
||||
limitation in exchange for zero server-side storage cost and
|
||||
the simplest possible architecture.
|
||||
2. **The browser SPA can do steps 1–7 (sender side) and step 8
|
||||
(notification + manifest entry visible), but cannot do step 10
|
||||
(fetch the blob)** — browsers can't speak native Iroh. Web users
|
||||
see "File available, open in CLI to download." Native CLI does
|
||||
the whole flow. v0.5 may revisit when Iroh's WebTransport story
|
||||
matures.
|
||||
|
||||
### 5.5 Browsing someone's files (Keybase-style)
|
||||
|
||||
@ -473,15 +569,27 @@ fetching is per-file deliberate. **Recipient never auto-syncs.**
|
||||
├── kez-chat/ ← THIS PROJECT
|
||||
│ ├── document.md (this file)
|
||||
│ ├── Cargo.toml
|
||||
│ ├── src/
|
||||
│ ├── src/ Rust server
|
||||
│ │ ├── main.rs binary entry
|
||||
│ │ ├── handles.rs handle registry (sqlite-backed)
|
||||
│ │ ├── nats_auth.rs NATS auth callout endpoint
|
||||
│ │ ├── webfinger.rs WebFinger discovery endpoint
|
||||
│ │ ├── static_files.rs serves the built web app (axum::ServeDir)
|
||||
│ │ └── api.rs axum routes + state
|
||||
│ ├── web/ Svelte web app (the test UI)
|
||||
│ │ ├── package.json
|
||||
│ │ ├── vite.config.ts
|
||||
│ │ ├── svelte.config.ts
|
||||
│ │ ├── tailwind.config.ts
|
||||
│ │ ├── src/
|
||||
│ │ │ ├── routes/ pages (login, contacts, chat, profile, settings)
|
||||
│ │ │ ├── lib/ crypto, nats client, sigchain helpers
|
||||
│ │ │ └── app.svelte
|
||||
│ │ └── dist/ build output (copied into Docker image)
|
||||
│ ├── deploy/
|
||||
│ │ ├── docker-compose.yml chat-server + nats + sig-server
|
||||
│ │ ├── nats.conf with auth_callout config
|
||||
│ │ ├── nats.conf with auth_callout + websocket config
|
||||
│ │ ├── Dockerfile multi-stage: build web → build rust → ship
|
||||
│ │ └── systemd/ alternative deployment
|
||||
│ └── tests/
|
||||
│ └── http.rs integration tests
|
||||
@ -522,6 +630,8 @@ import cleanly from the start.
|
||||
|
||||
### 6.3 Dependencies (planned)
|
||||
|
||||
**Rust server (`kez-chat-server`):**
|
||||
|
||||
| Crate | Why |
|
||||
|---|---|
|
||||
| `kez-core` (path) | Identity types, ed25519, signing |
|
||||
@ -533,13 +643,28 @@ import cleanly from the start.
|
||||
| `serde` / `serde_json` | Standard |
|
||||
| `thiserror` / `anyhow` | Standard |
|
||||
| `tracing` / `tracing-subscriber` | Logging |
|
||||
| `tower-http` | CORS, request tracing |
|
||||
| `tower-http` | CORS, request tracing, **`fs` feature for serving the SPA static files** |
|
||||
| `clap` | CLI args |
|
||||
|
||||
**Not** depended on by the chat-server:
|
||||
- `iroh` — server doesn't run an Iroh node in v0 (no pinning)
|
||||
- nats-server (Go) — separate container, not a Rust dep
|
||||
|
||||
**Web app (`web/`):**
|
||||
|
||||
| Package | Why |
|
||||
|---|---|
|
||||
| `svelte` 5.x | Framework |
|
||||
| `typescript` | Types |
|
||||
| `vite` | Build + dev server |
|
||||
| `nats.ws` | NATS client over WebSocket (browser-native NATS protocol) |
|
||||
| `@noble/curves`, `@noble/hashes` | Same crypto primitives used in our Node port |
|
||||
| `@scure/base` | bech32 (nsec/npub if needed), base64url |
|
||||
| `canonicalize` | RFC 8785 JCS — for signature interop with native clients |
|
||||
| `svelte-spa-router` | Hash-based routing |
|
||||
| `tailwindcss` | Styling (default; trivially swappable) |
|
||||
| `idb-keyval` | Tiny IndexedDB wrapper for the encrypted seed + cache |
|
||||
|
||||
### 6.4 NATS broker — bundled in compose, not in code
|
||||
|
||||
NATS is **not embedded in the Rust binary** — it's the official Go
|
||||
@ -604,34 +729,51 @@ fallback storage) is a future addition (§8).
|
||||
- [ ] Registration signature validation (uses kez-core)
|
||||
- [ ] WebFinger endpoint
|
||||
- [ ] NATS auth callout (POST /internal/nats/auth)
|
||||
- [ ] Static-file serving for the SPA (`tower-http` `ServeDir`)
|
||||
- [ ] Healthz / metrics
|
||||
- [ ] Integration tests against real nats-server + sig-server in a
|
||||
test docker-compose
|
||||
|
||||
### Deployment
|
||||
### Web app (`web/`)
|
||||
|
||||
- [ ] docker-compose.yml (chat + nats + sig-server)
|
||||
- [ ] nats.conf with auth_callout configured
|
||||
- [ ] systemd alternative deployment recipe
|
||||
- [ ] README with TLS / reverse proxy guidance
|
||||
- [ ] Project scaffold (Svelte 5 + Vite + TypeScript + Tailwind)
|
||||
- [ ] Account creation flow (key gen in-browser, mnemonic prompt,
|
||||
registration POST, sigchain upload)
|
||||
- [ ] Login flow (mnemonic in → derive key → unlock IndexedDB)
|
||||
- [ ] Contacts list (handle lookup, sigchain fetch + display)
|
||||
- [ ] 1:1 chat (NATS-over-WebSocket subscribe/publish, E2E encrypt/decrypt)
|
||||
- [ ] Manifest browse (fetch from sigchain → list entries)
|
||||
- [ ] "Download requires CLI" affordance on manifest entries
|
||||
- [ ] Identity verification view (visualize the sigchain)
|
||||
- [ ] Settings (re-show mnemonic, verify it, log out)
|
||||
- [ ] Build script integrated into the chat-server Docker image
|
||||
|
||||
### Client (`kez-chat-cli` — separate project later)
|
||||
### CLI client (`kez-chat-cli`)
|
||||
|
||||
Out of scope for the server work, but the **server isn't usable without**
|
||||
at least a CLI client that does:
|
||||
Same Rust core powers both the CLI and (later) a native GUI. CLI gets
|
||||
the **file** capabilities the web app can't have:
|
||||
- [ ] Account creation (key gen + mnemonic backup + handle registration)
|
||||
- [ ] Contact lookup + verification
|
||||
- [ ] Send / receive 1:1 chat messages (E2E via NATS)
|
||||
- [ ] Send / receive 1:1 chat messages (E2E via NATS native)
|
||||
- [ ] Send / receive files (E2E via Iroh)
|
||||
- [ ] Browse @user shared-files manifest
|
||||
- [ ] Browse `<handle>` shared-files manifest + download files
|
||||
|
||||
UI app comes after CLI proves the flow works.
|
||||
### Deployment
|
||||
|
||||
- [ ] docker-compose.yml (chat-server [includes SPA] + nats + sig-server)
|
||||
- [ ] nats.conf with auth_callout + websocket configured
|
||||
- [ ] Multi-stage Dockerfile (build web → build rust → final image)
|
||||
- [ ] systemd alternative deployment recipe
|
||||
- [ ] README with TLS / reverse proxy guidance (Caddy recommended)
|
||||
|
||||
---
|
||||
|
||||
## 8. Out of scope (v0)
|
||||
|
||||
- **Iroh pinning** (sender must be online for receiver to fetch)
|
||||
- **File transfer from the browser** (the web app can browse manifests
|
||||
but file download/upload needs the CLI; browsers can't speak Iroh
|
||||
natively in 2026)
|
||||
- **Group chat** (only 1:1 for v0)
|
||||
- **Forward secrecy / ratcheting** (Double Ratchet, MLS) — chat is
|
||||
encrypted but each message uses the same X25519-derived key per pair
|
||||
@ -675,6 +817,11 @@ Settle yes/no on this and the design is locked.
|
||||
| Handle scope: federation or global? | **Global for v0**, federation-ready design (see §3.5). |
|
||||
| Recovery if key lost? | **Paper backup (24-word mnemonic), Keybase-style.** No server-side recovery. |
|
||||
| Iroh pinning in v0? | **No.** Sender must be online for receiver to fetch. Pinning is a future tier. |
|
||||
| Test UI: TUI / web / native GUI? | **Web app, served by `kez-chat-server` as static files.** Built in Svelte 5 + TypeScript + Vite + Tailwind. Uses the same HTTP API native clients use, so it dogfoods the contract. Talks NATS over WebSocket (`nats.ws`). |
|
||||
| Browser file transfer? | **Not in v0.** Browsers can't speak Iroh natively in 2026. The web app shows manifests and prompts "Download requires CLI" for actual files. v0.5 revisit if Iroh's WebTransport story matures. |
|
||||
| Manifest format? | **Option A** — signed JSON blob, hash committed via a new `set_shared_files` sigchain op. Simpler, reuses sigchain primitives. |
|
||||
| Frontend framework? | **Svelte 5 + TypeScript + Vite**. Tailwind for styling (trivially swappable). |
|
||||
| In-browser key storage? | **Passphrase-encrypted IndexedDB.** Documented limitation: browsers lack a Keychain equivalent. Native clients (CLI, future GUI) use OS keychain. |
|
||||
|
||||
---
|
||||
|
||||
@ -739,18 +886,39 @@ When we start building:
|
||||
No UI. Enough to prove the chat flow works end-to-end against
|
||||
the server.
|
||||
|
||||
5. **Iroh integration in the client** (not the server).
|
||||
- Client runs a local Iroh node
|
||||
5. **Iroh integration in the CLI** (not the server).
|
||||
- CLI runs a local Iroh node
|
||||
- `kez-chat share @chris ./file.pdf`
|
||||
- `kez-chat fetch <ticket>`
|
||||
|
||||
6. **Shared-files manifest.** New `set_shared_files` sigchain op.
|
||||
`kez-chat browse @tudisco` lists his shared files.
|
||||
|
||||
7. **Deployment recipe.** docker-compose, systemd, deployment doc.
|
||||
7. **Web app scaffold** (Svelte 5 + Vite + Tailwind). Set up
|
||||
`kez-chat/web/`, wire Vite dev proxy to the running chat-server,
|
||||
"hello world" SPA served by axum's `ServeDir`. Multi-stage
|
||||
Dockerfile builds `web/dist/` then bakes it into the runtime image.
|
||||
|
||||
8. **Then** start the GUI app. Could be Tauri (Rust + web frontend),
|
||||
Iced (pure Rust UI), or something else.
|
||||
8. **Web app: account + contacts + identity.** Account creation in
|
||||
the browser (key gen, mnemonic backup, registration, sigchain
|
||||
upload). Contacts list with sigchain-based verification. Identity
|
||||
view (visualize the sigchain). No chat yet.
|
||||
|
||||
9. **Web app: chat.** `nats.ws` connection, nkey auth, subscribe to
|
||||
inbox subject, encrypt/decrypt with `@noble/curves`. Real-time
|
||||
chat in the browser. End-to-end: messages sent from CLI arrive
|
||||
in the web app and vice versa.
|
||||
|
||||
10. **Web app: manifest browse.** Fetch and decrypt the
|
||||
`set_shared_files` manifest of any contact; display the entries;
|
||||
show "Download requires CLI" affordances on each.
|
||||
|
||||
11. **Deployment recipe finalized.** Production-ready docker-compose
|
||||
(chat-server with embedded SPA + nats + sig-server), Caddy config
|
||||
for TLS, systemd alternative.
|
||||
|
||||
12. **Then** native GUI (Tauri, etc.) — if web app + CLI isn't
|
||||
enough. Likely v1 stretch, not MVP.
|
||||
|
||||
---
|
||||
|
||||
@ -763,19 +931,23 @@ the handle) backed by an ed25519 primary key. The same key authenticates to a NA
|
||||
(chat, presence, file tickets — broker is dumb, clients do E2E with
|
||||
ChaCha20-Poly1305 over X25519-derived keys) and identifies an Iroh
|
||||
node (P2P bulk transfer, content-addressed blobs, on-demand fetch).
|
||||
**Our project ships two Rust services** (`kez-chat-server` for handle
|
||||
registry + NATS auth callout + HTTP API, and the existing
|
||||
`kez-sig-server` for sigchain storage) **plus a docker-compose recipe
|
||||
that includes `nats-server`** for turn-key deployment. NATS isn't in
|
||||
our Rust code — it's the official Go binary running as its own
|
||||
container — but it's wired up in our compose so operators can
|
||||
`docker compose up` and have everything working. Operators with
|
||||
existing NATS deployments can disable the bundled service and point
|
||||
us elsewhere. The chat-server does not run an Iroh node
|
||||
and does not pin files in v0; file transfer is pure P2P between
|
||||
online peers. Account recovery is via a 24-word paper-backup
|
||||
mnemonic. Federation across home servers is deferred but the design
|
||||
keeps it as a flip-the-switch future change.
|
||||
**Our project ships two Rust services + a Svelte web app + a CLI:**
|
||||
`kez-chat-server` (handle registry + NATS auth callout + HTTP API +
|
||||
serves the SPA), the existing `kez-sig-server` (sigchain storage),
|
||||
the `web/` Svelte app (the test UI, served as static files by the
|
||||
chat-server, uses the same HTTP API any native client would —
|
||||
dogfoods the contract), and `kez-chat-cli` (Rust binary that's
|
||||
also the scripted-test surface). NATS isn't in our Rust code — it's
|
||||
the official Go binary running as its own container — but it's
|
||||
wired up in our docker-compose so operators can `docker compose up`
|
||||
and have everything working. Operators with existing NATS deployments
|
||||
can disable the bundled service. The chat-server does not run an
|
||||
Iroh node and does not pin files in v0; file transfer is pure P2P
|
||||
between online peers, and **the browser can't speak Iroh natively —
|
||||
so the web app shows manifests but file download requires the CLI**.
|
||||
Account recovery is via a 24-word paper-backup mnemonic. Federation
|
||||
across home servers is deferred but the design keeps it as a
|
||||
flip-the-switch future change.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user