Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Track Who Laravel Package

laravel-enso/track-who

Laravel Enso Track Who automatically records which users created, updated, or deleted Eloquent models. It provides traits and relationships for creator, updater, and deleter auditing, making it easy to track accountability across your Laravel application.

View on GitHub
Deep Wiki
Context7

Getting Started

Three steps to first tracked model:

  1. Install the package and publish its migration/ config:

    composer require laravel-enso/track-who
    php artisan vendor:publish --tag=track-who
    php artisan migrate
    

    (Publish tag name and whether a migration exists depends on version — inspect vendor/laravel-enso/track-who/src for the actual provider if the tag isn't found.)

  2. Add the columns created_by, updated_by (and deleted_by if you use soft deletes) to the tables you want to track. The package ships a migration helper/stub, but for existing tables you'll usually add these manually with a nullable unsignedBigInteger + foreign key to users.id.

  3. Drop the trait on the model:

    use LaravelEnso\TrackWho\App\Traits\CreatedBy;
    use LaravelEnso\TrackWho\App\Traits\UpdatedBy;
    use LaravelEnso\TrackWho\App\Traits\DeletedBy;
    
    class Post extends Model
    {
        use CreatedBy, UpdatedBy, DeletedBy;
    }
    

    If your version exposes a combined TrackWho trait, prefer that and opt out per-behaviour via config.

First use case: log in as a user, create a Post, then inspect the created_by column — it should equal auth()->id(). Add updated_by and deleted_by and repeat the create/update/soft-delete cycle to confirm.

Where to look first:

  • src/App/Traits/* — the actual hooks (bootCreatedBy, etc.) live here; read them before trusting the README.
  • src/App/ServiceProvider.php and config/track-who.php — confirm the user model, table, and foreign key names, since they're configurable.
  • The User side: the traits are worthless unless auth()->check() returns true on the write path.

Implementation Patterns

Full audit trail per model. Use all three traits together on content tables (posts, comments, invoices) where you need to answer "who created/edited/deleted this?" years later. The trait hooks fire on creating, updating, deleting events, so no controller changes are required.

Selective tracking. Don't blanket-apply. Only add UpdatedBy to models where edits matter; skip DeletedBy unless the model uses SoftDeletes (otherwise the hook is a no-op but you still pay a column and a relation).

Querying by author. The traits typically expose relations (createdBy(), updatedBy(), deletedBy()) returning BelongsTo(User::class). Use them for eager loading in list views:

Post::with(['createdBy', 'updatedBy'])->latest()->paginate();

If the relation names aren't what you expect, grep the trait for function createdBy — Enso sometimes uses user naming that collides with app relations.

Seeders, factories, and console commands. These run without an authenticated user, so the columns will stay null. Either wrap setup in actingAs/Auth::login(), or accept nulls and make the foreign key nullable. For backfills, prefer an explicit job that sets the column rather than relying on the trait.

API / queue / scheduled work. Same story: auth() is empty in queued jobs and scheduled commands. If you need an "owner" for background writes, pass the user id through and set the column explicitly before save; the trait will only overwrite it when auth()->check() is true.

Enso integration. The package is designed to slot into the wider Enso stack (enso/core, enso/helpers, role/permission middleware). If you're already running Enso, it will pick up the authenticated user from Enso's own auth chain, which is convenient — but it also means the package's assumptions about the user table (users, id) match Enso's defaults, not necessarily yours.

Soft-delete restore. A restore() typically leaves deleted_by set. If you want "who restored" tracking, you'll need an extra column and a custom trait — the package doesn't handle it out of the box.

Gotchas and Tips

  • Mass assignment silently kills tracking. If created_by, updated_by, deleted_by are not in $guarded = [] and the trait sets them via ->update() rather than direct property assignment, the write fails silently. In practice $guarded = [] or explicit $fillable entries are the safest bet; check the trait source to see which path it uses.
  • Query-builder updates bypass the trait entirely. Post::where(...)->update([...]) does not fire model events, so no updated_by is written. If audit accuracy matters, use model instances or an observer plus a manual stamp on bulk queries.
  • forceDelete() also bypasses deleting. Permanent deletes leave deleted_by at its previous value (or null). Only delete() on a SoftDeletes model is tracked.
  • No auth user = null columns. This is expected, but it means an "audit" table can legitimately have empty author fields. If your compliance logic requires non-null, add a policy check before writes rather than a DB constraint (which will break seeds and jobs).
  • Foreign key on user deletion. If a user is removed, ->constrained()->restrictOnDelete() on the author FK will block deletion. Use nullOnDelete() or cascadeOnDelete() deliberately — the package doesn't choose for you, and Enso's User model may or may not have its own handling.
  • Migration ordering. Add the created_by FK migration after users exists. In fresh installs this is fine; in existing projects migrating an old table you must sequence it manually.
  • Relation naming collisions. If your model already has a createdBy() accessor or a user() relation used elsewhere, the trait's BelongsTo may clash. Rename via config or drop the trait and add a local relationship instead.
  • Testing. $this->actingAs($user) before factory()->create() is required if any assertion checks created_by. Otherwise the factory-created record has a null author and tests are flaky between local and CI (where a session might leak).
  • Config quirks. If track-who.users.model (or equivalent key) is wrong, the trait will throw a class-not-found at runtime, not at boot — this often shows up only when the first tracked save happens. Publish and inspect the config once per project rather than relying on defaults.
  • Extension point. If you need conditional tracking (e.g., only track admin edits), override the trait method in your model — the boot methods are typically public static function bootCreatedBy() style, and you can redeclare them in the model to short-circuit. That's cleaner than forking the package.
  • Don't expect events or history tables. This package tracks who, not what changed. For a full audit-log (old → new values), pair it with spatie/laravel-activitylog or similar; track-who is a lightweight complement, not a replacement.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package