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

Workflow Laravel Package

atannex/workflow

Atannex Workflow brings state-machine style workflow management to Laravel Eloquent models. Define states and transitions, attach guards and actions, and move records through approval or processing pipelines with events and a clean, testable API.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by confirming the runtime matrix before adding the dependency: PHP 8.3+ and Laravel 11 or 12 only. On older Laravel/PHP versions this package is not an option without an upgrade plan.

composer require atannex/workflow

Then follow the README setup flow closely. For a package like this, the first places to look are:

  1. Configuration and migrations — publish/configure the package as documented, then run migrations. The audit trail, tasks, approvals, deadlines, and timers almost certainly need persistence tables.
  2. Model integration — identify the trait/interface/base class the package expects on your Eloquent model. Add it to one small model first, not your whole domain.
  3. Workflow definition — find how states, transitions, guards, and automatic transitions are declared. Confirm whether definitions live in PHP, config, attributes, or database records.
  4. Task inbox API — locate how assigned tasks/approvals are queried for a user or team. This is the primary day-to-day developer and UI integration point.

A sensible first use case is a single linear workflow on a low-risk model, for example:

  • draft → submitted → approved → published
  • One guard on submit (required fields present, user has permission)
  • One guard on approve (approver is not the submitter)
  • Audit trail enabled and inspected after each transition

Do not start with multi-person approvals, escalation, and timers simultaneously. Get one state machine working end-to-end first, including tests, then layer on approvals and time-based behavior.

Implementation Patterns

Define workflows close to the model, but keep business rules out of guards

Use the package’s workflow definition mechanism to declare states and transitions, but keep guards thin. A guard should answer “is this transition allowed right now?” — not send mail, call external APIs, or mutate unrelated models. For heavier work, use model/domain events or listeners after a transition succeeds.

A practical split:

  • States: stable business stages (draft, in_review, approved, rejected, expired).
  • Transitions: named actions (submit, approve, reject, escalate, expire).
  • Guards: authorization, required data, separation-of-duties checks.
  • Side effects: notifications, integrations, projections, search indexing — after commit.

Wrap transitions in transactions and treat them as commands

Day-to-day usage should look like application commands:

DB::transaction(function () use ($document, $user) {
    $document->transitionTo('submitted', actor: $user);
});

Confirm the exact method names in the README. The important pattern is: one transition call per business action, inside a transaction, with the acting user explicitly passed where supported. This keeps the audit trail attributable and makes retries safer.

Use approvals for separation of duties, not general authorization

Multi-person approvals fit workflows where a single actor must not be able to complete a step alone. Model approval steps explicitly:

  • Who may approve: role, team, permission, or explicit assignee.
  • How many approvals are required.
  • Whether approvals are parallel or sequential.
  • What happens on rejection: return to previous state, terminate, or require rework.

Keep Laravel policies for “can this user interact with this record at all” and use workflow guards/approvals for “can this user complete this specific transition.” Mixing the two leads to duplicated and inconsistent permission logic.

Query task inboxes through scopes, not ad hoc joins

The task inbox is the feature end users will notice first. Build a dedicated query layer around it:

  • Inbox for current user.
  • Inbox for a team/role.
  • Overdue tasks.
  • Tasks awaiting my approval versus tasks assigned to me.
  • Completed/historical tasks for audit views.

If the package exposes query scopes or relation methods, wrap them in your own repository/service so the rest of the application does not depend directly on package internals. This also gives you one place to add tenant scoping, soft-delete filtering, and eager loading.

Run timers and deadlines through the scheduler and queue

Deadlines, escalation, timers, and automatic transitions imply background processing. Treat these as production infrastructure, not optional extras:

  • Ensure the Laravel scheduler runs every minute in every environment that needs escalation.
  • Run queue workers with supervision.
  • Use a dedicated queue for workflow timers if escalation is latency-sensitive.
  • Make timer processing idempotent: a timer that fires twice must not double-escalate or double-approve.
  • Log timer execution with the workflow/audit trail so operations can debug missed escalations.

A useful pattern is to keep automatic transitions declarative where possible and use queued jobs only for external side effects. Avoid hiding critical state changes inside jobs that may be delayed indefinitely.

Use the audit trail as an operational tool

