Upgrade Guide
This document covers upgrades to the current v1.12.0 release. The later sections retain migration notes for older installations.
Upgrade from v1.11.0 to v1.12.0
No database migrations are required, and no routes, Gates or config keys changed. Existing configuration keeps working.
Update the package:
bashcomposer update ashraftalha/laravel-opconsole php artisan config:clearPublished assets or views: the Run migrations card changed (full-width list with a Run only this button per pending migration), and the stylesheet changed. Republish assets with
php artisan vendor:publish --tag=opconsole-assets --force. If you customised views, merge the changes from the package'sresources/views/index.blade.php.Permissions to review: anyone allowed to run
migratecan now apply a single pending migration, including one ahead of earlier pending files. The confirmation warns about this. The same Gate applies as before (migrateinauthorization.action_gates, or the run Gate).
Upgrade from v1.10.0 to v1.11.0
No database migrations are required, and no routes, Gates or existing config keys changed. Existing configuration keeps working.
Update the package:
bashcomposer update ashraftalha/laravel-opconsole php artisan config:clearPublished assets or views: the views gained a Failed jobs tab and an Octane section, and the stylesheet and script changed. Republish assets with
php artisan vendor:publish --tag=opconsole-assets --force. If you customised views, merge the changes from the package'sresources/views/index.blade.php.New optional config keys (published configs without them keep the defaults):
failed_jobs.enabled(OPCONSOLE_FAILED_JOBS, defaulttrue),failed_jobs.limit(OPCONSOLE_FAILED_JOBS_LIMIT,50),failed_jobs.allow_retry(OPCONSOLE_FAILED_JOBS_RETRY,true).octane.checks(OPCONSOLE_OCTANE_CHECKS,auto),octane.expected_in_production(OPCONSOLE_OCTANE_EXPECTED,false),octane.allow_actions_in_swoole(OPCONSOLE_OCTANE_ALLOW_ACTIONS,false).actions.octane_reload(OPCONSOLE_ACTION_OCTANE_RELOAD,true; only shown when Octane is installed).
Permissions to review:
- Anyone with the run Gate can now retry a failed job, which re-runs it with its original payload. To restrict that, map
queue_retryto its own Gate inauthorization.action_gates, or setOPCONSOLE_FAILED_JOBS_RETRY=false. - The Failed jobs tab is visible to anyone with the view Gate. It shows job class names, queues and the first line of each exception (sanitised), never payloads. Set
OPCONSOLE_FAILED_JOBS=falseto hide it.
- Anyone with the run Gate can now retry a failed job, which re-runs it with its original payload. To restrict that, map
Behaviour you may notice:
- If you serve the console with Laravel Octane on Swoole, timed operations (clear caches, optimize, migrate, maintenance on/off, storage link) are now refused from the browser, because their timeout signal would interrupt the Swoole worker itself. Run them from the CLI, or set
OPCONSOLE_OCTANE_ALLOW_ACTIONS=trueto accept that risk. The security scan and Octane reload still run. RoadRunner, FrankenPHP and PHP-FPM are unaffected. - The Health and History tabs no longer open empty when every check is healthy.
- If you serve the console with Laravel Octane on Swoole, timed operations (clear caches, optimize, migrate, maintenance on/off, storage link) are now refused from the browser, because their timeout signal would interrupt the Swoole worker itself. Run them from the CLI, or set
Upgrade from v1.9.0 to v1.10.0
No database migrations are required, and no routes, Gates, form actions or CSRF behaviour changed. Existing configuration keeps working.
Update the package:
bashcomposer update ashraftalha/laravel-opconsole php artisan config:clearPublished assets: the dashboard was redesigned around the OpConsole logo (new colours, health score, command palette, log timeline). If you published assets, republish them:
bashphp artisan vendor:publish --tag=opconsole-assets --forceThe package now also serves
opconsole.svg(the favicon). Republishing copies it topublic/vendor/opconsole/.Published views:
index.blade.phpwas rewritten and new partials were added (logo,segbar,fonts). If you customised views, diffresources/views/vendor/opconsoleagainst the package and merge the changes, or republish with--tag=opconsole-views --force. A customised view keeps the old markup and will look broken with the new stylesheet.Renamed CSS classes (only if you wrote CSS against them or kept old published views):
Before After oc-btn-soft-primaryoc-btn-accentoc-btn-soft-successoc-btn-successoc-btn-soft-warningoc-btn-warningoc-btn-soft-secondaryoc-btn-secondaryoc-card-bodyoc-card-contentNew optional key:
web_fonts(OPCONSOLE_WEB_FONTS, defaultfalse) loads IBM Plex from Google Fonts. Leave it off to keep the console free of external requests. If you turn it on, allowfonts.googleapis.com(style-src) andfonts.gstatic.com(font-src) in your Content-Security-Policy.Behaviour you may notice:
- Health filter chips update
?check_status=in place instead of reloading the page. - Security advisories now keep the full affected version range. Earlier scans stored a truncated range such as
>=12.0.0,. Runphp artisan opconsole:securityonce to refresh stored results. LogViewer::read()returns an additionaltimelinekey. Existing keys are unchanged.
- Health filter chips update
Upgrade from v1.8.0 to v1.9.0
No database migrations are required, and existing configuration keeps working.
- Composer metadata: the package now requires
laravel/frameworkinstead of individualilluminate/*components, because it uses classes that only ship in the framework (Illuminate\Foundation). Every working installation already has it, so no action is needed. - New optional key:
audit.policy(OPCONSOLE_AUDIT_POLICY, defaultbest_effort, the current behaviour). Set it torequiredto refuse actions, log deletes, and log downloads that cannot be audited first. Published configs without the key keep the default. - Dashboard redesign:
public/opconsole.css,public/opconsole.js, and the Blade views were restyled (new design tokens, tactile buttons, hold-to-confirm for high-risk actions, new summary tiles, a restructured Security tab). No routes, Gates, form actions, or CSRF behaviour changed.- If you published assets (
--tag=opconsole-assets), republish them with--forceto pick up the new styles and script:php artisan vendor:publish --tag=opconsole-assets --force. - If you published or customized views (
--tag=opconsole-views), diffresources/views/vendor/opconsoleagainst the package'sresources/viewsand merge the changes you want; a customized view otherwise keeps rendering with the old markup and the new stylesheet, which will look inconsistent. - High-risk confirmations (currently only
migrate) now require a press-and-hold or a second press instead of a single click; this is client-side only and has no server-side effect to account for.
- If you published assets (
- Behaviour you may notice:
- On a PHP runtime without
pcntl(common for PHP-FPM), every action was already refused, but only after the request had taken the lock and written astartedrow. Those actions are now disabled on the dashboard with the reason shown, andsecurity_scan(bounded by its own subprocess timeouts) now runs. Run the others from the CLI, or enablepcntlfor the web SAPI. - On Laravel < 12.63 / < 13.16, actions running longer than 10 seconds (for example migrations) were interrupted by a failed lease renewal. They now run to completion within
max_runtime_seconds. - A required
custom.*health check that throws now makes the reportcritical; previously it was silently omitted. - With an empty
route.prefix, maintenance mode now applies to the console too, instead of the whole application ignoring maintenance mode. - Deleting a log symlink removes the link, not its target.
- Notification failures no longer log transport messages (which could contain webhook URLs).
- On a PHP runtime without
Upgrade from v1.7.x to v1.8.0
Laravel 12 and 13 and PHP ^8.3 remain supported. The release adds an on-demand security scan action and redesigns the Logs tab. No database migrations are required.
Update the package:
bashcomposer update ashraftalha/laravel-opconsoleIf you publish
config/opconsole.php, add the newactions.security_scankey (defaulttrue;OPCONSOLE_ACTION_SECURITY_SCAN). It runsphp artisan opconsole:securityread-only from the Operations tab; set it tofalseto hide the button.If you publish or customize package views, merge the Logs tab and System information markup changes in
resources/views/index.blade.php, and the corresponding styles inpublic/opconsole.css(php artisan vendor:publish --tag=opconsole-assets --forceif you have not customized them).Clear and rebuild optimized caches:
bashphp artisan optimize:clear php artisan config:cache php artisan route:cache php artisan view:cache
See Configuration Reference for the actions.security_scan option.
Upgrade from v1.7.0 to v1.7.1
This patch fixes the blank System information tab, duplicate standalone page title, and extra spaces in dashboard values. No configuration changes or database migrations are required.
composer update ashraftalha/laravel-opconsole
php artisan view:clearIf package views were published or customized, merge the changes in resources/views/index.blade.php and resources/views/layout.blade.php into those copies. Older published configurations still need the keys described in the migration notes below; installing this patch does not overwrite host configuration.
Upgrade from v1.6.x to v1.7.0
Laravel 12 and 13 and PHP ^8.3 remain supported. The release adds an optional host Composer dependency security audit (opconsole:security) and a dashboard Security tab. No database migrations are required.
Update the package:
bashcomposer update ashraftalha/laravel-opconsoleIf you publish
config/opconsole.php, merge the newsecuritykey (composer,timeout,max_age_seconds,include_dev,store,schedule,trusted_proxy_https,risky_actions). The audit stays disabled until you runphp artisan opconsole:security; scheduling stays off until you setOPCONSOLE_SECURITY_SCHEDULE=true.Run an initial scan so the Security tab has a report instead of showing an unverified state:
bashphp artisan opconsole:securityClear and rebuild optimized caches after updating package routes, views, or config:
bashphp artisan optimize:clear php artisan config:cache php artisan route:cache php artisan view:cacheIf package assets were published, refresh them with
php artisan vendor:publish --tag=opconsole-assets --force.
See Configuration Reference for all security.* options and Security for scan scope, advisory network requests, exit codes, and remediation guidance.
Upgrade from v1.5.x to v1.6.0
Laravel 12 and 13 and PHP ^8.3 remain supported. The release adds per-action authorization, bounded owner-renewed action locks, configurable health status policy, connection-aware database checks, and optional health transition notifications.
Update the package and apply its new audit duration migration:
bashcomposer update ashraftalha/laravel-opconsole php artisan migrate --forceIf you publish
config/opconsole.php, merge the new keys from the package config:authorization.action_gates,concurrency.max_runtime_seconds,health.required_checks,health.unknown_policy, andnotifications. Keep the default lock store isolated (opconsole). Notifications stay disabled until explicitly enabled and scheduled.Review any custom database, session, or queue table connections. Health checks now inspect the connection and table configured by each service.
Clear and rebuild optimized caches after updating package routes, views, or config:
bashphp artisan optimize:clear php artisan config:cache php artisan route:cache php artisan view:cacheIf package assets were published, refresh them with
php artisan vendor:publish --tag=opconsole-assets --force.
For action-specific permissions, map action keys to host-defined Gates in authorization.action_gates. For alerts, configure notifications.channels and a persistent shared notifications.state_store, then schedule php artisan opconsole:health --notify. See Configuration Reference for all options and behavior.
Summary of Compatibility
- Supported PHP:
^8.3(unchanged) - Supported Laravel:
^12.0 | ^13.0(unchanged) - Database Schema (
opconsole_runs): Unchanged — no new database migrations are required. - Existing 2-Gate Setups (
viewOpConsole,runOpConsoleActions): 100% backward-compatible. Even if you keep an older publishedconfig/opconsole.phpwithoutdownload_gateanddelete_gate, OpConsole automatically defaultsdownload_gatetodownloadOpConsoleLogs(delegating to yourview_gate) anddelete_gatetodeleteOpConsoleLogs(delegating to yourrun_gate).
Reliability, action permissions, and notifications
- Copy the new
concurrency.max_runtime_seconds,health, andnotificationskeys into published configurations. Existing unknown statuses remain non-failing unless required orunknown_policyis changed. - Existing
run_gateremains the permission fallback for every action. Add only theauthorization.action_gatesentries you want to separate. Explicit mappings must name a Gate defined by the host. - Notifications remain disabled by default. Schedule
opconsole:health --notifyonly after configuring channels and a persistent sharedstate_store. - The runtime timeout uses PHP's
pcntlalarm support. When it is unavailable, maintenance actions fail closed rather than running without a bounded lease. This matters on some Windows and restricted shared-hosting setups. - Cache/database/queue checks now inspect each configured service connection. If those services use separate databases, ensure the configured tables exist on those connections.
Notable Behavioral Changes
1. Action Lock Store Defaults to Isolated 'opconsole' Store (Fail-Closed)
Previously, config('opconsole.concurrency.lock_store') defaulted to 'file'. On applications where CACHE_STORE=file (Laravel's file cache driver uses storage/framework/cache/data for both cache items and lock files), running optimize:clear (cache:clear) deleted active lock files mid-run.
What changed:
OpConsoleServiceProvidernow auto-registers an isolated file cache store named'opconsole'atstorage/framework/cache/opconsole.opconsole.concurrency.lock_storenow defaults to'opconsole'.ActionRunnervalidates the lock store fail-closed: iflock_storeis missing, does not implement atomic locks (null), usesarrayoutside unit tests, or shares storage withcache.defaultwithout separate lock storage (ActionRunner::hasSeparateLockStorage()across Laravel 12 and Laravel 13), actions refuse to execute rather than silently falling back toCache::lock().
Action required if you published config/opconsole.php: Update 'lock_store' in your published config/opconsole.php (or .env):
'concurrency' => [
'lock_store' => env('OPCONSOLE_LOCK_STORE', 'opconsole'),
'lock_seconds' => (int) env('OPCONSOLE_LOCK_SECONDS', 1800),
'max_runtime_seconds' => (int) env('OPCONSOLE_MAX_RUNTIME_SECONDS', 1500),
],The timeout requires PHP pcntl signal support. Lock leases are renewed during execution, and the audit view classifies runs as abandoned only after twice the effective lease window.
(Multi-server applications using Redis or database locks should point OPCONSOLE_LOCK_STORE to an isolated Redis or database store where hasSeparateLockStore() is true.)
2. Self-Contained Assets (Legacy assets.* CDN Keys Removed)
Previously, config/opconsole.php included an 'assets' array (use_cdn, bootstrap_css, bootstrap_js, icons_css) that loaded Bootstrap 5 CSS/JS and Iconscout Unicons from cdn.jsdelivr.net.
What changed:
public/opconsole.css,public/opconsole.js, and inline SVG icons (opconsole::partials.icon) are completely self-contained, dependency-free, scoped underoc-*classes, and strict-CSP compatible (zero inline<script>tags or inlinestyle=attributes).- The obsolete
assets.*CDN configuration keys and CDN<link>/<script>loaders have been removed. If an older publishedconfig/opconsole.phpstill contains'assets', those unused keys are harmlessly ignored and can be deleted. - An authenticated fallback asset route (
GET /admin/opconsole/assets/opconsole.{css,js}, namedopconsole.asset) serves the package CSS/JS automatically ifpublic/vendor/opconsole/has not been published yet.
Action required: Republish package assets on upgrade so public/vendor/opconsole/opconsole.{css,js} receives the self-contained stylesheet and dialog script:
php artisan vendor:publish --tag=opconsole-assets --force
php artisan view:clear3. Granular 4-Gate Authorization (view, run, download, delete)
config/opconsole.php now supports four distinct Gate keys:
'authorization' => [
'view_gate' => 'viewOpConsole',
'run_gate' => 'runOpConsoleActions',
'download_gate' => 'downloadOpConsoleLogs',
'delete_gate' => 'deleteOpConsoleLogs',
],- If you do not define
downloadOpConsoleLogsordeleteOpConsoleLogsyourself,downloadOpConsoleLogsdelegates to yourview_gateanddeleteOpConsoleLogsdelegates to yourrun_gate, preserving v0.1.0 behavior. - If you define
downloadOpConsoleLogsordeleteOpConsoleLogsinAppServiceProvider, your custom policy takes precedence in all environments. - Note: if you configure a custom gate name (for example
'view_gate' => 'canAccessOps'), you must define that Gate; custom undefined gate names now fail closed (403) even inlocal.
4. Mandatory web Middleware Preservation
routes/web.php now guarantees 'web' remains active even if config('opconsole.route.middleware') is overridden with custom middleware (such as ['verified']), preventing accidental removal of session state and CSRF protection. Keep 'middleware' => ['web'] (do not add 'auth').
5. Custom HealthCheck Contract Enhancements (Backward-Compatible)
AshrafTalha\OpConsole\Contracts\HealthCheck::run() continues to accept the existing 7-key array (group, label, ok, severity, hint, value, fix) and now optionally accepts:
'id'(non-empty-string): stable identifier (prefixed automatically ascustom.<slug>).'status'('healthy' | 'warning' | 'critical' | 'unknown'): explicit 4-state status when a check cannot be verified (for example, an unprobed external service).
Existing custom checks require no code changes. Note that duplicate custom check classes in config('opconsole.checks') and custom checks attempting to overwrite a built-in (group, label) pair are now skipped with a warning log.
Upgrade Commands
composer update ashraftalha/laravel-opconsole
php artisan vendor:publish --tag=opconsole-assets --force
php artisan optimize:clear