benjamin-rqt/data-watcher-bundle
Symfony bundle for database anomaly detection: define SQL or Doctrine checks, run them manually or on a cron schedule, store execution history, and send email notifications when anomalies are detected. Supports Symfony 6.3, 7.0 and 8.0, Messenger, Mailer and Twig.
Critical framing note: despite the request framing this as a "Laravel/PHP package," benjamin-rqt/data-watcher-bundle is a Symfony bundle, not a Laravel package. It declares Symfony 6.3/7.0/8.0 and hard dependencies on framework-bundle, messenger, mailer, twig-bundle, and scheduler. There is no Laravel service provider, no Artisan integration, and no Composer laravel auto-discovery. Any evaluation must therefore separate "can we use it in our Symfony services" from "can we use it in our Laravel services" — the latter is effectively no without a port.
Architecture fit. The bundle's intent is sound and narrowly scoped: run configurable database checks on a schedule, detect anomalies, send templated email notifications, and retain execution history. That maps well onto a Symfony application that already runs Messenger + Scheduler + Mailer. It is a poor fit for anything outside that envelope — it assumes the Symfony full-stack idioms (bundle registration, YAML config under data_watcher:, Doctrine DBAL connections, Twig templates).
Integration feasibility. For a Symfony service the footprint is small: add a VCS repository entry, composer require, register the bundle, drop in config/packages/data_watcher.yaml, and ensure a Messenger transport exists so the Scheduler can enqueue checks. Doctrine DBAL ^3/^4 is required; doctrine/orm only if extending AbstractDoctrineCheck. Cron-style triggers pull in dragonmantank/cron-expression. That is a light integration surface — days, not weeks, for a team already on Symfony 6.3+ with Messenger wired.
For a Laravel estate the feasibility drops to near-zero as a drop-in. You would be reimplementing the check/notify/persist loop natively (Laravel scheduler + queued jobs + notifications + an execution-history table), or standing up a small Symfony sidecar purely to host the bundle. Neither is justified by the package's current signal.
Technical risk. High, concentrated in adoption and maintenance rather than code design:
Key questions to resolve before any commitment:
Stack fit. Treat this as a Symfony-only candidate. Recommended target: a Symfony 6.3/7.x service that already has Doctrine DBAL, a Messenger transport, Mailer configured with a working DSN, Twig, and the Scheduler component. If a candidate service is missing any of those, the true cost is "stand up Messenger + Mailer + Scheduler," not "install a bundle."
For the Laravel side of the estate: do not integrate. The idiomatic equivalent (Laravel Scheduler → queued Job → Notification/Mail → check_executions table) is roughly the same amount of code as the bundle's integration config, is fully in-house owned, and avoids the Symfony/Laravel impedance mismatch entirely. Reuse the concept and the check taxonomy; do not reuse the code.
Migration path (Symfony service).
AbstractDoctrineCheck against a read replica. Confirm a scheduled run fires, an email lands, and a history row is written.composer.lock; forbid floating constraints. Record the tag in an ADR.Compatibility. Explicitly validate: PHP ≥ 8.2 in the target runtime; Symfony minor version within 6.3/7.0/8.0; DBAL major version (^3 vs ^4 affects the check base class); Messenger transport actually consumed by a running worker (the Scheduler enqueues, it does not execute); dragonmantank/cron-expression if using cron triggers. Add a CI job that fails on PHP/Symfony minor bumps so upgrades are deliberate.
Sequencing. Concept spike → security/license/maintainer review → pin + ADR → non-critical pilot → decision gate → (if promoted) document the fork-and-own contingency → only then expand to additional services. Never roll out to more than one service before the pilot gate passes.
Maintenance. This is the dominant cost. A two-star, single-maintainer bundle should be treated as effectively a fork you have not yet forked. Budget for: periodic Symfony/DBAL compatibility bumps, monitoring the upstream repo for activity, and a standing option to vendor the code into an internal package if upstream stalls. Assume you own the upgrade path, not the maintainer. Keep the surface area small (one service, one or two checks) so the fork burden stays bounded.
Support. No vendor, no SLA, no community. Support is internal-only: whoever integrates it becomes the SME. Issues filed upstream may go unanswered. This is acceptable for internal, non-customer-facing anomaly detection; it is not acceptable where alerting is a compliance or contractual obligation.
Scaling. The design scales with the Scheduler and DB, not with the bundle: cost is proportional to (number of checks × frequency × query cost). Guardrails needed: run checks against read replicas, cap query complexity, set timeouts, and prune the execution-history table — an append-only history on a frequently-scheduled set of checks grows unbounded. Alert fan-out is per-email; a noisy check against a large recipient list will burn Mailer throughput. Keep checks idempotent and side-effect-free.
Failure modes to instrument explicitly:
from_email, app_name) → alerts go to a stale alias. Treat data_watcher.yaml as reviewed config.Ramp-up. Low for a Symfony team already fluent in Messenger/Scheduler/Doctrine — half a day to read the bundle and one to two days for the spike. Moderate for a team that has never run Messenger workers and the Scheduler, because the bundle's usefulness is gated on infrastructure they must stand up anyway. Effectively not rampable for a Laravel-only team without a deliberate port, which should be evaluated as a separate build project, not an integration.
TPM recommendation. Conditional, low-priority candidate. Green-light a scoped Symfony spike and a non-critical pilot; do not adopt in Laravel; treat maintainer risk as the primary decision driver and pre-commit to a fork-or-replace contingency at the pilot gate.
How can I help you explore Laravel packages today?