Admin Dashboard

The admin dashboard is where event organizers manage everything about their events. It lives at /dashboard/account/[accountId]/event/[eventId] and is built with Next.js parallel routes — each tab is an independent @slot under @tabs/ that loads without blocking the others.

Tab state is stored in the URL query string (?tab=details) via nuqs, so tabs survive page refreshes and can be shared as links.

Event Header

Above the tabs, the event header shows the event name, its current status badge (Draft, Active, or Archive), and two actions:

  • Change Status — a dropdown to move the event between Draft, Active, and Archive. Draft events are only visible to producers. Active events are visible to all users. Archive freezes the event (no new users can be added). The dropdown also includes a Delete option with a confirmation dialog.
  • View Event — links to the public-facing event page at /event/[eventId].

Tabs Reference

Details (`@details`)

The general settings form for the event. Fields:

  • Event Name — displayed on event cards and in event details
  • Description — rich text editor content included in reminder emails and invitations
  • Banner Image — appears on the "my events" page, social/shared links, and event details
  • Schedule — start and end date/time pickers with timezone display, validation that end is at least 1 minute after start
  • Compositor Background — the background image used during the live stream (always visible behind participants)

Changes are saved explicitly via the "Save Changes" button, which enables only when the form is dirty.

Code: @tabs/@details/page.tsx — uses react-hook-form with Zod validation, useImageUpload hook for file uploads, and api.event.updateEvent mutation.

Users (`@users`)

Manages who has access to the event and what role they have in each room.

Features:

  • User table — shows image, name, display name, email, room count, and status (Active or Invited). Expandable rows reveal per-room assignments with role badges.
  • Search — fuzzy search across name, display name, and email
  • Room filter — dropdown to show users for a specific room only
  • Add users — form to invite new users by email, assigning them to rooms with roles
  • User detail sheet — click a room row to open a side sheet for editing that user's role in that room
  • Export CSV — exports user list to CSV, either for all rooms or a specific room
  • Email Reminder — send reminder emails to all attendees. Options: Week Out, Day Out, Hour Out (disabled if the event is closer than the interval), or Send Now for immediate dispatch
  • Auto-refresh — the user list polls every 20 seconds to reflect new signups and status changes

Code: @tabs/@users/list.tsx is the main component. add-user.tsx and AddUserModal.tsx handle invites, user-details.tsx powers the side sheet, roles.tsx handles role assignment.

Orders (`@orders`)

Unified view of all orders for the event, combining both internal (CSV-imported) orders and Shopify orders into a single sorted table.

Features:

  • Unified orders table — merges internal and Shopify orders, sorted by date (newest first)
  • Retailer filter — dropdown to filter orders by source retailer
  • Search — search across order data
  • Import CSV — upload a CSV file of orders from external retailers
  • SKU Mapping — when imported orders have SKUs that don't match internal products, a warning banner appears with a "Map SKUs" button. The mapping modal lets you link external SKUs to internal products.
  • Manage Retailers — create and manage external retailer entries
  • Order count — shows total count with breakdown if truncated

Code: @tabs/@orders/page.tsx orchestrates the tab. OrdersTable.tsx renders the unified table, ImportOrdersModal.tsx handles CSV upload, SkuMappingModal.tsx manages SKU-to-product mappings, CreateRetailerModal.tsx and ManageRetailersModal.tsx handle retailer CRUD.

Rooms (`@roomsv2`)

Create and manage the rooms (spaces) within the event.

Features:

  • Rooms table — lists all rooms with name, type badge (SHOW or MEET & GREET based on streamTypeHint), and description
  • Create Room — opens a wizard modal to configure a new room
  • Delete Room — per-room action via dropdown menu, with confirmation dialog

Rooms are the fundamental container for live streams. A "show" room is where the main broadcast happens, while a "meet & greet" room is for smaller interactive sessions.

Code: @tabs/@roomsv2/page.tsx and room-wizard-modal.tsx.

Tickets (`@ticketsv2`)

