# The dashboard

> The three pages, what the charts draw, and the settings for where the dashboard lives and who can open it.

Source: https://requizon.boring-observability.dev/docs/dashboard
Section: Configuration — Requizon documentation (version 0.2)
Updated: 2026-09-16

---

The dashboard is served by your application at `/requizon`, with its own views, stylesheet and script, so it does not depend on your front-end build. It has three levels, each one a drill-down from a row of the one above.

## The three pages

| Page | Lists | Reads |
| --- | --- | --- |
| `/requizon` | Every API, one row per host, with totals, success rate, average duration and failure count | The hourly rollup |
| `/requizon/{api}/paths` | The API's paths, most failures first. Opened from a host row, only that host's paths | The hourly rollup |
| `/requizon/{api}/requests` | Individual calls, newest first, with a Details panel for each failure | The detail table, 50 rows a page |

The overview and paths page read the rollup, so a call made in the current hour appears there once the hour has ended and [`requizon:aggregate`](https://requizon.boring-observability.dev/docs/retention) has run. The requests list reads the detail table and is current to the last call.

## The charts

Every page draws the same two charts over the selected window:

- **Response time**: the average across everything on the page, plus a line for each of the three slowest members. APIs on the overview, paths on the paths page, and on the requests list whatever its filters leave.
- **Responses**: calls per bucket, stacked by status code or failure type, so the height of each column is the request volume. The seven most frequent outcomes get their own colour and the rest are folded into *Other*.

Each chart has a **Data** disclosure underneath with the numbers behind it as a table. Windows longer than four days are drawn in wider buckets (two hours for a week, four for a fortnight), so a fortnight stays readable.

## Filtering the requests list

The requests list filters by host, path, outcome, status code and a date range. Host and path match exactly, using the values as stored, which is why the links from the paths page are the easiest way in.

- An outcome or status filter narrows the responses chart to the matching calls, so filtering to `503` charts only 503s per hour. Response time is not recorded per outcome, so that chart is hidden while one is applied.
- A date range replaces the window, widened to whole hours at both ends, because the charts are drawn from hourly buckets.

## Windows

```php
// config/requizon.php
'dashboard' => [
    'windows' => [24, 72, 168, 336],   // hours offered by the selector
    'default_window' => 72,
    'per_page' => 50,
],
```

A `default_window` that is not in `windows` falls back to the first entry, so the selector never claims one window while showing another. Offering a window longer than `retention.detail_days` works for the charts, which read the rollup, but the requests list will not reach that far back.

## Access

Every dashboard route runs through the middleware in `requizon.middleware` (`['web']` by default) and then Requizon's own check, which answers `403` to anyone it does not let in. The check your published `RequizonServiceProvider` installs is:

- In the `local` environment, everyone.
- Anywhere else, whoever the `viewRequizon` gate allows, and nobody until you define it.

```php
protected function gate(): void
{
    Gate::define('viewRequizon', fn ($user) => in_array($user->email, [
        'ops@example.com',
    ]));
}
```

The gate receives the authenticated user, so a guest is refused without the closure running. For a check that is not about a user at all (an IP allow-list behind a VPN, say), replace the whole callback in the provider's `boot()` method, after `parent::boot()`:

```php
use BoringO11y\Requizon\Requizon;

Requizon::auth(fn ($request) => $request->ip() === '10.0.0.5');
```

If the provider is not registered at all, no callback exists and the dashboard is reachable only in the `local` environment.

> **Assets are not gated**
>
> The dashboard's stylesheet and script are served without the middleware or the gate, so its own error pages stay styled. They are two fixed files with no data in them.

## Moving the dashboard

```bash
REQUIZON_PATH=ops/outbound          # served at /ops/outbound
REQUIZON_DOMAIN=ops.example.com      # served only on that host
```

Add middleware to the list rather than replacing it, so the routes keep their session and cookies:

```php
'middleware' => ['web', 'auth', 'verified'],
```

`php artisan about` prints the path the dashboard is currently served from.


## Common questions

### Can I serve the Requizon dashboard from a subdomain?

Yes. Set REQUIZON_DOMAIN to the host, and REQUIZON_PATH if you want something other than /requizon. The routes still run through the middleware listed in requizon.middleware and still ask the viewRequizon gate.
