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

121 lines
5.6 KiB
Markdown

# 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