dirop1 / frankendash
A secure, dependency-free Laravel dashboard for FrankenPHP metrics, logs, and Horizon.
Requires
- php: ^8.2
- illuminate/cache: ^12.0|^13.0
- illuminate/console: ^12.0|^13.0
- illuminate/contracts: ^12.0|^13.0
- illuminate/database: ^12.0|^13.0
- illuminate/routing: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- illuminate/view: ^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2026-07-30 15:07:05 UTC
README
A small, secure Laravel dashboard for applications running on FrankenPHP. Frankendash reads curated Prometheus metrics from Caddy's fixed loopback endpoint, displays stable frankenbase runtime/watchdog status, tails bounded Laravel log files, optionally records metric history, and reports or controls Laravel Horizon when available.
- PHP 8.2+
- Laravel 12 or 13
- No Node, Vite, frontend framework, or required database table
- Disabled and authorization-denied by default
Install
composer require dirop1/frankendash php artisan frankendash:install
Laravel package discovery registers the service provider. Define both abilities in an application service provider before enabling the package:
use Illuminate\Support\Facades\Gate; Gate::define('viewFrankendash', fn ($user) => $user->is_admin); Gate::define('manageFrankendash', fn ($user) => $user->is_admin && $user->can_manage_infrastructure);
Then set the strict runtime flag:
FRANKENDASH_ENABLED=true
Only the literal lowercase value true enables Frankendash. A missing or malformed runtime value fails closed. Missing Gates always deny access. The default URL is /frankendash.
Frankendash routes are registered even while disabled so Laravel's route cache remains valid. The first package middleware resolves the enabled state for every request; disabled routes return 404. If deployment builds cached configuration before runtime environment injection, the runtime FRANKENDASH_ENABLED=true value overrides the cached setting.
Configuration
Publish config/frankendash.php with the install command. It controls:
- dashboard path, read/manage Gate names, and additional route middleware;
- short metrics timeout, response/sample bounds, and cache duration;
- relative directories beneath
storage/logs, allowed extensions, and tail size; - optional history collection interval and retention;
- opt-in Horizon controls.
The Caddy URL remains http://127.0.0.1:2019/metrics. It cannot be redirected to user input or another host. Frankendash uses a direct bounded loopback socket request, follows no redirects, and uses no HTTP proxy. It never exposes Caddy's admin endpoint.
Likewise, frankenbase runtime paths are fixed and are not configuration options: /etc/frankenbase/version and /run/frankenbase/watchdog.json. Reads are size-bounded and fail closed for symlinks, non-regular files, malformed values, invalid schema-v1 types/states/timestamps, or unsupported schemas. A missing file is presented as a legacy or non-frankenbase environment instead of failing the dashboard.
The web middleware is always retained for session authentication and CSRF protection. Configured middleware is additional.
Optional metric history
Live metrics need no database. To enable persisted charts:
php artisan vendor:publish --tag=frankendash-migrations php artisan migrate
Then set:
FRANKENDASH_HISTORY_ENABLED=true
The migration is publish-only and is never loaded automatically. When Frankendash and history are both enabled, the package schedules frankendash:collect at the configured interval and frankendash:prune daily. The commands may also be run directly. Only curated aggregates are stored.
Request rates are derived when snapshots are read, so no migration or stored JSON rewrite is required. The first point, a non-positive time interval, a missing counter, or a counter decrease/reset produces an unavailable rate rather than a negative value.
The curated snapshot includes FrankenPHP worker/thread totals, ready/busy workers, separate regular and worker queue depths, worker request/crash/restart/request-time counters, Caddy in-flight requests, and process start time when those families are present. Worker utilization and process uptime are derived only from valid denominators/timestamps. Worker queue depth remains summed across labeled worker samples.
After changing cached environment/configuration, rebuild the application's configuration cache and restart long-running FrankenPHP workers.
Laravel logs
The viewer only lists configured regular files beneath the application's canonical storage/logs directory. Paths are relative, file extensions are allowlisted, reads are tail-bounded, and traversal or symlink escapes are rejected. Content is escaped by Blade.
Caddy, Horizon, scheduler, Supervisor, and container stdout/stderr are not available through this viewer. Use your platform's logging backend for those streams.
Horizon
Horizon is optional and is never required by Composer. The page distinguishes installation, strict runtime enablement (HORIZON_ENABLED=true), and responsive master supervisors.
Controls are off by default. Set FRANKENDASH_HORIZON_CONTROLS=true and define the manage Gate to permit pause, continue, or graceful terminate actions. Every action is POST-only, CSRF-protected, throttled, requires typed confirmation, uses a fixed supported Horizon Artisan command, and writes an audit log. Frankendash never accesses Supervisor or executes user-controlled commands.
Security
Every dashboard, JSON, asset, log, Horizon status, and Horizon action route passes enabled and read-Gate middleware. Actions additionally pass the manage Gate. Sensitive responses use no-store, CSP, frame denial, and MIME-sniffing protection.
Please report vulnerabilities according to SECURITY.md. Do not expose the Caddy admin listener beyond loopback.
Development
After intentionally installing development dependencies:
composer validate --strict vendor/bin/phpunit
The test suite covers default-denied access, strict runtime resolution, Gate behavior, method safety, curated Prometheus parsing/cardinality, and bounded/traversal-safe log reads. Network and full Laravel/Horizon integration tests require a prepared application environment; package installation does not run them automatically.
License
MIT. See LICENSE.