# 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=` → overlay unread counts 4. Open WebSocket `ws://localhost:8080/ws`, on open send `{"token": "..."}` **On connection selected:** 1. `GET /connection/messages?connectionid=` → 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