Installs laravel/telescope ^5.0 (v5.12.5) as a dev-dependency.
Three-layer production safety adapted to Laravel 11 layout (no
Kernel.php; routing/schedule in bootstrap/app.php +
routes/console.php):
1. composer.json `extra.laravel.dont-discover` lists
laravel/telescope. After editing, `php artisan package:discover`
regenerates bootstrap/cache/packages.php — without this step
the auto-discovery cache still registers the vendor provider.
2. AppServiceProvider::register() gates registration to local +
testing environments. Registers BOTH the vendor
Laravel\Telescope\TelescopeServiceProvider (routes, migrations,
publishing) AND the project's App\Providers\TelescopeService
Provider (gate + filter) — they're sibling classes that extend
ServiceProvider independently, not parent/child, so both must
register for the dashboard to work. bootstrap/providers.php
deliberately does NOT list either Telescope provider.
3. .env TELESCOPE_ENABLED flag (false in .env.example). Runtime
toggle that disables Telescope even when the providers are
registered.
Production safety verified via simulated APP_ENV=production check:
confirms no Telescope-* providers are loaded.
Authorization: viewTelescope gate restricts dashboard to users
with the super_admin Spatie Permission role. Even in local
environments, only super_admin can view. Default was an email
allow-list stub — replaced with `$user->hasRole('super_admin')`.
Pruning: Schedule::command('telescope:prune --hours=48') added in
routes/console.php (Laravel 11's schedule location), environment-
gated to local + testing only.
Documentation: /dev-docs/TELESCOPE.md added; CLAUDE.md gets a
Development-tooling section. The doc explicitly calls out the
dual-provider registration (vendor + app) which differs from the
single-provider pattern in older Laravel versions.
Migrations applied: telescope_entries, telescope_entries_tags,
telescope_monitoring tables. Route registration verified in local
(42 telescope.* routes).
Tests: 1208/1208 passing — Telescope loads in the testing
environment as well, so the suite exercised it without issues.
Deployment note (flag for separate docs): a production operator
who runs `php artisan migrate` manually will still apply the
Telescope migrations — but because the providers never register
in production, the tables stay empty.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3.3 KiB
Laravel Telescope (dev-only)
Local debugging dashboard for queries, jobs, mails, redis, events, exceptions. Never registered in production.
Access
- Local URL: http://localhost:8000/telescope
- Auth requirement: authenticated user with
super_adminrole (Spatie Permission). TheviewTelescopegate is the access control; even inlocal, only super_admin can view.
Production safety — three-layer defense
Crewli runs Laravel 11 (no Kernel.php; routing/schedule live in
bootstrap/app.php + routes/console.php). The defense layers
adapted to that layout are:
composer.jsonextra.laravel.dont-discoverlistslaravel/telescope, so Laravel's auto-discovery never registers the vendorLaravel\Telescope\TelescopeServiceProvider. After editing this list, runphp artisan package:discoveronce to refreshbootstrap/cache/packages.php.AppServiceProvider::register()gates manual registration tolocal+testingonly, and registers BOTH the vendor provider (routes/migrations/publishing) and the project'sApp\Providers\TelescopeServiceProvider(gate + filter):if ($this->app->environment('local', 'testing')) { $this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class); $this->app->register(\App\Providers\TelescopeServiceProvider::class); }bootstrap/providers.phpdeliberately does NOT list either Telescope provider — both registrations live behind this environment gate..envTELESCOPE_ENABLEDflag.falsein.env.example. Runtime toggle that disables Telescope even when the providers are registered (e.g. to silence Telescope locally during a profiling session).
If you ever see Telescope on production: revert immediately, audit the three layers above, and treat as a security incident. The dashboard exposes every query, payload, and job — including secrets in payloads.
Verifying production safety
APP_ENV=production php -r "
require 'vendor/autoload.php';
\$app = require 'bootstrap/app.php';
\$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
foreach (array_keys(\$app->getLoadedProviders()) as \$p) {
if (stripos(\$p, 'telescope') !== false) echo 'LOADED: ' . \$p . PHP_EOL;
}
"
Expected output: nothing. Any line means a layer is breached.
Pruning
Scheduled in routes/console.php (Laravel 11 layout):
Schedule::command('telescope:prune --hours=48')
->daily()
->environments(['local', 'testing']);
48-hour retention. Adjust if dev DB is filling up.
What Telescope captures
- All Eloquent queries with bindings + execution time (N+1 detection)
- Background jobs with payload + status + retry history
- Sent mails with rendered HTML + plaintext + recipient
- Redis commands
- Cache reads/writes
- Events fired with listeners
- Exceptions with stack traces
- HTTP requests with headers + payload
What NOT to use Telescope for
- Production debugging — never enabled there
- Long-term audit trails — Spatie ActivityLog handles that (see ARCH-FORM-BUILDER §17.1)
- Performance benchmarking — use APM tools designed for it
Disabling temporarily
If Telescope is slowing down a specific dev workflow:
TELESCOPE_ENABLED=false php artisan serve
Or set globally in .env and restart your server. Re-enable when
done.