# Leptos Rewrite — Frontend Architecture Design
**Date:** 2026-07-03
**Status:** Approved Design
## Overview
Rewrite the React 19 + Vite + Tailwind dashboard (46 source files, ~6k LOC) to a Rust Leptos CSR WASM app. All layers — components, styling, animations, WebSocket, audio, icons — are rewritten in Rust.
## Motivation
- **Performance** — WASM eliminates JS bundle parsing/execution overhead
- **Type Safety** — Rust's type system catches more errors at compile time
- **Bundle Size** — WASM binary smaller than equivalent JS bundle
## Status
The current React frontend (`services/frontend/`) remains in active use. The new Leptos app lives in `services/frontend-leptos/`. No React code is removed until the Leptos version is feature-complete.
## Tech Stack
| Layer | Choice | Rationale |
|-------|--------|-----------|
| Framework | Leptos 0.7 (CSR) | WASM-native reactive framework, signals-based |
| Styling | Plain CSS | No framework dependency, port from existing CSS |
| Animations | CSS keyframes + transitions | Replace all Framer Motion usage |
| Icons | `lucide-leptos` | Direct port of current lucide-react icons |
| HTTP | `gloo-net` | Rust fetch wrapper, works with WASM |
| WS | `web-sys::WebSocket` | Direct binding, no abstraction overhead |
| Audio Viz | Canvas 2D (`web-sys`) | AudioVisualizer, WaveformPlayer |
| Audio Playback | Web Audio API (`web-sys`) | PCM stream playback |
| State | Leptos signals + contexts | No external state library needed |
| Build | `trunk` | Standard WASM builder for Leptos |
## Architecture
```
Leptos App (WASM)
│
├── App Shell (layout, sidebar, header, tabs)
├── Messages Panel (feed, cards, search, filters)
├── Live Panel (voice, music, screen, recordings, audio viz)
└── Dashboard Panel (stats, users, channels)
Shared infrastructure:
├── WebSocket Context (singleton + per-event channels)
├── API Client (fetch wrapper + typed endpoint functions)
├── UI Primitives (Button, Card, Badge, Input, Tabs, Toast, etc.)
└── CSS Design System (custom properties, component classes, animations)
```
### Workspace Structure
```
services/frontend-leptos/
├── Cargo.toml # workspace root
├── shared-types/ # Rust types (port of @bete/shared)
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── message.rs # MessageRecord, AttachmentRecord
│ ├── guild.rs # Guild, Channel
│ ├── voice.rs # VoiceStatus, ActiveSpeaker
│ ├── media.rs # MediaItem, MediaState, MediaMode
│ ├── dashboard.rs # DashboardStats, DashboardUser, DashboardChannel
│ ├── recording.rs # VoiceRecording
│ └── ui_state.rs # UIState, AppConfig
├── frontend/
│ ├── Cargo.toml # Leptos + deps
│ ├── Trunk.toml # Build config
│ ├── index.html # Entry point (lang="id", Poppins font)
│ └── src/
│ ├── main.rs # mount_to_body with panic_hook + logger
│ ├── app.rs # Root component (providers + auth gate + routing)
│ ├── app.css # Full CSS design system
│ ├── lib.rs # Module declarations
│ ├── auth.rs # AuthOverlay + login logic
│ ├── ws/ # WebSocket context & event system
│ ├── api/ # HTTP client + typed API functions
│ ├── ui/ # Shared UI primitives
│ ├── layout/ # App shell components
│ └── features/
│ ├── messages/ # Message feed, cards, search, filters
│ ├── live/ # Voice, audio, media, recordings
│ └── dashboard/ # Stats, users, channels
├── rust-toolchain.toml # nightly (required by Leptos CSR)
└── .env # API_URL, WS_URL
```
### Component Tree
```
{!authenticated && !is_public → }
Messages | Live | Dashboard
{active_tab == "messages" → }
{active_tab == "live" → }
{active_tab == "dashboard" → }
```
### State Architecture
**Contexts** (provided at `` level via `provide_context`):
| Context | Key Signals | Persisted |
|---------|-------------|-----------|
| AuthContext | `authenticated: ReadSignal` | sessionStorage |
| WsContext | `status: ReadSignal`, per-event channels | — |
| UiContext | `active_tab: RwSignal`, `selected_guild: RwSignal