›
byrcsc/laravel-customer-health · 1.x
Product event declarations turn verified business activity into queryable customer history.
A product event is an application-level fact such as creating a workflow, inviting a teammate, or completing an export. Reach for it after the business operation succeeds and the event can be attributed to a customer subject.
Every event extends ProductEvent and declares a feature:
namespace App\CustomerHealth\Events;
use ByRcsc\LaravelCustomerHealth\Events\ProductEvent;
final class ExportCompleted extends ProductEvent
{
public static string $feature = 'exports';
}The default event name is the snake-cased class basename, so this class records
export_completed. Set a stable name when a class rename must not change
stored event identity:
public static string $name = 'report_exported';Every event class must appear in customer-health.events. Names must be unique
across the registry.
The subject is the customer entity whose health changes. It must be a
persisted Eloquent model implementing Trackable.
The actor is optional. When present, it must be a persisted Eloquent model that
also implements Laravel's Authenticatable contract:
CustomerHealth::track(new ExportCompleted(
subject: $team,
actor: $user,
));The package stores the subject and actor as Laravel polymorphic type and ID pairs. Integer and string keys are accepted. Unsaved models are rejected.
Properties carry event-specific context:
CustomerHealth::track(new ExportCompleted(
subject: $team,
actor: $user,
properties: [
'format' => 'csv',
'filters' => [
'status' => 'active',
'include_archived' => false,
],
],
));Values may be strings, integers, floats, booleans, null, or nested arrays of
those values. Objects are rejected with InvalidEventPropertiesException
before an inline write or queued dispatch occurs.
The constructor accepts an optional DateTimeInterface:
CustomerHealth::track(new ExportCompleted(
subject: $team,
occurredAt: $importedTimestamp,
));Omit it for the current time. The package normalizes the value to UTC and
hydrates it as CarbonImmutable.
Tracking writes a ProductEventRecord with subject_type, subject_id,
optional actor identity, name, feature, properties, and occurred_at.
The TracksCustomerHealth concern exposes the raw history:
$events = $team->productEvents()
->latest('occurred_at')
->get();After the package write transaction returns, it dispatches
ProductEventRecorded. Its public $record property contains the stored
model. An outer application transaction can still be open at that point; see
Events for dispatch timing.
Raw events are append-only from the package's public write path. Calling
track() twice records two rows, even when every field matches.
If the event is a milestone, only its first occurrence creates a milestone. This is enforced by a unique database index, including during concurrent writes.