Skip to content

Deployment Tracking

Record CI/CD deployments via webhook and visualize deployment history in the Laravel Pulse dashboard.

The deployment tracking system provides:

  • Webhook endpoint for CI/CD pipelines to record deployments
  • Bearer token authentication for secure webhook access
  • Pulse dashboard card showing deployment history
  • Environment-aware display with color-coded badges
GitHub Actions --> POST /api/deployments --> DeploymentController
|
v
DeploymentCompleted (Event)
|
v
DeploymentsRecorder (Pulse)
|
v
Pulse Dashboard Card

Record a deployment.

Authentication: Bearer token via Authorization header

Rate limit: 10 requests per minute

Request:

{
"environment": "production",
"version": "v1.2.3",
"commit": "abc123def456",
"build_date": "2025-01-15T10:30:00Z",
"build_id": "12345"
}
FieldTypeRequiredConstraints
environmentstringYesMax 50 chars
versionstringYesMax 100 chars
commitstringYesMax 40 chars (SHA)
build_datestringYesISO 8601 date
build_idstringNoMax 50 chars

Response (201 Created):

{
"status": "recorded"
}

Error Responses:

StatusDescription
401 UnauthorizedInvalid or missing bearer token
422 Unprocessable EntityValidation failed
429 Too Many RequestsRate limit exceeded
500 Internal Server ErrorToken not configured on server

Source: backend/app/Http/Controllers/Api/DeploymentController.php

Terminal window
# Required: Secret token for webhook authentication
DEPLOYMENT_API_TOKEN=your-secure-random-token

Generate a secure token:

Terminal window
openssl rand -hex 32

services.php:

config/services.php
'deployment' => [
'token' => env('DEPLOYMENT_API_TOKEN'),
],

pulse.php:

config/pulse.php
'recorders' => [
\App\Pulse\Recorders\DeploymentsRecorder::class => [],
// ... other recorders
],

The Deployments card displays:

  • Environment (color-coded badge)
  • Version and commit SHA
  • Relative timestamp
  • Deployment count
EnvironmentColor
productionGreen
stagingYellow
OtherBlue

Navigate to /pulse (requires authentication).

The card:

  • Shows last 20 deployments
  • Polls for updates every 5 seconds
  • Respects selected time period filter

Source: backend/app/Livewire/Pulse/Deployments.php

.github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [master]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# ... deployment steps ...
- name: Record deployment
if: success()
run: |
curl -X POST "${{ secrets.API_URL }}/api/deployments" \
-H "Authorization: Bearer ${{ secrets.DEPLOYMENT_API_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{
"environment": "production",
"version": "${{ github.ref_name }}",
"commit": "${{ github.sha }}",
"build_date": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
"build_id": "${{ github.run_id }}"
}'
SecretDescription
API_URLBase URL (e.g., https://api.volare.com)
DEPLOYMENT_API_TOKENSame token as DEPLOYMENT_API_TOKEN env var

The middleware uses timing-safe comparison to prevent timing attacks:

// ValidateDeploymentToken middleware
if (!hash_equals($expectedToken, $token)) {
return new JsonResponse(['error' => 'Unauthorized'], 401);
}
  • Use a strong, random token (32+ characters)
  • Rotate tokens periodically
  • Store tokens in secret managers (GitHub Secrets, AWS Secrets Manager)
  • Never commit tokens to version control
  • Monitor for failed authentication attempts
  1. Verify token matches between CI/CD and server
  2. Check Authorization: Bearer <token> header format
  3. Ensure no whitespace in token
  1. Check DEPLOYMENT_API_TOKEN is set in .env
  2. Run php artisan config:clear
  3. Verify config/services.php includes deployment config
  1. Check Pulse is enabled: PULSE_ENABLED=true
  2. Verify recorder is registered in config/pulse.php
  3. Check database for pulse_entries table
  4. Clear Pulse cache: php artisan pulse:clear
  • Health Monitoring - Application health and Pulse overview
  • Source: backend/app/Pulse/Recorders/DeploymentsRecorder.php
  • Source: backend/app/Http/Middleware/ValidateDeploymentToken.php