jeffersongoncalves/laravel-report-url
A lightweight Laravel package for adding URL reporting to your application. It provides configuration, routes, and controller scaffolding to collect, store, and manage reports associated with URLs, making it easy to integrate into existing Laravel projects.
ReportUrl::store() / storeFile() keeps the file on a private disk and returns a time-limited signed URL instead of an attachment.ttl (7-day default, per-call override) plus report-url:prune with --dry-run gives a concrete data-retention story: files do not live forever, links die on schedule, and the cleanup job is inspectable before it runs. That is a policy artifact you can show in a security review, not just a cron job.ReportUrlDownloaded plus a download counter and last_downloaded_at mean you can answer "did the customer actually get the report?" and "was this link hammered?" without instrumenting anything yourself — a real support-cost reducer.restrict_to_owner is a config flag, not a permission system. Deciding whether you need per-recipient sharing, revocation UI, or multi-tenant access control is a roadmap decision this release forces you to make explicitly rather than by accident.laravel-saved-filter 1.9+ binding (HostsReportFiles) is a ready-made answer to "scheduled reports too big to attach" for teams already on that stack — a same-day win, and a signal the package is being maintained against real downstream needs.Consider it when all of the following roughly hold:
laravel-saved-filter integration is close to a drop-in.Look elsewhere, or build deliberately, when:
restrict_to_owner is binary. Per-recipient links, team/org-level access, revocation dashboards, or delegated sharing are out of scope — do not adopt this and then discover you need an ACL layer underneath it.report-url:prune.Storage::temporaryUrl() covers it and you have no retention, telemetry, or cleanup needs, the package is extra surface area for little gain.onOneServer()/single-node assumptions need to match your infrastructure.Two adoption cautions worth stating plainly to engineering: the 410-on-expiry behaviour and the owner-check are the security-relevant bits, so they need test coverage in your app, not just trust in the package. And the coupling to laravel-saved-filter is a version-bounded integration (1.9+) — verify it against whatever you actually run before promising the "reports by link" feature to anyone.
For executives — one paragraph. We can now deliver large or sensitive generated files — scheduled reports, exports, statements — as secure, expiring download links instead of email attachments. That removes a hard blocker on report delivery, gives us a defensible retention story (links and files expire on a configurable schedule and are cleaned up automatically), and gives us an audit trail of who downloaded what and when. It is a small, single-purpose library rather than a platform commitment, so the cost of trying it is low; the main caveat is that it is a first release, so we pin the version and keep our usage narrow.
For engineering — the practical summary. It wraps Laravel signed URLs over a private disk: store() / storeFile() return a URL plus expires_at, with a 7-day default TTL and per-call override. Downloads go through a named route (report-url.download) that is signed, has configurable middleware, returns 410 after expiry, optionally enforces restrict_to_owner, and fires ReportUrlDownloaded while incrementing a counter and last_downloaded_at. report-url:prune --dry-run deletes expired rows and their files; schedule it daily on a single server. If you already use laravel-saved-filter 1.9+, HostsReportFiles is bound for you and oversized scheduled reports arrive as links.
For the business, framed as risk. The failure mode we are avoiding is customer data sitting at durable, guessable URLs indefinitely. Expiry-by-default plus scheduled pruning plus a dry-run mode means retention is a configuration decision we can review, not an accident. The residual risks are ordinary and manageable: it is a 1.0.0 with no long track record (pin it, keep the integration thin), owner restriction is coarse so we should not market it as sharing/permissioning, and the prune job needs a single-runner guarantee in our infrastructure. None of these are blockers for the report-delivery use case; all of them should be written down before we expand scope.
How can I help you explore Laravel packages today?