---
id: "frontend/overview"
title: "Frontend overview"
description: "Three packages that cover everything browser-side in a Titan app."
---

# Frontend overview

> The **server-side** Netron lives inside Titan itself
> (`@omnitron-dev/titan/netron`, including all four
> transports). This section covers the **browser side**.

Browser-side packages:

| Package                                                         | Role                                                                   | Framework                                                                                 | Size                                                                   |
| --------------------------------------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| [`@omnitron-dev/netron-browser`](/docs/frontend/netron/browser) | RPC transport (HTTP + WebSocket), middleware, auth, multi-backend pool | **Framework-agnostic** — vanilla JS, Vue, Svelte, Solid, Angular, Lit, React, Web Workers | \~25 kB gz                                                             |
| [`@omnitron-dev/netron-react`](/docs/frontend/netron/react)     | React hooks, query/mutation cache, auth guards, devtools               | **React-only** — optional layer on top of netron-browser                                  | \~15 kB gz                                                             |
| [`@omnitron-dev/prism`](/docs/frontend/prism)                   | Design system: MUI v9 components, blocks, layouts, forms, hooks        | **React-only** (MUI v9 is React) — optional                                               | Depends on selected components and peers; unused modules are discarded |

`netron-browser` works everywhere. Add `netron-react` + `prism`
**only** for React apps. For Vue / Svelte / Solid / Angular / Lit,
use `netron-browser` directly and wrap calls in your framework's
reactivity primitives.

## How they compose

```mermaid
flowchart LR
  Comp["React component<br/>built with Prism"]
  Hook["netron-react hook<br/>(useQuery / useService)"]
  Client["netron-browser<br/>NetronClient"]
  Wire["HTTP / WebSocket"]
  Server["Titan @Service / @Public"]

  Comp --> Hook --> Client --> Wire --> Server
```

A typical screen:

```tsx
import { DataGridBlock }   from '@omnitron-dev/prism/blocks';
import { useService }      from '@omnitron-dev/netron-react';

interface UserService {
  list(filter: UserFilter): Promise<User[]>;
}

function UsersPage() {
  const users = useService<UserService>('users');
  return (
    <DataGridBlock
      title="Users"
      columns={[
        { field: 'email',  header: 'Email' },
        { field: 'role',   header: 'Role'  },
      ]}
      query={({ page, sort, filter }) =>
        users.list.useQuery([{ page, sort, filter }])
      }
    />
  );
}
```

Three packages, one screen, no codegen.

## End-to-end types

There is no schema file, no codegen step, no manual sync. The
TypeScript compiler is the source of truth:

```typescript
// Shared package — the contract:
export interface UsersService {
  findById(id: string): Promise<User | null>;
}

// Browser — type flows through:
const users = useService<UsersService>('users');
const { data } = users.findById.useQuery([id]);
//      ^? User | null | undefined
```

A method signature change on the server fails the build on
every caller in the same `tsc` pass.

## Wiring an app from scratch

```tsx
import { NetronReactClient, NetronProvider }   from '@omnitron-dev/netron-react';
import { AuthProvider }                        from '@omnitron-dev/netron-react/auth';
import { PrismProvider, ProviderStack }        from '@omnitron-dev/prism/core';
import { RouterProvider }                      from 'react-router-dom';

const client = new NetronReactClient({
  url:       import.meta.env.VITE_API_URL,
  transport: 'http',
});

// `AuthProvider` takes a `config` (refreshEndpoint?, logoutEndpoint?,
// storage?: 'local' | 'session' | 'memory', autoRefresh?, refreshThreshold?)
// and an `onLogin` handler that performs the actual sign-in and returns
// an AuthResult.
function App() {
  return (
    <ProviderStack
      providers={[
        [NetronProvider, { client }],
        [AuthProvider,   {
          config:  { storage: 'local', autoRefresh: true, refreshEndpoint: '/auth/refresh' },
          onLogin: (credentials) => signIn(client, credentials),
        }],
        [PrismProvider,  { defaultSettings: { mode: 'dark', primaryColor: '#7c4dff' } }],
        [RouterProvider, { router }],
      ]}
    >
      <Outlet />
    </ProviderStack>
  );
}
```

