---
title: Features
description: Dashboard capabilities including micro-frontend shell, contributor system, authentication, bridge, SSE, search, and security
---

## ForgeUI Dashboard Shell

The dashboard is a ForgeUI-powered micro-frontend shell served from the Forge HTTP router. It uses a **layout hierarchy** for page structure:

| Layout | Purpose |
|---|---|
| `root` | HTML shell with head, scripts, sidebar, topbar. Detects HTMX partial requests and skips the outer shell. |
| `dashboard` | Default layout. Inherits root, adds breadcrumbs, page title, and content area. |
| `base` | Minimal layout with sidebar and topbar but no breadcrumbs. |
| `full` | Full-width layout without sidebar (e.g., for standalone pages). |
| `settings` | Settings layout with sidebar navigation for settings pages. |
| `auth` | Centered card layout for login/register pages. No sidebar or topbar. |

Navigation between pages uses **HTMX partial requests** -- clicking a sidebar link fetches only the page content (not the full HTML shell), swaps the `#content` div, and updates the browser URL. This gives a SPA-like experience without client-side JavaScript routing.

**Alpine.js** manages client-side state (sidebar collapse, theme toggle, SSE connection status, notification count) and is available in all layouts.

## Contributor System

The dashboard uses a **contributor-based architecture**. Extensions register pages, widgets, and settings via a manifest, and the shell merges everything into a unified UI.

### Local Contributors

Local contributors run in-process and render `gomponents.Node` values directly:

```go
type LocalContributor interface {
    Manifest() *contributor.Manifest
    RenderPage(ctx context.Context, route string, params Params) (g.Node, error)
    RenderWidget(ctx context.Context, widgetID string) (g.Node, error)
    RenderSettings(ctx context.Context, settingID string) (g.Node, error)
}
```

Register a local contributor:

```go
dashExt.RegisterContributor(&MyContributor{})
```

### Remote Contributors

Remote contributors are separate HTTP services that expose fragment endpoints:

- `GET <baseURL>/_forge/dashboard/manifest` -- JSON manifest
- `GET <baseURL>/_forge/dashboard/pages/*` -- HTML page fragments
- `GET <baseURL>/_forge/dashboard/widgets/:id` -- HTML widget fragments

The dashboard proxies requests via the **fragment proxy**, which includes an LRU cache with TTL and stale-while-revalidate fallback.

### Manifest

Each contributor provides a manifest describing its capabilities:

```go
&contributor.Manifest{
    Name:        "users",
    DisplayName: "User Management",
    Icon:        "users",
    Version:     "1.0.0",
    Nav: []contributor.NavItem{
        {Label: "Users", Path: "/", Icon: "users", Group: "Identity", Priority: 0},
        {Label: "Roles", Path: "/roles", Icon: "shield", Group: "Identity", Priority: 1},
    },
    Widgets: []contributor.WidgetDescriptor{
        {ID: "active-users", Title: "Active Users", Size: "sm", RefreshSec: 60},
    },
    Settings: []contributor.SettingsDescriptor{
        {ID: "user-defaults", Title: "User Defaults", Description: "Default settings for new users"},
    },
}
```

`NavItem` entries become sidebar links grouped by `Group` and sorted by `Priority`. The sidebar is constructed automatically from all contributor manifests.

See the [Contributors guide](/docs/forge/extensions/dashboard/contributors) for full details.

## Built-in Pages

Four pages are provided by the built-in core contributor:

| Page | Path | Description |
|---|---|---|
| Overview | `/` | Application health, extension count, uptime, key metrics |
| Health | `/health` | Per-extension health checks with status indicators |
| Metrics | `/metrics` | Counters, gauges, and histograms from the Forge metrics system |
| Services | `/services` | Registered services with status and configuration |

## Widgets

Contributors register widgets via `WidgetDescriptor`. Widgets are rendered as HTMX fragments that **auto-refresh** at the interval specified by `RefreshSec`:

```go
Widgets: []contributor.WidgetDescriptor{
    {ID: "active-users", Title: "Active Users", Size: "sm", RefreshSec: 60, Group: "Identity"},
}
```

Widget sizes: `sm`, `md`, `lg`, `xl`. The overview page displays widgets from all contributors.

