MediaRouter / docs /frontend-architecture-v2.md
basyx's picture
Upload 794 files
1b2323a verified
|
Raw
History Blame Contribute Delete
11.5 kB
# MediaRouter Frontend Architecture v2
## Purpose
Frontend Architecture v2 is the incremental, feature-oriented foundation for
MediaRouter. It preserves the existing Next.js App Router URLs, authentication
and backend contracts while making the current product areas and future
AI-first workspace modules independently maintainable.
It is intentionally an architecture migration, not a visual redesign or a new
product surface. The MediaRouter Design System remains the sole UI primitive
layer; features compose it and do not recreate buttons, forms, navigation or
feedback elements.
## Layering
```text
app routes (thin route and metadata adapters)
|
feature boundary (screen, hooks, schemas, local state, feature API facade)
|
shared application services (auth, query, flags, capabilities, realtime)
|
lib/api/client.ts -> authenticated same-origin BFF -> MediaRouter backend
```
All browser requests use the shared Axios client at
`frontend/lib/api/client.ts`, whose base URL is the same-origin
`/api/backend` bridge. UI components must not call `fetch()` directly.
`app/api/backend/[...path]/route.ts` remains the only frontend transport proxy.
It owns authentication forwarding, backend authorization and safe request
forwarding; no frontend API contract changed in this migration.
## Directory structure
```text
frontend/
app/
(auth)/ authentication routes
(platform)/ preserved workspace URLs during incremental migration
(public)/ public/legal routes
api/ BFF and authentication route handlers
components/
ui/ layout/ navigation/ feedback/ design-system consumers only
design-system/ tokens, themes, icons, motion and foundations
features/
auth/ workspace/ templates/ social/ jobs/ media/ developer/
dashboard/ settings/ operations/ marketplace/ mcp/
search/ commands/ plugins/ editor/
lib/
api/ auth/ query/ capabilities/ feature-flags/ realtime/ config/
hooks/ cross-feature compatibility or presentation hooks
```
The existing `(platform)` route group intentionally remains in place. Route
groups do not affect URLs, so `/dashboard`, `/templates`, `/social`,
`/developer/*`, and every existing bookmark retain their current address. New
workspace routes should be introduced below the agreed `(workspace)` group only
when their corresponding product module is implemented; no duplicate or mock
pages are created by this foundation.
## Feature boundary
Each feature is the owner of its screen-level components, feature hooks,
schemas/types, local stores, services and an `api/` facade. The facade imports
the shared transport modules from `lib/api`; it does not instantiate a second
HTTP client. This keeps authentication, error handling, timeout and BFF policy
consistent while allowing a feature to control its public data interface.
Current active feature boundaries include:
- `auth`: session hook and protected route integration.
- `workspace`: discovery bootstrap, shared discovery queries, navigation and
workspace chrome state.
- `templates`: browser, detail, runner, preferences store and template API
facade.
- `social`: social screens, query/mutation hooks and social API facade.
- `jobs`: job monitor and reusable job realtime adapter.
- `media`: media input, transfer state and upload service.
- `developer`, `settings`, `operations`, `mcp`, `marketplace`, `dashboard`:
their existing screens behind explicit feature entry points/API facades.
- `search`, `commands`, `plugins`, `editor`: reusable infrastructure with no
new product UI or mock data.
Foundational feature declarations live in `features/manifest.ts`. They let
tooling and navigation identify active, foundation and planned product areas
without turning planned functionality into visible routes.
## State management
State is deliberately split by lifecycle and ownership:
| State | Location | Rule |
| --- | --- | --- |
| Global workspace chrome | `features/workspace/stores/workspace-ui-store.ts` | sidebar and command-palette visibility only |
| User template preferences | `features/templates/stores/template-preferences-store.ts` | browser-local persisted preferences only |
| Transfers | `features/media/stores/transfer-store.ts` | active browser transfer state only |
| Server data | feature TanStack Query hooks | never copied into Zustand |
| Editor state | `features/editor/index.ts` | one vanilla Zustand store per editor instance |
Authentication remains session-backed through NextAuth and is exposed through
`features/auth/hooks/use-auth.ts`. Workspace/project/server data remains
authoritative on the backend. Do not create a catch-all Zustand store.
## API and TanStack Query policy
`lib/api/errors.ts` converts transport failures into a safe `MediaRouterApiError`
and normalized categories: authentication, authorization, validation,
not-found, rate-limited, offline, timeout, server and unknown.
`lib/query/client.ts` configures one QueryClient with bounded retry/backoff for
retryable transport failures only. Query keys are stable and feature-owned;
shared cross-feature keys live in `lib/query/keys.ts`. Features must:
1. Call a feature API facade or shared discovery hook, never `fetch()` from a
UI component.
2. Define a stable query key.
3. Invalidate only the keys affected by a successful mutation.
4. Use optimistic updates only with a rollback snapshot.
5. Surface `normalizeApiError()` through the feedback states rather than raw
server payloads.
The shared feedback layer provides API, validation, permission and offline
error-state building blocks, plus retry banners. Backend error details and
request IDs stay safe to render, but credentials and private upstream targets
never enter the browser.
## Server and client component strategy
Route pages, metadata and authorization checks remain Server Components by
default. A component is marked client-side only when it needs browser state,
TanStack Query, event handlers, uploads, realtime, drag-and-drop, command
palette interaction, a browser API or animation.
Examples of client-only infrastructure are the app shell, global search,
upload service consumers, job subscriptions, forms and editor stores. New
features should keep route adapters thin, use `Suspense` boundaries around
client data islands, and avoid pulling heavy editor/timeline modules into the
workspace shell.
## Permissions, capabilities and feature flags
The backend remains authoritative. `lib/auth/permissions.ts` provides the
frontend UX check and the BFF separately checks every forwarded request.
`lib/capabilities/index.ts` evaluates a declarative requirement containing an
optional backend capability, permission and feature flag. Navigation, commands
and plugins use this same resolver. Do not hardcode role checks in components.
`lib/feature-flags/index.ts` is the only environment-backed flag resolver.
`useFeatureFlags()` supplies the UI layer, supports future workspace,
organization and user overrides, and keeps pages from reading environment
variables directly. A backend-provided override can be passed as scoped
metadata when the backend exposes it.
## Navigation
`features/workspace/navigation/registry.ts` declares workspace, developer and
footer navigation. `useWorkspaceNavigation()` combines it with the authenticated
subject, backend OpenAPI discovery, feature flags and plugin registrations.
`AppSidebar` only renders resolved entries, so it contains no route-specific
permission policy. Dynamic badges may be supplied in a future navigation
registration without changing the shell.
## Commands and plugins
`features/commands/registry.ts` is an empty-by-default command-palette
registry. A command has a group, shortcut, capability requirement and an
optional lazy `load()` function. Infrastructure exists; this migration does not
populate product commands.
`features/plugins/registry.ts` is a metadata registry for future modules.
Plugins can register routes, navigation, commands, settings and capability
requirements. Plugins cannot bypass route authorization, feature flags,
capability checks or the shared API client. The registry does not load remote
code and no marketplace plugin is enabled by this foundation.
## Realtime, uploads, search and editor foundation
- `lib/realtime/subscription.ts` defines a generic subscription and React hook.
Jobs adapt their existing WebSocket/SSE/polling fallback to it through
`features/jobs/services/realtime.ts`; other features can use the same
contract.
- `features/media/services/upload-service.ts` is the single feature-level
entry point to the existing chunked upload protocol. It supports cancellation
via `AbortController`; transport/protocol discovery remains in `lib/api`.
- `features/search` maps real template, operation and MCP discovery metadata to
internal routes. It has no hard-coded backend payloads or client-provided
URLs.
- `features/editor/index.ts` supplies isolated selection/history/undo/redo and
plugin state. It intentionally does not implement an editor surface,
collaboration protocol or timeline UI.
## Performance and accessibility
The refactor keeps the workspace shell small, centralizes QueryClient policy,
uses stable query keys and makes command/plugin work lazy-loadable. Heavy
future modules (editor, timeline, media inspection, collaboration) must be
loaded behind feature boundaries and `Suspense` rather than imported by the
shell. Existing image handling stays under Next.js configuration.
Architecture changes preserve the Design System’s WCAG AA baseline: semantic
tokens, keyboard-capable Radix primitives, labelled controls, focus management,
reduced motion and responsive workspace shell behavior. New capability checks
hide unavailable UI but do not substitute for backend authorization.
## Testing
Vitest tests are colocated with the behavior they protect. Shared fixtures and
setup remain centralized in `frontend/vitest.setup.ts`. The architecture suite
covers feature flag resolution, capability evaluation, navigation filtering,
command and plugin registration, editor history, safe search mapping and API
error classification. Existing component/auth/API tests remain unchanged.
Run locally:
```sh
cd frontend
npm run typecheck
npm run lint
npm test
```
The current Android/Termux environment cannot complete native Turbopack and
Storybook production builds because their native bindings are unavailable. This
is an environment limitation, not a reason to bypass typecheck, lint or unit
tests.
## Migration and contribution guide
1. Preserve the route URL and add/refine its feature boundary first.
2. Put requests in a feature `api/` facade that reuses `lib/api/client.ts`.
3. Put server data in TanStack Query, browser-only local interaction in a
narrowly scoped store, and domain algorithms in feature services/utils.
4. Register capability-driven navigation, commands or plugin metadata instead
of editing the shell directly.
5. Reuse the Design System and shared error/realtime/upload primitives.
6. Add focused tests, then run typecheck, lint and the full unit suite.
Do not move existing routes solely for directory aesthetics, duplicate API
clients/hooks, read environment variables in a product page, create mock data
or encode backend authorization in a UI-only permission check. The migration is
backward compatible by design; there are no public route, API or authentication
breaking changes in v2.