Bug Fix & Patch Report
alpha_v0.1.0 – v0.9.0

Every fix shipped across nine alpha releases — from UI overhauls and WebSocket sync to a full voice architecture rewrite and live user testing. The complete engineering record.

55+Bugs Fixed
~8,200JS/JSX Lines
27Components
10Automated Tests
α 0.1.0 UI Overhaul & Feature Restoration 8 bugs
CriticalUI / Dark Mode
Settings overlay completely hid side panels in dark mode
The settings modal overlay used a high-opacity background that made both the server list and member panels completely invisible when settings were open.
→ Fix
Adjusted overlay transparency values to maintain panel visibility behind the settings modal. Dark mode now uses a lighter semi-transparent backdrop.
Settings.jsxglobal.css
CriticalTheming
Accent color changes had zero effect — 28+ hardcoded values
The accent color picker looked functional but changing it did nothing. 28+ color values were hardcoded as hex literals throughout CSS and inline styles, bypassing the CSS variable system.
→ Fix
Replaced all 28+ hardcoded hex values with dynamic color-mix() CSS functions referencing the --accent variable. Every themed element now responds to accent color changes in real time.
global.cssChannelPanel.jsxMemberList.jsxSettings.jsx
HighUI / Layout
Compact mode made messages completely unreadable
Toggling compact mode hid avatars entirely and collapsed message rows so aggressively that text was impossible to parse.
→ Fix
Redesigned compact mode to be subtler: reduced avatar size and padding rather than removing avatars, tightened line height without collapsing it.
MessageList.jsxglobal.css
CriticalChat Input
Emoji & GIF pickers completely non-functional
Clicking the emoji or GIF picker buttons opened nothing. Pickers were rendering but positioned off-screen or behind other elements.
→ Fix
Root cause: missing position: relative on the chat input wrapper. Without it, the absolutely-positioned picker panels had no positioning context. Single CSS property fix.
ChatInput.jsxglobal.css
HighVoice / Video
Screen share & streamer mode missing entirely
Screen sharing and streamer mode 2.0 (webcam overlay on screen share) had no implementation. Voice UI only showed mute/deafen.
→ Fix
Implemented full screen share + streamer mode with draggable webcam overlay (grab/grabbing cursor, viewport clamping). Color-coded voice states: mute → yellow, deafen → red, share → teal, streamer → purple.
ChannelPanel.jsxvoiceService.jsglobal.css
MediumNavigation
Full-screen call view locked users out of navigation
Joining a 1-on-1 call took over the entire viewport. Users couldn't check messages or switch channels during a call.
→ Fix
Replaced full-screen call view with a compact call banner above messages. Floating mini call bar when away from the call thread. Controls remain accessible without blocking the app.
CallView.jsxLayout.jsx
MediumUX / Settings
No unsaved changes warning in settings
Users could modify settings then close the modal or navigate away without saving — losing all changes with no warning.
→ Fix
Added dirty-state tracking and a confirmation dialog when users attempt to close settings with unsaved modifications.
Settings.jsx
MediumHome / Dashboard
Home page was an empty welcome screen
The home view was a static "Welcome to KOMMZ" page with no useful content — no server list, no friend activity, no quick actions.
→ Fix
Transformed into a four-card interactive dashboard: favorite servers, online friends activity, quick action buttons, and a streams placeholder.
Home.jsxglobal.css
α 0.2.0 LiveKit Migration & Deployment Stabilization 9 bugs
CriticalVoice / Architecture
P2P WebRTC voice crashed at 3+ concurrent users
The simple-peer mesh network suffered fatal SDP race conditions and ICE coordination failures with 3+ users. Each participant exponentially increased peer connections; the signaling server couldn't handle the coordination overhead.
→ Fix
Complete architecture rewrite: migrated from P2P mesh to self-hosted LiveKit SFU. All clients now connect to a single server that relays audio. Deleted signaling/ and coturn/ directories. Rewrote voiceService.js to use LiveKit SDK with Web Audio API gain nodes for 0–200% volume. Backend mints LiveKit JWTs via livekit-server-sdk.
voiceService.jsdocker-compose.ymlvoice.jslivekit.yamlnginx.conf
CriticalDeployment
package.json files swapped between frontend & backend
During LiveKit migration deployment, the frontend package.json ended up in the backend directory and vice versa. Neither side could start.
→ Fix
Identified and corrected the file swap. Frontend gets livekit-client ^2.9.1, backend gets livekit-server-sdk ^2.9.1. Added verification step to deployment checklist.
package.jsonbackend/package.json
HighInfrastructure
Missing nginx proxy for LiveKit WebSocket endpoint
LiveKit was running on port 7880 but clients couldn't connect. The nginx config still had the old /ws/signal proxy block and was missing the /livekit/ block entirely.
→ Fix
Removed stale /ws/signal block, added /livekit/ proxy to localhost:7880 with proper WebSocket upgrade headers.
nginx.conf
HighVoice State
Ghost users in voice channels after hard refresh
Hard-refreshing or closing the browser tab while in voice left phantom entries in the database. Other users saw ghost connections with no way to remove them.
→ Fix
Added cleanupVoiceState() in ws.js that fires on every WebSocket disconnect — not just when socks.size === 0. Catches hard refreshes, tab closes, and network drops.
ws.js
HighAuth / Config
Placeholder LiveKit API keys never replaced with real ones
Migration template shipped with placeholder LIVEKIT_API_KEY and LIVEKIT_API_SECRET. Placeholders were copied to production — LiveKit rejected every token.
→ Fix
Generated proper API credentials via openssl rand -base64. Updated .env and livekit.yaml with matching keys. Added key generation instructions to deployment docs.
backend/.envlivekit.yaml
CriticalDatabase
Database auth failure after merge — password mismatch
After merging the LiveKit branch, the backend threw auth_failed from PostgreSQL. The merge overwrote DATABASE_URL in .env with a different password, but the Postgres Docker volume still had original credentials.
→ Fix
Retrieved original password from pre-merge env backup, restored correct DATABASE_URL, restarted backend. Added cp .env .env.bak to merge procedure.
backend/.env
HighDeployment
Rogue backend process running with stale API key
After updating LiveKit API keys, voice still didn't work. An orphan Node.js process was still running with the old, invalid key — bound to the same port intermittently.
→ Fix
Identified and killed the rogue process, restarted the systemd service cleanly. New process picked up correct API keys immediately.
kommz-backend.service
MediumVoice UX
Mute/deafen handlers received wrong data shape
After the LiveKit rewrite, ChannelPanel.jsx still expected booleans from toggle functions, but the new voiceService returned {isMuted, isDeafened} objects. Audio state didn't match UI.
→ Fix
Updated handlers to destructure the new object format. Added type-safe ID comparison using String() to prevent silent mismatches.
ChannelPanel.jsx
MediumVoice UX
Optimistic channel switch left stale voice connected state
Switching voice channels didn't reset the connected state. UI briefly showed the user connected to both old and new channels, and sometimes left phantom entries.
→ Fix
Added setVCConnected(null) as first step in optimistic channel switching to clear previous state before establishing new connection.
ChannelPanel.jsx
α 0.3.0 Voice, Roles & UI Polish 4 fixes
Settings overlay transparency
Settings panels had transparent/semi-transparent backgrounds, causing the main app to bleed through behind modals. Fixed with solid background: var(--bg-surface) on all settings panels.
Deafen / mute logic
Unmuting while deafened didn't undeafen — left user unable to hear. Fixed: unmuting while deafened now auto-undeafens. Undeafening also unmutes.
Esc handler with unsaved changes
Pressing Escape in settings would discard edits without warning. Added confirmation dialog: "You have unsaved changes — discard?"
Member panel role display
Members showed no role indication. Added 👑🛡️⚔️ icons next to names based on top assigned role.
α 0.4.0 Notifications, Mentions & Members 3 fixes
MESSAGE_UPDATE / MESSAGE_DELETE sync
Edits and deletes were local-only; other clients saw stale messages. Added real-time WebSocket handlers so edits and deletes propagate across all connected clients immediately.
Unread badge accuracy
Channel unread counts were incrementing on your own messages. Fixed to only count messages from other users.
Mention badge stacking
Multiple @mentions in the same channel would overwrite instead of accumulating. Fixed badge counter to properly sum mentions.
α 0.5.0 Dashboard, Context Menus & Chat Features 7 fixes
Emoji / GIF picker resize
Picker was rendering at full size (400px+), overlapping the chat input on smaller screens. Compacted to 320px overlay that auto-minimizes when user starts typing.
Multiline chat input
Enter was the only way to submit. Fixed: Enter sends, Shift+Enter inserts newline. Textarea auto-expands up to 120px then scrolls.
Message editing
No way to edit messages after sending. Added: press Up Arrow to edit your last message. Inline edit mode with save/cancel.
# hash icon
Text channels were showing a chat bubble icon (confusing with DMs). Replaced with # hash for clear visual distinction.
Resizable channel panel
Panel was fixed-width, wasting space on larger screens. Added drag-to-resize (180–400px), persisted to localStorage.
Image lightbox
Clicking images in chat did nothing. Added full-size overlay view with click-outside-to-close.
Link rendering
URLs in messages were plain text. Now auto-detected and rendered as clickable links with accent color.
α 0.6.0 Settings, Roles Redesign & Polish 8 fixes
Voice bar layout
Buttons were inconsistently arranged. Reorganized to an intuitive layout: [Mic] [Deafen] | [Share Screen] [Disconnect] in a single row.
Screen share modal
Share Screen button opened nothing. Added modal with Screen Share vs Streamer Mode cards + source picker (Entire Screen / Application Window).
Pinned messages background
Pin popover had a transparent background, making pinned messages unreadable over chat. Fixed with solid 340px fixed-width popover.
Jump to message
"Jump" button on pinned messages did nothing. Wired up: scrolls to original message location and flashes it with a 2-second highlight animation.
Audit log readability
Entries showed raw event names like ROLE_CREATE. Replaced with human-readable descriptions with action-specific icons and resolved usernames.
Settings tabs visibility
Voice & Video, Privacy, Keybinds, and Sessions tabs weren't appearing for some users. Root cause: stale deploy. Documented redeployment requirement.
Removed "Copy Server ID"
Unnecessary dev-facing action in the server context menu. Removed.
Removed "Request My Data"
Was in Privacy settings but incompatible with planned E2EE architecture. Removed to avoid false promises.
α 0.7.0 QA Pass & Role UX Overhaul 40+ identified · 10 shipped
QA Assessment
Full code review of all 27 components (~7,000 lines). Identified 40+ issues across 4 severity tiers.
data-msg-id missing on continuation messages
When messages from the same user were grouped (continuation style), the data-msg-id attribute was only on the first message. "Jump to message" from search/pinned silently failed on continuation messages. Fixed: added data-msg-id={m.id} to both msg-group and msg-cont divs.
DM reply payload dropped
Replying in DMs looked like it worked (reply UI appeared) but the reply_to field was never sent to the server. Root cause: handleSend built the payload with reply_to but the DM branch called api.sendDM(activeDM, text) without passing it. Fixed: DM send now passes the full payload.
Auto-select first text channel on server switch
Clicking a server set curServer but not curChannel, leaving users staring at a blank dashboard. Additionally, auto-select could pick a voice channel. Fixed: goServer now filters for the first text channel specifically.
"Unknown" users in member list
Member names showed as "Unknown" or "??" when the user cache didn't have their data. The API returns users in 4+ formats (flat fields, nested objects, from_user, raw IDs). Fixed cacheUser to flatten nested objects and try multiple field names. Boot loop falls back to fetching /users/:id for anyone still showing "??".
Role UX Redesign
  • Left-click member now opens profile card instead of role manager
  • Role management moved to profile card — colored pills with ✕ remove buttons, "+" add dropdown for owners
  • Old RoleManager checkbox popover deleted entirely
  • Role tags styled: colored border + transparent fill, uppercase monospace, removable tags shrink to fit
