
## 単一ファイルのワークフロー

ワークフローは、PHPファイル1つで完結させられます。ステップクラスとビルダーを同じファイルで定義し、ディレクトリに配置して、`Queuety::load_workflows()`でそのディレクトリを読み込みます（下記参照）。Queuetyは、それ自体でディレクトリをスキャンすることはありません。

```php
// workflows/onboard-user.php
use Queuety\Queuety;

class CreateAccount implements \Queuety\Step {
    public function handle(array $state): array {
        $user = create_user($state['email']);
        return ['user_id' => $user->id, 'user_name' => $user->name];
    }
    public function config(): array {
        return ['max_attempts' => 3];
    }
}

class SendWelcome implements \Queuety\Step {
    public function handle(array $state): array {
        wp_mail($state['email'], 'Welcome ' . $state['user_name'], '...');
        return ['welcomed' => true];
    }
    public function config(): array {
        return [];
    }
}

return Queuety::define_workflow('onboard_user')
    ->then(CreateAccount::class, 'create_account')
    ->then(SendWelcome::class, 'send_welcome');
```

ファイルは`WorkflowBuilder`を返します。各ステップクラスはファイル内に定義します。ファイルを読み込むと、クラスが利用可能になり、ワークフローがテンプレートとして登録されます。

## ワークフローの読み込み

ディレクトリからすべてのワークフローファイルを読み込みます:

```php
// Load all .php files from the workflows directory
$count = Queuety::load_workflows(__DIR__ . '/workflows/');
```

または、単一ファイルを読み込みます:

```php
$template = Queuety::load_workflow_file(__DIR__ . '/workflows/onboard-user.php');
```

次に、名前を指定してディスパッチします:

```php
$workflow_id = Queuety::run_workflow('onboard_user', ['email' => 'user@example.com']);
```

## 再帰的な読み込み

サブディレクトリをスキャンするには、2つ目の引数として`true`を渡します:

```php
Queuety::load_workflows(__DIR__ . '/workflows/', recursive: true);
```

これにより、ワークフローをフォルダーごとに整理できます:

```
workflows/
├── onboarding/
│   ├── new-user.php
│   └── trial-upgrade.php
├── reports/
│   ├── daily-summary.php
│   └── weekly-digest.php
└── notifications/
    └── digest-email.php
```

## すべてのワークフロー機能を使う

ファイルワークフローでは、ビルダーの機能をすべて利用できます。ただし`idempotency_key()`はテンプレートに保存されないため除きます。代わりに、ディスパッチごとに`Queuety::run_workflow( $name, $payload, [ 'idempotency_key' => '...' ] )`で渡してください。遅延、シグナル、並列ステップ、条件分岐、ワークフローの実行、キャンセルハンドラー、状態の整理はいずれも利用できます:

```php
// workflows/approval-flow.php
use Queuety\Queuety;

class SubmitRequest implements \Queuety\Step {
    public function handle(array $state): array {
        return ['submitted_at' => date('Y-m-d H:i:s')];
    }
    public function config(): array { return []; }
}

class ProcessApproval implements \Queuety\Step {
    public function handle(array $state): array {
        return [
            'approved_by' => $state['approved_by'],
            'processed' => true,
        ];
    }
    public function config(): array { return []; }
}

class CleanupRequest implements \Queuety\Handler {
    public function handle(array $payload): void {
        delete_pending_request($payload['request_id']);
    }
    public function config(): array { return []; }
}

return Queuety::define_workflow('approval_flow')
    ->then(SubmitRequest::class)
    ->delay(hours: 24)
    ->wait_for_signal('approved')
    ->then(ProcessApproval::class)
    ->on_cancel(CleanupRequest::class)
    ->prune_state_after(2);
```

## ファイルワークフローを使う場面

ファイルワークフローは、次の場合に最適です:

- LLMまたはコード生成ツールでワークフローをプログラムから作成する
- ワークフローが単一ファイルに収まるほどシンプルである
- ステップのロジックをワークフロー定義の近くに置きたい
- プロトタイプを作成して素早く反復したい

複数のワークフローで共有するステップクラス、複雑なミドルウェア、再利用するステップを含む大規模なワークフローでは、クラスファイルを分けてPSR-4オートローディングを使う標準的な方法のほうが保守しやすくなります。

## 仕組み

内部では、ファイルワークフローはビルダーAPIとまったく同じエンジンを使います。各ステップはデータベース内の個別のジョブです。状態は`queuety_workflows`テーブルを介して引き継がれます。リプレイはなく、決定性の要件もなく、性能差もありません。

読み込みの呼び出しごとにファイルを`require`します（`require_once`ではありません）。そのため、各ファイルはリクエストごとに1回だけ読み込んでください。同じファイルを2回読み込むとクラスが再宣言され、エラーになります。返された`WorkflowBuilder`は`WorkflowTemplate`に変換され、`WorkflowRegistry`に保存されます。ディスパッチと実行の動作は、他のすべてのワークフローと同じです。