Create ticket SKUs that are added to your product catalog (e.g., Shopify) to sell access to the event.

Features:

  • Ticket cards — each ticket shows its SKU ID (with copy button), label, description, whether it's an upgrade ticket, its assigned role, and the rooms it grants access to
  • Create Ticket — form to define a new ticket with name, room assignments, and upgrade flag
  • SKU workflow — after creating a ticket, you copy its SKU and add it to your product catalog or product variants in Shopify

Tickets connect e-commerce to event access. When someone purchases a product with a matching SKU, they get assigned the ticket's role and room access.

Code: @tabs/@ticketsv2/page.tsx, new-ticket-form.tsx, create-room-form.tsx.

Livestreams (`@cloudcaster`)

The operational control center for live streaming sessions. This is the most complex tab — it's where you monitor and manage active streams.

Sections:

  1. Current Room Status — a live preview panel with two columns:

    • Live Stream Preview — an embedded Mux player showing what viewers currently see (or OFFLINE / Starting states)
    • Room Status Data — raw JSON of the room's current state from the Durable Object (recording status, playback status, Mux/LiveKit IDs)
    • Room selector dropdown to switch between rooms
  2. Cloudcaster Streams — table of all recording/streaming sessions across rooms. Each row shows:

    • Status indicator (green dot = active, yellow = transitioning, gray = stopped, orange warning = orphaned)
    • Session ID, recording/playback status badges
    • Room ID, Mux stream ID, LiveKit egress ID
    • Actions: Stop Stream, Abort & Cleanup (for stuck sessions), Copy Playback ID, Copy JSON, Delete Orphaned
  3. Cloudcaster Logs — structured log viewer with filters by session, room, and level (DEBUG/INFO/WARN/ERROR). Logs come from the coordinator, workflows, and services. Each entry is expandable to show JSON data and stack traces. Supports auto-refresh.

  4. LiveKit Network Diagnostics — network diagnostic panel for the LiveKit connection

Code: @tabs/@cloudcaster/page.tsx (server component checking LiveKit config), table.tsx (the main client component with all sections).

Recordings (`@recordingsv2`)

Browse and manage recordings from completed live stream sessions.

Features:

  • Recording cards — each recording shows a Mux thumbnail (animated GIF on hover), duration overlay, date, room name
  • Play — opens a dialog with an embedded Mux player
  • Download — triggers asset preparation with polling (checks every 5 seconds for up to 1 minute until the Mux asset is ready), then opens the download URL
  • Clips — expandable section per recording showing auto-generated clips. Each clip shows a thumbnail, the user who was speaking, duration, time offset range, and play/download buttons. Clips can be in "processing", "ready", or "failed" states.
  • Room filter — filter recordings by room, or view all grouped by room

Code: @tabs/@recordingsv2/page.tsx — single large component with RecordingCard subcomponent. Uses useReducer for download state management across recordings and clips.

The dashboard sidebar (_components/sidebar-nav.tsx) provides account-level navigation:

Section Items
Main Dashboard, Events (with sub-items: All Events, Scheduled, Live Now, Drafts, Past Events, Create Event), Users, Tickets, Assets (Images, Videos, Audio, Documents), Analytics, Messages, Notifications
Accounts Account switcher with avatar badges, Manage Accounts link
Settings General, Billing, Team, Integrations

The sidebar is collapsible to icon-only mode and uses a dark theme.

Key Patterns for Developers

Adding a new tab: Create a @tabs/@newtab/ directory with a page.tsx, then add the slot to the layout.tsx type signature, and add TabsTrigger + TabsContent entries. The tab value in the URL is controlled by nuqs — no route changes needed.

Data fetching: All tabs use tRPC hooks. Most use useSuspenseQuery for tab content that should show loading boundaries. The Livestreams tab uses polling (refetchInterval) for real-time data.

Mutations: Follow the pattern of useMutation with onSuccess that calls refetch() on the relevant query and shows a toast.success(). Destructive actions use AlertDialog for confirmation.