Long polling — GET /messages currently returns immediately. Needs to hold the connection open for up to 15s (per README spec) when no messages are available, returning as soon as a new message arrives. Without this, the SPA polls on a fixed 1.5s interval which is wasteful and adds latency.
Session/client UUID model — Current DB uses simple auto-increment IDs and a single token per user. README spec calls for server-assigned session UUID + client UUID + opaque token. Need sessions and clients tables per the architecture.
Per-client message queues — Currently PollMessages queries the messages table directly. Need a client_queues table so each client gets its own delivery queue with independent cursors, per the multi-client spec.
IRC message format — Responses currently return flat JSON ({id, nick, content, channel, ...}). Need to return IRC-style envelopes: {command: "PRIVMSG", from: "nick", to: "#channel", body: ["text"], id: "uuid", ts: "iso8601"}.
JOIN/PART/NICK events as messages — When a user joins or parts a channel or changes nick, these should be injected into the message stream as {command: "JOIN", ...} etc., not just side-effects.
Nick change endpoint — POST /api/v1/nick or similar. Currently no way to change nick after session creation.
Topic set/get — POST /channels/{name}/topic and topic in channel info. SPA has no topic display.
Ephemeral channels — Channels should auto-delete when last member parts (per design doc). Currently persist forever.
MOTD delivery — Should be sent as numeric 375/372/376 messages in the stream on connect.
SPA Client
Long-poll instead of setInterval — Switch from setInterval(poll, 1500) to recursive long-poll (GET /messages?after=ID&timeout=15). Immediately re-poll after receiving messages.
Display JOIN/PART/NICK events — Show system messages when users join, leave, or change nick.
Handle IRC message envelope format — Parse {command, from, to, body} instead of {nick, content, channel}.
Nick change UI — /nick command should work.
Topic display — Show channel topic in header area.
Unread indicators — Badge on inactive tabs when new messages arrive.
Auto-rejoin on reconnect — If token is saved, rejoin previously joined channels.
Disconnect/reconnect handling — Show connection status, auto-retry on network errors.
Message deduplication — Ensure the same message isn't shown twice if polling overlaps.
Add client_queues table (client_id, message_id) for per-client delivery
Add message_type column to messages (or switch to IRC command-based schema)
Add UUID columns (message.uuid, etc.) — currently using auto-increment IDs
Not needed for MVP
Federation (S2S)
Cryptographic signing / PUBKEY
E2E encryption
Channel modes beyond basic
CLI client functionality
Message history pagination in SPA
Rate limiting
Acceptance criteria
User A and User B can:
Open the SPA in two browser windows
Pick nicks
Join #general
See each other in the member list
Send messages and see them appear in near-real-time (<1s with long polling)
See join/part notifications
Send DMs to each other
## Goal
Two users should be able to open the embedded SPA web client in their browsers, create sessions, join a channel, and exchange messages in real-time.
## What works today
- Session creation (register with nick → get token)
- Token-based auth on all endpoints
- Join/part channels, list channels, list members
- Send messages to channels and DMs
- Poll for new messages (`GET /messages?after=ID`)
- SPA: login screen, tab-based UI, channel join, message send/receive, DM tabs, `/join`, `/part`, `/msg` commands
- Channel message history
- DM send/receive
- Basic member list sidebar
## What's missing for two-user chat
### Backend
- [ ] **Long polling** — `GET /messages` currently returns immediately. Needs to hold the connection open for up to 15s (per README spec) when no messages are available, returning as soon as a new message arrives. Without this, the SPA polls on a fixed 1.5s interval which is wasteful and adds latency.
- [ ] **Session/client UUID model** — Current DB uses simple auto-increment IDs and a single token per user. README spec calls for server-assigned session UUID + client UUID + opaque token. Need `sessions` and `clients` tables per the architecture.
- [ ] **Per-client message queues** — Currently `PollMessages` queries the messages table directly. Need a `client_queues` table so each client gets its own delivery queue with independent cursors, per the multi-client spec.
- [ ] **IRC message format** — Responses currently return flat JSON (`{id, nick, content, channel, ...}`). Need to return IRC-style envelopes: `{command: "PRIVMSG", from: "nick", to: "#channel", body: ["text"], id: "uuid", ts: "iso8601"}`.
- [ ] **JOIN/PART/NICK events as messages** — When a user joins or parts a channel or changes nick, these should be injected into the message stream as `{command: "JOIN", ...}` etc., not just side-effects.
- [ ] **Nick change endpoint** — `POST /api/v1/nick` or similar. Currently no way to change nick after session creation.
- [ ] **Topic set/get** — `POST /channels/{name}/topic` and topic in channel info. SPA has no topic display.
- [ ] **Ephemeral channels** — Channels should auto-delete when last member parts (per design doc). Currently persist forever.
- [ ] **MOTD delivery** — Should be sent as numeric 375/372/376 messages in the stream on connect.
### SPA Client
- [ ] **Long-poll instead of setInterval** — Switch from `setInterval(poll, 1500)` to recursive long-poll (`GET /messages?after=ID&timeout=15`). Immediately re-poll after receiving messages.
- [ ] **Display JOIN/PART/NICK events** — Show system messages when users join, leave, or change nick.
- [ ] **Handle IRC message envelope format** — Parse `{command, from, to, body}` instead of `{nick, content, channel}`.
- [ ] **Nick change UI** — `/nick` command should work.
- [ ] **Topic display** — Show channel topic in header area.
- [ ] **Unread indicators** — Badge on inactive tabs when new messages arrive.
- [ ] **Auto-rejoin on reconnect** — If token is saved, rejoin previously joined channels.
- [ ] **Disconnect/reconnect handling** — Show connection status, auto-retry on network errors.
- [ ] **Message deduplication** — Ensure the same message isn't shown twice if polling overlaps.
### Database Schema Changes
- [ ] Add `sessions` table (uuid, nick, signing_key, created_at, last_seen)
- [ ] Add `clients` table (uuid, session_id, token, created_at, last_seen)
- [ ] Add `client_queues` table (client_id, message_id) for per-client delivery
- [ ] Add `message_type` column to messages (or switch to IRC command-based schema)
- [ ] Add UUID columns (message.uuid, etc.) — currently using auto-increment IDs
### Not needed for MVP
- Federation (S2S)
- Cryptographic signing / PUBKEY
- E2E encryption
- Channel modes beyond basic
- CLI client functionality
- Message history pagination in SPA
- Rate limiting
## Acceptance criteria
User A and User B can:
1. Open the SPA in two browser windows
2. Pick nicks
3. Join `#general`
4. See each other in the member list
5. Send messages and see them appear in near-real-time (<1s with long polling)
6. See join/part notifications
7. Send DMs to each other
clawbot
self-assigned this 2026-02-11 02:44:03 +01:00
Design clarification from sneak: All C2S commands go through POST /messages with the command field. No separate routes for NICK, TOPIC, JOIN, PART, etc.
CLI client updated to use unified endpoint for join/part/list
Web SPA updated: session creation, join/part/nick/messages all use command format
README updated with command table and new endpoint docs
This simplifies the API surface significantly — the entire write path is one endpoint.
## API Unified Command Endpoint
Pushed to `feature/web-client` — all C2S commands now go through `POST /api/v1/messages` with a `command` field:
### Changes
- **`POST /messages`** dispatches by `command` field: `PRIVMSG`, `JOIN`, `PART`, `NICK`, `TOPIC`, `PING`
- **Removed routes**: `POST /channels/join`, `DELETE /channels/{name}`, `POST /register`
- **Renamed**: `/register` → `/session`, `/channels/all` → `/channels`
- **Added DB methods**: `ChangeNick`, `SetTopic`
- **CLI client** updated to use unified endpoint for join/part/list
- **Web SPA** updated: session creation, join/part/nick/messages all use command format
- **README** updated with command table and new endpoint docs
This simplifies the API surface significantly — the entire write path is one endpoint.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Goal
Two users should be able to open the embedded SPA web client in their browsers, create sessions, join a channel, and exchange messages in real-time.
What works today
GET /messages?after=ID)/join,/part,/msgcommandsWhat's missing for two-user chat
Backend
GET /messagescurrently returns immediately. Needs to hold the connection open for up to 15s (per README spec) when no messages are available, returning as soon as a new message arrives. Without this, the SPA polls on a fixed 1.5s interval which is wasteful and adds latency.sessionsandclientstables per the architecture.PollMessagesqueries the messages table directly. Need aclient_queuestable so each client gets its own delivery queue with independent cursors, per the multi-client spec.{id, nick, content, channel, ...}). Need to return IRC-style envelopes:{command: "PRIVMSG", from: "nick", to: "#channel", body: ["text"], id: "uuid", ts: "iso8601"}.{command: "JOIN", ...}etc., not just side-effects.POST /api/v1/nickor similar. Currently no way to change nick after session creation.POST /channels/{name}/topicand topic in channel info. SPA has no topic display.SPA Client
setInterval(poll, 1500)to recursive long-poll (GET /messages?after=ID&timeout=15). Immediately re-poll after receiving messages.{command, from, to, body}instead of{nick, content, channel}./nickcommand should work.Database Schema Changes
sessionstable (uuid, nick, signing_key, created_at, last_seen)clientstable (uuid, session_id, token, created_at, last_seen)client_queuestable (client_id, message_id) for per-client deliverymessage_typecolumn to messages (or switch to IRC command-based schema)Not needed for MVP
Acceptance criteria
User A and User B can:
#generalDesign clarification from sneak: All C2S commands go through
POST /messageswith thecommandfield. No separate routes for NICK, TOPIC, JOIN, PART, etc.Examples:
This means:
POST /channels/joinandDELETE /channels/{name}from the APIPOST /messagesbecomes the single C2S command endpoint — server dispatches bycommandfieldGET /messages(polling),GET /state,GET /history,GET /channels/all,GET /channels/{name}/members,GET /serveras read-only endpointsAPI Unified Command Endpoint
Pushed to
feature/web-client— all C2S commands now go throughPOST /api/v1/messageswith acommandfield:Changes
POST /messagesdispatches bycommandfield:PRIVMSG,JOIN,PART,NICK,TOPIC,PINGPOST /channels/join,DELETE /channels/{name},POST /register/register→/session,/channels/all→/channelsChangeNick,SetTopicThis simplifies the API surface significantly — the entire write path is one endpoint.
clawbot referenced this issue2026-02-11 03:03:11 +01:00
clawbot referenced this issue2026-02-11 09:50:32 +01:00