# MediaRouter Frontend Workspace Shell v1 ## Purpose Workspace Shell v1 is the authenticated application frame around existing MediaRouter routes. It provides one responsive, accessibility-first navigation and command experience without changing page content, backend contracts, or feature business logic. The shell is composed in `frontend/components/app-shell.tsx` and wraps the existing authenticated platform routes. Existing pages remain responsible for their own content while the shell owns global chrome only: ```text AppShell ├── DiscoveryBootstrap ├── WorkspaceSidebar ├── WorkspaceTopbar ├── existing route content ├── GlobalSearch (lazy) ├── WorkspaceActivityDrawer (lazy) └── WorkspaceKeyboardShortcuts ``` ## Architecture The implementation builds on the Frontend Architecture v2 boundaries: - `features/workspace/navigation/registry.ts` is the one navigation manifest. - `useWorkspaceNavigation()` resolves capabilities, permissions, feature flags, and plugin registrations before anything is rendered. - `features/workspace/stores/workspace-ui-store.ts` holds shell-only transient UI state. Only the desktop sidebar collapse preference is persisted. - `features/commands/registry.ts` is the command extension point. Shell commands are registered from resolved navigation rather than being embedded in the palette UI. - Existing shared API/query modules supply backend discovery, global search, and jobs. Shell components never call `fetch()` directly. ## Navigation The desktop sidebar, tablet layout, mobile drawer, global search navigation group, and shell navigation commands all use the same manifest. A destination is rendered only if the route exists and its capability, permission, and feature flag requirements resolve for the signed-in user. Currently enabled destinations, when authorized by backend metadata, are: | Section | Destinations | | --- | --- | | Workspace | Home, Jobs | | Create | Create (existing playground) | | Library | Templates, Assets | | Publish | Publish (existing social route) | | Automation | Operations, MCP, API | | Developer | Developer Portal | | Settings | Settings, API Keys, Administration | Sections with no existing authorized destination are omitted. Planned destinations such as Projects, AI Studio, Content Studio, Insights, Team, Calendars, Campaigns, Workflows, and Marketplace are deliberately absent. Their existing routes, where any exist, are preserved but are not advertised prematurely. `features/workspace/navigation/breadcrumbs.ts` contains centralized route metadata used by the topbar. It generates route-aware breadcrumb hierarchies without page-specific breadcrumb definitions. ## Sidebar and responsive behavior - Desktop (`md` and above): persistent expanded/collapsed sidebar with hover expansion when collapsed. - Tablet: the same collapsible sidebar remains available. - Mobile: the same resolved manifest renders inside an off-canvas navigation drawer. The drawer has a visible close control, closes when a destination is selected, and closes with Escape. - All shell action controls and navigation rows meet a 44px minimum touch target. - Sidebar collapse is activated with `⌘/Ctrl+B`; on narrow screens this shortcut opens navigation instead. The drawer backdrop is intentionally non-focusable. Focusable navigation is contained in the labeled drawer, and its close button is the accessible close action. ## Workspace switcher and user menu `WorkspaceSwitcher` accepts authoritative workspace and recent-workspace values through its typed adapter props. The current backend does not expose workspace membership/discovery or workspace creation endpoints, so the shell does not infer, create, or fabricate workspaces. It instead presents an explicit context-unavailable state until an authoritative adapter supplies data. The user menu is route- and permission-aware. It exposes Profile, Preferences, Keyboard Shortcuts, Developer Portal when authorized, API Keys for administrators, and Logout. Workspace Settings is intentionally not shown because an authoritative workspace settings destination is not currently available. ## Search and commands The topbar opens global search with `⌘K` or `Ctrl+K`. The lazy-loaded palette combines only: - already-authorized navigation destinations; - commands currently registered through `CommandRegistry`; and - results returned by the existing backend search/discovery layer, filtered against authorized routes. There is no client-side mock search index and no fabricated results. Commands currently registered by the shell are resolved navigation commands plus **Open activity** and **Show keyboard shortcuts**. Product modules can add commands through `features/commands/registry.ts`; they should define their own capability/permission requirements and lazy-load the command implementation. The existing design-system `QuickActions` primitive remains the extension point for a future floating action surface. Shell v1 deliberately renders no floating action because no upload, project-creation, AI-generation, publishing, import, or recording action has an authoritative implementation to register yet. ## Activity and realtime The lazy-loaded Activity Drawer uses the existing `useLiveJobs()` adapter only. It uses the existing jobs realtime subscription where the backend advertises one and falls back to the established job polling transport. It never invents jobs, notifications, upload progress, or AI activity: - unavailable jobs capability: explicit unavailable state; - no returned jobs: “You’re all caught up”; and - backend jobs: real activity rows. Notifications, uploads, AI, publishing, transcription, and collaboration can join the drawer later by adding shell-level adapters to their existing shared realtime infrastructure. They should not introduce a separate socket client or write directly into shell state. ## Keyboard shortcuts | Shortcut | Action | | --- | --- | | `⌘K` / `Ctrl+K` | Open global search and commands | | `⌘B` / `Ctrl+B` | Toggle desktop sidebar; open mobile navigation | | `⌘J` / `Ctrl+J` | Open activity drawer | | `Escape` | Close mobile navigation; Radix dialogs, menus, and drawers also close through their standard behavior | ## Accessibility The shell uses semantic navigation landmarks, `aria-current` for the active route, labeled icon controls, Radix focus management for menus/dialogs/drawers, visible design-system focus rings, keyboard operability, and the existing reduced-motion-aware Framer Motion presets. Semantic color tokens and the shared theme system support dark and high-contrast themes. Tooltip-only labels are not relied on for icon control names. ## Extension points To add a real future destination, first preserve the route and then add a navigation manifest entry with its capability, permission, and feature-flag requirements. Its command becomes available automatically when resolved shell commands are registered. To add a new global activity source, create an adapter above the existing realtime/query layer and provide real backend records only. Do not add raw network calls to shell components, inspect environment variables in UI components, create duplicate Zustand stores, add placeholder counters/actions, or duplicate navigation arrays for mobile and desktop. ## Validation Focused tests cover manifest filtering, active routes, breadcrumbs, persisted shell preference, command registration, keyboard shortcuts, mobile drawer reuse, workspace-switcher no-data behavior, activity empty state, and user-menu authorization. Type checking and linting are part of the shell change validation. Production builds are attempted separately because Android/Termux may not provide Next/Turbopack or Storybook native bindings.