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

Approval Laravel Package

cjmellor/approval

Approval is a Laravel package that provides a simple way to approve new Model data before it is persisted. Add an approval workflow to any Eloquent model, keeping unapproved changes out of your database until reviewed. Requires PHP 8.3+ and Laravel 12.4+.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Ship-vs-assemble for approval workflows. This package answers a recurring PM question — "do we build a moderation/approval queue from scratch again?" — with a ~1-day integration (composer require, publish migrations, add MustBeApproved to a model). That turns a multi-sprint build into a config-and-policy decision.
  • Feature scoping: single-state review queues. It cleanly supports one review gate per model (Pending → Approved/Rejected, plus configurable states like in_review, needs_info). Good fit for editorial publishing, marketplace listing review, user-profile/company-detail change review, supplier onboarding data, and any "dirty data is captured now, applied later" flow.
  • Roadmap sequencing for compliance and audit. original_data + new_data as JSON, audited_by, creator_id/creator_type, and rolled_back_at give an out-of-the-box audit trail. This can justify pulling an "auditability" epic forward without buying a GRC platform.
  • SLA and queue-hygiene policy decisions. Time-based approvals (expiresIn(hours: 24)->thenReject(), thenPostpone(), thenCustom()) plus approval:process-expired on a scheduler let you define policy — "unreviewed price changes auto-reject after 48h" — as a config value rather than an engineering project. Approval::expired() / hasExpiration() support ops dashboards.
  • Scoping which fields need review. protected array $approvalAttributes = ['name'] lets you make a product decision like "only display name and pricing changes require approval, bio edits are instant," and enforce it declaratively.
  • Escape hatches as product features. withoutApproval(), isApprovalBypassed(), and per-model getApprovalForeignKeyName() (e.g. author_id instead of user_id) support trusted-user fast paths and non-standard data models without forking.
  • Integration planning via events. ApprovalCreated, ModelApproved, ModelSetPending, ModelRejected, ModelRolledBack, ApprovalExpired define the seams where your notifications, Slack pings, and analytics hook in. That's roadmap input: notification delivery is explicitly out of scope and must be staffed.
  • Build-vs-buy on the "apply" step. The README is explicit: it stores proposed data, it does not approve for you. So the decision is really "buy the approval ledger, build the approval policy engine." Budget accordingly — the policy layer (who can approve what, and the code that actually mutates the model) is still yours.

When to Consider This Package

Adopt when most of these hold:

  • You're on Laravel 12.4+ or 13 and PHP 8.3+ (v2.1 dropped Laravel 11 — that's a hard gate, and it forces an upgrade decision).
  • You need one approval gate per model, keyed off Eloquent create/update events, and are fine with a polymorphic approvals table as the source of truth for pending change requests.
  • The value is in capturing the diff and the state machine; your team is happy to own the "apply the approved data" logic and the UI.
  • You want audit + rollback + expiry semantics without designing a schema: rollback(), rollback(bypass: false), conditional rollbacks, rolled_back_at.
  • You're a small-to-mid team optimizing for time-to-first-approval-queue and are comfortable with an MIT-licensed, single-maintainer dependency you can vendor or fork if needed.
  • You need a review queue quickly behind a feature flag, treating the package as a reversible bet.

Look elsewhere or plan to build when:

  • You need multi-step / sequential approvals (manager → finance → legal), quorum, or per-approver records. This package records one state per approval row; approval chains are not modeled.
  • You need RBAC-driven routing ("only finance can approve price changes"). Pair with spatie/laravel-permission — but recognize that authorization is entirely your build.
  • You need approvals on deletes, relationship changes, or bulk imports — the trait hooks model dirty attributes, not the full lifecycle.
  • Data integrity edge cases matter a lot: unique constraints, foreign keys to not-yet-existing parents, and validation on data that isn't persisted yet. Also verify exactly what happens to the original row on create vs. update before committing to user-facing copy.
  • You need versioned document comparison, rich-text diffs, or a review UI — you're buying a ledger, not a content platform.
  • Dependency risk tolerance is low. 374 stars, 0 dependents, solo maintainer, and a recent breaking major (v2 dropped Laravel 11 with an UPGRADE.md migration path) all point to "wrap it in an internal adapter interface" rather than letting it leak across the domain.
  • High write volume or strict latency budgets — every create/update writes a JSON row and fires events; measure before promising throughput.

How to Pitch It (Stakeholders)

To executives: We can stand up a review-and-approve workflow for [content / listings / profile changes] in days instead of a sprint or two, at zero license cost (MIT). It ships with the things audit and compliance will ask for later — a record of what changed, who changed it, who approved it, when it was rolled back, and automatic rejection of stale requests after a deadline. It's reversible: it's a Composer package behind an internal interface, so we can swap it out without touching product surfaces. The main non-negotiable is that it requires Laravel 12.4+; if we're behind on framework upgrades, that becomes the critical path, not the approval feature.

To engineering: Add the MustBeApproved trait to a model and every dirty attribute on create/update lands in a polymorphic approvals table as original_data/new_data JSON with a state enum — Pending, Approved, Rejected, plus configurable states. You get query scopes (approved(), pending()), transition helpers (approve(), rejectIf(), postponeUnless()), events for all state changes, rollback with re-approval control, and an approval:process-expired command for the scheduler. What you don't get: the authorization model, the "apply this data to the real model" logic, notifications, or any UI. Those are ours — so let's define an ApprovalPolicy service boundary now, restrict usage to explicitly declared $approvalAttributes, and avoid depending on Approval models outside that layer. Also budget the Laravel 12.4 upgrade and pin ^2.1, since v2 introduced schema changes and dropped Laravel 11.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource