Files
go-socket/docs/superpowers/specs/2026-04-28-discord-client-design.md

5.6 KiB

Discord-like Client Design

Context

The go-socket backend has a full real-time messaging API (REST + WebSocket) but the React client is nearly empty — only AuthPage and an empty MainApp placeholder exist. This spec covers building the main app UI: a Discord-inspired layout with a connections/DM sidebar and chat panel, wired to the real backend.

Layout

Two-column layout, full viewport height:

┌──────────────────────────────────────────────────────┐
│  [280px sidebar]          │  [flex chat area]         │
│                           │                           │
│  ○ ○ ○ +   ← hub row     │  Contact Name             │
│  ─────────────────        │  ────────────────         │
│  Search...                │                           │
│  ▸ Contact A     [3]      │  [message history]        │
│  ▸ Contact B              │                           │
│  ▸ ...                    │  ──────────────────────   │
│  ─────────────────        │  [ type a message... ] ➤  │
│  [avatar] You  ⚙          │                           │
└──────────────────────────────────────────────────────┘

Sidebar (280px):

  • Hub row: horizontal strip of small icon circles + a + stub button (empty for now, layout ready for hubs)
  • Search input to filter the connections list
  • Scrollable connections list: colored avatar circle (initial fallback), name, unread badge, last-message preview
  • Bottom bar: current user avatar + username + settings gear (stub — no action yet)

Chat area:

  • Header bar: contact name + pronouns
  • Scrollable message history (newest at bottom)
  • Message input + send button

Components

src/
  context/
    AppContext.jsx       — connections, selectedId, messages, currentUser, ws ref
  components/
    MainApp.jsx          — root layout, mounts context provider
    Sidebar.jsx          — hub row + search + connection list + user bar
    HubRow.jsx           — stub hub icons + add button
    ConnectionList.jsx   — filtered, sorted list of ConnectionItem
    ConnectionItem.jsx   — single row: avatar, name, unread badge, last message
    UserBar.jsx          — bottom of sidebar: own avatar, name, settings gear stub
    ChatArea.jsx         — header + message list + input bar
    MessageList.jsx      — scrollable history, auto-scrolls to bottom on new message
    MessageItem.jsx      — single message bubble: sender avatar, content, timestamp
    MessageInput.jsx     — textarea + send button, Enter to send
  api/
    http.js              — thin fetch wrapper; reads token from localStorage; sends token header
    ws.js                — WebSocket singleton: connect, send, onMessage dispatcher

Data Flow

On MainApp mount:

  1. Read token + userId from localStorage (App.jsx already guards this route)
  2. GET /connections → load sidebar list
  3. GET /connections/unreadmessages?connections=<ids> → overlay unread counts
  4. Open WebSocket ws://localhost:8080/ws, on open send {"token": "..."}

On connection selected:

  1. GET /connection/messages?connectionid=<id> → render history
  2. Clear unread badge locally for that connection

Sending a message:

  1. POST /connection/message body: connectionid, msgContent
  2. Optimistically append to message list

Incoming WebSocket events:

Type Action
1 — DirectMessage Append to open chat if matches; else bump unread badge
2 — ConnectionCreated Prepend new connection to sidebar
3 — ConnectionDeleted Remove from sidebar; clear chat if open
4/5 — Elevated/DeElevated Update connection state field (Friend/Stranger cosmetic label)
6/7/8 — Profile/Avatar/BgChange Refresh contact display data

API Reference

All requests send token as a plain header (not Bearer). Token and userId stored in localStorage from login.

Endpoint Usage
GET /connections Load sidebar list on mount
GET /connections/unreadmessages?connections=UUID,UUID Unread counts array
GET /connection/messages?connectionid=UUID Load history for selected DM
POST /connection/message Send message (body: connectionid, msgContent)
WS /ws → send {"token":"..."} Authenticate WebSocket

Design Aesthetic

  • Dark theme (bg-gray-900 base, matching existing index.css)
  • Natural, human-designed feel — no generic AI look
  • User-assigned color (RGBA from server) used as avatar background and accent
  • Subtle hover/active states, no heavy borders
  • Tailwind utility classes, no CSS files

Out of Scope (this spec)

  • Hub channels and hub management
  • User profile/customization UI (gear stub present, no action)
  • File attachments
  • Friend request flow (elevate/deelevate)
  • Connection creation UI

Verification

  1. pnpm dev in client/ — app loads at localhost:5173
  2. Log in with existing credentials → redirects to MainApp
  3. Sidebar shows real connections from the server
  4. Clicking a connection loads message history
  5. Sending a message appears in the chat
  6. Open a second browser tab as another user — send a message → first tab receives it via WebSocket without refresh
  7. Unread badges update when a message arrives for a non-selected connection