Scroll-to-top snap bug (3 interacting bugs)
Scrolling to load older messages locked the view at the top. Root causes: (1) auto-scroll effect fired on msgs.length change including prepends, (2) scroll restoration used a single requestAnimationFrame before React committed DOM, (3) re-renders re-triggered the scrollTop < 60 check creating a load loop. Fixed with: lastMsgIdRef tracking, isLoadingOlderRef flag, and double requestAnimationFrame for proper DOM timing.
Chat author name colors
getMemberRole refactored to return { badge, color } so author names in chat are colored to match their top role color.
Profile card role tag styling
Changed from dot + text to bordered pill style for a cleaner role chip design.
α 0.8.0 Allen's Backend Merge + 9 Bug Fixes 9 fixes + integration
Context
Allen delivered a merged backend build with real LiveKit voice integration (WebRTC). This build merges Allen's backend changes with all α 0.7.0 frontend fixes, plus 9 new bug fixes discovered during testing.
1. Emoji tooltips
Hovering over emoji in the picker showed nothing. Built a reverse lookup map from SHORTCODES, added title attribute to every emoji item (e.g., hovering 🤡 shows :clown:).
2. Reply display
Replies had no visual indicator of what was being replied to. Fixed reply reference rendering to show original author and content above the reply.
3. Reactions cross-client sync
Reactions were stored in useState — completely ephemeral. Other users never saw your reactions, they vanished on refresh. Wired up api.addReaction / api.removeReaction calls and WebSocket event handlers for persistence and sync.
4. Reaction picker positioning
The "+" add reaction button opened the emoji picker at the top of the screen. Fixed: picker now anchors to the message hover bar position.
5. Chat disappearing on refresh
Messages were lost on page reload due to a race condition between message loading and channel selection. Fixed message persistence flow.
6. Speaking indicators (green ring)
No visual indication of who was talking in voice. Added green animated ring around active speaker avatars using LiveKit's audio level events.
7. Muted speaking alert
Users would talk while muted with no feedback. Added toast notification: "You're muted! Click to unmute."
8. Volume percentage persistence
Per-user volume slider reset to 100% on refresh. Fixed: volume levels saved to localStorage and restored on boot — applied to both UI state and LiveKit audio gain nodes.
9. Friend requests showing "Unknown"
API returns friend requests in multiple formats (from_user as string ID, nested object, or flat fields). Fixed with three-layer solution: boot caching (App.jsx) with all data shapes, WebSocket handler for real-time requests, and HomePanel self-healing useEffect that auto-fetches any user still showing Unknown.
LiveKit & Frontend Merge
  • Preserved Allen's LiveKit voice service (voiceService.js — 322 lines) with Room events, audio gain nodes, mute/deafen logic
  • Preserved getLiveKitToken API endpoint
  • Merged voice join/leave flows between Allen's WebRTC implementation and frontend state management
  • Applied all α 0.7.0 fixes on top of Allen's merged codebase
  • Resolved conflicts in ChannelPanel.jsx where Allen's LiveKit imports overlapped with UI-only voice logic
