›
byrcsc/laravel-customer-health · 1.x
Track onboarding activity and compute an explainable health score for one customer.
This tutorial records two customer milestones, reads onboarding progress, and computes a health score. Start after publishing and running the package migrations.
Use a model that represents the customer whose health you want to measure:
namespace App\Models;
use ByRcsc\LaravelCustomerHealth\Concerns\TracksCustomerHealth;
use ByRcsc\LaravelCustomerHealth\Contracts\Trackable;
use Illuminate\Database\Eloquent\Model;
final class Team extends Model implements Trackable
{
use TracksCustomerHealth;
}The model must already exist in the database when you track an event.
Imagine Acme is onboarding. Taylor creates the team's first workflow, then invites Morgan to collaborate. These are business events your application already knows happened. The package records them as evidence of Acme's progress.
Create one event class for each action:
namespace App\CustomerHealth\Events;
use ByRcsc\LaravelCustomerHealth\Events\ProductEvent;
final class WorkflowCreated extends ProductEvent
{
// Group this event with other workflow activity.
public static string $feature = 'workflows';
// Preserve the first workflow as a lasting sign of adoption.
public static bool $milestone = true;
}namespace App\CustomerHealth\Events;
use ByRcsc\LaravelCustomerHealth\Events\ProductEvent;
final class TeammateInvited extends ProductEvent
{
// Group this event with other team activity.
public static string $feature = 'team';
// Preserve the first invitation as a lasting onboarding step.
public static bool $milestone = true;
}WorkflowCreated names what happened. Its $feature value groups the event
with other workflow activity. Setting $milestone to true preserves the
first occurrence, even after older raw events are pruned.
The first workflow shows that Acme tried a core feature. The first invitation shows that its account has started expanding beyond one person. Later workflows and invitations remain raw product events, but they do not create duplicate milestones.
Put the milestone events in their required order:
namespace App\CustomerHealth;
use App\CustomerHealth\Events\TeammateInvited;
use App\CustomerHealth\Events\WorkflowCreated;
use ByRcsc\LaravelCustomerHealth\Onboarding\Checklist;
final class Onboarding extends Checklist
{
public function steps(): array
{
return [
WorkflowCreated::class,
TeammateInvited::class,
];
}
}Combine recent activity, feature adoption, and onboarding progress:
namespace App\CustomerHealth;
use ByRcsc\LaravelCustomerHealth\Scoring\HealthScore;
use ByRcsc\LaravelCustomerHealth\Scoring\Signals\FeatureAdopted;
use ByRcsc\LaravelCustomerHealth\Scoring\Signals\OnboardingProgress;
use ByRcsc\LaravelCustomerHealth\Scoring\Signals\RecentActivity;
final class CustomerHealthScore extends HealthScore
{
public function signals(): array
{
return [
new RecentActivity(days: 30, weight: 2),
new FeatureAdopted(feature: 'workflows', weight: 1),
new OnboardingProgress(checklist: Onboarding::class, weight: 1),
];
}
public function states(): array
{
return [
'at_risk' => 0,
'needs_attention' => 50,
'healthy' => 75,
];
}
}Weights are relative. In this definition, recent activity contributes half of the final value and each remaining signal contributes one quarter.
Add the classes to config/customer-health.php:
'events' => [
App\CustomerHealth\Events\WorkflowCreated::class,
App\CustomerHealth\Events\TeammateInvited::class,
],
'checklists' => [
App\CustomerHealth\Onboarding::class,
],
'scores' => [
App\CustomerHealth\CustomerHealthScore::class,
],Track the event after the business operation succeeds:
use App\CustomerHealth\Events\WorkflowCreated;
use ByRcsc\LaravelCustomerHealth\Facades\CustomerHealth;
CustomerHealth::track(new WorkflowCreated(
subject: $team,
actor: $request->user(),
properties: ['template' => 'approval'],
));The properties array may contain JSON primitives and nested arrays. It cannot contain models, date objects, enums, or other objects.
$progress = CustomerHealth::onboarding($team);
$progress->completedSteps(); // 1
$progress->totalSteps(); // 2
$progress->percent(); // 50
$progress->currentStep(); // TeammateInvited::class
$result = CustomerHealth::compute($team);
$result->value; // 88
$result->state; // "healthy"
$result->breakdown; // one entry per signalThe value is 88: recent activity contributes 50, workflow adoption
contributes 25, and 50 percent onboarding progress contributes 12.5 before the
total is rounded.
Each call to compute() appends a score record and updates the current
summary. Use score() to read the newest stored result without recomputing it.