Layout baru single-screen ops console: - TopBar 48px (brand monogram, guild, ws status, clock UTC/local, focus mode) - LeftRail 80px (icon+label nav, signal accent bar, no boxes) - Hero strip (display headline + mono counters: clean/warned/flagged/ratio) - EventFeed (vertical timeline of message events, severity dots, no cards) - NowMarker (inline pulse + cluster band insert per 10 events / 30s) - RightRail 320px collapsible (ai verdicts / voice / mod queue / socket) - DashCommandLine bottom 44px (mono prompt, '/' focuses, /mute /jump /find /clear) Replace Spine + StatusBar lama untuk /dashboard via pathname branch di (dashboard)/layout.tsx — route lain (messages/voice/media/dll) tetap pakai ClassicShell, tidak ter-regress. SSR seed tetap lewat page.tsx (server fetch stats + activity), synthetic seed events dari daily buckets sampai WS message_created kick in. WS event mapper: severity di-derive dari ai_status + ai_severity, excerpt dipotong 140 char, channel tail 4 char. No card chrome, no shadow, no bento grid, no tab panels.
Bete Frontend
Next.js 16 (React 19) dashboard untuk Discord Moderation Watcher.
Stack: Next.js 16 (App Router, static export), React 19, TypeScript strict, Tailwind v4, shadcn/ui, base-ui, lucide-react.
Dev
bun run dev # next dev — port 3000 (lokal; prod via nginx 4009)
bun run build # next build — static export ke out/
bun run lint # Biome check
Architecture
src/
├── app/ # Pages
│ ├── page.tsx # Redirect ke /dashboard
│ └── dashboard/ # Dashboard layout + tabs
│ ├── layout.tsx # Sidebar, header, WS provider, chatbot
│ └── page.tsx # Tab routing (messages/live/dashboard)
├── features/
│ ├── messages/ # Message feed, search, review, detail modal
│ ├── live/ # Voice connection, music player, recordings
│ ├── dashboard/ # Stats, users, channels overview
│ └── chatbot/ # AI chatbot
├── lib/
│ ├── api/ # Fetch-based API client (all BE endpoints)
│ ├── ws/ # WebSocket client + React context
│ └── hooks/ # Shared hooks (config, auth)
└── components/
└── layout/ # Sidebar, header, mobile tab bar
API
Backend berjalan di port 4001. Frontend mengakses API via window.location (same-origin atau proxy).
WebSocket terhubung otomatis ke /ws di host yang sama.