6 Commits

Author SHA1 Message Date
Tudisco
a1d1aa6983 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
2026-05-24 23:10:48 -06:00
Tudisco
055040423e plan(kez-chat): handles are tudisco@kez.lat, not @tudisco@kez.lat
Fix the doc: a kez-chat handle looks like an email address —
local@server — with NO leading @. The leading @ is mention syntax
in chat ("hey @tudisco look at this"), the same convention Slack /
Twitter / Discord use. It's not part of the handle.

Three forms now spelled out in §3.1:

  Storage / wire    tudisco@kez.lat        (always fully qualified)
  Display (UI)      tudisco                (when default server; full when cross-server)
  Mention (chat)    @tudisco               (in-message convention; UI resolves)

Specifically updated:
- §1 opener mentions the email-style form + note about mention syntax
- §3.1 fully qualified form, no leading @, with the three-forms table
- §5.1 account creation heading and step 12 now use tudisco@kez.lat
- §5.2 local cache key is "chris@kez.lat" not "@chris@kez.lat"
- §12 summary updated

ActivityPub identifiers in SPEC.md (ap:@jason@mastodon.social) are
unchanged — that's the ActivityPub convention for a different
addressing system.

In-text narrative mentions like "@tudisco shares a file with @chris"
and CLI examples like `kez-chat add @chris` are intentionally
preserved — those use the mention syntax, which the CLI resolves
to the full handle.
2026-05-24 22:55:08 -06:00
Tudisco
7b8b136e92 plan(kez-chat): NATS is bundled in docker-compose, not in Rust code
Correcting an overcorrection. Previous version pushed NATS fully
external — "operator brings their own, we don't ship it." That went
too far. The right line is:

- NATS isn't *Rust code we wrote* — it's the official Go nats-server,
  separate process. We don't embed it. ✓ (unchanged)
- NATS *is* part of our deployment recipe — docker-compose includes a
  `nats` service alongside chat-server and sig-server so operators
  can `docker compose up` and have everything working.

This is the standard "we ship docker-compose with the dependencies
wired up" pattern (like projects that include Postgres in their
compose). Operators with existing NATS deployments can disable the
bundled service and set NATS_URL to their own broker.

Changes:

- §4.2 process diagram: NATS back inside the "our deployment" box,
  with a note that it's bundled-but-separable
- §4.3 docker-compose: nats service restored alongside chat-server
  and sig-server. Reference nats.conf path documented. Instructions
  for swapping in your own NATS broker.
- §6.4 NATS section retitled from "external dependency" to
  "bundled in compose, not in code." Same requirements (NATS 2.10+,
  JetStream, auth_callout) but framed as turn-key by default.
- Decisions-locked NATS row updated: "not in Rust code, yes in
  docker-compose; swap-able by config."
- §11 sequenced plan step 3: wire up the bundled nats service rather
  than "spin up a separate broker for dev."
- §12 summary: "we ship two Rust services PLUS a docker-compose
  recipe that includes nats-server."
- Appendix A trimmed: now just "running NATS standalone if you're
  iterating on chat-server in cargo watch and don't want the full
  compose stack." The full compose IS the standard dev setup.
2026-05-24 22:45:29 -06:00
Tudisco
f0aa86f71a plan(kez-chat): NATS is external infrastructure, not part of our stack
Sharpen the framing: our project doesn't ship, embed, supervise, or
even sit-next-to NATS. NATS is external infrastructure the operator
provides (their own server, Synadia Cloud, whatever) and we connect
to it the way an app connects to a database.

Changes:

- §4.2 process model: redraw the diagram showing NATS *outside* our
  deployment boundary (with a dashed line for "external"), our two
  services on one side, chat-server reaches out to the operator's
  NATS via the auth callout.

- §4.3 docker-compose sketch: remove the nats container entirely.
  Our compose ships chat-server + sig-server only. NATS_URL is an
  environment variable the operator sets. We document the nats.conf
  snippet the operator needs to add to their own NATS deployment.

- §6.4 NATS broker section rewritten as "external dependency" — what
  we require from the operator's NATS (version, JetStream, callout
  config), and why we don't bundle it (NATS is its own ops problem;
  operators may already have one; we shouldn't lock them in).