## Real-Time Updates

The dashboard uses **Server-Sent Events (SSE)** for live updates. When `EnableRealtime` is true, the SSE broker broadcasts events to all connected browsers:

```go
broker := ext.SSEBroker()

// Broadcast a custom event
broker.BroadcastJSON("deployment", map[string]any{
    "service": "api",
    "version": "2.1.0",
})
```

The SSE endpoint is at `{basePath}/sse`. The broker sends keep-alive pings at the configured interval (default 15s).

Event types include metric updates, health state changes, and contributor health transitions (e.g., when a remote contributor becomes unreachable).

<Callout type="info">
The dashboard uses SSE (Server-Sent Events), not WebSocket. SSE is simpler, works over standard HTTP, and is sufficient for server-to-client push.
</Callout>

## Go-JS Bridge

The **Go-JS bridge** lets the dashboard UI call Go functions directly from the browser via Alpine.js magic helpers:

```javascript
// From Alpine.js in the browser
const overview = await $go('dashboard.getOverview')
const detail = await $go('dashboard.getServiceDetail', { name: 'api' })
```

8 built-in functions are registered automatically. Extensions can register custom functions:

```go
dashExt.RegisterBridgeFunction("myapp.getData", handler,
    bridge.WithDescription("Get application data"),
    bridge.WithFunctionCache(10 * time.Second),
)
```

Bridge endpoints: `POST {basePath}/bridge/call` for single calls, `GET {basePath}/bridge/stream/` for streaming responses.

See the [Bridge guide](/docs/forge/extensions/dashboard/bridge) for full details.

## Federated Search

When `EnableSearch` is true, the dashboard provides a cross-contributor search API. Contributors implementing the `SearchableContributor` interface are searched in parallel:

```go
type SearchableContributor interface {
    DashboardContributor
    Search(ctx context.Context, query string, limit int) ([]SearchResult, error)
}
```

The search API is at `GET {basePath}/api/search?q=query`. Results include the contributor name, matched item, and a link to the relevant page.

## Settings Aggregation

When `EnableSettings` is true, contributor settings are merged into a unified settings page at `{basePath}/settings`. Each contributor's `SettingsDescriptor` entries appear as form sections that can be edited and submitted.

## Data Export

Export dashboard data in three formats when `EnableExport` is true:

| Endpoint | Format | Description |
|---|---|---|
| `GET /export/json` | JSON | Full snapshot of overview, health, metrics, and services |
| `GET /export/csv` | CSV | Metrics as rows with name, type, value, and timestamp |
| `GET /export/prometheus` | Prometheus | Text exposition format for external scraping |

Configurable export formats:

```go
dashboard.WithExportFormats([]string{"json", "csv", "prometheus"})
```

## Service Discovery

When `EnableDiscovery` is true and a discovery service is configured, the dashboard automatically discovers remote contributors tagged with `forge-dashboard-contributor`:

```go
dashExt.SetDiscoveryService(discoveryExt.Service())
```

Discovered services have their manifests fetched and are registered as remote contributors. The discovery integration polls at the configured interval (default 60s).

## Authentication & Authorization

The dashboard supports optional authentication with three page access levels:

| Level | Behavior |
|---|---|
| `public` | Always accessible, no login required |
| `protected` | Requires authentication; unauthenticated users are redirected to the login page |
| `partial` | Always accessible but can render differently based on auth state |

### Enabling Auth

```go
dashExt := dashboard.NewExtension(
    dashboard.WithEnableAuth(true),
    dashboard.WithDefaultAccess("protected"),
    dashboard.WithLoginPath("/auth/login"),
    dashboard.WithLogoutPath("/auth/logout"),
)
```

### AuthChecker

The `AuthChecker` interface is the primary abstraction for validating requests. Implement it to integrate with your auth system (JWT, sessions, OAuth, etc.):

```go
import dashauth "github.com/xraph/forge/extensions/dashboard/auth"

type MyChecker struct{ /* your auth service */ }

func (c *MyChecker) CheckAuth(ctx context.Context, r *http.Request) (*dashauth.UserInfo, error) {
    // Return nil (not an error) when unauthenticated.
    // Return *UserInfo when authenticated.
    // Return an error only for infrastructure failures.
}
```

