serendipity_hq/features-bundle
Serendipity HQ Features Bundle adds a flexible feature-flag system to PHP applications, letting you enable or disable functionality per environment, user, or context. Define features in configuration, check them anywhere, and ship changes safely without redeploying code.
Architecture fit. The package is a Symfony bundle, not a Laravel package. That distinction is the dominant finding in this evaluation. Bundles are idiomatic to Symfony's runtime: they ship a Bundle class, register services through the Symfony DI container, expose configuration trees via the Config component, and typically hook into the kernel lifecycle (compiler passes, cache warmers, event subscribers). None of that maps onto Laravel's service-provider/kernel model without an adapter layer. A Laravel team cannot composer require this and expect Feature::active()-style ergonomics; there is no FeaturesServiceProvider, no facade, no publishable config, no Blade directive. So the first question is not "does it work?" but "is the underlying domain model separable from the Symfony plumbing?"
What is genuinely valuable here. The domain — plans, features, and the resolution logic that answers "does plan X include feature Y?" — is framework-agnostic in principle and is a recurring need in SaaS billing and entitlement work. If the bundle cleanly separates a manager/service layer from its Symfony wiring, the domain is extractable and portable. If the feature resolution is entangled with DI tags, container parameters, and Symfony event dispatching, extraction becomes a rewrite. That is the single most important thing to determine before committing engineering time.
Integration feasibility. Low as-is for a Laravel codebase; moderate-to-high only if the domain is portable and we are willing to own a small adapter. Practically there are three paths:
symfony/* components alongside Laravel and bootstrap the bundle manually. Technically possible; almost certainly the wrong call. You would be maintaining a bespoke Symfony-in-Laravel shim forever, for a dependency with 11 stars.Technical risk. High on several axes:
Key questions for the maintainer / code review. Before any commitment, I would want answers to:
symfony/dependency-injection only, or does it require the full kernel?Stack fit. Laravel and Symfony share PHP, Composer, PSR interfaces, and many underlying components, so coexistence is not the problem — idiomatic integration is. A Laravel application expects a package to present: a service provider, a config file merged from config/, container bindings under stable contracts, optional facade, and publishable migrations. This bundle presents none of those. Treat stack fit as conditional: acceptable only behind a thin, first-party adapter that we own and can test independently of the vendor repo.
Migration path. I would sequence this as a spike, not a rollout:
FeatureResolver::forPlan($planId, $featureKey): bool — with a config-driven or database-driven backend. Keep the vendor package as an internal implementation detail behind that seam, so swapping it out later is a one-file change.If the spike is not green — which, at 11 stars and zero dependents, is the base case — skip to adopting a maintained alternative and use the bundle only as a data-model reference.
Compatibility. Two compatibility surfaces to pin explicitly: PHP version support (does it run on our runtime, including patch-level behaviour) and Symfony component versions (the bundle will constrain these even inside Laravel, and that constraint lives in our composer.json forever). I would also check for abandoned transitive dependencies, since low-traffic bundles routinely pull in packages that have gone quiet.
Sequencing. Do not build billing or entitlement logic on top of this in the same sprint as the integration. Land the abstraction first, prove resolution correctness with fixtures, then wire it into gating paths. Any place where a wrong answer costs money — plan upgrades, invoice generation, seat limits — should be the last consumer, not the first.
Maintenance. This is the dominant operational cost and it is easy to understate. Because we are running a Symfony bundle in a Laravel context, we are the de facto maintainers of the integration on day one. That means: tracking upstream commits, re-testing on every Symfony minor, and being prepared to take over the repository entirely if the maintainer steps away. Budget for a named owner and a quarterly review. If we cannot commit to that, we should not adopt it — a low-adoption dependency with no owner inside the org is a slow-motion incident.
Support. There is no vendor to call and no commercial support tier. Escalation is "read the source" or "fork it." That is acceptable for an internal convenience library; it is a poor fit for anything in the revenue path.
Scaling. The package is unlikely to be a throughput bottleneck — plan/feature resolution is a small, cache-friendly lookup, and I would expect it to sit behind a request-scoped or Redis cache regardless of implementation. The real scaling concern is organisational, not technical: as the number of plans, features, and exceptions grows, the model needs runtime editability and an audit trail. If the bundle only supports config-file-defined plans, every pricing change becomes a deploy, which does not scale past a handful of plan tiers. Confirm this before committing.
Failure modes. The ones I would design against:
false for an entitled customer is a support ticket; one that returns true for an unentitled customer is revenue leakage. Mitigation: assert the resolver's output against a fixture matrix in CI, and log every gating decision with plan, feature, and result for a bounded retention window.Ramp-up. Two audiences, different costs. Engineers need enough Symfony literacy to read DI configuration and compiler passes — likely a day or two for a competent PHP developer, but it is friction that never fully goes away. Product and operations need a stable, documented mental model of plans and features; if the bundle's abstractions do not match how the business actually talks about packaging, we will spend the integration budget translating between them. Write the internal docs ourselves — none will arrive from upstream.
Overall recommendation. Treat this as an evaluation candidate, not an adoption. Fund a short, time-boxed spike to determine whether the domain core is separable; do not commit to the Symfony bundle as runtime infrastructure in a Laravel stack. If the spike shows clean separation, fork-and-wrap behind a first-party interface and own it deliberately. If it does not, extract the ideas and adopt a maintained feature-flag or entitlement product. The score of ~5.8 with 11 stars and zero dependents reads correctly to me: interesting domain, weak package posture, and a framework mismatch that shifts the real cost onto us.
How can I help you explore Laravel packages today?