maize-tech/laravel-model-expires
A Laravel package that gives Eloquent models expiration dates. Add the trait, set an expiry, and use scopes to query active or expired records. Includes commands to prune expired models automatically, keeping your database clean and your data fresh.
Scope of this assessment: First formal assessment of maize-tech/laravel-model-expires, performed at release 1.2.0. No prior baseline exists, so this documents the package as a new candidate dependency rather than a delta review.
Architecture fit: The package follows the idiomatic Laravel package shape — a trait applied to Eloquent models that introduces an expiry timestamp, a global scope that hides expired records by default, and an Artisan command intended for scheduled purging. This is a well-worn pattern (conceptually "soft deletes, but for time") and slots into a standard Laravel domain layer without requiring a service container rebind, custom query builder, or event bus of its own. For teams already comfortable with SoftDeletes, the mental model transfers almost directly.
Integration feasibility: Low-friction. Expected path is composer require, publish/run a migration adding a nullable expires_at column, add the trait, and schedule the purge command. No external services, no credentials, no infrastructure prerequisites. The primary integration cost is not installation but semantic: deciding which models should expire, what expiry means (hidden vs. deleted vs. archived), and how existing queries behave once a global scope is active.
Technical risk:
laravel-pint-action, fetch-metadata). That is CI hygiene, not product change. Low churn is reassuring for stability but weak evidence of active maintenance.DB:: queries that bypass Eloquent. This is a design-consequence risk, not a defect.SoftDeletes, model observers, and queued jobs that serialise models is unverified for this package.Key questions to resolve before adoption:
expires_at indexed by the published migration, and is null treated as "never expires"?composer.json constraint for laravel/framework and php, and is Laravel 13 stable or dev-only?withExpired() / withoutGlobalScope) and is it documented?Stack fit: Targets conventional Laravel applications on Eloquent with a relational database. Best fit is content-oriented domains with a natural lifecycle — invitations, trials, OTP/token tables, listings, cached artefacts, draft records. Poor fit for event-sourced or heavily audited schemas where records must never silently disappear from reads.
Migration path:
expires_at timestamp with an index via a new migration; do not modify existing columns.NULL (never expire) or a computed date. NULL-means-immortal is the safe default for rollout, since it makes the change a no-op until data is populated.Compatibility: Audit every read path that touches the target models — API resources, admin listings, exports, analytics jobs, and raw query builder calls. Anything using DB::table() or withoutGlobalScope() will not honour expiry. Verify interaction with SoftDeletes (two overlapping scopes can produce confusing admin behavior) and with queued jobs that resolve models by ID after the record has expired.
Sequencing: Dev spike on a branch → confirm Laravel/PHP constraint resolution in composer.lock → staging migration plus query audit → schedule the purge command with overlap protection → production rollout model-by-model, not table-by-table wholesale.
Maintenance: Expect near-zero code maintenance and a steady drip of Dependabot PRs in the upstream repo — a signal of hygiene, not of feature investment. Pin to ^1.2 and let Renovate/Dependabot surface majors. Budget a review whenever the package announces a new Laravel major, since that is historically the only substantive change type here.
Support: Community/vendor OSS with no contractual support. Treat the package as "adopt with an exit plan": keep the trait usage thin and centralised (e.g., a base model or shared concern) so replacing it with an in-house trait is a contained change rather than a codebase-wide edit.
Scaling: The purge command is the scaling pressure point. Large expiry volumes turn a scheduled job into a burst of deletes — watch for lock contention, replication lag, and long-running transactions. Prefer batched deletion with a bounded chunk size and a per-run cap; run off-peak. The expires_at index is non-negotiable at scale, both for the purge scan and for scoped reads.
Failure modes to instrument:
Ramp-up: Low. A mid-level Laravel developer can adopt, migrate, and schedule purge in under a day; the real cost is the query audit, which is proportional to how widely the target models are read. Allocate review capacity for that audit rather than for the install itself.
How can I help you explore Laravel packages today?