Concepts

Context-aware preferences

Attach preferences to an organization, project, team, or another application scope.

Pass a context when changing or inspecting a preference:

app/Services/NotificationPreferences.php
$context = new NotificationContext('team', $team->getKey());

$user->notificationPreferences()->for('incident.created', $context)->disable('mail');

For delivery checks, implement notificationContext on the notification when the convention is sufficient:

app/Notifications/IncidentCreatedNotification.php
public function notificationContext(object $notifiable): ?NotificationContext
{
    return new NotificationContext('team', $this->team->getKey());
}

The default ConventionNotificationContextResolver validates that the method returns a NotificationContext or null. Bind NotificationContextResolver to your own implementation when context discovery needs application-specific rules.

Context contract

NotificationContext uses a stable lowercase type format. Types start with a letter and may contain lowercase letters, numbers, dots, hyphens, and underscores in separated segments, such as organization, workspace.project, or notification-team.

Identifiers may be non-negative integers or opaque strings containing letters, numbers, dots, hyphens, underscores, and tildes. Numeric strings are canonicalized, so community:1 and community:01 produce the same canonicalKey() and key() value: community:1.

The reference value is optional and accepts only JSON-compatible scalar values and arrays. Do not pass an Eloquent model, a service, a closure, or another object as a reference. This restriction keeps the structured toArray() representation JSON-safe and lets Laravel serialize the context when a notification is queued.

app/Notifications/CommunityDigest.php
$context = new NotificationContext('community', '01', [
    'slug' => 'acme',
]);

$context->toArray();
// ['type' => 'community', 'id' => '1', 'reference' => ['slug' => 'acme'], 'key' => 'community:1']

The package validates the shape and serialization contract only. It does not know whether a context exists, whether an identifier belongs to the application, or whether a user may access it.

Authorize context access

NotificationContextAuthorizer delegates context access checks to the application. Use it when a user must belong to an organization, team, project, community, or another application-specific scope before reading or changing its preferences.

app/Support/ApplicationNotificationContextAuthorizer.php
use NotificationCompass\Contracts\NotificationContextAuthorizer;
use NotificationCompass\ValueObjects\NotificationContext;

final class ApplicationNotificationContextAuthorizer implements NotificationContextAuthorizer
{
    public function authorize(object $notifiable, NotificationContext $context): bool
    {
        return match ($context->type) {
            'team' => $notifiable->teams()->whereKey($context->id)->exists(),
            'organization' => $notifiable->organizations()->whereKey($context->id)->exists(),
            default => false,
        };
    }
}

Bind the authorizer in an application service provider:

app/Providers/AppServiceProvider.php
use NotificationCompass\Contracts\NotificationContextAuthorizer;
use App\Support\ApplicationNotificationContextAuthorizer;

$this->app->bind(
    NotificationContextAuthorizer::class,
    ApplicationNotificationContextAuthorizer::class,
);

The default authorizer allows every context. When a custom authorizer returns false, the preference manager rejects the operation and NotificationGate prevents delivery for that context.

Context policy administration uses a separate NotificationContextPolicyAuthorizer. It receives the administrator and context, so an application can apply different rules to membership access and organization-wide policy management. Enable notificationcompass.authorization.strict to make both default authorizers deny contextual operations until the application binds its own implementations.

Store context policies

Use NotificationContextPreferenceManager to set a preference owned by a context instead of a user:

app/Actions/SetContextNotificationPolicy.php
use NotificationCompass\Managers\NotificationContextPreferenceManager;
use NotificationCompass\ValueObjects\NotificationContext;
use NotificationCompass\ValueObjects\NotificationContextPreferenceMode;

$administrator = auth()->user();
$manager = app(NotificationContextPreferenceManager::class);
$manager->set(
    $administrator,
    new NotificationContext('organization', $organizationId),
    'incident.created',
    'mail',
    false,
    NotificationContextPreferenceMode::ENFORCED,
);

Use NotificationContextPreferenceMode::DEFAULT for a context suggestion that users can override. Use NotificationContextPreferenceMode::ENFORCED for a rule that users cannot override. The manager authorizes the administrator and validates the policy before calling the store. The default EloquentNotificationContextPreferenceStore persists the context key, notification key, channel, enabled value, and mode. It does not require a Community, Team, Organization, or Workspace model. Bind MutableNotificationContextPreferenceStore to another implementation when the application uses a different persistence layer.