PHPackages                             wundii/flowcrafter - 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. wundii/flowcrafter

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

wundii/flowcrafter
==================

PHP library for defining, executing, and monitoring message-driven workflows (state machines)

0.24.6(3w ago)2106↑100%MITPHPPHP &gt;=8.2CI failing

Since Apr 12Pushed 2w agoCompare

[ Source](https://github.com/wundii/flowcrafter)[ Packagist](https://packagist.org/packages/wundii/flowcrafter)[ RSS](/packages/wundii-flowcrafter/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (10)Dependencies (141)Versions (45)Used By (0)

flowcrafter
===========

[](#flowcrafter)

[![PHP-Tests](https://camo.githubusercontent.com/d6a8da57a14635e30f4a60326178b9c4582bdb955c576fa99f52268304511545/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f77756e6469692f666c6f77637261667465722f636f64655f7175616c6974792e796d6c3f6272616e63683d6d61696e267374796c653d666f722d7468652d6261646765)](https://github.com/wundii/flowcrafter/actions/workflows/code_quality.yml)[![PHPStan](https://camo.githubusercontent.com/e15d364c7c0af383f9784d4af8419c1fcd87fbb5b44f0d48e32ce327be958008/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c25323031302d627269676874677265656e2e7376673f7374796c653d666f722d7468652d6261646765)](https://phpstan.org/)[![VERSION](https://camo.githubusercontent.com/703cf06471042fc928d72ec5d7e38841130005b29089475b14b4771e9bbb53fa/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f77756e6469692f666c6f77637261667465723f7374796c653d666f722d7468652d6261646765)](https://camo.githubusercontent.com/703cf06471042fc928d72ec5d7e38841130005b29089475b14b4771e9bbb53fa/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f77756e6469692f666c6f77637261667465723f7374796c653d666f722d7468652d6261646765)[![PHP](https://camo.githubusercontent.com/d374dcedf34393fedd265e8a1e046f289f2763a8a3e2ed276423f6cd5ded724a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f77756e6469692f666c6f77637261667465723f7374796c653d666f722d7468652d6261646765)](https://www.php.net/)[![Rector](https://camo.githubusercontent.com/bd6dd5b52a4347de5aa8bd284d980f474d87da595a4c90d3300b9645c2bcbf7f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f526563746f722d382e322d626c75652e7376673f7374796c653d666f722d7468652d6261646765)](https://getrector.com)[![ECS](https://camo.githubusercontent.com/0f7ade62b75eb86dd60ed170f954932994f60c2b4678e94ad0c7a892d31d77b8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4543532d636865636b2d626c75652e7376673f7374796c653d666f722d7468652d6261646765)](https://tomasvotruba.com/blog/zen-config-in-ecs)[![PHPUnit](https://camo.githubusercontent.com/729283066c222d92f175922debb3efc12d423e06e2880f6cc08e9c8601764ff3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d2d556e69742d636865636b2d626c75652e7376673f7374796c653d666f722d7468652d6261646765)](https://phpunit.org)[![codecov](https://camo.githubusercontent.com/fb0da8ebfb134de4cb31c415edb75e575bc0a8bdd2b74ccc187293414a081ecf/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f77756e6469692f666c6f77637261667465722f6d61696e3f746f6b656e3d544e43324d4d304d5753267374796c653d666f722d7468652d6261646765)](https://codecov.io/github/wundii/flowcrafter)[![Downloads](https://camo.githubusercontent.com/c7c07bbdce4b58e0abfe4f77558bc53c685ab638eada34b4d37633ddf3dbb3c3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f77756e6469692f666c6f77637261667465722e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/wundii/flowcrafter)

> **PHP-Engine für message-driven Workflows** — Geschäftsprozesse als typsichere State Machines in reinem PHP, mit synchroner, asynchroner und zeitgesteuerter Ausführung und lückenlosem Audit-Log.

Ein Workflow besteht aus typisierten **Messages**, die zwischen **Steps** fließen. Das Routing schreibt man nicht — es ergibt sich aus den Constructor-Signaturen der Steps: Welche Message ein Step im Constructor verlangt, bestimmt, wann er läuft. Daraus entsteht ein typsicherer DAG, der sich versionieren, ausführen und in Echtzeit überwachen lässt. Kein YAML, kein XML, keine Annotations.

Features
--------

[](#features)

- **Schema-as-Code** — Workflows als PHP-Klassen, Routing direkt aus den Step-Constructors abgeleitet
- **Drei Ausführungsmodi** — synchron (`FlowRunner`), asynchron über Queue (`FlowObserver`) und zeitgesteuert per Cron (`FlowScheduler`)
- **Read-Model-Projektionen** — Handler reagieren asynchron auf einzelne Messages (`ProjectionWorker`)
- **Pluggable Storage** — MySQL, Redis, EventSourcingDB; eigene Backends via `StorageInterface`
- **Lückenloses Audit-Log** — jede Message, Exception und Statusänderung wird erfasst, Schemas via Hash versioniert
- **Automatischer Retry** — pro Step konfigurierbare Wiederholungen bei transienten Fehlern
- **Observability** — REST-API, Prometheus/OpenMetrics-Endpunkt und optionales [Web-UI](#web-ui)
- **Developer Experience** — Console Commands, storageless Testing, Mermaid-Diagramme und [Claude-Code-Plugin](#claude-code-plugin)

Installation
------------

[](#installation)

```
composer require wundii/flowcrafter
```

Quickstart
----------

[](#quickstart)

```
vendor/bin/flowcrafter config:create   # 1. flowcrafter.php anlegen
vendor/bin/flowcrafter storage:init    # 2. Storage initialisieren
vendor/bin/flowcrafter dev             # 3. Dev-Server starten (API + Observer + Scheduler + Projection-Worker)
```

Schritt für Schritt: [docs/getting-started.md](docs/getting-started.md).

Beispiel
--------

[](#beispiel)

Ein vollständiger Order-Flow in drei Bausteinen — Messages, Steps, Flow.

### 1. Messages

[](#1-messages)

`readonly` Value-Objects. Drei Typen steuern das Routing: `Init` startet den Flow, `Data` fließt zwischen Steps, `Return` beendet ihn.

```
use Wundii\Flowcrafter\AbstractMessage;
use Wundii\Flowcrafter\Interface\MessageDataInterface;
use Wundii\Flowcrafter\Interface\MessageInitInterface;
use Wundii\Flowcrafter\Interface\MessageReturnInterface;

readonly class OrderInit extends AbstractMessage implements MessageInitInterface
{
    public function __construct(private string $sku) {}
    public function getSku(): string { return $this->sku; }
}

readonly class OrderValidated extends AbstractMessage implements MessageDataInterface
{
    public function __construct(private string $sku, private int $quantity) {}
    public function getSku(): string { return $this->sku; }
    public function getQuantity(): int { return $this->quantity; }
}

readonly class OrderCompleted extends AbstractMessage implements MessageReturnInterface
{
    public function __construct(private string $summary) {}
    public function getSummary(): string { return $this->summary; }
}
```

> Braucht der erste Step keinen externen Input, gibt es die mitgelieferte `Wundii\Flowcrafter\EmptyInitMessage` statt einer eigenen Init-Klasse.

### 2. Steps

[](#2-steps)

Reine PHP-Klassen. Der Constructor-Typ entscheidet das Routing, der Rückgabetyp den weiteren Verlauf: `MessageData` (Flow läuft weiter), `MessageReturn` (Flow endet) oder `bool` (Leaf-Result, kein Weiterleiten).

```
use Wundii\Flowcrafter\Interface\MessageDataInterface;
use Wundii\Flowcrafter\Interface\MessageReturnInterface;
use Wundii\Flowcrafter\Interface\StepInterface;

class ValidateStep implements StepInterface          // Init → Data
{
    public function __construct(private readonly OrderInit $init) {}

    /** @return class-string[] */
    public function returnTypes(): array { return [OrderValidated::class]; }

    public function process(): MessageDataInterface
    {
        return new OrderValidated($this->init->getSku(), quantity: 1);
    }
}

class CompleteOrderStep implements StepInterface     // Data → Return (beendet den Flow)
{
    public function __construct(private readonly OrderValidated $validated) {}

    /** @return class-string[] */
    public function returnTypes(): array { return [OrderCompleted::class]; }

    public function process(): MessageReturnInterface
    {
        return new OrderCompleted(sprintf(
            'Order %s x%d completed',
            $this->validated->getSku(),
            $this->validated->getQuantity(),
        ));
    }
}

class AuditStep implements StepInterface             // Data → bool (FlowResult)
{
    public function __construct(private readonly OrderValidated $validated) {}

    /** @return class-string[] */
    public function returnTypes(): array { return []; }

    public function process(): bool
    {
        return $this->validated->getQuantity() > 0;
    }
}
```

### 3. Flow

[](#3-flow)

Das Schema entsteht via `FlowBuilder`. Hier konsumieren `CompleteOrderStep` und `AuditStep` dieselbe `OrderValidated`-Message — also laufen sie parallel.

```
use Wundii\Flowcrafter\Attribute\FlowGroup;
use Wundii\Flowcrafter\FlowBuilder;
use Wundii\Flowcrafter\FlowSchema;
use Wundii\Flowcrafter\Interface\FlowInterface;

#[FlowGroup('Order Management')]   // optionale UI-Gruppierung, ohne Einfluss auf den Schema-Hash
class OrderFlow implements FlowInterface
{
    public static function schema(): FlowSchema
    {
        $builder = new FlowBuilder('flow.order.v1', OrderInit::class, OrderCompleted::class);
        $builder->addStep(ValidateStep::class);
        $builder->addStep(CompleteOrderStep::class, retries: 3, delay: 500);
        $builder->addStep(AuditStep::class);
        return $builder->build();
    }
}
```

Das passende Diagramm liefert `vendor/bin/flowcrafter diagram:mermaid App\\OrderFlow`:

 ```
---
title: flow.order.v1
theme: neo
---
stateDiagram-v2
[*]-->ValidateStep: OrderInit
ValidateStep-->CompleteOrderStep: OrderValidated
ValidateStep-->AuditStep: OrderValidated
CompleteOrderStep-->[*]: OrderCompleted
```

      Loading Flows auslösen
--------------

[](#flows-auslösen)

**Synchron** — direkter Aufruf, Ergebnis sofort verfügbar:

```
use Wundii\Flowcrafter\FlowRunner;

$flowRunner = new FlowRunner(
    type: 'flow.order.v1',
    flowSource: OrderFlow::class,
    flowSubject: 'sku-42',   // optionaler Geschäfts-Key zur späteren Suche
    storage: $storage,       // aus $flowcrafterConfig->getStorage()
);

$result = $flowRunner->run(new OrderInit('sku-42'));   // MessageReturnInterface|bool
```

**Asynchron** — Message in die Queue legen, ein `FlowObserver`-Worker führt sie aus:

```
$queue = $flowcrafterConfig->getQueue();

$queue->appendObserveItem(
    type: 'flow.order.v1',
    flowSource: OrderFlow::class,
    flowHash: null,                 // null = neuer Flow, sonst Re-Run einer bestehenden Instanz
    messageSource: OrderInit::class,
    message: (new OrderInit('sku-42'))->jsonSerialize(),
    flowSubject: 'sku-42',
);
```

**Zeitgesteuert** — Schedule-Klasse mit Cron-Ausdruck, automatisch vom `FlowScheduler` aus dem Composer-Classmap entdeckt:

```
use Wundii\Flowcrafter\Attribute\FlowSchedule;
use Wundii\Flowcrafter\Schedule\AbstractSchedule;

#[FlowSchedule('0 */6 * * *', name: 'order-cleanup', group: 'Maintenance')]
class OrderCleanupSchedule extends AbstractSchedule
{
    public function process(): void
    {
        $this->enqueue(OrderFlow::class, new OrderInit('scheduled-cleanup'));
        // oder synchron: $this->run(...)
    }
}
```

Per REST-API geht es auch: `POST /api/flow/flow-run` (synchron) bzw. `POST /api/queue/enqueue` (async) — siehe [docs/api.md](docs/api.md).

Weitere Funktionen
------------------

[](#weitere-funktionen)

### Step Retry

[](#step-retry)

Steps können bei transienten Fehlern automatisch wiederholt werden — konfiguriert pro Step über `addStep(retries:, delay:)`. `retries: 3` bedeutet ein Erstversuch plus drei Wiederholungen; die Retry-Konfiguration fließt in den Schema-Hash ein.

```
$builder->addStep(ExternalApiStep::class, retries: 3);             // 3 Versuche, 200 ms Delay (default)
$builder->addStep(SlowServiceStep::class, retries: 5, delay: 500); // 5 Versuche, 500 ms Delay
```

### Read-Model-Projektionen

[](#read-model-projektionen)

Projection-Handler reagieren **asynchron** auf einzelne Messages eines Flows — ideal für Read Models, Benachrichtigungen oder Side-Effects. Jede Methode wird per `#[FlowProjectionMessage]` an einen Message-Source gebunden, die Klasse per `#[FlowProjection]` an einen oder mehrere Flow-Typen. Handler werden automatisch aus dem Composer-Classmap entdeckt und vom `ProjectionWorker`(`vendor/bin/flowcrafter projection:worker`) abgearbeitet.

```
use Wundii\Flowcrafter\Attribute\FlowProjection;
use Wundii\Flowcrafter\Attribute\FlowProjectionMessage;
use Wundii\Flowcrafter\FlowMessageReadonly;
use Wundii\Flowcrafter\Interface\ProjectionHandlerInterface;

#[FlowProjection(['flow.order.v1'])]
class OrderProjection implements ProjectionHandlerInterface
{
    #[FlowProjectionMessage(OrderCompleted::class)]
    public function onCompleted(FlowMessageReadonly $message): void
    {
        // Read Model aktualisieren, Benachrichtigung verschicken, ...
    }
}
```

Die Zustellung ist **at-least-once** — Handler-Methoden müssen idempotent sein. Wirft eine Methode, wird die Exception als `ProjectionException` protokolliert und mit der nächsten Message weitergemacht; die Queue blockiert nicht.

### Dependency Injection

[](#dependency-injection)

Steps erhalten neben Messages auch externe Services per Constructor-Injection. Registriert werden sie über eine `DependencyRegistry` (per `FlowcrafterConfig::setDependencyRegistry()` bzw. im Konstruktor von `FlowRunner`, `FlowScheduler`, `FlowObserver`, `ProjectionWorker`). Jede Registrierungsart ist eine benannte Methode:

MethodeVerhalten`instance(object)`Konkrete Instanz, gebunden an die eigene Klasse`bind(string $id, object|class)`Interface-Binding: Objekt → synthetic + Alias; class-string → autowire + Alias`autowire(class)`Einzelklasse per Autowiring`autowireNamespace(string)`Alle instanziierbaren Klassen unter einem PSR-4-Namespace`autowireDirectory(string)`Alle instanziierbaren Klassen unter einem Verzeichnis`factory(class, Closure, ?alias)`Lazy: Closure erhält den PSR-11-Container und liefert den Service```
use Wundii\Flowcrafter\DependencyInjection\DependencyRegistry;
use Wundii\Flowcrafter\Env;
use Psr\Container\ContainerInterface;

$registry = (new DependencyRegistry())
    ->bind(HttpClientInterface::class, new CurlHttpClient())  // Interface → Instanz
    ->instance(new MyLogger())                                // Instanz ohne Interface
    ->autowireNamespace('App\\Service')                       // ganze Namespaces autowiren
    ->factory(ApiClient::class,                               // lazy, für rohe Skalare
        fn(ContainerInterface $c) => new ApiClient($c->get(HttpClientInterface::class), Env::string('API_KEY')),
    );

$flowRunner = new FlowRunner(
    type: 'flow.order.v1',
    flowSource: OrderFlow::class,
    storage: $storage,
    dependencyRegistry: $registry,
);
```

### Testing

[](#testing)

Storageless mit `FlowTestCase` — kein Docker nötig. Vollständiger Leitfaden: [docs/testing.md](docs/testing.md).

```
use Wundii\Flowcrafter\Testing\FlowTestCase;

final class OrderFlowTest extends FlowTestCase
{
    public function testHappyPath(): void
    {
        $this->runFlow(
            flowType: 'flow.order.v1',
            flowSource: OrderFlow::class,
            initMessage: new OrderInit('sku-42'),
        );

        $this->assertFlowOk();
        $this->assertStepExecuted(CompleteOrderStep::class);
        $this->assertFlowBoolResult(true);   // AuditStep lieferte true

        $return = $this->assertFlowReturned(OrderCompleted::class);
        $this->assertSame('Order sku-42 x1 completed', $return->getSummary());
    }
}
```

Web-UI
------

[](#web-ui)

Das optionale Frontend [FlowCrafter UI](https://github.com/wundii/flowcrafter-ui) visualisiert Flows, Messages, Exceptions, Schedules und Queues in Echtzeit:

```
docker run -p 5173:5173 -v ./data:/flowcrafter/data wundii/flowcrafter-ui:latest
```

  ![Overview](https://raw.githubusercontent.com/wundii/flowcrafter-ui/refs/heads/main/assets/01-overview.png)

  ![Flow Detail](https://raw.githubusercontent.com/wundii/flowcrafter-ui/refs/heads/main/assets/04-flow-detail.png)

  ![Flow Input Modal](https://raw.githubusercontent.com/wundii/flowcrafter-ui/refs/heads/main/assets/05-flow-input-modal.png)

  ![Flow Devtool](https://raw.githubusercontent.com/wundii/flowcrafter-ui/refs/heads/main/assets/08-devtool.png)

Claude Code Plugin
------------------

[](#claude-code-plugin)

Das optionale Plugin [flowcrafter-claude](https://github.com/wundii/flowcrafter-claude) erweitert [Claude Code](https://claude.ai/code) um Flowcrafter-Wissen — Flows, Steps, Messages, Projektionen und Schedules lassen sich per Slash-Command generieren und analysieren.

```
/plugin marketplace add wundii/flowcrafter-claude
/plugin install flowcrafter@flowcrafter-claude

```

CommandBeschreibung`/create-flow`Flow-Klasse mit FlowBuilder-DSL generieren`/create-step`Step-Klasse mit Message-Injection generieren`/create-message`Message-Klasse (init / data / return) generieren`/create-projection`Projection-Handler für asynchrone Read Models generieren`/create-schedule`Schedule-Klasse mit Cron-Ausdruck generieren`/analyze-flow`Flow auf Fehler und Verbesserungen prüfenDer `flowcrafter`-Skill aktiviert sich zusätzlich automatisch, sobald Flowcrafter-Begriffe im Gespräch auftauchen.

Dokumentation
-------------

[](#dokumentation)

KapitelInhalt[Getting Started](docs/getting-started.md)Erste Schritte: Config, Storage, Dev-Server[Konzepte](docs/concepts.md)Flow, Status, Schema, Messages, includeSteps, Observer, Scheduler, Projektion[Konfiguration](docs/configuration.md)`flowcrafter.php`, Storage-Backends, Server-Einstellungen[Console Commands](docs/commands.md)Command-Referenz[REST-API](docs/api.md)Endpunkte, Pagination, Auth[Testing](docs/testing.md)Flows &amp; Steps testen mit PHPUnit 11+[Deployment](docs/deployment.md)Produktion: FrankenPHP + Docker[Monitoring](docs/monitoring.md)Prometheus / OpenMetrics, CheckMK[Entwicklung](docs/development.md)QA-Scripts für ContributorLizenz
------

[](#lizenz)

MIT — siehe [LICENCE](LICENCE).

###  Health Score

44

—

FairBetter than 91% of packages

Maintenance96

Actively maintained with recent releases

Popularity16

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

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 ~2 days

Total

44

Last Release

23d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/55cca8c4c5dafd979e8cfc4fc14747edc8e7abeda94074b5fa927b7687af55f9?d=identicon)[wundii](/maintainers/wundii)

---

Top Contributors

[![wundii](https://avatars.githubusercontent.com/u/58734845?v=4)](https://github.com/wundii "wundii (217 commits)")

---

Tags

workflowflowstate-machineorchestrationmessage-driven

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StyleECS

Type Coverage Yes

### Embed Badge

![Health badge](/badges/wundii-flowcrafter/health.svg)

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

###  Alternatives

[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.4M514](/packages/shopware-core)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M196](/packages/sulu-sulu)[laravel/framework

The Laravel Framework.

34.8k532.1M19.4k](/packages/laravel-framework)[symfony/framework-bundle

Provides a tight integration between Symfony components and the Symfony full-stack framework

3.6k246.0M11.1k](/packages/symfony-framework-bundle)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.8M712](/packages/sylius-sylius)

PHPackages © 2026

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