The audit trail is not only for compliance. Use it for:

  • Customer support: “why is this record stuck in review?”
  • Debugging: which guard rejected the transition, and for which actor?
  • Reporting: time spent per state, approval latency, escalation frequency.
  • Testing: assert that a transition produced the expected audit entry.

Expose a read-only timeline in your admin UI rather than requiring developers to query package tables directly. That keeps the presentation stable if internal table names change.

Integrate at the edges

Good integration points for a workflow engine:

  • Events/listeners after transitions for notifications and integrations.
  • Policies for record-level access.
  • Form requests/validation before attempting a transition.
  • Jobs for slow side effects after commit.
  • API resources for exposing available transitions and inbox tasks to a frontend.

A useful frontend contract is: for a given record and user, return current state, available transitions, required approvals, and pending tasks. Build that as an application endpoint rather than letting the frontend infer workflow rules.

Gotchas and Tips

Version constraints are strict

PHP 8.3+ and Laravel 11/12 are non-negotiable. Check CI matrices, Docker images, and shared package constraints before adopting. A v1.0.0 release is stable by declaration, but a new package still deserves a spike branch and a rollback plan.

Concurrency is the main correctness risk

Two users may attempt transitions at the same time. Use database transactions and, where the package supports it, optimistic locking or row locks. Test the race explicitly:

  • Two approvers approve the final required step simultaneously.
  • A user submits while a timer escalates.
  • An admin force-transitions while an approval is pending.

If the package does not provide locking guarantees, add them at the application layer and document the boundary.

Guard side effects will bite you

Guards are often evaluated multiple times — during UI rendering, API responses, and the actual transition. Any guard that writes data, sends notifications, or calls external services will produce duplicate or premature side effects. Keep guards pure and cheap.

Time zones and deadlines

Deadlines and escalation are deceptively hard. Decide and document:

  • Are deadlines stored in UTC and displayed in the user’s timezone?
  • Do business hours affect escalation?
  • What happens to timers during daylight-saving changes?
  • Are deadlines extended when a record is reassigned?

Use Carbon::setTestNow() or Laravel’s time-travel helpers in tests, and write explicit tests for boundary conditions.

Automatic transitions can create loops

Automatic transitions and escalation rules can chain. A rejected approval that automatically returns to review, which immediately re-escalates, can create noisy loops. Add:

  • Maximum escalation counts.
  • Cooldowns between automatic transitions.
  • Terminal states that no timer can leave.
  • Monitoring for records that change state unusually often.

Audit volume and retention

A full audit trail grows quickly. Plan for retention, archival, and indexing from the start. At minimum, index by workflow subject, actor, transition, and timestamp. If audit entries are written synchronously in the same transaction, watch for write amplification on high-volume models.

Existing records need a backfill strategy

If you add workflow state to an existing table, every row needs an initial state. Do not rely on a nullable column and implicit defaults scattered through code. Write a migration/backfill that sets a known initial state, and make the application treat unknown states as an error rather than silently allowing transitions.

Inbox permissions are easy to get wrong

A task inbox must respect both workflow assignment and application authorization. A user may be the assigned approver but no longer have access to the record due to team changes, soft deletes, or tenant moves. Always join inbox queries back to your authorization layer, and test reassignment and revocation scenarios.

Extension points to identify early

Before building much on top of the package, locate and document:

  • How to add custom guards.
  • How to customize notifications or escalation actions.
  • Whether transition metadata can be stored.
  • How to override table names or model classes, if supported.
  • Whether workflow definitions are cached in production and how to clear that cache after deployment.

If definitions are cached, a deploy that changes states or transitions needs an explicit cache-clear step. Missing this is a common source of “works locally, broken in production” workflow bugs.

Testing strategy

Write tests at three levels:

  1. Definition tests — every state has an exit, every transition has a guard where needed, no unreachable states.
  2. Transition tests — allowed and denied paths, actor attribution, audit entries, side effects after commit.
  3. Time-based tests — deadlines, escalation, timers, automatic transitions, including duplicate timer execution.

Use RefreshDatabase, factories for workflow subjects, and time travel for deadlines. For inbox features, test as different users and teams, not only as an administrator.

Start narrow, then expand

The package covers a lot: states, guards, approvals, inboxes, deadlines, escalation, timers, automatic transitions, and audit. Adopt it incrementally. A single model with a simple state machine and audit trail is a good production pilot. Add multi-person approvals and escalation only after the basics are observable, tested, and understood by the team operating them.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo