Root cause of 'navbar mobile tak bisa pindah halaman': Next <Link>
client-side navigation is dead app-wide. A React hydration mismatch
(#418: 'server rendered text didn't match the client') is thrown by the
SSR-seeded live feeds — relative times (formatRelativeTime(e.edited_at) /
m.created_at) computed with Date.now() render slightly differently on
server vs client, which breaks the Next client router (router.push is a
no-op). The desktop NavRail worked only because it uses plain <a href>
(hard navigation bypasses the broken router).
Fixes:
- mobile-nav.tsx: use plain <a href> (NOT Next <Link>), identical to the
working sidebar NavRail, so mobile nav always navigates regardless of
router state ('ikuti cara kerja sidebar').
- Add suppressHydrationWarning to the SSR-seeded relative-time spans so
server/client drift no longer throws #418 (EditHistory, LiveModerationFeed,
messages/results + detail rows, recordings, TermGlossary,
ChannelCultureGlossary, CategoryDrilldown).
Verified on non-prod :4024 @375px: Voice/Media/Search all navigate, no #418
in console. Plan: .hermes/plans/mobile-nav-hydration-fix.md
Use fixed w-[72px] shrink-0 pills (not flex-1) so the 7 bottom-nav items
keep their shape and scroll horizontally instead of compressing labels to
overlap; add truncating 10px mobile label (12px >=sm).
- Root cause of 'navbar mobile tak bisa pindah halaman': the chatbot FAB
(fixed right-4 bottom-5 z-50) overlapped the rightmost mobile bottom-nav
items (z-40) and intercepted taps. Raise the FAB above the nav on mobile
(bottom above nav, md:bottom-5 on desktop) so it never blocks nav taps.
- Mobile bottom nav now mirrors the FULL desktop sidebar (all 7 items:
dashboard, messages, voice, media, recordings, moderation, analysis);
horizontally scrollable + snap-to-active on narrow screens.
- Select dropdown: clamp portal position within viewport + min-width so it
never overflows off-screen on mobile triggers near the right edge; larger
tap targets on touch.
- Input/Textarea: text-base (16px) on touch to prevent iOS auto-zoom on
focus, text-sm on >=sm; comfortable mobile min-height for chat input.
- Add .hermes/plans/mobile-nav-form-responsive.md spec.
Extract server_nick from metadata.member.displayName in backend messageMapper,
add server_nick to frontend MessageRecord type, and update messages view +
analysis view to display the member's server-specific nickname (with @username
as secondary context) instead of the global username.
Rename server_name (guild name) to server_nick and populate it from
the member's server-specific display name (metadata.member.displayName)
at write time. This is what the moderation dashboard should show as
TARGET — e.g. server nick 'Bandar Togel「✔ ᵛᵉʳᶦᶠᶦᵉᵈ 」' for global
username '.nichiyobi'. Backfilled 210 existing actions from messages
metadata (reset_nickname rows now show 'Sarjana .jav', 'Penindas
Minoritas', etc). Frontend TARGET shows server nick with global
username as secondary context.
Denormalize guild name alongside username so the moderation dashboard
shows both TARGET and server even after message table purges.
Migration 0018. Frontend displays 'username · server_name' in TARGET.
Gateway (transmitter.ts):
- Auto-stop on FFmpeg crash: non-zero exit triggers stop() to prevent
silent audio loss and resource leaks
- Voice activity timeout (10s): auto-stops transmitter when no PCM
received, preventing dead-air CPU waste on backgrounded tabs
- Stderr cap (4KB): prevents unbounded memory growth in long sessions
Gateway (voice.handler.ts):
- Double-check voiceController.getStatus().connected before starting
transmitter — detects stale player state after gateway disconnect
Frontend (context.tsx):
- Force-refetch voice status on WS reconnect — UI converges in <1s
instead of waiting up to 4s for SWR poll interval
All: tsc clean, biome clean
- Updated RootLayout to include a noise overlay class.
- Refactored LiveModerationFeed to use CSS animations for item entry.
- Simplified AmbientCanvas by removing WebGL and using pure CSS for ambient effects.
- Converted Chatbot to use CSS for floating window animations.
- Updated Card component to include a gradient border.
- Refactored PageTransition to use CSS for fade-scale animations.
- Enhanced SectionHeader with reveal-up animation class.
- Replaced GSAP animations in NavRail with CSS animations for item entry.
- Refactored VoiceStage to use CSS for speaker node animations and pulse rings.
- Removed GSAP dependencies from use-gsap-animation hook, implementing CSS-based stagger reveal.
- Refactored ChannelCultureGlossary, LiveModerationFeed, TermGlossary, and Chatbot components to use new design tokens and styles.
- Updated button, badge, and section components to align with the new design system.
- Enhanced the visual hierarchy and accessibility of various UI elements.
- Improved responsiveness and hover states across components.
- Replaced hardcoded colors with design tokens for better maintainability.
- Cleaned up imports and removed unused hooks in ModerationView and RecordingsView.
- Updated UI elements for better visual consistency and accessibility.
- Improved performance by optimizing rendering logic and reducing unnecessary state updates.
- Added filtering functionality in ChannelCultureGlossary and TermGlossary components.
- Enhanced LiveModerationFeed with GSAP animations for smoother transitions.
- Updated chatbot component for better user experience and responsiveness.
- Refined NavRail component for cleaner code and improved navigation item rendering.