α 0.9.0 Live User Testing Fixes 4 bugs + 5 UX + QA suite
Context
First real multi-user testing session with ShadowDoomKnight, antagonism, ToxicRain, and fami all in the app simultaneously. Every bug in this build was discovered by real users — not QA simulation. Also introduced automated Playwright test suite (10 tests).
HighReactions / UI
Reaction picker appeared at top-left of browser (regression)
Clicking "+" to add a reaction opened the emoji picker at coordinates (0, 0) — completely disconnected from the message. The context menu's "+" button couldn't find a [data-msg-id] parent via .closest() because the context menu DOM sits outside the message tree.
→ Fix
openReactPicker now clears the context menu first and falls back to querying the DOM directly with msgsRef.current.querySelector('[data-msg-id="${msgId}"]'). Picker anchors to the message's bounding rect, clamped to viewport.
ChatArea.jsx
HighStatus / State
Status change reverted immediately — DND, Idle, Invisible all broken
Changing status from Online to Idle, DND, or Invisible appeared to work for a split second then snapped back to Online. Root cause: api.updateMe({ status }) returned an error (backend may not support the field) and the error handler auto-reverted to 'online'.
→ Fix
Three-layer fix: (1) removed auto-revert — status persists locally regardless of API response, (2) saved to localStorage('kommz-status') so it survives refresh, (3) boot sequence in App.jsx restores saved status after getMe() and broadcasts via WebSocket. Status picker also added to HomePanel (was only available inside servers).
ChannelPanel.jsxHomePanel.jsxApp.jsx
HighChat / Replies
Reply display showed no reference to original message
Replies rendered as normal messages with no indication of what was being replied to. Users couldn't tell conversation threads apart. Backend stores the reply reference under inconsistent field names across endpoints.
→ Fix
Reply lookup now checks four field names: reply_to, reply_to_id, replied_to, parent_id. Send payload includes both reply_to and reply_to_id for backend compatibility. Shows "↩ Unknown — Original message not loaded" fallback when referenced message isn't in scroll buffer. Reply references render with ↩ icon prefix.
ChatArea.jsx
MediumScroll / Pagination
Scroll pagination could permanently lock up
isLoadingOlderRef could get permanently stuck if the async fetch hung or errored silently — blocking all future pagination attempts until a hard refresh.
→ Fix
Added 5-second safety timeout that force-resets isLoadingOlderRef and loadingMore. Timer clears on successful completion so it doesn't interfere with normal operation.
ChatArea.jsx
Status picker on HomePanel
Status could only be changed from inside a server (ChannelPanel). Added full HomeUserArea component with the same status picker dropdown — click the status text to open, click outside to close.
Server gradients on rail icons
Server buttons in the left sidebar rail all showed default gray regardless of assigned gradient. rail-btn now uses style={{ background: s.gradient }} with white text and text-shadow for contrast.
Voice channel readability
Voice channel names and user names were 11px with low contrast. Bumped to 12px with explicit var(--text-secondary) for better readability on dark backgrounds.
DM header casing
DM conversation headers showed names in all caps. Added text-transform: none guard on .chat-h-name to preserve original casing.
Quick Actions de-emojified
Edit button showed "✏️ Edit" with a colorful emoji. Replaced with themed text-only button matching the app's monochrome design language.
From User Feedback — Already Implemented
  • Create / Join server with invite code (α 0.8.0 — Modals.jsx)
  • 2000 character message limit with counter (α 0.8.0 — ChatArea.jsx)
  • Chat name color reflects top role (α 0.7.0 — getMemberRole)
  • Settings as centered popup overlay with Esc close + unsaved warning (α 0.1.0 / α 0.6.0)
  • Notification bell and settings gear as SVG icons (α 0.8.0 — HomeDashboard)
