›
byrcsc/laravel-customer-health · 1.x
Current health summaries can live beside score history or on a shared landlord connection.
A score computation writes append-only history and one current summary. Use the summary table for operational queries such as listing every at-risk customer.
The package identifies a summary by tenant ID, subject morph type, subject ID, and score name. Recomputing the same score updates that row while preserving every entry in the score history table.
$atRisk = CustomerHealth::inState(
state: 'at_risk',
score: 'customer_health',
)->get();
$all = CustomerHealth::summaries()->get();Both methods return an Eloquent builder for HealthSummary. You can add normal
query constraints before calling get(), paginate(), or another terminal
method.
Each summary exposes tenant_id, subject_type, subject_id, score,
value, state, and computed_at. subjectIdentity() returns a
MorphIdentity for explicit resolution.
The defaults are:
'connection' => null,
'summary_connection' => null,
'tenant_resolver' => NullTenantResolver::class,Both history and summaries use Laravel's current default connection. Summary rows have a null tenant ID.
Set connection to the tenant connection and summary_connection to the
landlord connection:
'connection' => 'tenant',
'summary_connection' => 'landlord',
'tenant_resolver' => App\Tenancy\CurrentTenantId::class,The resolver must be an invokable class implementing TenantResolver:
namespace App\Tenancy;
use ByRcsc\LaravelCustomerHealth\Contracts\TenantResolver;
final readonly class CurrentTenantId implements TenantResolver
{
public function __invoke(): int|string|null
{
return tenant()?->getKey();
}
}It may return an integer, non-empty string, or null. The package stores a
non-null value as a string. Invalid classes or return values throw
InvalidTenantResolverException.
Run the events, milestones, and scores migrations on each tenant connection. Run the summaries migration on the landlord connection.
The optional SpatieTenantResolver reads Tenant::current()?->getKey():
'tenant_resolver' =>
ByRcsc\LaravelCustomerHealth\Tenancy\SpatieTenantResolver::class,The package core does not depend on Spatie. The adapter returns null when
the Spatie tenant class is unavailable or no tenant is current.
When Spatie's queues are tenant-aware, queued product-event jobs contain only primitive identity data. Spatie can restore the dispatching tenant before the worker writes to the tenant connection.
When history and summaries share a connection, score history and summary updates occur in one transaction.
When they use different connections, there is no distributed transaction. The history transaction calls the summary connection during computation, and an exception prevents the history record from committing. An infrastructure failure after the landlord write but before the tenant commit can still leave a summary ahead of history.
Recomputing known subjects rebuilds missing or stale summaries from current signals.
$summary->subjectIdentity()->resolve() queries the model using its default
connection unless you pass a connection name:
$subject = $summary->subjectIdentity()->resolve('tenant');A landlord summary cannot infer which tenant database contains the model from
tenant_id. Switch tenant context or supply the correct connection before
resolving it.