revoltify/subscriptionify
Subscriptionify is a Laravel package for adding subscription plans and feature access to your app. Define plans, features, and usage limits, subscribe Eloquent models, and check access through a clean, flexible API.
The package is a Laravel-native entitlements/subscription library that models plans, subscriptions, and direct feature grants against "subscribables" (polymorphic Eloquent models). Release 1.0.2 is a patch-level bug fix with a documented behavior change, not an architectural shift.
Architecture fit: The library plugs into Eloquent via a Subscribable trait and a DTO layer (FeatureInfoBuilder, subscriptionInfo(), allFeatures()). 1.0.2 corrects an inconsistency where allFeatures() disagreed with featureInfo() for direct grants — this matters because allFeatures() is the enumeration API most consumers will use to render "what does this record have access to." Prior to 1.0.2, enumeration and per-slug lookup had divergent semantics, which is exactly the class of bug that produces silent authorization/display mismatches in downstream code. The fix unions plan and grant slugs with plan ordering preserved and overlap deduplication (additive quota, override semantics for unit price and reset cycle). That is a coherent resolution model, and it is now documented as such.
Integration feasibility: High. No new dependencies, no framework version changes. Dependency bumps are CI-only (actions/checkout 7.0.0 → 7.0.1, actions/cache 6.0.0 → 6.1.0). Drop-in for any consumer on 1.0.1.
Technical risk: Moderate and concentrated in one place — subscriptionInfo() now delegates to allFeatures(), so its features collection gains direct-only grant entries. Any consumer that serializes that DTO to an API response, cache entry, or audit log will see additional array entries. This is a silent payload expansion: it will not throw, will not fail tests that assert on presence of specific features, and will only surface in strict snapshot tests, response-schema validation, or downstream clients that iterate the collection. Conversely, strict consumers that reject unknown keys or count features may break. The "no subscription returns empty DTO" carve-out is preserved, which limits blast radius, but it also creates a live footgun: subscriptionInfo() is empty for grant-only subscribables while allFeatures() is not. Any code path that assumes subscriptionInfo() is the canonical entitlement view is now subtly wrong for a class of records that 1.0.2 explicitly legitimizes (grants without a subscription).
Key questions for the maintainer/vendor:
subscriptionInfo() payload expansion considered covered by semver patch semantics, or should it have been 1.1.0? Our answer determines whether we can float the constraint.FeatureInfo/SubscriptionInfo DTOs — is the shape versioned?Stack fit: Standard Laravel package — service provider, config publish, migrations, Eloquent trait on subscribable models. Nothing here changes stack assumptions. Works with existing Laravel/PHP versions already validated at 1.0.1.
Migration path: Treat 1.0.2 as a low-friction upgrade with a mandatory audit step rather than a blind composer update.
subscriptionInfo() and allFeatures(), separating read paths (UI rendering) from contract paths (API responses, webhooks, exports, cached payloads, audit records).subscriptionInfo() emptiness as a proxy for "no entitlements." Those paths must move to allFeatures().Compatibility: No runtime or PHP/framework constraint changes; CI action bumps are internal. Behaviorally compatible with 1.0.1 except for the documented DTO expansion and the corrected allFeatures() output — both are strict improvements in correctness but observable.
Sequencing: Pin to 1.0.2 in staging with snapshot diffing on serialized DTOs; add regression tests asserting allFeatures() returns direct-only grants and that a grant overlapping a plan feature appears exactly once with additive quota. Promote to production only after contract surfaces are reconciled. Adopt the new "Entitlements without a subscription" pattern deliberately (as a designed feature, with tests) rather than discovering it incidentally.
Maintenance: Minimal. The change is a correctness fix plus documentation realignment. No new configuration, migrations, or scheduled jobs. Ongoing cost is the cognitive load of two enumeration APIs with deliberately different semantics — document internally which one is canonical for which question, and encode that in a short decision table mirroring the vendor's new compatibility table.
Support: Expect a small wave of "why did our API response get bigger" tickets if any external consumers depend on the subscriptionInfo() shape. Pre-empt with a changelog note to integrators and, where relevant, a versioned response schema. Also expect questions from teams that used subscriptionInfo() as their entitlement source and now see grant-only records returning empty — that is the failure mode most likely to be reported as a bug rather than understood as designed.
Scaling: Neutral. allFeatures() now performs a union across plan slugs and grant slugs; for subscribables with many grants this is slightly more work per call than the prior plan-only iteration, and it is a per-call computation, not cached by the package. If allFeatures() gets called in list/loop contexts (e.g. rendering an index of 500 child records), budget for N+1-style overhead and cache or eager-load accordingly. Verify the deduplication logic doesn't degrade with large grant sets.
Failure modes to watch:
subscriptionInfo() breaking strict consumers — highest likelihood, highest surprise.subscriptionInfo() for grant-only subscribables being misread as "no entitlements," producing incorrect access denial in UI or policy checks.Ramp-up: Low for anyone already versed in Laravel packages. The genuinely new concepts to internalize are (a) direct grants as a standalone mechanism that resolves with no subscription, and (b) overlap semantics — additive quota vs. override for unit price and reset cycle. Both are now documented, so onboarding cost is a short read plus the internal decision table. Allocate a half-day of review for the engineer owning the entitlements surface to validate contract-path diffs before rollout.
How can I help you explore Laravel packages today?