Playwright Test Suite — 10 Tests
  • Login flow and dashboard rendering
  • Real-time message delivery (two-user, dual browser context)
  • Status persistence across page refresh
  • Reply reference display after right-click → Reply
  • Reaction picker positioning (not at 0,0)
  • Scroll pagination without position glitch
  • DM header proper casing
  • Settings overlay sizing (popup, not fullscreen)
  • 2000 character limit enforcement
  • Server rail gradient rendering
··· Known Issues (Deferred)
IssueStatusNeeds
Replies don't ping the recipientOpenBackend: notification event on reply_to
Role member avatars show ?? in server settingsOpenFrontend: user caching in role tab
Status API may silently failOpenBackend: verify PATCH /auth/me schema
Reactions partially ephemeral (client-side)PartialBackend: WS events + reactions in payloads
Search is client-only (loaded messages only)OpenBackend: server-side search endpoint
File upload button has no handlerOpenFrontend: wire file input to backend
No unpin functionalityOpenBackend: confirm DELETE endpoint
confirm() blocks UI thread on delete/kick/banOpenFrontend: replace with modal components
No "Leave Server" for non-ownersOpenFrontend + Backend
Notification bell is a no-opOpenFrontend: build dropdown
Boot loads servers sequentiallyOpenFrontend: Promise.all
No @mention highlightingOpenFrontend
XSS surface in fmtMsgOpenFrontend: sanitize onclick handlers
Admin badge should be toggle-ableOpenFrontend: per-user setting
Server image upload (icon + banner)OpenBackend: multipart endpoints
Public/private server toggleOpenBackend: is_public field
Role hierarchy drag-to-reorderOpenFrontend + Backend
Permissions UI overhaulOpenFrontend: collapsible, search, sticky save
Server gradient UI (separate pic/banner controls)OpenFrontend
Quick Actions overhaul (templates, group chat)OpenFrontend
··· Roadmap to 1.0.0
VersionFocus
alpha_v0.10.0Permissions UI, role hierarchy, server customization
alpha_v0.11.0File uploads, search, notification dropdown
alpha_v0.12.0Quick Actions (server templates, group chat)
alpha_v0.13.0Security (XSS, confirm→modal, boot parallelization)
beta_v0.14.0Public/private servers, discovery, onboarding
beta_v0.15.0Polish pass, performance, mobile responsiveness
1.0.0Public Launch
··· Cumulative Stats
Impact Overview
55+Bugs Fixed
6Critical Fixes
28+Hardcoded Values
1Arch. Rewrite
20Known Issues
9Releases
Metricα 0.1.0α 0.5.0α 0.7.0α 0.8.0α 0.9.0
Components627272727
JS/JSX lines~1,500~4,200~5,700~8,000~8,200
CSS lines~400~1,250~1,370~1,400~1,450
Bug fixes shipped8~2230+35+
User Settings tabs24888
Server Settings tabs37888
Context menus01555
VoiceNoneSimulatedSimulatedLiveKit WebRTCLiveKit WebRTC
Live user testedNoNoNoNoYes ✓
Automated tests000010

KOMMZ Engineering · Complete Devblog · alpha_v0.1.0 – v0.9.0 · February 2026