Files
GMW/docs/specs/2026-06-01-frontend-major-refactor-design.md
T
MythEclipseandClaude Opus 4.8 1aab0d1df1 docs: frontend major refactor design document
Design for feature-sliced architecture, 8 bug fixes, and glass-morphism UI redesign.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 15:51:28 +07:00

202 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Frontend Major Refactor — Design Document
**Date:** 2026-06-01
**Scope:** `/mnt/code/bete/frontend/` — React + Vite + Tailwind
**Stack:** React 18, Vite, TailwindCSS, TanStack Query, lucide-react
## Problem Statement
1. `package.json` hilang — project tidak bisa `pnpm install`
2. `App.tsx` 285 baris monolithic (audio, socket, state, layout semua satu file)
3. `useMemo` dipakai untuk side effect (LivePanel:47) — anti-pattern React
4. Shared `ArrayBuffer` bug saat kirim PCM ke WebSocket (App:166)
5. `ws/client.ts` duplikat socket logic dengan `hooks/useDashboardSocket.ts`
6. Async handler tanpa await (MessageCard:88)
7. UI terlihat "jelek" — flat dark theme tanpa depth/visual interest
8. Mobile UX buruk — tab bar di atas, tidak ada sidebar drawer
## Section 1: Arsitektur — Feature-Sliced Directory
```
frontend/
├── index.html
├── package.json # [NEW] Lengkap dengan semua deps
├── vite.config.ts
├── tailwind.config.js
├── postcss.config.js
├── tsconfig.json
└── src/
├── main.tsx # React entry + QueryClient
├── styles.css # Tailwind + design tokens
├── App.tsx # Thin shell (~60 baris)
├── entities/ # Domain types
│ ├── message/types.ts
│ ├── guild/types.ts
│ ├── voice/types.ts
│ ├── media/types.ts
│ └── ui/types.ts
├── shared/ # Cross-cutting utilities
│ ├── api/client.ts # HTTP client + typed endpoints
│ ├── ws/socket.ts # WebSocket connection manager
│ ├── ws/events.ts # Typed event map + dispatcher
│ ├── hooks/useAudioPlayback.ts
│ ├── hooks/useAudioTransmit.ts
│ ├── hooks/useLocalStorage.ts
│ └── ui/ # UI primitives
│ ├── button.tsx
│ ├── card.tsx
│ ├── badge.tsx
│ ├── input.tsx
│ ├── select.tsx
│ ├── tabs.tsx
│ └── scroll-area.tsx
├── features/ # Feature-specific logic + presentation
│ ├── live/
│ │ ├── hooks/useVoiceControl.ts
│ │ ├── hooks/useMediaControl.ts
│ │ ├── index.tsx # LivePanel
│ │ ├── components/VoiceConnectionCard.tsx
│ │ ├── components/AudioVisualizer.tsx
│ │ ├── components/ActiveSpeakers.tsx
│ │ ├── components/NowPlaying.tsx
│ │ ├── components/MusicSubPanel.tsx
│ │ ├── components/ScreenSubPanel.tsx
│ │ └── components/RecordingsSubPanel.tsx
│ ├── messages/
│ │ ├── hooks/useMessages.ts
│ │ ├── index.tsx # MessagesPanel
│ │ ├── components/MessageFeed.tsx
│ │ ├── components/MessageCard.tsx
│ │ └── components/ImageGrid.tsx
│ ├── analytics/
│ │ ├── hooks/useAnalytics.ts
│ │ ├── index.tsx # AnalyticsPanel
│ │ └── components/ # (charts, tables kept as-is)
│ └── auth/
│ └── index.tsx # AuthOverlay
└── widgets/ # Composite layouts
├── DashboardLayout.tsx
├── Header.tsx
└── Sidebar.tsx
```
### Key Architectural Decisions
- **`App.tsx`** = hanya layout shell + providers. Semua hooks pindah ke `features/`.
- **Socket** = satu instance di `shared/ws/socket.ts`. Features subscribe via typed event bus.
- **Entities** = pure types, zero logic.
- **Features** = self-contained (hooks + components). Tidak cross-import antar feature.
- **Widgets** = layout compositions (sidebar, header, dashboard shell).
## Section 2: Bug Fixes
| # | Bug | Location | Fix |
|---|-----|----------|-----|
| 1 | `useMemo` untuk async fetch (anti-pattern) | `LivePanel.tsx:47` | Ganti ke `useEffect` + `useCallback` |
| 2 | Shared `ArrayBuffer` dikirim ke WS | `App.tsx:166` | `.slice()` sebelum send |
| 3 | Missing useEffect deps | `App.tsx:187` | Add proper dependency arrays |
| 4 | Unstable keys (`i` sebagai fallback) | `LivePanel.tsx:246` | Gunakan `s.userId ?? 'unknown-${i}'` |
| 5 | Async handler tanpa await | `MessageCard.tsx:88` | `onReanalyze``Promise<void>`, di-await |
| 6 | `monitorGuild` recompute tiap render | `App.tsx:65` | Pakai `useMemo` |
| 7 | Socket localStorage tanpa validasi | `useUIState.ts:9` | Schema validation sebelum parse |
| 8 | Duplikat socket (`ws/client.ts` vs `hooks/useDashboardSocket.ts`) | Global | Hapus `ws/client.ts`, satu socket di `shared/ws/socket.ts` |
## Section 3: UI Redesign — Glass-morphism Modern
### Color Tokens
```css
--background: 222 47% 8%; /* slightly darker */
--foreground: 210 40% 98%;
--card: 222 47% 12% / 0.7; /* semi-transparent */
--card-border: 222 47% 25% / 0.4;/* translucent border */
--primary: 199 89% 52%; /* brighter cyan-blue */
--accent: 217 33% 20%;
--muted: 217 33% 20%;
--radius: 0.85rem;
```
### Visual Changes
- **Background**: Gradient mesh (dark → dark-purple → dark) dengan subtle noise overlay
- **Cards**: `backdrop-blur-xl` + semi-transparent bg + subtle glow border
- **Sidebar**: Expandable — icon-only (w-16) ↔ full (w-64) dengan smooth transition
- **Mobile**: Bottom tab bar (bukan top tabs), slide-in sidebar
- **Typography**: Inter tetap, heading scale lebih besar, weight lebih variatif
- **Micro-interactions**: `transition-all duration-200`, hover scale `1.01`, focus rings
- **Audio Visualizer**: CSS animated bars (bukan static levels map)
- **Message cards**: Rounded-xl, subtle shadow, AI badge dengan color coding yang lebih jelas
- **Charts**: Recharts-based (existing), tapi dengan color scheme yang matching theme
### Responsive Breakpoints
| Breakpoint | Layout |
|------------|--------|
| `< 768px` | Bottom tab bar, no sidebar, full-width content |
| `768px1024px` | Collapsed sidebar (icon-only), full content |
| `> 1024px` | Full sidebar (w-64), spaced content |
## Section 4: Error Handling
- **Error Boundaries**: Setiap feature punya error boundary (existing `AnalyticsErrorBoundary` pattern)
- **API Errors**: Global error toast via `shared/ui/Toast` component
- **Socket Errors**: Auto-reconnect dengan exponential backoff (existing pattern, diperbaiki)
- **Loading States**: Skeleton loaders (bukan text "Loading...") untuk semua data panels
## Section 5: Data Flow
```
Browser → shared/ws/socket.ts → shared/ws/events.ts (dispatch)
features/* subscribe via typed handlers
features/*/hooks/ (React Query / useState)
features/*/components (render)
widgets/ (layout shell)
```
- **REST API**: React Query hooks di `features/*/hooks/`
- **WebSocket Events**: Event bus di `shared/ws/events.ts`, hooks subscribe ke events
- **UI State**: `localStorage` + `shared/ws/socket.ts` sync (existing pattern, dengan validasi)
## Section 6: Testing Strategy
- **Unit**: Hooks testing dengan `@testing-library/react` — socket mocking
- **Integration**: Component render tests untuk panels
- **E2E**: Tidak termasuk scope initial refactor (future enhancement)
## Section 7: Migration Plan
### Phase 1: Foundation
1. `package.json` lengkap
2. `tsconfig.json` + `vite.config.ts` verified
3. `shared/` structure + UI primitives
4. `entities/` types extracted
### Phase 2: Bug Fixes + Hooks Extraction
5. Extract hooks dari `App.tsx``features/*/hooks/`
6. Fix semua 8 bugs yang teridentifikasi
7. Single socket instance di `shared/ws/socket.ts`
8. `App.tsx` thin shell
### Phase 3: UI Polish
9. Design tokens baru (glass-morphism)
10. Sidebar redesign (expandable + mobile drawer)
11. Audio visualizer animated
12. Message card redesign
13. Loading skeletons
14. Error boundaries + toast
### Phase 4: Verification
15. `pnpm run typecheck` — zero errors
16. `pnpm run lint` — zero warnings
17. App runs + all 3 tabs functional
18. WebSocket connects + events work
19. Mobile responsive verified