coringawc/filament-action-approvals
Filament Action Approvals adds configurable approval workflows to Filament actions, letting users submit, approve, or reject requests with multi-step chains, role-based permissions, and audit history. Integrates directly into your existing Filament resources and actions.
The package adds a maker–checker (approval) workflow to Filament actions: instead of executing immediately, an action creates a pending approval record, and an authorised approver later approves or rejects it.
composer require coringawc/filament-action-approvals
php artisan vendor:publish --tag="filament-action-approvals-migrations"
php artisan migrate
Publish the config tag too if you need to change table names, approver resolution, or notification behaviour.config/filament-action-approvals.php — the model/table names, approver resolution, and notification classes.DeleteAction, a refund, a "force sync", a status transition. Gate it behind approval, submit one as a normal user, then approve it as a second user and confirm the side effect only happens on approval.php artisan boost:install (or re-run it) so your assistant picks up the package's trait, config, and action-API conventions. This is developer tooling only — it has no runtime effect.Start with one high-risk action, not everything. Wire approval onto a single action, verify the full round trip (submit → notify → approve → side effect → audit row), then roll out. Retrofitting approvals across a whole panel at once makes failures hard to attribute.
Capture intent, execute later. The approval row should record enough to replay the action (subject type + key, action identifier, scalar arguments). Keep the decision data in the record and the execution logic in your action class — don't put business logic in the approval handler.
Two separate authorisations. Model them as distinct gates/policies: canRequestApproval (usually your normal resource update permission) and canApprove (a supervisor/ops role). Separation of duties is the whole point — enforce "requester ≠ approver" explicitly if your compliance context requires it, since it is not always the default.
Approver workflow UI. Either surface pending approvals as a dedicated Filament page/resource with a status filter and nav badge, or as a relation manager on the subject record ("Approvals" tab). The resource approach suits central ops teams; the relation-manager approach suits record owners. Many teams ship both, sharing one query scope.
Notifications are part of the contract. Queue submission, approval, and rejection notifications. In tests, use Notification::fake() and assert the right people were notified — silent approvals are the most common production complaint.
Reuse the same service outside Filament. Scheduled jobs, artisan commands, and API endpoints should create approvals through the same entry point as the Filament action, so the audit trail is uniform. Don't hand-insert rows into the approvals table.
Testing pattern. Two assertions per case:
// submitting does not perform the side effect
livewire(ManageOrders::class)->callTableAction('refund', $order);
$this->assertDatabaseHas('approvals', ['status' => 'pending']);
$this->assertNull($order->fresh()->refunded_at);
// approving does
$this->actingAs($supervisor);
// approve via the package's UI/service
$this->assertNotNull($order->fresh()->refunded_at);
migrate, not after. On existing apps, check for a table-name collision (approvals is generic) and override it in config before running.php artisan config:clear (and on deployed environments, a fresh config:cache).laravel.log for replay exceptions, queue workers running for notifications, and the panel provider registration. Those four cover most "it didn't work" reports.How can I help you explore Laravel packages today?