Project context for Claude Code and AI-assisted development.
workflow-engine-core is a framework-agnostic PHP workflow engine. Zero production dependencies. PHP 8.3+. MIT licensed.
Status: v0.0.2-alpha — active development, not production-ready.
Related package: solution-forest/workflow-engine-laravel (Laravel integration layer).
# Run tests
composer test
# Run tests with coverage
composer test:coverage
# Static analysis (PHPStan level 6)
composer analyze
# Code formatting (Laravel Pint)
composer pint
# Check formatting without changes (CI mode)
composer pint:test
# Full quality check: format + analyze + test
composer quality
# CI pipeline: check format + analyze + test
composer ciWorkflowBuilder → WorkflowDefinition → WorkflowEngine → Executor → Actions
↓
StateManager → StorageAdapter
↓
EventDispatcher
| Namespace | Purpose |
|---|---|
Core\ |
WorkflowEngine, WorkflowBuilder, Executor, StateManager, WorkflowInstance, WorkflowDefinition, WorkflowContext, ActionResult, Step, DefinitionParser, ActionResolver |
Actions\ |
BaseAction, LogAction, EmailAction, HttpAction, DelayAction, ConditionAction |
Contracts\ |
WorkflowAction, StorageAdapter, EventDispatcher, Logger |
Attributes\ |
WorkflowStep, Retry, Timeout, Condition |
Events\ |
WorkflowStartedEvent, WorkflowCompletedEvent, WorkflowFailedEvent, WorkflowCancelledEvent, StepCompletedEvent, StepFailedEvent, StepRetriedEvent |
Exceptions\ |
WorkflowException (base), InvalidWorkflowDefinitionException, InvalidWorkflowStateException, ActionNotFoundException, StepExecutionException, WorkflowInstanceNotFoundException |
Support\ |
NullLogger, NullEventDispatcher, SimpleWorkflow, Uuid, Timeout, ConditionEvaluator, Arr |
PENDING → RUNNING → COMPLETED
↓ ↓ ↑
FAILED WAITING
↑ ↓ ↑
FAILED ← PAUSED
↑
CANCELLED ← (any non-terminal state)
Valid transitions (enforced at runtime):
PENDING→RUNNING,FAILED,CANCELLEDRUNNING→WAITING,PAUSED,COMPLETED,FAILED,CANCELLEDWAITING→RUNNING,FAILED,CANCELLEDPAUSED→RUNNING,FAILED,CANCELLED- Terminal states (
COMPLETED,FAILED,CANCELLED) → no transitions allowed
Invalid transitions throw InvalidWorkflowStateException.
Every custom integration implements one of these:
WorkflowAction—execute(WorkflowContext): ActionResult+canExecute(WorkflowContext): boolStorageAdapter—save(),load(),findInstances(),delete(),exists(),updateState()EventDispatcher—dispatch(object $event): voidLogger— PSR-3 style:info(),error(),warning(),debug()
Actions are instantiated by Executor with new $actionClass($config, $logger). They receive a WorkflowContext containing workflowId, stepId, data, config, and the instance reference. They return ActionResult::success($data) or ActionResult::failure($message).
- Laravel Pint with Laravel preset
- Alphabetically ordered imports
- Short array syntax
[] - No trailing commas in single-line arrays
- PHPDoc left-aligned
- Pest PHP 2.0 with PHPUnit 10 base
- Test structure:
tests/Unit/,tests/Integration/,tests/RealWorld/ - Base test class:
TestCase(provides$this->engineand$this->storageviaInMemoryStorage) - Use
test('description', function () { ... })syntax - Use
describe()blocks for grouping related tests - Use
expect()fluent assertions, not$this->assert*() - Architecture tests in
tests/ArchTest.php— nodd,dump,raycalls
- Step IDs:
snake_case, must match/^[a-zA-Z][a-zA-Z0-9_-]*$/ - Workflow names:
kebab-case(e.g.,user-onboarding,order-processing) - Action classes: PascalCase ending in
Action(e.g.,ProcessPaymentAction) - Event classes: PascalCase ending in
Event(e.g.,StepCompletedEvent) - Exception classes: PascalCase ending in
Exception
- PHP 8.3 readonly properties and classes
- Backed enums with methods (
WorkflowState) - Named arguments throughout builder API
- Match expressions instead of switch
- Union types (
string|WorkflowAction) - Constructor promotion
// Fluent builder (primary API)
$workflow = WorkflowBuilder::create('order-flow')
->description('Process customer orders')
->addStep('validate', ValidateOrderAction::class)
->when('order.total > 1000', function ($builder) {
$builder->addStep('fraud_check', FraudCheckAction::class);
})
->addStep('payment', ProcessPaymentAction::class, timeout: 300, retryAttempts: 3)
->build();
// Quick templates
$workflow = WorkflowBuilder::quick()->userOnboarding();
$workflow = WorkflowBuilder::quick()->orderProcessing();$engine = new WorkflowEngine($storageAdapter, $eventDispatcher);
$instanceId = $engine->start('my-workflow', $definition->toArray(), ['key' => 'value']);
$instance = $engine->getInstance($instanceId);
$engine->cancel($instanceId, 'reason');GitHub Actions workflows:
run-tests.yml— Matrix: PHP 8.3/8.4 × prefer-lowest/prefer-stablephpstan.yml— Static analysis on .php changesfix-php-code-style-issues.yml— Auto-format with Pint on pushupdate-changelog.yml— Auto-update CHANGELOG on releasedependabot-auto-merge.yml— Auto-merge minor/patch dependency updates
- 46 source files in
src/ - 25 test files in
tests/ - 93 tests, 224+ assertions
- PHPStan level 6 compliance