PHPackages                             ovac/guardrails - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. ovac/guardrails

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

ovac/guardrails
===============

Operational approvals engine for Laravel applications.

v1.1.0(3mo ago)4474↑425%MITPHPPHP ^8.2CI failing

Since Sep 19Pushed 3mo agoCompare

[ Source](https://github.com/ovac/guardrails)[ Packagist](https://packagist.org/packages/ovac/guardrails)[ Docs](https://github.com/ovac/guardrails)[ GitHub Sponsors](https://github.com/ovac4u)[ RSS](/packages/ovac-guardrails/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (8)Versions (5)Used By (0)

Guardrails
==========

[](#guardrails)

```
              Follow me anywhere @ovac4u                         | GitHub
              _________                          _________       | Twitter
             |   ___   |.-----.--.--.---.-.----.|  |  |.--.--.   | Facebook
             |  |  _   ||  _  |  |  |  _  |  __||__    |  |  |   | Instagram
             |  |______||_____|\___/|___._|____|   |__||_____|   | Github + @ovac
             |_________|                        ovac.github.io   | Facebook + @ovacposts
```

 [![](https://camo.githubusercontent.com/bd19274b6f5c17fccda6394e6e3c96831ad26a49745be2b3ee47ff7fe914de71/68747470733a2f2f7265732e636c6f7564696e6172792e636f6d2f6f7661632f696d6167652f75706c6f61642f685f35302c775f36302c635f66696c6c2f76313530363833323939322f6c61726176656c2d6c6f676f5f61746c7666772e706e67)](#)

 [![Total Downloads](https://camo.githubusercontent.com/5618f73889022ea095fc2cd6880fc77a534301c28766cb545e5fc1428c8316cc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6f7661632f67756172647261696c732e737667)](https://packagist.org/packages/ovac/guardrails) [![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE) [![Tests](https://github.com/ovac/guardrails/actions/workflows/run-tests.yml/badge.svg)](https://github.com/ovac/guardrails/actions/workflows/run-tests.yml) [![PHP](https://camo.githubusercontent.com/77c688e6a661306d31b301f3a9a0e83289e07d4096fbce377928c0fc0c603878/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d3737374242333f6c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/77c688e6a661306d31b301f3a9a0e83289e07d4096fbce377928c0fc0c603878/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d3737374242333f6c6f676f3d706870266c6f676f436f6c6f723d7768697465) [![Laravel](https://camo.githubusercontent.com/c164fc284fdd9f0bfb8756072091c7595dd322c22b8b0293fab426a7af8d8559/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d3131253246313225324631332d4646324432303f6c6f676f3d6c61726176656c266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/c164fc284fdd9f0bfb8756072091c7595dd322c22b8b0293fab426a7af8d8559/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d3131253246313225324631332d4646324432303f6c6f676f3d6c61726176656c266c6f676f436f6c6f723d7768697465)

What is Guardrails?
-------------------

[](#what-is-guardrails)

Guardrails is an operational approvals engine for Laravel. Capture every high‑risk change, route it through the right reviewers, and apply the update only after the required signatures land. You decide which attributes are guarded, who can approve, and how many voices it takes to ship a change.

### Why teams reach for Guardrails

[](#why-teams-reach-for-guardrails)

- **Protect critical workflows** – turn dangerous writes into reviewable approval requests without rewriting business logic.
- **Model or controller first** – opt in with an Eloquent trait or intercept at the edge of your HTTP layer.
- **Fluent, composable flows** – stack steps, mix roles and permissions, count initiators, and codify escalation in code.
- **Complete toolkit** – ships with migrations, API routes, reviewer UI, and exhaustive docs so you can go live quickly.
- **Laravel-native** – PHP 8.2+, Laravel 11/12/13, works with Spatie permissions or Sanctum token abilities out of the box.

### How it fits together

[](#how-it-fits-together)

1. Mark attributes as guarded or intercept controller payloads.
2. Use `Flow::make()` / `FlowBuilder` to describe who can sign each step.
3. Guardrails persists the request (`requests → steps → signatures`) and emits events as people approve or reject.
4. Once the final step meets its threshold, Guardrails applies the captured changes to your model for you.

Quickstart
----------

[](#quickstart)

Online Docs &amp; Tools
-----------------------

[](#online-docs--tools)

- Full documentation:
- Interactive Playground (flow builder):
- AI Assistant (BYO API key, grounded in docs):

Install via Composer:

```
composer require ovac/guardrails
```

1. Register the service provider (if not auto‑discovered):

```
// config/app.php
OVAC\Guardrails\GuardrailsServiceProvider::class,
```

2. Publish assets:

```
php artisan vendor:publish --provider="OVAC\\Guardrails\\GuardrailsServiceProvider" --tag=guardrails-config
php artisan vendor:publish --provider="OVAC\\Guardrails\\GuardrailsServiceProvider" --tag=guardrails-migrations
php artisan vendor:publish --provider="OVAC\\Guardrails\\GuardrailsServiceProvider" --tag=guardrails-views
php artisan vendor:publish --provider="OVAC\\Guardrails\\GuardrailsServiceProvider" --tag=guardrails-assets
php artisan vendor:publish --provider="OVAC\\Guardrails\\GuardrailsServiceProvider" --tag=guardrails-docs
```

3. Run migrations:

```
php artisan migrate
```

60‑Second Example
-----------------

[](#60second-example)

Guard a model and require a quick two‑man rule (initiator + one peer):

```
use OVAC\Guardrails\Concerns\Guardrail;
use OVAC\Guardrails\Services\Flow;

class Post extends Model
{
    use Guardrail;

    public function guardrailAttributes(): array
    {
        return ['published'];
    }

    public function guardrailApprovalDescription(array $dirty, string $event): string
    {
        return 'Publish flag changes require editorial approval.';
    }

    public function guardrailApprovalFlow(array $dirty, string $event): array
    {
        return [
            Flow::make()
                ->anyOfPermissions(['content.publish'])
                ->includeInitiator(true, true)
                ->signedBy(2, 'Editorial Review')
                ->build(),
        ];
    }
}
```

When the initiator supplies a justification (for example through a form field), pass it into the guardrails context before saving:

```
$post->guardrails()
    ->description($request->input('approval_description'))
    ->meta(['reason_code' => $request->input('reason_code')]);

$post->fill($request->validated())->save();
```

Prefer controllers? Intercept without touching models:

```
$result = $this->guardrailIntercept($post, ['published' => true], [
    'description' => 'Editorial approval required before publishing.',
    'only' => ['published'],
    'extender' => Flow::make()->anyOfRoles(['editor','managing_editor'])->signedBy(1, 'Editorial Approval'),
]);
```

### Configurable controller flows (no code changes)

[](#configurable-controller-flows-no-code-changes)

Keep controllers tiny and let ops override steps from `config/guardrails.php`. The helper will (a) look for `guardrails.flows..`, (b) fall back to your coded flow when missing, and (c) merge handy meta defaults (like `summary`/`hint`) onto every step.

```
// config/guardrails.php
'flows' => [
    'posts' => [
        'publish' => [
            [
                'name' => 'Editorial Approval',
                'threshold' => 1,
                'signers' => [
                    'guard' => 'web',
                    'permissions' => ['content.publish'],
                    'permissions_mode' => 'any',
                    'roles' => [],
                    'roles_mode' => 'all',
                ],
                'meta' => [
                    'include_initiator' => false,
                    'preapprove_initiator' => true,
                    'hint' => 'Editor must sign off before publishing.',
                ],
            ],
        ],
    ],
],
// or flatten the key if you prefer:
// 'flows' => ['posts.publish' => [[ /* steps */ ]]],
// single-step shorthand is also valid (no extra brackets):
// 'flows' => [
//     'posts.publish' => [
//         'name' => 'Editorial Approval',
//         'threshold' => 1,
//         'signers' => ['guard' => 'web', 'permissions' => ['content.publish']],
//     ],
// ],
```

```
// Controller
use OVAC\Guardrails\Services\Flow;

// Resolve "posts.publish" flow: config first, fallback to code, merge meta defaults.
$flow = $this->guardrailFlow(
    'posts.publish',
    Flow::make()->anyOfPermissions(['content.publish'])->includeInitiator(true, true)->signedBy(2, 'Editorial Approval')->build(),
    ['summary' => 'Publish request for '.$post->title]
);

$result = $this->guardrailIntercept($post, ['published' => true], [
    'description' => 'Editorial approval required before publishing.',
    'flow' => $flow,
]);
```

Why Teams Use It
----------------

[](#why-teams-use-it)

- Approval confidence for critical data while keeping code changes small.
- Human-readable flow rules with real-world patterns (two-man rule, peer review, escalation).
- Works with your auth today — Spatie permissions if present, token abilities otherwise.

Use Cases (with examples)
-------------------------

[](#use-cases-with-examples)

1. Publish a blog post — one more editor must approve

```
Flow::make()
  ->anyOfPermissions(['content.publish'])    // any editor with publish permission
  ->includeInitiator(true, true)            // author counts as one approval
  ->signedBy(2, 'Editorial Review')          // needs one more editor
  ->build();
```

2. Delete a user account — two steps, different roles

```
Flow::make()
  ->anyOfRoles(['support_lead'])             // support lead approves first
  ->signedBy(1, 'Support Approval')
  ->anyOfRoles(['security_officer'])         // then security approves
  ->signedBy(1, 'Security Approval')
  ->build();
```

3. Refund an order — one of finance OR operations

```
Flow::make()
  ->anyOfRoles(['finance_manager','ops_manager'])
  ->signedBy(1, 'Management Approval')
  ->build();
```

4. Sensitive setting change — peer with same permission must co‑sign

```
Flow::make()
  ->permissions(['settings.update'])       // list all required permissions
  ->requireAnyPermissions()                // switch to any‑of
  ->samePermissionAsInitiator(true)        // peer must share at least one
  ->includeInitiator(true, true)           // initiator pre‑approved
  ->signedBy(2, 'Peer Review')
  ->build();
```

5. Multi‑step escalation — ops first, then execs

```
Flow::make()
  ->anyOfPermissions(['ops.change'])
  ->includeInitiator(true, true)
  ->signedBy(2, 'Ops Review')
  ->anyOfRoles(['cto','cfo'])
  ->signedBy(1, 'Executive Sign‑off')
  ->build();
```

API (3 endpoints)
-----------------

[](#api-3-endpoints)

- GET `/{route_prefix}` — list pending approval requests with steps/signatures.
- POST `/{route_prefix}/{request}/steps/{step}/approve` — approve a step.
- POST `/{route_prefix}/{request}/steps/{step}/reject` — record a rejection signature.

UI
--

[](#ui)

A minimal page at `/{page_prefix}` consumes the API for reviewers. Publish and customize the Blade view.

Docs
----

[](#docs)

- Start here: [Documentation Index](resources/docs/README.md)
- Or publish locally: `php artisan vendor:publish --provider="OVAC\\Guardrails\\GuardrailsServiceProvider" --tag=guardrails-docs` (to `docs/guardrails`).

Highlights worth reading next:

- [Organization Playbook](resources/docs/organization-playbook.md)
- [Use Cases](resources/docs/use-cases.md)
- [Advanced Flows (dynamic/risk‑based)](resources/docs/advanced.md)
- [Voting Models](resources/docs/voting-models.md)
- [Auditing &amp; Changelog](resources/docs/auditing-and-changelog.md)
- [Custom Controllers](resources/docs/custom-controllers.md)
- [External Signing (DocuSign/DocuSeal)](resources/docs/external-signing.md)
- [Email &amp; SMS Verification](resources/docs/verification-examples.md)
- [Ideas &amp; Examples (10)](resources/docs/ideas-and-examples.md)
- [Extending Models &amp; Migrations](resources/docs/extending-models-and-migrations.md)
- [Full Testing Guide](resources/docs/testing-full.md)

How It Works (Data Flow)
------------------------

[](#how-it-works-data-flow)

 ```
flowchart TD
  Start[Change attempted] --> Guard{Guardrails guard?}
  Guard -- No --> ApplyNow[Apply change immediately]
  Guard -- Yes --> Capture[Capture request and steps]
  Capture --> Review{Reviewer decision}
  Review -- Approve --> Apply[Apply new data]
  Review -- Reject --> Halt[Reject request]
  Apply --> Done[Emit completion events]
  Halt --> Done
```

      Loading Keep approvals close to where changes happen (models) or intercept in controllers. Steps define who can sign and how many signatures you require.

Extending Migrations and Models
-------------------------------

[](#extending-migrations-and-models)

- Add columns to the published migrations (e.g., reason, category, workspace\_id) with a new migration; the package models use `$guarded = []`, so new attributes are writable.
- If you need JSON casting or extra relations, create an app model that extends the package model:

```
// app/Models/ApprovalRequest.php
namespace App\Models;

class ApprovalRequest extends \OVAC\Guardrails\Models\ApprovalRequest
{
    protected $casts = [
        'meta' => 'array',
        'reason' => 'string',
    ];

    public function workspace()
    {
        return $this->belongsTo(Workspace::class);
    }
}
```

Use events like `ApprovalRequestCaptured` to populate new columns or meta. See [Config Recipes](resources/docs/config-recipes.md) and [Auditing &amp; Changelog](resources/docs/auditing-and-changelog.md).

Search keywords: "laravel approval workflow", "laravel multi signature approvals", "human in the loop approvals", "laravel model guarded changes", "laravel approval steps thresholds", "spatie permissions approval flow", "controller intercept approvals", "two-man rule laravel".

Documentation Website
---------------------

[](#documentation-website)

Guardrails ships build scripts instead of doc sources so the Composer install stays slim. The GitHub Pages deployment uses `scripts/docs-site/build-docs-site.js` to assemble a Docusaurus bundle from `resources/docs` on demand.

- Generate a local bundle with `node scripts/docs-site/build-docs-site.js ./build/docs-site` (requires Node 20+). When previewing locally, open `http://localhost:3000/guardrails/` after running `npx serve ./build/docs-site`. For a root-based preview, run `DOCS_BASE_URL=/ node scripts/docs-site/build-docs-site.js ./build/docs-site-local && npx serve ./build/docs-site-local`.
- Configure optional environment variables (`DOCS_SITE_URL`, `DOCS_BASE_URL`, `DOCS_REPOSITORY_URL`, `DOCS_PACKAGIST_URL`) to tune canonical URLs and metadata. Defaults infer the correct GitHub Pages paths from the current repository.
- The published site exposes `/playground` and `/assistant` routes for the interactive flow builder and BYO-key AI chat, both running entirely in the browser.
- Tags that start with `v` automatically generate frozen documentation snapshots so visitors can browse historical releases.
- `.github/workflows/docs-site.yml` runs on every push and tag, rebuilding the static site and deploying it to GitHub Pages (`gh-pages` branch).

Tests &amp; Coverage
--------------------

[](#tests--coverage)

Run the full suite with Pest (quiet mode by default):

```
composer test
```

Generate coverage locally when you need instrumentation or Clover output for CI:

```
composer test:coverage
composer test:ci # emits coverage.xml
```

See the [Full Testing Guide](resources/docs/testing-full.md) for environment setup, Laravel Testbench tips, and additional testing recipes.

Support
-------

[](#support)

If this package saves you time, please consider:

- Starring the repo:
- Sponsoring on GitHub:

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance82

Actively maintained with recent releases

Popularity22

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~48 days

Total

4

Last Release

97d ago

PHP version history (2 changes)v1.0.0PHP ^8.1

v1.1.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/805b47d522cbd469b4ce2cdc5f6cf1df088b54bd995d2cfce91fca02b9527765?d=identicon)[ovac](/maintainers/ovac)

---

Top Contributors

[![ovac](https://avatars.githubusercontent.com/u/5038672?v=4)](https://github.com/ovac "ovac (1 commits)")

---

Tags

approval-workflowsapprovalsguardguardrailslaravel-approvalsoperational-approvalsphpplaygroundlaravelworkflowhuman-in-the-loopmoderationapprovalsguardrails

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ovac-guardrails/health.svg)

```
[![Health](https://phpackages.com/badges/ovac-guardrails/health.svg)](https://phpackages.com/packages/ovac-guardrails)
```

###  Alternatives

[brexis/laravel-workflow

Integerate Symfony Workflow component into Laravel.

283125.6k](/packages/brexis-laravel-workflow)[ringierimu/state-workflow

Laravel State Workflow provide tools for defining and managing workflows and activities with ease.

3251.1k](/packages/ringierimu-state-workflow)[diego-ninja/sentinel

A content moderation and sentiment analysis library for Laravel 10+

384.3k](/packages/diego-ninja-sentinel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
