filagora/filagora-notifications
Adds a ready-to-use notification layer to Filagora, with configurable channels, database and mail delivery, and clean integration into Laravel's notification system so marketplace users stay informed about activity.
Bottom line: v0.1.0 is a coherent, well-scoped preference engine with real production lineage (it is an extraction of a live site's behaviour, and the differences are documented). It is integrable within a sprint for a Laravel team, but it is a 0.x release with deliberate behavioural tightenings, an incomplete compliance story (no audit, no retention), and one gap that must be closed by the host (entitlement-based email suppression). Treat it as adoptable behind flags, not as drop-in parity with the site it came from.
Architecture fit
EmailSuppression), events (PreferenceChanged), a Filament relation manager, and a privacy contributor. Low conceptual overhead for a Laravel team.NotificationCategories, first registration wins) is the right call over a fixed enum, but it converts a compile-time concept into a runtime, boot-order-dependent one. Category ids are effectively a public contract because they are persisted per row.web group — no session, no CSRF — which is correct for RFC 8058 one-click and relies entirely on signature integrity. Sound, but it needs a security review sign-off rather than a rubber stamp.filagora-*). Coupling is currently optional and toggleable, but roadmap and versioning will track the suite, not this package alone.Integration feasibility
filagora:adopt and a schema snapshot indicating a supported path for adopting an existing user_notification_preferences table rather than recreating it. That materially lowers migration risk for sites coming from the source implementation.allows(), mode(), set(), setMode(), matrix(), isSuppressed(), canDeliver(), plus Unsubscribe::url/oneClickUrl/decorate/apply. A single developer can wire the read path in a day.Technical risk
InvalidPreference is thrown where the source site answered "on". Unknown category, unsupported channel, or mode/switch mismatch now raises. In a notification send path this converts a silent default into an exception — the blast radius depends on whether callers wrap it. This is the single highest-risk delta for a team porting from the source site.allow_private_messages is missing. Sensible for engagement, risk-bearing for anything regulated or high-volume.filagora.notifications.view, declared in filagora-entitlements when installed. Sites without that package must define the ability themselves or the UI is invisible/leaky.register_standard and stored data. Turning standard registration off, or re-registering a category id with different channel support, will make existing rows unreadable or cause InvalidPreference on a channel the category no longer supports.Key questions for the maintainers
InvalidPreference at the send site — is there a safe allows()-style non-throwing variant, or must every caller try/catch?unsubscribe.signed_ttl and the exact signature parameters — is a link reusable within its TTL, and is there replay protection on the one-click POST?filagora:adopt handle an existing table with differing indexes or extra columns, and is it reversible?EmailSuppression be bound relative to the bridge bindings?Stack fit
filagora-entitlements for gate declaration, and optional sibling packages (filagora-push, filagora-forums, filagora-messages) via bridges.receives_email, email_status, allow_private_messages) without writing them, except where the host chooses to sync.Migration path
filagora:adopt and verify the snapshot matches reality, including indexes. Otherwise run the package migration.user_notification_preferences with PreferenceSource set distinctly (e.g. imported/legacy vs. user-chosen) so the source is filterable in the relation manager and attributable later.PreferenceChanged, or drop the column after backfill and cut readers over in one release.EmailSuppression if entitlement-based revocation is required. Do this before switching any send path to canDeliver().decorate()) can ship while routes.enabled is false — but note the routes reuse the paths the existing site already mailed (email-preferences/unsubscribe/{user}/{category}), so any link already in a customer's inbox will 404 until routes are on. Turn routes on in the same release you start emitting new links, and keep the paths unchanged.Compatibility
allows()/mode() call site for a category that might be unregistered at runtime (for example, a notification dispatched by a package whose category registration was disabled).InvalidPreference.register_standard off means you own all seven ids yourself; only do this if you are replacing, not supplementing, the standard taxonomy.Sequencing (suggested releases)
allows()/canDeliver() in one low-risk notification stream, with InvalidPreference handled. Observe.Maintenance
Support
EmailSuppression (attribute or host policy), or an InvalidPreference exception silently killing the send. Support needs a diagnostic runbook and ideally a log line at the send site.filagora.notifications.view) must be assigned to the support/admin role explicitly; default-deny will look like a broken UI.Scaling
set()-on-every-save patterns can make it dense. At 7 categories × 3 channels and a large user base, plan indexing around (user, category, channel) and verify matrix() — it is the query that will be called on admin screens and preference pages.matrix() on a per-user page is fine; matrix() in a loop over users is not. Any reporting or admin grid over all users' preferences needs a different query strategy.set() is covered by the PreferenceChanged event only if the host uses it; in-process caches in singleton services must be cleared explicitly.Failure modes
InvalidPreference in a send path → notifications silently dropped, or worse, an exception that fails the whole job/batch. Highest-severity failure; mitigate with a wrapper and alerting on the exception class.List-Unsubscribe-Post. Enable atomically with link emission.signed_ttl semantics match the old links, or those legacy links will fail validation and appear broken.filagora:adopt succeeding against a table with different indexes can hide a performance cliff that only appears at scale.Ramp-up
How can I help you explore Laravel packages today?