whilesmart/eloquent-owner-access
A lightweight Laravel package that adds owner and access-control behavior to Eloquent models, letting you assign owners and authorize who can view, edit, or share records with simple, reusable traits.
Architecture fit. The package targets a real gap: reusable Laravel packages that ship domain records (documents, projects, comments) need an ownership column pair (owner_type/owner_id) but cannot assume whether the host is single-tenant, multi-tenant, team-based, or user-based. This package inverts the dependency — the package declares that a record is owned, the host decides who the owner is and what they may do. That is the correct seam for a library. It is best understood as a contract + trait layer sitting beneath Laravel's Gate/Policy system, not a replacement for it.
Integration feasibility. Low mechanical cost: composer require, add the trait (or use models that already include it), bind an authorization resolver in a service provider, run migrations for the two columns plus a composite index. The real work is not installation — it is deciding and encoding the host-side authorization policy, which the package deliberately leaves to you.
Technical risk. This is an authorization path with zero adoption (0 stars, 0 dependents), a single apparent maintainer, and no external security review. For code that governs record visibility, that is the dominant risk, ahead of any functional concern. Specific items to verify by reading source (small enough to audit in an afternoon):
->ownedBy() scope, or only expose a Gate helper? Global scopes are convenient but silently affect withoutGlobalScopes(), eager loads, and raw queries; explicit scopes are safer but easy to forget.owner_type, and what happens to historical rows if the map changes.Key questions. Laravel/PHP support matrix and CI coverage? Test suite depth on adversarial cases (owner deleted, owner reassigned, nested eager loads)? Does it publish config and migrations, or assume existing columns? Are there documented upgrade paths? Is the license/CLA clean for an internal fork?
Stack fit. Native Laravel/Eloquent, MIT. It composes with — rather than competes against — spatie/laravel-permission (roles/capabilities), Laravel Policies (decision logic), and tenancy packages like stancl/tenancy (owner identity). The clean layering is: tenancy resolves the owner; this package associates records to the owner and filters; Policies answer "may this actor act on this record."
Migration path. Two distinct cases. Greenfield: adopt columns from day one, cheapest. Retrofit: add nullable owner_type/owner_id + composite index, backfill from existing user_id/tenant_id, dual-write during transition, then flip reads. Backfill is the schedule risk, not the code.
Compatibility. Check illuminate/* version constraints, PHP floor, and whether the package installs a global scope that could collide with existing tenant scopes. Two global scopes on the same model can double-filter or mask each other.
Sequencing. (1) Source audit and security read-through. (2) Pin the version or vendor a fork with a documented patch path. (3) POC on one low-risk model behind a feature flag. (4) Define and test the host authorization resolver, including fail-closed assertions. (5) Backfill and dual-write. (6) Roll out per model. (7) Add denial telemetry before enabling broadly.
Maintenance. Tiny surface area means low ongoing cost, but you will effectively own it: expect to carry a fork or patch file to track Laravel majors, which ship annually. Budget a small recurring line item rather than assuming upstream responsiveness.
Support. No community, no Stack Overflow corpus, no docs ecosystem. Troubleshooting is reading source. Internal documentation of your resolver contract is mandatory, because that is where the actual behavior lives.
Scaling. The (owner_type, owner_id) composite index is load-bearing — query filtering by owner must be index-driven, not post-filtered in PHP. Watch for N+1 patterns if ownership checks resolve per row, and for per-request authorization cost on large listings. Cache ownership lookups if the resolver is non-trivial.
Failure modes. Ranked: (1) fail-open default exposing cross-owner records; (2) forgotten scope on a new endpoint — mitigate with a test that asserts every owner-scoped model is filtered by default; (3) orphaned rows after owner deletion; (4) stale cache after ownership reassignment; (5) morph map drift breaking historical owner_type values; (6) silent double-scoping after a tenancy migration.
Ramp-up. A Laravel-fluent engineer is productive in under a day. The slow part is not the package — it is the product decision about who may see what, which must be specified by the TPM before code is written. I would approve a scoped POC on one model, gated on a fail-closed guarantee and a documented fork path, and not adopt it as a platform dependency until the source audit clears.
How can I help you explore Laravel packages today?