Monitoring & alerts
What to watch on a live install, where each signal lives, and which signal maps to which runbook — health endpoint, Meta, WhatsApp, billing and the scheduler.
Monitoring & alerts
Zodiac Tech CRM is deliberately pragmatic about monitoring: there is one public health endpoint you can point any uptime monitor at, plus in-app health surfaces that already do the deeper checking for you. This page is the map — every built-in signal, where it lives, and which runbook to open when it fires.
Who this is for
- The person who owns uptime for a live install.
- Developers wiring an external monitor or an on-call rota.
Difficulty: Easy · Time: 15 minutes to read and wire up · Prerequisites: Super Admin access; access to whatever uptime-monitoring tool you use.
The one endpoint to monitor externally
GET {your app URL}/api/v1/health is public and designed for monitors:
- HTTP 200 with
status: ok— web app up, and thedb,cacheandstoragechecks passed. - HTTP 503 with
status: degraded— one of those checks failed; the payload'schecksobject shows which.
Alert on non-200 and on the literal string "status":"degraded". Also monitor the login page itself (/admin) — a monitor should prove the app renders, not just that PHP answers. Suggested cadence: every 1–5 minutes for the health URL, every 5–15 minutes for the login page.
The in-app signal table
| Signal | Where it lives | Healthy looks like | When it fires, go to |
|---|---|---|---|
| System health, disk, queue driver, debug mode | Super Admin → Settings → System Health (/super-admin/settings/system-health) |
Queue driver not sync, debug off, disk headroom |
Incident response |
| Meta connection problems | leadhub:meta-health (every 6 h) + Super Admin → Meta Ads → Needs Attention (/super-admin/meta-ads/needs-attention) |
All connections healthy; no open CRITICAL issues |
Meta won't connect |
| Meta connection statuses | Health report + connection record | healthy (or expiring as an early warning only) |
Meta won't connect |
| WhatsApp connection, templates, message volume | System Health → WhatsApp card | Connections connected, templates approved, queue_failures 0 |
WhatsApp not sending |
| Inbound webhook rejects | Admin → Webhook Logs (/admin/webhook-logs) |
All rows accepted |
Leads not entering the CRM |
| Lead source health | Admin → Lead Source Health Report (/admin/lead-source-health-report) |
Every connection healthy or explainably paused | Meta won't connect |
| Payment failures and lifecycle states | Super Admin → Billing → Commercial (/super-admin/billing/commercial) |
payment_failures, grace_period, restricted, suspended cards all quiet |
Payments failing |
| Provider reconciliation drift | Billing overview → "Needs Attention" (BillingReconciliationAlert) |
No open alerts | Payments failing |
| Failed jobs / queue health | System Health + php artisan queue:failed |
Empty failed list, worker running | Incident response |
| Scheduler health | storage/logs/laravel.log for schedule task failed: {name} |
No such lines | Daily checks |
| App errors | storage/logs/laravel.log (stack → single) |
No repeating ERROR families | Deployment & server errors |
The log lines worth grepping Grep the log for these exact keys to catch the failures the app already reports: healthcheck.db.failed, healthcheck.cache.failed, healthcheck.storage.failed, schedule task failed, [leadhub:meta-health] unhealthy Meta connections detected, Webhook: unknown token.
What has no built-in alerting
Be honest about the gaps, and cover them with habit or an external probe:
- Email/SMS delivery failures — queue failures and provider errors are logged but there is no dedicated alert. The 5-minute IMAP checks and the hourly digest exist, but a hard email outage surfaces through support tickets first.
- Push notification (FCM) delivery — device-side states are on the phone's Device Health screen; the platform does not alert on FCM failures. Use
php artisan leadhub:test-push {email}when verifying. - Individual scheduled task pauses — there is no per-task toggle. If you need to pause something, you stop the cron/worker (see Incident response); note it in your pager or you will forget it is off.
Suggested monitoring setup
- Uptime monitor →
GET /api/v1/health, alert on non-200. - Uptime monitor →
/adminlogin page, alert on non-200 or missing marker text. - Daily check habit or script →
schedule task failedandhealthcheck.greps in the log (see Daily checks). - Weekly human pass → Webhook Logs, Needs Attention, billing cards (see Weekly & monthly reviews).
- External check → does the message queue drain? Insert a controlled test lead and watch it reach the CRM on a schedule you choose; alert if it stops.
Expected result
A monitor that would page you within minutes of the app going down, and a human process that would notice within a day if anything subtler (Meta, WhatsApp, webhooks, payments) drifted.
Common mistakes
| Mistake | Why it hurts | Do this instead |
|---|---|---|
| Monitoring only the homepage | The homepage may render while the DB check fails | Use /api/v1/health and read status |
Treating expiring as fine |
It silently becomes expired and leads stop |
Reconnect while it is still expiring |
| No external monitor | "The team would notice" is a monitoring plan with a gap | Wire the health URL today |
| Ignoring Needs Attention badges | They exist because nav pages are rarely visited | Clear them weekly, at minimum |
Technical details
- The health endpoint lives in
App\Http\Controllers\Api\HealthController; failure paths loghealthcheck.db.failed,healthcheck.cache.failed,healthcheck.storage.failed. - Scheduled failures are logged by the scheduler wrapper as
Log::error("schedule task failed: {$name}"). leadhub:meta-health(every 6 hours) writes the warning log line quoted above; per-connection statuses come fromMetaConnectionHealthService.- Webhook rejects are stored as
WebhookLogrows and are the fastest per-lead diagnostic in the app. - The billing reconciliation cadence is 30 minutes; alerts appear in the billing overview's "Needs Attention" list and are not emailed.
Related guides
Was this page helpful?
Thanks — noted. ✦