@dunx/dashboard

An opt-in operations page for a running dunx app: routes, the provider graph, gateways, config and runtime health, with bull-board mounted for the queues

@dunx/dashboard
@dunx/dashboard/ui

One page over a running dunx app: the routes it serves, the container it built, the gateways it upgrades, Redis, the config keys and the process itself, with bull-board mounted for the queues.

Every panel reads data dunx already computes, so the page is cheap.

There is one running at demo.dunx.win/api/dashboard, mounted by examples/full with commands: false so the board is read-only.

Usage

TS
import { Module } from '@dunx/core';
import { DashboardMiddleware, DashboardModule } from '@dunx/dashboard';
import { HttpFactory } from '@dunx/http';
import { JobPublisher } from '@dunx/infra/queue';
import { RedisConnection } from '@dunx/infra/redis';

@Module({
  imports: [
    DashboardModule.forRootAsync({
      imports: [JobsModule, CacheModule],
      inject: [JobPublisher, RedisConnection],
      useFactory: (queues: JobPublisher, redis: RedisConnection) => ({
        path: '/api/_dunx',
        queues,
        redis,
        authorize: (req) => isOperator(req),
      }),
    }),
  ],
})
export class OpsModule {}

const app = await HttpFactory.create(AppModule);
app.use(DashboardMiddleware); // first, ahead of any session guard

The panels

Seven panels, each with a JSON sibling under {path}/api/*, so curl is a real way to read this on a box with no browser. The queues page is bull-board's.

PanelShows
RoutesEvery route, its guards and metadata, linked to /docs
ProvidersThe container graph, by module
GatewaysEvery WebSocket gateway and its events
RedisConnection state and INFO
ConfigKeys always, values only where reveal says so
RuntimeThe process, its memory and its probes
StatsRequest, query and cache timings, each half independent

Three things that are decisions

  • authorize has no default. Leaving it out serves the page to anyone who can reach the port. Omitting it logs a warning naming the mount at boot.
  • A rejected request gets 404, not 403. Register the middleware ahead of any session guard: a guard running first answers 401 and tells a prober the mount exists. authorize takes the raw Request so it can be self-sufficient. Return a Response instead of false to answer a browser with a sign-in page or a redirect. The type is @dunx/http's, and @dunx/openapi takes the same one, so a single function gates the dashboard and the API explorer alike.
  • Config values are redacted by default. reveal is an opt-in allow-list; a deny-list of the usual suspects leaks the first key nobody thought of.

Notes

  • QueueSource and RedisProbe have the same shape as JobPublisher and RedisConnection, so queues: publisher is all the wiring you need. The package depends on neither @dunx/infra nor bullmq.
  • The board is built on the first request for the queues page, never at boot, so an app that never opens it holds no broker socket.
  • commands: false maps onto bull-board's own readOnlyMode.
  • The page's React bundle is its own subpath, @dunx/dashboard/ui, which DashboardMiddleware imports on the first request for the page. An app that mounts the module and never opens it does not parse the bundle, and nothing imports the subpath directly.
  • homeHref is a link back to your app. It appears in this page's own navigation, and in bull-board's links menu, which is reached from the last control in its header. bull-board renders it there rather than in the header bar, and dunx renders no queue UI of its own to put it anywhere else.