byrcsc/laravel-assignment
A Laravel package for managing assignments between Eloquent models, letting you attach, reassign, and track assigned records through a simple, configurable API. Lightweight, flexible, and easy to drop into any Laravel project for quick assignment handling.
Install the package and publish its config/migrations, then run migrations. The first place to look is the package README for the HasOffers-style trait/contract applied to your assignable model, followed by the config file for the queue table and notification settings.
Minimal first use case: add the trait to a model (e.g. User), define offerTtl() to return a positive number of seconds, then in a service or controller call offer($assignable, $ttl)->expiresIn(...) or use autoAssign(). Schedule php artisan assignment:tick in Kernel::schedule() (or the Laravel 11+ scheduler) to drive expiry and queue flushing. Confirm the pipeline by asserting a notification lands for the assignee, and that an expired offer produces the offer_expired notification.
offer() plus expiresIn(); read the current holder with assignee() (default slot) or assignee($role). Treat the offer as the unit of work and expiry as the state transition.'reviewer', 'backup'). Reserve null for the default slot. This keeps reads and writes aligned across assignee() and assignee($role).offerTtl() on the profile/model and call autoAssign() from a job or scheduled command. Because offerTtl() now must return >= 1, validate it at the source (config, DB column) rather than catching exceptions downstream.flushQueue() and assignment:tick on a schedule. The tick handles expiry dispatch and now also purges orphaned queue rows, so scheduling it is the primary hygiene mechanism rather than an optional cleanup.OfferExpired if you need custom side effects; the assignee's offer_expired notification is dispatched by the package. Listener should be idempotent — reassigning or re-offering against an expired offer can dispatch the event again for the same offer.offer, autoAssign, flushQueue) in a transaction when they're part of a larger state change, and keep assignment:tick out of request paths.'') now throws InvalidArgumentException on every read and write. Previously '' shared the default slot with null but reads filtered on role = '', so assignee('') and assignee() disagreed. Audit any code passing '' — migrate to null for the default slot. This is the highest-risk change for existing callers.InvalidArgumentException from offer() and expiresIn(). A zero or negative offerTtl() now makes autoAssign(), flushQueue(), and assignment:tick throw — including the scheduled command, so a bad profile value can break your whole tick run. Validate TTLs and add a guard/clamp at the profile boundary.OfferExpired for that offer, so the assignee receives offer_expired. If you previously relied on silent overwrite, expect notifications and listener invocations on that path.flushQueue() and assignment:tick now delete queue entries whose assignable model no longer exists. Previously these persisted indefinitely — expect log/metrics changes if you were monitoring queue growth, and be aware deletes now touch rows you may have been counting on for auditing.autoAssign() or the tick throws, check offerTtl() return values first, then role arguments, since both new exception classes surface there. Catch InvalidArgumentException explicitly in tests to assert these guards.OfferExpired and custom notification channels over overriding package internals; the notification name (offer_expired) is the stable contract to hook into.How can I help you explore Laravel packages today?