Repository navigation
Operations
Choose an existing durable Laravel queue connection. A sync connection executes inline, so configure database or redis when asynchronous delivery is required. Create the host's native Laravel queue/failed-job tables if its chosen connection requires them; the package does not own a second queue service.
NOTIFICATIONS_QUEUE_CONNECTION=database
NOTIFICATIONS_QUEUE=notificationsphp artisan queue:work --queue=notifications --timeout=60Configure the host's scheduler:
use Illuminate\Support\Facades\Schedule;
Schedule::command('moztopia-notifications:recover')->everyMinute()->withoutOverlapping();
Schedule::command('moztopia-notifications:cleanup')->daily()->withoutOverlapping();Run schedule:run or the application's established scheduler service. When using a named connection, pass it to queue:work if it differs from the application's default connection.
The queue connection's retry_after must exceed worker/job timeout, which must exceed bounded provider HTTP timeouts. Restart workers on configuration changes. Use Laravel's native failed-job storage and commands for operational inspection.
queue.tries bounds provider attempts per intent. Backoff defaults to 30, 120, 600 and 1800 seconds, using the final value when needed. FCM retry-after guidance can extend that delay. Workers release jobs using Laravel's native queue machinery and persist available_at so duplicate/recovered jobs cannot retry early. TTL is rechecked before every attempt.
Permanent failures stop. Transient quota, availability and connection failures retry; unknown/configuration failures fail closed as permanent rather than being retried indefinitely. Inspect the safe classification and correct credentials, environment or payload before issuing a genuinely new event. Terminal deliveries are not automatically replayed.
The transport checks returned channel reports, not merely exceptions. FCM UNREGISTERED and APNs 410 Unregistered are definitive token invalidations. Malformed payloads, wrong credentials, sender mismatch and APNs BadDeviceToken are not treated as proof that a current registration should be destroyed. Invalid-token cleanup can be disabled by configuration.
php artisan moztopia-notifications:recoverRecovery scans due pending/retryable intents for the configured application and environment, in bounded batches, and dispatches jobs. This closes the database-commit/queue-enqueue outage window. It also retains work after a queue job fails before it can complete the database lifecycle. The job failure hook records only a stable delivery identity and safe code.
Recovery can enqueue duplicates when a queue is delayed. Recipient/delivery coordination and terminal state checks prevent simultaneous processing or resubmission of a recorded accepted intent. Do not disable recovery merely because workers are running. Monitor pending age and provision adequate recovery batches/worker capacity.
php artisan moztopia-notifications:cleanupCleanup considers expired messages older than delivery_retention_days. It removes associated delivery details and encrypted payloads. It retains application/recipient/event identity and cancellation metadata until deduplicate_until, controlled by deduplication_retention_days. Visible history is retained until the application deletes it.
Deleting visible history through NotificationHistoryService cancels pending/retryable deliveries immediately and preserves the event tombstone. After the deduplication deadline, repeated submission of the same key is allowed as a new logical notification even if an old history record remains. That deadline is the guarantee; cleanup frequency does not extend it. Configure retention to cover the longest expected event replay window.
Do not purge message/device tables manually while queue work is outstanding. Retained revoked device rows are intentional safety metadata. Design additional retention policies with lifecycle coordination and any application data-erasure requirements in mind.
Structured diagnostics include delivery UUID, safe state/error code and attempt number. Provider errors, token values, credentials and payload contents are not included. The adapter uses a private event dispatcher for dependency failure events because their normal event data may contain tokens. Applications should consume safe package state rather than attaching broad logging to raw provider events.
Provider acceptance is not a receipt metric. A queue outage or permanent provider failure does not remove history. A timeout after remote acceptance is ambiguous; see guarantees.
The package owns no deployment service, provider account, public API routes or Flutter client. It does not confirm device receipt and does not implement receipt acknowledgment storage. SQLite has an independent-connection coordination test; other database concurrency behavior must be verified on the actual consuming environment before claiming it proven there. Real-device verification is a separate step.
Moztopia Notifications
One notification per recipient. Independent delivery to every device.
Documentation · Source · Report an issue · MIT License
© 2026 Moztopia. Distributed under the MIT License.