- §11 sequenced plan step 3: developers spin up a local NATS for
  testing via Appendix A, not "run nats-server in a sibling container."

- Decisions-locked row for NATS now explicit: "We don't ship, embed,
  or supervise it. We connect to whatever broker NATS_URL points at."

- New Appendix A: "running a NATS broker locally for development" —
  one-liner docker run for testing, with explicit "this is dev only,
  not the production deployment recipe."

- §12 one-paragraph summary updated to reflect "our project ships two
  services" (chat-server + sig-server), NATS is external.
2026-05-24 22:40:15 -06:00
Tudisco
f586129787 plan(kez-chat): lock design decisions; rewrite document.md
Sweep through the design doc with all the open questions resolved:

- Microservices: chat-server does NOT bundle sigchain mirror — depends
  on the existing kez-sig-server as a separate container.
- NATS: not embedded in the Rust server. nats-server (Go) runs as its
  own container; chat-server provides an auth callout endpoint that
  nats-server invokes on each client connection.
- No nostr in chat. KEZ is identity-only; nostr only participates as a
  verifiable claim in someone's sigchain, not as transport.
- Global handle namespace for v0, federation-ready design (qualified
  internal handles, HTTP-based lookups, WebFinger from day one).
- Paper-backup recovery (24-word BIP-39-style mnemonic shown at
  account creation, user writes it down, app verifies recall). No
  server-side recovery.
- No Iroh pinning in v0. Files transfer pure P2P; if sender is offline,
  receiver waits. Chat-server doesn't run an Iroh node at all.

Concrete additions to the document:

- §3.4 Paper-backup recovery flow
- §3.5 Federation-ready design notes (qualified handle storage,
  HTTP-based lookups, WebFinger)
- §4.1 Responsibility table now explicitly lists what's NOT in this
  server (sigchain, NATS, Iroh, channel verification)
- §4.3 Sketch of docker-compose.yml showing the three-container
  microservices layout
- §9 collapsed: only one open question remains (manifest format —
  signed blob via sigchain op vs Iroh Doc). Recommended default: A.
- New "Decisions locked" table at the end of §9 summarizing all the
  closed questions
- §5.4 file sharing flow notes "both peers online for v0"
- §6.5 explicitly states "chat-server doesn't run an Iroh node"
- §7 MVP scope trimmed (no Iroh pinning checkbox)
- §11 sequenced plan reflects microservices ordering

Ready to attack once the manifest format decision lands.
2026-05-24 22:37:08 -06:00
Tudisco
008875a2ad plan(kez-chat): add design doc for the chat + file share project
Pre-implementation planning document for kez-chat — a Keybase-class chat
and file sharing app built on the KEZ stack.

Architecture (no code yet, just the plan):

- Identity: KEZ ed25519 primary keys; handles look like
  @username@kez.lat (placeholder default home server).
- Messaging: NATS broker, dumb relay, clients do E2E with
  ChaCha20-Poly1305 over X25519-derived keys. nkeys-auth means the
  user's KEZ primary key literally IS their NATS credential.
  JetStream handles offline delivery.
- File transfer: Iroh peer-to-peer, content-addressed blobs.
  On-demand fetch (no folder sync, no surprise downloads).
  Shared-files manifest committed via a new sigchain `set_shared_files`
  op; per-entry encryption for private shares.

Server: a single Rust binary `kez-chat-server` that bundles the
handle registry, NATS auth callout, optional sigchain mirror, and
optional Iroh pinning. NATS broker and Iroh node run alongside it.

Includes:
- End-to-end flows (account creation, add contact, send message,
  share file, browse files)
- Proposed folder restructure: pull kez-core + kez-channels out into
  a top-level `rust-lib/` workspace so downstream projects (sig-server,
  chat-server, future) can path-depend cleanly without reaching into
  each other's crate trees
- MVP scope and explicit out-of-scope list
- 7 open design questions with my recommended defaults
- Sequenced build plan (refactor first → server scaffold → NATS auth
  → CLI client → Iroh → manifest → deploy → GUI)
2026-05-24 22:21:03 -06:00