Appearance
Site Health
The site's checks — database, cache, disk, PHP, queue, scheduler — on the schedule, with alerts to the site's admin.
kitloom/health · admins: kitloom/health-filament, kitloom/health-nova
Video lessons
Recorded in the Filament admin; the Nova admin works the same way.
Site Health for a kitloom site — WordPress's Tools → Site Health — on top of spatie/laravel-health. The page is kitloom/health-filament or kitloom/health-nova. Installing the package is enough: the checks, the schedule, the results table and the mail plug themselves in.
The checks
| Check (spatie name) | What it says | Registered |
|---|---|---|
Database connection (Database) | The default connection answers | always |
Cache (Cache) | A value written to the default store reads back | always |
Redis (Redis) | The default Redis connection answers a ping | when the cache, the queue or the session runs on Redis |
Disk space (UsedDiskSpace) | The disk of the storage folder: a warning above 80 % used, a failure above 90 % | always |
Writable folders (Writable) | storage/app, storage/framework/{cache,sessions,views}, storage/logs, bootstrap/cache and the root of the uploads disk (MEDIA_DISK, public) | always |
Uploads address (uploads_address) | Uploads kept off this server (a bucket, SFTP) have an address visitors can open: MEDIA_UPLOADS_URL or the disk's own. A warning when neither gives one — the pages would link to /wp-content/uploads on this site, where those files are not — or when MEDIA_DISK names no disk. A local disk is left to the web server | with kitloom/media |
Files kept between deploys (ephemeral_disk) | Nothing the site must keep is on this host's disk: uploads (MEDIA_DISK), a WXR waiting for its import (IMPORT_EXPORT_DISK), static page files (SITE_CACHE_STATIC), the cache and the sessions on file, an SQLite database. A warning that lists what is | on a host whose disk does not last (below) |
PHP version (PhpVersion) | Older than 8.3 fails, older than 8.4 warns | always |
Environment (Environment) | APP_ENV is the expected one (HEALTH_EXPECTED_ENVIRONMENT, production) | always |
Comments awaiting moderation (comments_awaiting_moderation) | Comments and product reviews still waiting for approval after 7 days: a warning with how many and the oldest one's date, a failure when more than 50 wait (checks.comments.days, fail_above). Order notes, spam and trash do not count. They are approved, spammed or trashed on the admin's Comments screen | always — the Comments screen is the admin's own, with or without kitloom/comments |
Email delivery (email_delivery) | kitloom/emails' log of the last 24 hours (checks.emails.hours): emails that failed while others went out are a warning, with how many and the server's last error; failures and nothing sent at all are a failure — order, booking and password emails reach nobody. On a live site, a mailer that writes the emails to the log (log, array) instead of sending them is a warning too | with kitloom/emails |
Debug mode (DebugMode) | APP_DEBUG is off | always; judged in production only |
Cached configuration and routes (OptimizedApp) | php artisan optimize ran | always; judged in production only |
Queue worker (Queue) | A heartbeat job on the default queue ran in the last 10 minutes | when the queue is not sync and the cache keeps values between processes |
Scheduler (Schedule) | The scheduler beat in the last 2 minutes | when the cache keeps values between processes |
Debug mode and the cached configuration are a developer's everyday setup, so they are judged in production only; the environment check is what catches a live site that says local. A developer's machine sets HEALTH_EXPECTED_ENVIRONMENT=local.
The checks keep spatie's names, and a check whose name is already registered is left out: an application that calls Health::checks([DatabaseCheck::new()->connectionName('reports')]) replaces the module's Database check, in whatever order the providers boot. kitloom-health.checks.register set to false leaves the list to the application.
Hosts without a lasting disk
Laravel Cloud and DigitalOcean App Platform reset the file system on every deploy, and each instance there — as each server of several — has its own. What works on one server breaks there: uploads on the server's disk, a WXR file the queue worker looks for on another instance, static page files. The ephemeral_disk check says what the site still keeps on such a disk.
It runs only where the disk is known not to last: on Laravel Cloud, recognised by itself (LARAVEL_CLOUD, which the platform sets and Laravel's laravel_cloud() reads), and wherever HEALTH_EPHEMERAL_DISK=true says so — App Platform, several servers behind a load balancer. HEALTH_EPHEMERAL_DISK=false turns it off on Laravel Cloud too. Nothing else is guessed: a Redis cache or a real queue says nothing about how many servers there are.
kitloom/backup adds its own check, BackupDestinations: a warning when backups are in use and "This server" is their only destination. kitloom/privacy adds privacy_exports_disk, asked only on such a host: a warning when the personal data archives (PRIVACY_EXPORTS_DISK) are on its disk. A module's check that matters only here asks SiteChecks::diskIsEphemeral() in its ->if().
Checks of other modules
spatie's registry is already the extension point: a module adds its checks from its own service provider, and the Site Health page shows them with the others — no kitloom contract or tag in between.
php
use Spatie\Health\Facades\Health;
public function boot(): void
{
Health::checks([
LocalCopyFreshCheck::new()->name('SentryLocalCopy')->label('Sentry: local copy of the settings'),
]);
}- The check extends
Spatie\Health\Checks\Checkand returns aResult:ok()with an empty message (spatie mails every result that has one) and ashortSummary(),warning(...)orfailed(...)with what is wrong. - Its name is unique — prefixed with the module: two checks of one name make spatie throw.
- The module requires
spatie/laravel-health(MIT) itself, not kitloom/health: the check runs withphp artisan health:checkwhether the Site Health module is installed or not. A module that needs no check to run may only suggest it and register the check whenclass_exists(\Spatie\Health\Health::class), as kitloom/backup does.
Results, schedule, mail
| What | How |
|---|---|
| Results | spatie's EloquentHealthResultStore: table health_check_result_history_items under the connection's prefix (wp_health_check_result_history_items), created by the module's migration unless spatie's own was published and ran |
| Schedule | health:check every five minutes (schedule.checks), the scheduler's and the queue's heartbeats every minute, model:prune of results older than spatie's keep_history_for_days (5) daily; the server runs php artisan schedule:run every minute. Each runs on one server of several, by a lock in the cache, so a site on several servers needs a shared cache store (Redis, the database) — with each server's own cache the lock is local and the task runs on every one |
| On demand | SiteHealth::run() — the page's "Run checks now": the same run, without the mail |
Failures and warnings of a scheduled run go to the site's Administration Email Address (option admin_email) — HEALTH_TO_ADDRESS still wins — at most once in spatie's throttle_notifications_for_minutes (60), counted in the default cache store | |
| Off switch | Option health_notify_admin (1/0, on by default), switched on the Site Health page |
The module replaces spatie's notifiable and notification only while they are spatie's defaults: a published config/health.php with its own keeps them.
AI agents
With kitloom/ai installed, an agent whose user has manage_options reads Site Health as the checks last found it (health_report) and runs them again (health_run) — it changes nothing on the site but the stored results, so a read-only key may run it. It also lists the queue's failed jobs (health_failed_jobs): the job's class, the queue and when it failed — never why, since a failure's message may carry an address or a key. kitloom-health.ai.register false — no health tools.
Configuration
php artisan vendor:publish --tag=kitloom-health-config for kitloom-health.php: the thresholds (disk space, PHP, heartbeats, comments awaiting moderation, the hours of email log read), the writable folders and disks, the expected environment, whether the host's disk lasts (checks.host.ephemeral), the schedule, the admin pages (filament.register, nova.register). spatie's own config/health.php (result stores, throttle, Slack, Oh Dear) works as documented by spatie.
Tests
From the application that installs the package: php vendor/bin/phpunit --testsuite Health.