diff --git a/kez-chat/deploy/Dockerfile b/kez-chat/deploy/Dockerfile index 68f55d2..a248f52 100644 --- a/kez-chat/deploy/Dockerfile +++ b/kez-chat/deploy/Dockerfile @@ -1,33 +1,42 @@ -# Multi-stage build for kez-chat-server. +# Multi-stage build for kez-chat-server + bundled Svelte SPA. # -# Stage 1: build the Rust binary against kez-core (path dep). The build -# context must be the *repository root* (the dir that contains both -# `kez-chat/` and `rust/`), not `kez-chat/` itself — see the -# `docker-compose.yml` which sets `context: ..`. +# Stage 1: build the Svelte SPA → web/dist/ +# Stage 2: build the Rust binary against kez-core (path dep) +# Stage 3: minimal runtime image with binary + SPA +# +# Build context = repo root (so we can see kez-chat/web/ and rust/). +# docker-compose.yml sets `context: ../..` accordingly. +# ─── Stage 1: build the SPA ──────────────────────────────────────────────── +FROM node:22-slim AS webbuild +WORKDIR /src/web +COPY kez-chat/web/package.json kez-chat/web/package-lock.json* ./ +RUN npm install --no-audit --no-fund +COPY kez-chat/web/ ./ +RUN npm run build + +# ─── Stage 2: build the Rust binary ──────────────────────────────────────── FROM rust:1.86-slim AS build RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config libssl-dev ca-certificates \ && rm -rf /var/lib/apt/lists/* WORKDIR /src - -# Copy what we need: -# - rust/crates/kez-core (path dep) -# - kez-chat (this project) COPY rust/ /src/rust/ COPY kez-chat/ /src/kez-chat/ - WORKDIR /src/kez-chat RUN cargo build --release --bin kez-chat-server -# Stage 2: minimal runtime image +# ─── Stage 3: runtime ────────────────────────────────────────────────────── FROM debian:bookworm-slim RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ && rm -rf /var/lib/apt/lists/* \ && useradd -r -u 10001 -m kez +# Rust binary COPY --from=build /src/kez-chat/target/release/kez-chat-server /usr/local/bin/kez-chat-server +# SPA static files +COPY --from=webbuild /src/web/dist/ /app/web/ USER kez WORKDIR /data @@ -36,6 +45,7 @@ ENV KEZ_CHAT_BIND=0.0.0.0:6969 \ KEZ_CHAT_DB=/data/kez-chat.db \ KEZ_CHAT_SERVER=kez.lat \ KEZ_CHAT_SIG_SERVER_URL=http://sig-server:7878 \ + KEZ_CHAT_WEB_DIR=/app/web \ RUST_LOG=info EXPOSE 6969 diff --git a/kez-chat/web/.gitignore b/kez-chat/web/.gitignore new file mode 100644 index 0000000..c0e66cc --- /dev/null +++ b/kez-chat/web/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +dist/ +.vite/ +*.tsbuildinfo +.DS_Store diff --git a/kez-chat/web/index.html b/kez-chat/web/index.html new file mode 100644 index 0000000..03fc8d9 --- /dev/null +++ b/kez-chat/web/index.html @@ -0,0 +1,13 @@ + + +
+ + +{selected.instructions(envelope.payload.subject)}
+ {format === "markdown" ? toMarkdown(envelope) : toPrettyJson(envelope)}
+
+
+ ✓ Claim saved
+
+ You signed a claim for
+ {envelope.payload.subject}.
+ Once you've published the proof on that channel, come back to the
+ Claims page and mark it published.
+
+ A claim is a signed envelope that says "I control this other account." + Publish the proof on the channel itself (a public gist, a DNS TXT + record, a nostr event, etc.) and anyone can verify it without + trusting this server. +
+ + {#if loading} +Loading…
+ {:else if claims.length === 0} +No claims yet.
+ + Add your first claim + ++ {c.envelope.payload.subject} +
++ Channel: {c.channel} · + Signed: {c.envelope.payload.created_at} +
+ {#if c.published_at} ++ ✓ You marked this published at {c.published_at} +
+ {:else} ++ ⚠ Not marked as published yet +
+ {/if} ++ Couldn't reach the chat server. Try refreshing. +
+ {/if} + + ++ {error} +
+ {/if} + + {#if step === "handle"} + + {/if} + + {#if step === "seed" && id} +⚠️ Back up your seed now
++ This is the only way to recover your account on another device + (or after clearing this browser). The server doesn't have it. + Write it down or paste into a password manager. +
+Ready to register:
+{id.identity}Submitting registration to {serverInfo?.server}…
+ {/if} + + {#if step === "done"} +✓ Account created
++ You are {handle}@{serverInfo?.server}. +
+ +Identity
++ {session.unlocked.handle}@{session.unlocked.server} +
++ {session.unlocked.primary} +
+ + {#if loading} +Loading server record…
+ {:else if error} ++ {error} +
+ {:else if registryRecord} +Claims
++ Link other accounts (GitHub, your domain, nostr, Bluesky, ActivityPub) + to your KEZ identity by signing claims and publishing the proofs. +
+Backup
++ Your seed is the only thing that can recover this account. + Make sure you have it written down. +
+ ++ A decentralized identity + chat system. Create an account, link your + online identities, prove who you are without trusting a central server. +
+Checking local state…
+ {:else if existing} +Existing account on this device:
++ {existing.handle}@{existing.server} +
++ {existing.primary} +
+What is this?
+
+ Your identity is an Ed25519 keypair — not a username + password.
+ Account creation makes a handle (tudisco@kez.lat),
+ stores your seed locally under a passphrase, and registers your public
+ key with this server. There's no email, no recovery flow — keep the
+ seed safe.
+
+ v0.1 limitation: the seed alone doesn't tell us which
+ handle to restore. For now this flow doesn't work end-to-end — we'll
+ add GET /v1/by-primary/<id> on the server in v0.2
+ so the SPA can look up the handle from the public key.
+
+ Unlocking {meta.handle}@{meta.server} +
+ + + + + {/if} +