draliragab/filament-cloudflare-mail-monitor
A Filament plugin for monitoring Cloudflare email routing directly from your admin panel. View inbound mail activity, delivery status, and routing events in a searchable, filterable interface.
This is a Laravel package that ships its own quality gate, so the fastest path to productivity is to get it installed and get composer verify green on a scratch branch before you write any feature code.
Install and confirm discovery
composer require <vendor>/<package>
php artisan about # confirm the service provider is listed
php artisan vendor:publish --provider="<Vendor>\\<Package>\\<Package>ServiceProvider"
Laravel auto-discovery means you should not hand-register the provider in config/app.php unless the README says otherwise. If artisan about doesn't show it, your composer.json extra.laravel.providers block or a stale bootstrap/cache/services.php is the culprit — php artisan package:discover --ansi and a cache clear usually resolves it.
Where to look first, in order
README.md — the canonical usage snippet; copy it verbatim before adapting.config/<package>.php after publishing — every knob the package exposes lives here, and defaults are usually production-sane.register()/boot() — shows you exactly which contracts are bound and which are singletons, which determines how you resolve things from the container.CHANGELOG.md / release notes — check for behavioural changes between the version you pinned and the one you're reading about.tests/ — the package's own Pest suite is the best documentation of expected inputs and edge cases.First use case
Resolve the package's primary entry point from the container inside a controller or job rather than instantiating it, so config and any bound dependencies come along for free:
public function __construct(
private readonly \Vendor\Package\Client $client,
) {}
Then write one Pest feature test that exercises the happy path with the package's config defaults. That test becomes your regression harness for every later release.
If you're contributing to the package itself, the entry point is now:
composer verify
That single script runs Rector, Pint, PHPStan and Pest with coverage. Nothing else needs to be invoked individually in a pre-push workflow.
Configuration over code. Almost every package behaviour is driven from config/<package>.php. Prefer publishing the config and overriding values there (or via env() indirection the package already defines) rather than subclassing or rebinding internals. Config caching interacts with this — anything you read via env() outside the config file will return null once php artisan config:cache has run.
Container-first resolution. Bind the package's contract to a decorator in a service provider when you need cross-cutting behaviour (logging, metrics, retry) without forking:
$this->app->extend(\Vendor\Package\Contracts\Client::class,function ($inner, $app) {
return new InstrumentedClient($inner, $app->make(LoggerInterface::class));
});
This survives package upgrades far better than copying classes.
Queue and event integration. If the package dispatches events or ships jobs, register listeners in EventServiceProvider/bootstrap/app.php rather than inside the package's config callbacks, and use Event::fake() / Queue::fake() in tests. Assert on the event payload, not on the package's internal method calls — those are the most likely thing to change in a minor release.
Testing pattern (package consumers). Use RefreshDatabase plus the package's own factories/fakes where offered. For anything that hits an external service, look for a fake or a Http::fake()-compatible client before reaching for mockery:
it('processes an item', function () {
Http::fake([/* ... */]);
$result = app(\Vendor\Package\Client::class)->handle($payload);
expect($result->ok)->toBeTrue();
Http::assertSentCount(1);
});
Testing pattern (contributors). The suite runs on Testbench. The CI matrix covers PHP 8.4 against Laravel 12/Testbench 10 and Laravel 13/Testbench 11, so when you add a test, run it locally against both where your machine allows, or at minimum avoid APIs that only exist in one of the two Testbench majors. Version-conditional tests belong behind ->skip() guards rather than in a separate suite.
CI wiring. Mirror the package's matrix in your own app pipeline if you support both Laravel 12 and 13. A single-version pipeline will happily pass while the other major is broken, and Testbench majors do not always agree on testing-helper signatures.
Release hygiene. Because the package refreshes its dependency set each release, pin it with a caret constraint and let your lockfile do the work; then run your own suite plus a manual smoke test of the integration point after composer update. Transitive bumps in illuminate/* are the usual cause of surprise breakage, not the package's own code.
composer check is gone — it's composer verify now. This is the v1.2.0 change most likely to bite you. Anything referencing the old script name will fail with Script "check" is not defined in this package, which reads like a Composer misconfiguration but is just a rename. Audit before merging the upgrade:
run: composer check → composer verify).git/hooks/ or Husky/captainhook configsscripts entries in your own composer.json that shell out to the package's scriptScripts don't cascade across packages. You cannot invoke another package's Composer script directly from yours by name; if you were wrapping check in your own quality script, you'll need to either re-point it at verify or call the underlying tools (vendor/bin/rector, vendor/bin/pint, vendor/bin/phpstan, vendor/bin/pest) yourself.
Rector before Pint. Running Pint first means Rector's rewrites can leave unformatted diffs, and re-running Pint afterwards produces a second commit. Keep the order the package uses so local and CI diffs match.
PHPStan after Rector. Rule sets drift between releases; a clean verify on the previous tag does not guarantee a clean one after a dependency refresh. If PHPStan starts reporting on generated or vendored files, check the package's phpstan.neon ignore list before adding your own baseline — baselines that mask package internals tend to hide real upgrade breakage.
100% coverage is a floor, not a signal. The gate asserts lines executed, not behaviour verified. Don't relax your own review standard because the badge is full.
Testbench version skew. Testbench 10 (Laravel 12) and Testbench 11 (Laravel 13) differ in application bootstrapping helpers. Tests that pass locally on one can fail in CI on the other. If you maintain a package that depends on this one, run the matrix locally with --prefer-lowest occasionally.
Coverage on PHP 8.4 only. If you run a different PHP minor locally, PCov/Xdebug configuration differences can make coverage numbers disagree with CI. Use the same coverage driver (XDEBUG_MODE=coverage or PCOV) that CI uses before chasing a phantom regression.
Extension points worth knowing. The published config file, the container bindings in the service provider, and any Macroable traits on the package's public classes are the three supported seams. Reaching past these — overriding protected methods, or replacing classes via class_alias — will break silently on minor releases, and the package's own 260-assertion suite won't catch it because it never exercises your override.
Debugging. When behaviour doesn't match the config you set, check in this order: php artisan config:cache staleness, an unpublished config file (defaults silently win), and a competing binding registered later in the boot order. php artisan tinker plus app()->make(...) and config('<package>') will confirm which of the three you're hitting in about ten seconds.
How can I help you explore Laravel packages today?