anomaly/preferences-module
Anomaly Preferences Module adds a flexible user preferences system to Laravel/Streams Platform applications, letting you define, store, and retrieve per-user settings via a simple API, with control panel integration for easy management.
What this actually is. anomaly/preferences-module is not a general-purpose Laravel settings package — it is an addon for the Streams Platform (Anomaly Labs' modular Laravel CMS, the architecture behind PyroCMS 3.x and the Streams successor). Its job is narrow and well-understood: persist namespaced key/value preferences (global, per-module, and typically per-user), expose a repository/facade for reading and writing them, ship the migrations, and register an admin surface for editing them.
Architecture fit. Fit is binary, not gradient. If you are on Streams/PyroCMS, this is the idiomatic answer to a real problem and slots in with zero architectural friction. If you are on a conventional Laravel application (9/10/11), there is no clean path: the module will pull anomaly/streams-platform, its addon loader, its service-provider contracts, its asset/view registration conventions, and quite possibly a pinned illuminate/* constraint from the Laravel 5.x–8.x era. That is a large dependency surface acquired for what is functionally a 200-line key/value store with a cache in front of it.
Technical risk. Two distinct risks, do not conflate them:
Key questions to resolve before any commitment.
php and illuminate/* constraints does composer.json declare, and does the solver survive contact with your composer.lock?anomaly/streams-platform explicitly, or does it degrade to a standalone installable module?boot() — i.e. route/view namespace pollution risk in a non-Streams app?Stack fit. Recommend adoption only where a Streams/PyroCMS instance already exists — the marginal cost there is one composer require plus a migration run, and consistency with the platform's conventions has real value. For every other Laravel codebase, this package is a reference implementation, not a dependency: read the schema and the resolution logic, then reimplement.
Migration path — if on Streams. Install into the platform's addon path, register in the addon manifest, run migrations, seed defaults, and enable the module in the admin. Verify that existing preferences table(s) are not duplicated and that the namespace convention you choose (app.*, module.*) doesn't collide with other addons.
Migration path — if not on Streams (the likely case). Do not fork-and-integrate; extract. Take the table shape (namespace, key, value, optionally user_id), the repository contract, and the read-through cache behaviour, and build a small first-party PreferencesRepository bound to an interface. Typical effort is one to two engineer-days, which is almost certainly cheaper than the platform pull-in and leaves you with no upstream coupling. MIT makes the copy-and-adapt path clean; preserve the license header if you lift code.
Compatibility and sequencing.
PreferencesRepository interface so the implementation is swappable. This is the single decision that de-risks the whole exercise.Maintenance. Assume zero upstream maintenance. There is no release cadence to track, no security advisory channel, and no community to absorb breaking changes from Laravel. Budget an explicit fork-ownership line item — even if small, it must be named, or it becomes invisible debt.
Support. No issue triage, no maintainer responsiveness, no Stack Overflow corpus. Internal support is the only support. In exchange, the domain is simple enough that a competent Laravel engineer can fully understand the module in an afternoon.
Scaling. The workload is read-heavy and write-light, which is the easy shape. The risks are (a) a query per preference lookup on every request — mitigate with a read-through cache (Redis) hydrated once per request, and (b) write amplification if admin saves are per-key — batch the writes. If preferences are per-user and you are multi-tenant, confirm the scope column exists before designing around it; retrofitting tenancy onto a flat preferences table is unpleasant.
Failure modes to design against.
Ramp-up. Low conceptual ramp-up, moderate contextual ramp-up. A Laravel developer unfamiliar with Streams will spend most of their time on the addon loader and service-provider conventions, not on the preferences logic. Net: half a day to evaluate and understand, one to two days to reimplement natively.
Recommendation. Do not adopt as a dependency for a non-Streams Laravel application. The feature is small, the upstream is dormant, and the platform coupling is disproportionate to the value. Use it as a design reference, extract the schema and caching pattern into first-party code, and keep the dependency graph clean. Reserve genuine adoption for teams already committed to Streams, where the calculus inverts and convention consistency outweighs lifecycle risk.
How can I help you explore Laravel packages today?