laravel-interaction/subscribe
Laravel Interaction Subscribe adds reusable subscribe and unsubscribe behavior to Eloquent models, letting users follow posts, topics, or any model through polymorphic relationships with simple helper methods and query scopes.
Build vs. buy on the "follow / subscribe" primitive. Every product surface that lets a user track something — a creator, a channel, a thread, a category, a saved search, a product — needs the same underlying mechanic: a durable, queryable, on/off relationship between a subscriber and a subscribable. This package supplies that substrate as a polymorphic pivot with subscribe(), unsubscribe(), toggleSubscribe(), and isSubscribedTo(). What we'd otherwise fund is a week or two of schema design, unique-constraint handling, trait wiring, and the edge cases (double-clicks, deleted targets, eager-loading) that only surface after launch. What stays in-house either way is the differentiated part: what a subscription triggers, digest cadence, preference granularity, and the UX around it.
Roadmap sequencing and reuse. Shipping the substrate once unblocks a family of adjacent roadmap items cheaply: notification opt-ins, follower feeds, "new from people you follow," watch-this-thread, re-engagement campaigns aimed at subscribers of dormant channels. The second and third features reuse the same table instead of introducing yet another bespoke pivot. That compounding reuse, not the first feature, is where the value sits.
Consistency and product analytics. Standardizing on one subscription model makes questions we currently hand-wave answerable: how many users follow more than one channel, what the median subscription lifetime is, how often people toggle off after a digest, which acquisition source produces subscribers who stay. Those numbers decide whether to invest next in preference UX or in content quality — and they're only tractable if subscriptions live in one place.
Release 1.4.0 is a pinning decision, not a feature decision. The bump from 1.3.0 to 1.4.0 shipped with only an auto-generated compare link and no changelog body. Semver says no breaking changes and nothing signals a deprecation, but there is no documented evidence either way. Treat 1.4.0 as unverified rather than safe: pin the exact version, read the commit diff before upgrading, and confirm the trait signatures and migration stubs we depend on are unchanged. This doesn't change the adoption calculus, but it does inform how tightly we pin and how much we wrap.
Maturity is a first-class input here. 8 stars, zero dependents, a single maintainer, and a last release in February 2022 put this firmly in "small community package" territory. That's acceptable for undifferentiated plumbing behind an internal interface; it is not acceptable as a load-bearing dependency with no exit.
Adopt when most of these hold:
Look elsewhere — or build — when:
Operational caveats to budget for if we adopt: verify the published migration actually carries a unique index across the full morph quartet, because duplicate subscriptions from a double-click are a race condition, not just a UI glitch; purge subscriptions when a subscribable is deleted, since morph relations have no cascading foreign key; treat isSubscribedTo() as a query and pre-load the user's subscription set rather than calling it inside a loop; and enforce a morph map before launch, because renaming a model class afterward silently orphans rows.
For executives — one paragraph. Subscription and "follow" mechanics are a recurring product primitive, and we currently rebuild the underlying data model every time a new feature needs one. This package supplies that model off the shelf in our existing framework, removing roughly a week of engineering plus its testing and maintenance from each feature that touches it. The strategic value isn't the code we skip writing once — it's that a single, consistent subscription substrate lets us ship notification opt-ins, follower feeds, and "new from people you follow" as a sequence of small features rather than a series of mini-projects, and it finally gives us one place to measure subscriber behavior. The trade-off is real but bounded: this is a small, single-maintainer package last released in 2022, so we adopt it pinned to an exact version, behind a thin internal interface, with a documented exit path. That costs about an hour of engineering and converts a dependency risk into a contained swap.
For engineering — the practical summary. Laravel-native, MIT, trait-based, one polymorphic subscriptions table serving every subscriber/subscribable pair. Install via Composer, publish config and migrations, migrate. Add the subscriber trait to User and the subscribable trait to Channel, Newsletter, Topic, and so on. Three extension points matter and we should stick to them rather than overriding trait methods: the package's state-change events (listen for SubscriptionCreated and branch on resulting state for toggles, which fire in both directions), the config's model/table mappings (pointing it at a custom model means extending theirs, not a plain Model), and the relation on the subscriber trait. Two things to verify on day one rather than after launch: that the published migration has the full unique index, and that our morph map and key types (UUID vs. bigint) match on both sides. Pin to 1.4.0, since its release body is only a diff link — diff the config and migration stubs against ours on any upgrade and run migrate:fresh in CI. Wrap all of it in an internal repository so the day we outgrow it, we replace an interface instead of chasing traits through the codebase.
How can I help you explore Laravel packages today?