Wire it after registration:

```go
typedDash := dashExt.(*dashboard.Extension)
typedDash.SetAuthChecker(&MyChecker{})
```

### UserInfo

`UserInfo` represents an authenticated user. It is decoupled from any auth provider:

```go
type UserInfo struct {
    Subject      string            // unique user ID
    DisplayName  string            // display name
    Email        string            // email address
    AvatarURL    string            // avatar image URL
    Roles        []string          // user roles
    Scopes       []string          // OAuth2 scopes
    ProviderName string            // which auth provider
    Claims       map[string]any    // additional claims
    Metadata     map[string]any    // provider metadata
}
```

Helper methods: `Authenticated()`, `HasRole(role)`, `HasScope(scope)`, `HasAnyRole(roles...)`, `Initials()`.

### Auth Page Provider

Auth extensions provide login/register/logout pages by implementing `AuthPageProvider`:

```go
type AuthPageProvider interface {
    AuthPages() []AuthPageDescriptor
    RenderAuthPage(ctx *router.PageContext, pageType AuthPageType) (g.Node, error)
    HandleAuthAction(ctx *router.PageContext, pageType AuthPageType) (redirectURL string, errNode g.Node, err error)
}
```

Supported page types: `login`, `logout`, `register`, `forgot-password`, `reset-password`, `callback`, `profile`.

Auth pages use the `auth` layout (centered card, no sidebar) and are always publicly accessible so unauthenticated users can reach the login form.

### Per-Page Access Levels

Contributors can set access levels on individual `NavItem` entries:

```go
Nav: []contributor.NavItem{
    {Label: "Public Stats", Path: "/stats", Access: "public"},
    {Label: "Admin Panel", Path: "/admin", Access: "protected"},
    {Label: "Dashboard", Path: "/", Access: "partial"},
}
```

Empty `Access` falls back to the dashboard `DefaultAccess` config.

### Reading User Info

Page handlers and contributors can read the authenticated user from the request context:

```go
user := dashauth.UserFromContext(ctx)
if user.Authenticated() {
    // Personalize content for the user
}
```

### HTMX-Aware Redirects

When an HTMX partial request hits a protected page without authentication, the middleware returns a 401 status with an `HX-Redirect` header. The `AuthRedirectScript` (automatically injected when auth is enabled) reads this header and performs a full-page redirect to the login page.

### Middleware Stack

The auth system uses two middleware layers:

1. **`ForgeMiddleware`** -- runs on the forge.Router catch-all, calls `AuthChecker.CheckAuth()`, and stores the `UserInfo` in the request context. Never blocks requests.
2. **`PageMiddleware`** -- runs per ForgeUI page, enforces the access level. Redirects to the login page for `protected` pages when the user is unauthenticated.

Additional middleware helpers: `RequireRole(role)` and `RequireScope(scope)` for fine-grained authorization.

<Callout type="info">
The dashboard auth system is intentionally decoupled from the `extensions/auth` package. The `dashauth` package defines its own `AuthChecker` interface and `UserInfo` type so the dashboard has no hard dependency on any specific auth provider.
</Callout>

## Security

### Content-Security-Policy

When `EnableCSP` is true (default), the dashboard adds CSP headers to prevent XSS and other injection attacks.

### CSRF Protection

When `EnableCSRF` is true (default), form submissions and bridge calls are protected with CSRF tokens.

### HTML Sanitization

Remote contributor HTML fragments are sanitized before embedding to prevent XSS from untrusted remote services.

## Theming

Three theme modes are supported:

```go
dashboard.WithTheme("auto")  // Follows system preference (prefers-color-scheme)
dashboard.WithTheme("light") // Always light mode
dashboard.WithTheme("dark")  // Always dark mode
```

Custom CSS can be injected:

```go
dashboard.WithCustomCSS(".my-class { color: red; }")
```

## Error Recovery

The **recovery manager** implements a circuit-breaker pattern for remote contributors. If a remote service becomes unreachable, the recovery manager tracks its health state transitions (healthy -> degraded -> unhealthy) and broadcasts state changes via SSE for real-time UI updates.
