NAME

Developer::Dashboard::Web::DancerApp - Dancer2 route layer for Developer Dashboard

SYNOPSIS

my $psgi_app = Developer::Dashboard::Web::DancerApp->build_psgi_app(
    app             => $web_app,
    default_headers => \%headers,
    paths           => $paths,
);

DESCRIPTION

This module owns the HTTP route table for the dashboard web UI under Dancer2. It loads active skill Dancer2 extensions before constructing the shared app, normalizes each request, enforces authorization for dashboard and skill routes, and delegates the page and action work to Developer::Dashboard::Web::App. The skill lib/Dashboard.pm modules load while the PSGI app is constructed at server startup, not once per request; their registered hooks still execute for each matching request. A hook before => sub { ... } may set Dancer2 app variables or response headers. The page CODE runtime can read a hook variable when it imports Dancer2 appname => 'DeveloperDashboard'. When a hook sets a header also present in the dashboard defaults, that existing hook value wins; an explicit header returned by the backend wins over both.

For example, a skill extension can set a request-scoped value and a response policy:

use Dancer2 appname => 'DeveloperDashboard';
hook before => sub {
    var foo => 'bar';
    response_header 'Content-Security-Policy'
        => "script-src 'self' 'unsafe-inline' 'unsafe-eval'";
};

Skill bookmark CODE that needs the variable imports that same app:

use Dancer2 appname => 'DeveloperDashboard';
print var('foo');

The route adapter intentionally hands the namespaced /app, /ajax, /js, /css, and /others surfaces back to the backend dispatcher so the installed PSGI server stays in lock-step with the backend smart router. The /favicon.ico route is deliberately registered without the authorization wrapper, because browsers request the tab icon implicitly on every page load, including on the login page itself. The header normalizer forwards the Origin, Referer, and Sec-Fetch-Site headers on every request so the backend's cross-site request forgery check can refuse requests that arrive from a foreign browser context — including the unauthorized /login POST route, whose backend handler applies the same check itself. Sec-Fetch-Site has to ride along too because it is the only one of the three that defends a GET: the browser sets it, and page script can neither forge nor suppress it, which is what stops a foreign page from executing a saved /ajax handler on the cookie-less loopback-admin tier.

METHODS

build_psgi_app, _load_skill_dashboard_modules, _authorize_skill_dashboard_routes, _current_backend, _request_headers, _request_args, _response_header_overrides, _response_from_result, _run_backend, _run_authorized

Build and serve the Dancer2 application around the dashboard route handlers.

PURPOSE

This module adapts the dashboard route backend to PSGI/Dancer-style request handling. It turns the backend app object into a PSGI coderef, translates request and response state, and preserves the dashboard default headers while keeping the route logic out of the transport adapter.

WHY IT EXISTS

It exists because the transport adapter should be small and separate from the actual route behavior. The dashboard needs a bridge from PSGI requests to the backend app object without forcing the backend to know about Dancer internals.

WHEN TO USE

Use this file when changing PSGI wrapping, response translation, or the way the backend app is exposed to Plack and Starman.

HOW TO USE

Call build_psgi_app with the backend app object, default headers, and path registry, then pass the returned coderef to a PSGI server. Active installed skills are scanned recursively; each lib/Dashboard.pm is loaded with its own lib/ first in @INC so it can add routes or settings using use Dancer2 appname => 'DeveloperDashboard'. Skill routes are inserted before the final catch-all and are checked through the dashboard authorization handler. These are trusted local Perl extensions; load failures stop startup with an explicit error. Route behavior and core auth logic should stay in Developer::Dashboard::Web::App, including the smart namespaced route resolution for installed skill-local pages, Ajax handlers, and public assets.

WHAT USES IT

It is used by app.psgi, by Developer::Dashboard::Web::Server, and by tests that verify the PSGI adapter keeps dashboard headers and route responses intact.

EXAMPLES

Example 1:

perl -Ilib -MDeveloper::Dashboard::Web::DancerApp -e 1

Do a direct compile-and-load check against the module from a source checkout.

Example 2:

prove -lv t/03-web-app.t t/08-web-update-coverage.t t/web_app_static_files.t

Run the focused regression tests that most directly exercise this module's behavior.

Example 3:

HARNESS_PERL_SWITCHES=-MDevel::Cover prove -lr t

Recheck the module under the repository coverage gate rather than relying on a load-only probe.

Example 4:

prove -lr t

Put any module-level change back through the entire repository suite before release.