Four providers, one app. Anything Titan-side becomes
discoverable through `useService`. The auth API is `login` / `logout`
(from `useAuth()`) with `<AuthGuard>` / `<GuestGuard>` /
`<RoleGuard>` / `<PermissionGuard>` route guards — see
[netron-react / Auth](/docs/frontend/netron/auth) for the full surface.

## Multi-backend out of the box

Talking to several Netron servers? Swap `NetronProvider` for
`MultiBackendProvider`:

```tsx
import { createMultiBackendClient }
  from '@omnitron-dev/netron-browser';
import { MultiBackendProvider, useBackendService }
  from '@omnitron-dev/netron-react';

const client = createMultiBackendClient({
  baseUrl: 'https://api.example.com',
  backends: {
    auth:      { path: '/auth',      transport: 'http' },
    media:     { path: '/media',     transport: 'http' },
    analytics: { path: '/analytics', transport: 'http' },
  },
  routing: {
    patterns: [
      { pattern: 'users.',   backend: 'auth' },
      { pattern: 'objects.', backend: 'media' },
      { pattern: 'reports.', backend: 'analytics' },
    ],
  },
});

<MultiBackendProvider client={client}>
  <Outlet />
</MultiBackendProvider>

// In components:
const users = useBackendService<UserService>('auth', 'users');
```

→ [netron-react / Multi-backend](/docs/frontend/netron/react#multi-backend-support).

## What lives where

| You want…                                         | Reach for                                                  |
| ------------------------------------------------- | ---------------------------------------------------------- |
| Theme, colors, typography                         | `@omnitron-dev/prism/theme`                                |
| Dashboard / auth / data-grid shell                | `@omnitron-dev/prism/blocks`                               |
| Sidebar + topbar layout                           | `@omnitron-dev/prism/layouts`                              |
| Card / Table / Drawer / Form field                | `@omnitron-dev/prism` or `@omnitron-dev/prism/components`  |
| Schema-aware forms                                | `@omnitron-dev/prism/forms`                                |
| Persisted UI state (sidebar open, dark mode)      | `@omnitron-dev/prism/state`                                |
| Plain React hooks (`useArray`, `useFocusTrap`, …) | `@omnitron-dev/prism/hooks`                                |
| Type-safe RPC call inside a component             | `useService` from `@omnitron-dev/netron-react`             |
| Live data over WebSocket                          | `useSubscription` from `@omnitron-dev/netron-react`        |
| Sign-in flow + route guards                       | `@omnitron-dev/netron-react/auth` + `<AuthGuard>`          |
| Multi-backend setup                               | `MultiBackendProvider` from `@omnitron-dev/netron-react`   |
| Raw RPC client (no React)                         | `createClient` from `@omnitron-dev/netron-browser`         |
| Cross-tab auth sync                               | `AuthenticationClient` from `@omnitron-dev/netron-browser` |
| Cache, retry, circuit breaker                     | `@omnitron-dev/netron-browser/middleware`                  |

## Bundle strategy

| Stage                     | Bundle goal                                                         |
| ------------------------- | ------------------------------------------------------------------- |
| First paint (auth screen) | Load the auth screen and its providers                              |
| Authenticated shell       | Add the dashboard layout and shared navigation after authentication |
| Per-route page            | Lazy-load with `React.lazy()` and measure the emitted route chunks  |
| Charts / editor / maps    | Load engines and styles with the routes that use them               |

Named imports from the root and `@omnitron-dev/prism/components` discard unused
modules. Public subpaths such as `components/card`, `components/chart`,
`components/map`, `components/editor` and `components/emoji-picker` are also
available for explicit composition and lazy loading. Only declared exports are
public; there is no wildcard mapping from every source directory.

Import each component's documented CSS entry when required. CSS remains in the
production output. The package archive check verifies that a simple `Card`
consumer does not retain optional engines and that selected calendar, map and
stylesheet dependencies remain. It does not set an application-wide size promise:
measure initial requests, route chunks and shared peer dependencies in the actual
production build.

## Production reference

The Omnitron Console (`apps/omnitron/webapp/`) is built entirely
from these three packages. \~20 pages, multi-backend, full RBAC,
real-time subscriptions, devtools — see
[Console](/docs/omnitron/console) for the route map.

## Read on

- [Prism](/docs/frontend/prism) — design system in depth
- [netron-browser](/docs/frontend/netron/browser) — the transport client
- [netron-react](/docs/frontend/netron/react) — React hooks