rulr/laravel-authored
A small Laravel package for recording and querying authorship on your models, so you can see who created or changed a record. Simple traits and helpers keep attribution consistent across your app without extra tables or boilerplate.
Architecture fit. The package addresses a single cross-cutting concern — stamping rows with the acting user — through two idiomatic Laravel extension points: an Eloquent trait (model lifecycle events) and a schema macro on Blueprint (migration ergonomics). This is the lowest-friction shape a package like this can take. It adds no runtime service container bindings you must reason about, no middleware, and no queue/console hooks; it participates only in the creating/updating model events. For an application already on Eloquent, the architectural delta is near zero, and the concept maps directly onto conventions most teams have already hand-rolled at least once.
Integration feasibility. High in the mechanical sense: composer require, add the trait to target models, add columns via the macro in a new migration. The friction is not installation but coverage: Eloquent events do not fire for bulk operations (insert(), insertOrIgnore(), upsert()), for saveQuietly(), or inside Model::withoutEvents(). Any ingestion path or performance-sensitive write in your codebase will silently bypass authorship. Feasibility is therefore "easy to adopt, non-trivial to adopt completely."
Technical risk. The dominant risk is not code quality but signal. Four stars, zero dependents, and a composite score of 0.02 mean there is effectively no evidence of production use — no downstream projects surfacing bugs, no ecosystem pressure on edge cases, and likely a single maintainer. Treat the score as "unproven," not "defective." The surface area is small enough (a trait plus a macro, on the order of dozens of lines) that a fork-and-own strategy is cheap insurance; MIT licensing makes that legally uncomplicated.
Secondary risks are behavioral and worth explicit design decisions before rollout:
auth()->id() directly, it will write null in queued jobs, Artisan commands, seeders, and scheduled tasks. Columns must be nullable, and you need a policy for "system" writes (sentinel user ID vs. null vs. explicit override).updated_by, it will clobber values you set deliberately (e.g., data-migration scripts, imports attributed to an integration user).Key questions to resolve before committing:
created_by/updated_by) and their types configurable, or hard-coded? Does it support UUID/ULID primary keys?nullOnDelete vs. restrictOnDelete on the users FK is a real operational choice.composer.json, and is there CI covering the versions you run?Stack fit. Assumes a conventional Laravel application (Eloquent models, standard auth guards, relational database with a users table). It is a poor fit for event-sourced or CQRS-style write paths, for services that write primarily through raw query builder or bulk upserts, and for multi-tenant systems where the users table is per-tenant rather than global — in that case the foreign key target becomes a schema-level problem.
Migration path. Add columns in a new, additive migration using the macro rather than editing historical migrations; nullable at first, backfilled afterward, tightened to non-null only once write coverage is verified. On large tables, create indexes and foreign keys CONCURRENTLY (Postgres) or via ALGORITHM=INPLACE (MySQL 8) to avoid write stalls. Backfill strategy needs a decision: leave historical rows null and document the cutoff, or attribute them to a synthetic "migration" user — the latter is better for reporting integrity but requires a seeded sentinel account.
Compatibility. The two compatibility questions that matter are version constraints (Laravel 10/11/12 and PHP 8.1+ coverage) and coexistence with existing audit tooling. If you already run spatie/laravel-activitylog, owen-it/laravel-auditing, or a homegrown observer stack, you now have two systems asserting authorship. Pick one as the source of truth for created_by/updated_by and make the other read-only with respect to those columns, or you will get divergent values that are expensive to reconcile after the fact.
Sequencing. (1) Spike: install in a branch, apply to one low-traffic model, inspect generated SQL. (2) Verify in staging under realistic conditions — dispatch a job, run a seeder, hit an API route behind a token guard — and confirm the null/attribution behavior is what you want. (3) Roll out model by model, prioritizing models where "who touched this" is a compliance or support requirement. (4) Backfill. (5) Enforce non-nullability and add indexes. Resist a big-bang trait application across every model; the failure mode (missing column on an outlier model → SQL exception in production) is trivially avoidable by sequencing.
Maintenance. Low ongoing cost if pinned to an exact version, higher if you track upstream, because a single-maintainer package with no dependents carries abandonment risk and no deprecation runway. Budget for a periodic fork check: the code is small enough that "vendor it into app/Support/" is a legitimate alternative to a Composer dependency, and it eliminates the supply-chain and abandonment questions entirely at the cost of losing upstream fixes you probably don't need.
Support. Effectively none beyond GitHub issues from a maintainer with no evident commercial backing. Internal ownership must be explicit — name a team or engineer as steward. Do not let this become an unowned dependency that only surfaces during an incident.
Scaling. Runtime cost is negligible: two integer columns and one extra assignment per write. The scaling concern is query-shaped, not write-shaped. Authorship columns invite "my records" filters; those need composite indexes ((created_by, created_at)) or they degrade into scans on large tables. Foreign keys to a high-churn users table introduce lock contention on user deletion/merging — nullOnDelete is usually the right default, but that decision must be made at migration time, not retrofitted.
Failure modes to design against:
| Failure | Symptom | Mitigation |
|---|---|---|
| No auth context (queue, CLI, scheduler) | created_by null across ingested data |
Nullable columns; explicit system-user resolver; monitor null rate |
| Bulk writes bypass model events | Rows with null author in high-volume tables | Audit ingestion paths; set authorship explicitly in those writers |
| Guard mismatch | Wrong or null ID behind non-default guard | Verify resolver configurability; assert in tests |
| Missing column on a model | SQL exception at write time | Staged rollout, one model at a time |
| Dual audit systems | Divergent authorship values | Single source of truth for these columns |
| Impersonation | Attribution records the wrong principal | Decide effective vs. acting user before rollout |
Ramp-up. Engineer-level ramp-up is roughly an hour: the API surface is a trait and a macro. Organizational ramp-up is the real cost — agreeing on what authorship means for system writes, imports, impersonation, and historical data, then enforcing those conventions across teams. That policy work is identical whether you adopt this package, fork it, or hand-roll it, which is precisely why the package's low adoption signal should weigh heavily: it saves perhaps fifty lines of code and a design conversation you still have to have. Recommendation: viable as an internal, pinned or vendored dependency for teams with a clear authorship policy and a named steward; not appropriate as an unreviewed drop-in for a compliance-critical audit trail.
How can I help you explore Laravel packages today?