원클릭으로
bedrud-frontend
Full React frontend code map. Load for any UI/component/route/state/hook/stylesheet work.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Full React frontend code map. Load for any UI/component/route/state/hook/stylesheet work.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Admin endpoints — users, rooms, queue, settings, invite tokens, webhooks, overview, recordings.
Auth endpoints — JWT flow, local/OAuth/passkey/verify/password-reset/avatar/preferences.
Room endpoints — CRUD, join, moderation, presence, chat upload, stage stubs, recording.
Complete Bedrud API endpoint reference. Dense index of every route, middleware, status code; deep detail in leaf skills.
All DTO definitions, source file index, Swagger reference.
Auth service + middleware — JWT, passkeys, OAuth, session store, rate limiting, recordings gate.
| name | bedrud-frontend |
| description | Full React frontend code map. Load for any UI/component/route/state/hook/stylesheet work. |
| license | Apache License |
React 19 SPA. Root: apps/web/. TanStack Router (file-based) + TanStack Query 5 + Zustand 5 + LiveKit Components + TailwindCSS v4 + Biome + Bun.
Path aliases: #/* → ./src/*, @/* → ./src/*. Prefer #/*. Never ../src/*.
| Skill | Owns |
|---|---|
bedrud-fe-platform | Routes map, lib/api.ts, Vite ports/proxy, vendor aliases, tooling |
bedrud-fe-state | All 10 Zustand stores |
bedrud-fe-meeting | LiveKit room, chat, stage, whiteboard, YouTube, presence, recording shells |
bedrud-fe-admin | Admin routes, tables, overview, settings tabs, recordings stub |
bedrud-fe-ui-foundation | Design tokens, shadcn primitives, settings panels, hard UI rules |
This umbrella is the scannable index. Prefer the matching leaf for implementation work.
@/components/ui/* wrappers over raw HTMLcn() for dynamic classNames; no template-literal class stringsstyle={} (inline only: color-mix, palettes, computed dims)theme.cssDESIGN.md, apps/web/AGENTS.md, apps/web/src/theme.cssFull rules → bedrud-fe-ui-foundation.
| File | Role |
|---|---|
src/router.tsx | getRouter() — TanStack Router (scrollRestoration, preload intent, default not-found/error) |
src/routes/__root.tsx | Shell: QueryClient, ErrorBoundary, Intl, Sonner, theme flash script, auth initialize() |
src/routeTree.gen.ts | Auto-gen — never edit (~32 route modules) |
scripts/embed.mjs | Prod bridge: build → SSR shell → copy to server/frontend/ |
Not 3000 / 8090. Source: apps/web/vite.config.ts.
| Port | Role |
|---|---|
| 7070 | Vite / TanStack Start (web) |
| 7071 | Go API (make dev) |
| 7072 | Embedded LiveKit |
| 7074 | TanStack devtools event bus |
| Path | Target | Notes |
|---|---|---|
/api | localhost:7071 | API |
/uploads | localhost:7071 | Chat/media uploads |
/livekit | 127.0.0.1:7072 | Direct to LiveKit (ws: true, rewrite strips /livekit) |
Do not chain /livekit through the Go API — double WS proxy breaks /rtc/v1/validate.
VITE_API_URL empty in dev → relative /api → proxy → :7071.
__root__ QueryClient, theme, Intl, auth init
├── / landing + guest join (no forced auth redirect)
├── /$ splat → ErrorPage not-found
├── /new auth → POST /api/room/create → /m/$meetId
├── /auth layout; tokens → /dashboard
│ ├── /auth/ guest join
│ ├── /auth/login email/pass + passkey + OAuth; ?redirect=
│ ├── /auth/register name/email/pass + invite token
│ ├── /auth/callback OAuth → GET /api/auth/me
│ ├── /auth/verify email verify
│ ├── /auth/forgot-password
│ └── /auth/reset-password
├── /dashboard layout; require tokens
│ ├── /dashboard/ My Rooms + Recent
│ ├── /dashboard/archived/$roomId archived room (stub)
│ ├── /dashboard/settings settings layout
│ │ ├── /dashboard/settings/ profile
│ │ ├── /dashboard/settings/security
│ │ ├── /dashboard/settings/audio
│ │ └── /dashboard/settings/video
│ └── /dashboard/admin admin|superadmin|moderator
│ ├── /dashboard/admin/ overview
│ ├── /dashboard/admin/queue
│ ├── /dashboard/admin/rooms
│ ├── /dashboard/admin/rooms/$roomId
│ ├── /dashboard/admin/rooms/events
│ ├── /dashboard/admin/users
│ ├── /dashboard/admin/users/$userId
│ ├── /dashboard/admin/users/recent-signups
│ ├── /dashboard/admin/recordings placeholder
│ └── /dashboard/admin/settings admin/superadmin only
└── /m/$meetId live meeting
| File | Path | Type | Guard / loader | Purpose |
|---|---|---|---|---|
__root.tsx | (root) | Layout | — | Shell, providers, theme, auth init |
index.tsx | / | Leaf | init auth; me if tokens | Landing + guest join |
$.tsx | /$ | Leaf | — | Catch-all not-found |
new.tsx | /new | Leaf | auth; loader creates room | Instant meeting |
auth.tsx | /auth | Layout | tokens → /dashboard | Auth chrome |
auth.index.tsx | /auth/ | Leaf | — | Guest join |
auth.login.tsx | /auth/login | Leaf | redirect? | Login |
auth.register.tsx | /auth/register | Leaf | — | Register |
auth.callback.tsx | /auth/callback | Leaf | — | OAuth completion |
auth.verify.tsx | /auth/verify | Leaf | token/status/reason | Email verify |
auth.forgot-password.tsx | /auth/forgot-password | Leaf | — | Request reset |
auth.reset-password.tsx | /auth/reset-password | Leaf | token | Set password |
dashboard.tsx | /dashboard | Layout | no tokens → /auth; me loader | App chrome |
dashboard.index.tsx | /dashboard/ | Leaf | — | Rooms + recent |
dashboard/archived_.$roomId.tsx | /dashboard/archived/$roomId | Leaf | — | Archived stub |
dashboard/settings.tsx | /dashboard/settings | Layout | — | Settings tabs |
dashboard/settings/index.tsx | /dashboard/settings/ | Leaf | — | Profile |
dashboard/settings/security.tsx | /dashboard/settings/security | Leaf | — | Password |
dashboard/settings/audio.tsx | /dashboard/settings/audio | Leaf | — | Audio prefs |
dashboard/settings/video.tsx | /dashboard/settings/video | Leaf | — | Video prefs |
dashboard/admin.tsx | /dashboard/admin | Layout | admin/superadmin/moderator | Admin shell + AdminContext |
dashboard/admin/index.tsx | /dashboard/admin/ | Leaf | — | Overview |
dashboard/admin/queue.tsx | /dashboard/admin/queue | Leaf | — | Queue stats |
dashboard/admin/rooms.tsx | /dashboard/admin/rooms | Leaf | — | Rooms table |
dashboard/admin/rooms_.$roomId.tsx | /dashboard/admin/rooms/$roomId | Leaf | — | Room detail |
dashboard/admin/rooms_.events.tsx | /dashboard/admin/rooms/events | Leaf | — | Room events |
dashboard/admin/users.tsx | /dashboard/admin/users | Leaf | — | Users table |
dashboard/admin/users_.$userId.tsx | /dashboard/admin/users/$userId | Leaf | — | User detail |
dashboard/admin/users_.recent-signups.tsx | /dashboard/admin/users/recent-signups | Leaf | — | Recent signups |
dashboard/admin/recordings.tsx | /dashboard/admin/recordings | Leaf | — | Placeholder |
dashboard/admin/settings.tsx | /dashboard/admin/settings | Leaf | block moderator | System settings |
m.$meetId.tsx | /m/$meetId | Leaf | join in-page | Live meeting |
Counts: 32 route modules · 5 layouts (__root, auth, dashboard, settings, admin) · rest leaves.
| Area | Rule |
|---|---|
/auth/* | Tokens → /dashboard |
/ | Does not redirect authenticated users |
/dashboard | No tokens → /auth |
/new | No tokens → /auth/login?redirect=/new |
/dashboard/admin | isSuperAdmin or access admin or moderator |
/dashboard/admin/settings | Moderator blocked; need admin/superadmin |
Full route notes → bedrud-fe-platform. Admin pages → bedrud-fe-admin. Meeting → bedrud-fe-meeting.
All in src/lib/*.store.ts. Full field/actions → bedrud-fe-state.
| File | Hook | Persist | Role |
|---|---|---|---|
auth.store.ts | useAuthStore | manual auth_remember / auth_at | Tokens + cookie refresh init |
user.store.ts | useUserStore | — | User incl. isSuperAdmin / isAdmin |
theme.store.ts | useThemeStore | theme | light/dark/system + DOM class |
audio-preferences.store.ts | useAudioPreferencesStore | audio-preferences | NS, EC, AGC, gain, gate, beep, PTT |
video-preferences.store.ts | useVideoPreferencesStore | video-preferences | Webcam mirror |
experimental-preferences.store.ts | useExperimentalPreferencesStore | experimental-preferences | Whiteboard / YouTube + disclaimer |
interface-preferences.store.ts | useInterfacePreferencesStore | interface-preferences | Welcome screen |
recent-rooms.store.ts | useRecentRoomsStore | bedrud-recent-rooms | Cap 20 |
participant-overrides.store.ts | useParticipantOverridesStore | — | Local mute/volume Maps |
profile-sync.store.ts | useProfileSyncStore | — | version bump signal |
Related (not a store): user-preferences.ts deep-merges server prefs blobs → /api/auth/preferences.
src/lib/api.ts — sole HTTP client:
api.get / post / put / delete
API_URL, class ApiError
| Concern | Behavior |
|---|---|
| Base | VITE_API_URL or '' → proxy :7071 |
| Auth | Bearer access token; CSRF meta/cookie fallback |
| Credentials | include (HTTP-only refresh cookie) |
| 401 | Singleton refresh → retry once → clear + /auth |
| Errors | ApiError with parsed message |
Code root: src/components/meeting/. Route: m.$meetId.tsx. Deep map → bedrud-fe-meeting.
LiveKitRoom
└── MeetingErrorBoundary
└── MeetingStageProvider ← exclusive stage (youtube | whiteboard | screenshare)
└── MeetingProvider ← room + chat contexts
└── YoutubeWatchProvider
└── WhiteboardWatchProvider
├── StageJoinNotifier, BeforeUnloadLock, KickDetector, AskActionBanner
├── AudioProcessorManager, MeetingRoomAudioRenderer, MeetingSoundEffects
└── MeetingRoomShell
├── MeetingLayout | YoutubeWatchOverlay | WhiteboardOverlay | StageScreenShareOverlay
├── MeetingPresenceCursors (enabled=false)
├── ParticipantVideoSidebar (stage active)
├── MeetingHeader + MeetingPanels
└── YoutubeShareDialog
Topic stage (stage/stageWire.ts + MeetingStageContext). Server stage HTTP is stub.
Kinds: youtube | whiteboard | screenshare — single owner. Wire: stage_set / stage_clear / stage_request / stage_state / stage_youtube_sync.
| Topic | Purpose |
|---|---|
chat | Messages, chunks, reactions, poll votes |
system | kick/ban/ask/spotlight/deafen/room_* |
presence | deafen_state, profile_changed |
stage | Exclusive stage ownership + youtube sync |
youtube | Legacy wire (active sync via stage) |
whiteboard / whiteboard-yjs / whiteboard-pointer / whiteboard-follow | Canvas + Yjs + collab |
meeting-pointer | Grid presence cursors |
Experimental (experimental-preferences.whiteboardEnabled + disclaimer gate).
whiteboard → WhiteboardWatchProvider owns Y.Doc + LiveKitYjsProviderMeetingSharedWhiteboard lazy-loads vendored Excalidraw bound via bindExcalidrawToYDocmeeting/whiteboard/; vendor is dependency onlyExperimental (youtubeEnabled). Stage kind youtube; host heartbeat ~2.5s; remote drift 1.5s. Files under meeting/youtube/.
MeetingPresenceCursors + meetingPointerWire — wire ready, enabled = false. Same for MeetingViewportPan (enabled = false).
Text + image upload (POST /api/room/{id}/chat/upload) + polls + reactions + emoji + chunking (>~60KB) + sessionStorage persistence (chat:{roomId}). Caps: 400 in-memory / 200 persisted. Components under meeting/chat/.
FE keeps context surface + shells; UI not mounted in live controls:
| Piece | Status |
|---|---|
MeetingContext recording fields / toggleRecording | Present; toggle body no-op |
recordingsEnabled / join recordingsAllowed | Forced off |
RecordingButton / RecordingList | Export exists; return null |
| ControlsBar / Header | Recording slots removed |
| Intended API | `POST …/recording/start |
POST /api/room/join or guest-joininterface-preferences)refresh-token + transport fallback (preferRelay)Path: apps/web/src/vendor/excalidraw/ (0.18 hybrid). README documents packages + shims.
| Import | Resolves under packages/ |
|---|---|
@excalidraw/excalidraw | excalidraw/ |
@excalidraw/common | common/src/ |
@excalidraw/element | element/src/ |
@excalidraw/math | math/src/ |
@excalidraw/utils | utils/src/ |
@excalidraw/fractional-indexing | fractional-indexing/src/ |
@excalidraw/laser-pointer | laser-pointer/src/ |
Aliases: src/vendor/excalidraw/aliases.ts → Vite resolve.alias + tsconfig paths. Platform owns wiring; meeting owns runtime. Biome excludes src/vendor.
Access: admin/superadmin full; moderator shell read-only (isReadOnly); settings admin-only.
| Route | Purpose |
|---|---|
/dashboard/admin | Overview KPIs / health / charts |
…/queue | Queue + email queue stats |
…/rooms, …/rooms/$roomId, …/rooms/events | Rooms + live detail + events |
…/users, …/users/$userId, …/users/recent-signups | Users + bulk |
…/recordings | Placeholder (“future release”) |
…/settings | 9 active tabs (general…webhooks); RecordingsTab code present but not in TABS |
Sidebar: Overview, Queue, Users, Rooms, Settings. Recordings nav commented out.
No standalone UserTable / RoomTable — list UIs live in route files. Data-table primitives + overview widgets under components/admin/.
Full → bedrud-fe-admin.
| Area | Path | Highlights |
|---|---|---|
| Root | components/ | ErrorPage, ErrorBoundary, ThemeToggle |
| Auth | components/auth/ | PasskeyButton, OAuthButtons |
| Dashboard | components/dashboard/ | RoomCard, CreateRoomDialog, RoomSettingsDialog |
| Settings | components/settings/ | BedrudSettingsDialog + profile/audio/video/security/experimental/appearance panels (tone: default | meeting) |
| Admin | components/admin/ | DataTable*, overview/*, settings tabs, QueueStats, RecordingsTable stub |
| Meeting | components/meeting/ | Shell, tiles, controls, chat/, stage/, whiteboard/, youtube/, presence/ |
| UI | components/ui/ | 26 shadcn primitives (Button, Dialog, Command, Slider, …) |
m.$meetId → LiveKitRoom → MeetingStageProvider → MeetingProvider
→ Youtube/Whiteboard providers → MeetingRoomShell
├── Layout / stage overlays
├── MeetingPanels → ControlsBar (stage claims, WB/YT menu)
│ → ChatPanel (polls, reactions, upload)
│ → ParticipantsList
└── Header / presence (disabled) / video sidebar
| Area | Modules |
|---|---|
| Platform | api, handle-auth-success, webauthn, jwt-user, use-public-settings, i18n, user-preferences, useLongPress, text-direction |
| Admin | use-admin-overview (60s), use-queue-stats (10s), types/admin.ts |
| Meeting | audio-processor.service, rnnoise-processor, meeting-sounds, livekit-publish, livekit-transport-type, meeting-device-storage, push-to-talk-*, usePinnedParticipants |
| UI util | utils.cn, errors.getErrorMessage, participant-palette, avatar-* |
| File | Role |
|---|---|
src/theme.css | Rose primary + teal accent tokens (light/dark) |
src/styles.css | Tailwind v4 + dark variant + zero radius + keyframes |
src/components/meeting/meeting.css | Meet tiles, speak bars, chat scroll, --meet-* |
src/theme.example-blue.css | Rebrand template |
| Type | Where |
|---|---|
| Store shapes | lib/*.store.ts → fe-state |
PublicSettings | use-public-settings.ts (incl. chat TTL/count, recordingsEnabled flag) |
AdminUser / AdminRoom / roles | types/admin.ts |
| Chat / system / stage | meeting components + wire modules |
| Item | Detail |
|---|---|
| Scripts | dev, build, build:embed, check (biome+tsc), test (vitest) |
| Manual chunks | meeting-context, react, tanstack, livekit, charts, ui, markdown, excalidraw-vendor |
| optimizeDeps | livekit, yjs, roughjs, jotai, … |
| Biome | 2-space, width 120, single quotes, semicolons asNeeded; excludes vendor + css + routeTree |
| shadcn | components.json — default style, slate base, Lucide |
router → routeTree.gen
__root → QueryClient, theme.store, auth.store.initialize, Intl, ErrorBoundary
routes → api.ts → auth.store
→ fe-admin hooks / types
→ m.$meetId → meeting tree (stage/chat/whiteboard/youtube)
vite → ports 7070/7071/7072, /livekit direct proxy, excalidrawAliases
stores → 10 × lib/*.store.ts
| Task | Load |
|---|---|
| Routes, ports, API client, embed, vendor aliases | bedrud-fe-platform |
| Any Zustand store | bedrud-fe-state |
| Meeting / chat / stage / WB / YT / presence / recording shells | bedrud-fe-meeting |
| Admin tables, overview, system settings | bedrud-fe-admin |
| Tokens, shadcn, settings panels, a11y chrome | bedrud-fe-ui-foundation |
| Endpoint shapes | bedrud-api (+ api-* leaves) |