amjadiqbal/filament-audience-sync
A Filament plugin for syncing audience and subscriber records with external marketing platforms. It adds admin screens to configure field mappings, trigger syncs, and monitor status from your Laravel app, with queued jobs for reliable background processing.
Architecture fit. The package is a Filament panel plugin, not a standalone sync engine. It slots into the standard Filament plugin registration model (->plugin(AudienceSyncPlugin::make())), publishes its own migrations for a local subscription-state table, and exposes behavior through record actions, bulk actions, a status column/entry, and dashboard widgets. For teams already running a Filament 4 or 5 admin panel, this is a low-ceremony fit: no new service to operate, no separate auth model, and the admin surface is where the audience management work already happens.
Two design decisions are worth calling out positively from a TPM perspective. First, the local status table means list views and status columns do not make a per-row provider API call — that is the difference between a usable resource table and a table that rate-limits itself into failure on page load. Second, the driver contract plus AudienceSync::extend() is the right seam: it gives us a supported extension point if we need MailerLite, Kit, or an internal provider, rather than forking.
The main architectural caveat is that the package is a push-and-mirror design. State flows from the panel out to the provider, and provider-side state is reflected back into a local table. There is no mention of webhook ingestion, so provider-initiated changes (a contact unsubscribing from an email footer, a hard bounce, an archive in Mailchimp) appear to reach the local mirror only on the next sync. Consent enforcement depends entirely on the freshness of that mirror.
Integration feasibility. Mechanically straightforward: one Composer require, one vendor:publish + migrate, one plugin registration, plus model trait and resource wiring per the README. The declared compatibility matrix (PHP 8.2–8.5 × Laravel 12/13 × Filament 4/5) is broad enough that most current Filament estates will not need a framework upgrade to adopt it. The work is not in installation but in the per-resource setup: which models implement Subscribable, how tags and merge fields map to our domain, and what our consent semantics actually are.
Technical risk. The dominant risk is stated plainly in the release notes and should not be softened: provider evidence is fixture-based. The 70 Pest tests and the browser passes ran against HTTP fakes and a stateful fake of the Mailchimp and Brevo APIs. Nothing has been run against a live account. Fixtures built from documented API shapes validate our code's parsing and branching, but they cannot surface real-world behaviors: Mailchimp's actual merge-field validation errors, double opt-in state transitions, Brevo attribute type coercion, per-plan rate-limit tiers, or the specific error envelopes returned for suppressed/bounced contacts. Until a live-account pass is done, treat the driver layer as unproven and the consent guarantees as unverified.
Secondary risks: consent-first logic is the package's most safety-critical claim and the least externally auditable — "never subscribed again" needs a written, tested definition of what the local mirror considers a terminal state, and what happens when the mirror is stale or the provider call fails mid-bulk. Bulk actions are queued with chunking and retries; that is correct, but it means a bulk subscribe of 10,000 contacts is a queue-throughput and provider-quota planning exercise, not a button. The MIT license and single-maintainer authorship mean no SLA, no security disclosure process stated, and a 1.0.0 with no upgrade history — we inherit the maintenance relationship. Finally, the security posture (keys in .env, redaction from errors) is a stated intention that should be verified with a deliberate failure test, because redaction bugs are exactly the kind that only appear in production logs.
Key questions.
AudienceSync::extend() survive minor-version upgrades?Stack fit. Adopt only if we are already on Filament 4/5 with Laravel 12/13 and PHP 8.2+. Retrofitting a framework or panel upgrade to get an audience-sync feature is not justified by this package alone. If our panel is on an older Filament major, this is a no.
Migration path. There is no prior assessment and no prior integration, so this is greenfield. The practical migration is: no data migration from the panel side (the package creates its own table), but a state reconciliation migration from whatever we use today. If we already have Mailchimp/Brevo audiences with real subscribers, the local table starts empty and must be populated by a controlled initial sync. That first sync is the highest-risk operation in the whole rollout: it is the moment where an incorrect consent interpretation could re-subscribe suppressed contacts at volume. Run it against a non-production audience first, with a hard cap on batch size, and diff the resulting provider state against the pre-sync export.
Compatibility. Two dimensions. Framework compatibility is declared and CI-covered. Provider compatibility is not: we should confirm our specific Mailchimp plan tier and Brevo plan tier, since rate limits and feature availability (double opt-in, tags vs. attributes) vary by plan. Also confirm whether our provider accounts use any features the drivers do not mention — nested audiences, transactional-only lists, or custom suppression policies.
Sequencing.
Maintenance. The package adds a Composer dependency, a published migration set, and a queue workload. Ongoing cost is real but bounded: dependency bumps on Filament major releases (the 4→5 transition is explicitly supported, which is a good signal for the next one), migration review on each upgrade, and periodic reconciliation of the local mirror against provider truth. The published-migrations pattern means schema changes arrive as new publishable files rather than auto-migrations; someone must own reviewing them.
Support. MIT, community-maintained, no stated SLA or security disclosure channel. We should assume best-effort upstream and plan to vendor or fork if a critical fix is needed. The driver contract is the mitigation here: if the Mailchimp driver becomes unmaintained, we can swap in our own via AudienceSync::extend() without leaving the plugin. Budget a named internal owner — this is a "someone is accountable" dependency, not a "set and forget" one.
Scaling. Two independent ceilings. Provider-side: Mailchimp and Brevo rate limits are per-account and tier-dependent, and the package's Retry-After/backoff handling protects correctness but not throughput — heavy backoff means long bulk jobs, not failed ones. Panel-side: bulk actions consume queue workers, and the local status table plus widgets consume database reads. Size the queue separately so a 50k-contact sync does not starve other jobs. The local-table read model scales well; the write path scales only as fast as the provider allows, so plan bulk operations in windows rather than on demand.
Failure modes. The realistic ones, roughly by likelihood:
Ramp-up. Installation is an afternoon; competent operation is a couple of weeks. The people who need training are not just developers: whoever runs bulk syncs needs to understand chunking, retry semantics, and what a flagged row means, and whoever owns compliance needs to understand what the local mirror does and does not guarantee. Expect a half-day of developer onboarding to the driver contract if we intend to extend it, and a short written runbook covering bulk-job failure, reconciliation, and credential rotation. The single biggest onboarding item is instilling the correct default posture: the local table is a cache, not the source of truth.
How can I help you explore Laravel packages today?