24
Operations

Idempotency and Automations

Mutation replay safety and post-submission automation execution.

Idempotency

Management mutations support Idempotency-Key.

  • same key + same payload => replay previous response
  • same key + different payload => 409 Conflict

Config:

  • formforge.http.idempotency.ttl_minutes

Submission automations

Automations execute after submission persistence.

Registration APIs:

  • Form::automation('form-key')->sync()->handler(...)
  • Form::automation('form-key')->queue(...)->handler(...)
  • Form::automationForResolver(ResolverClass::class)->...

Contracts:

  • SubmissionAutomation
  • SubmissionAutomationResolver

Runs are tracked in formforge_submission_automation_runs and execution is idempotent per submission plus automation key.

Add metadata from an automation

EvanSchleret\FormForge\Models\FormSubmission provides a helper to update submission.meta and persist immediately:

meta(string|array $key, mixed $value = null): self

Supported usages:

$submission->meta('team_request_id', (int) $id);
$submission->meta([
    'team_request_id' => (int) $id,
    'source' => 'automation',
]);

Complete automation example

<?php

declare(strict_types=1);

namespace App\FormForge\Automations;

use App\Models\TeamRequest;
use EvanSchleret\FormForge\Automations\Contracts\SubmissionAutomation;
use EvanSchleret\FormForge\Models\FormSubmission;

final class CreateTeamRequestFromSubmission implements SubmissionAutomation
{
    public function handle(FormSubmission $submission): void
    {
        $request = TeamRequest::query()->create([
            'email' => (string) ($submission->payload['email'] ?? ''),
            'team_name' => (string) ($submission->payload['team_name'] ?? ''),
            'status' => 'pending',
        ]);

        $submission->meta([
            'team_request_id' => (int) $request->getKey(),
            'source' => 'automation',
        ]);
    }
}

Expose team_request_id in submit HTTP response

Use a custom submission resource and map the meta value explicitly:

<?php

declare(strict_types=1);

namespace App\Http\Resources\FormForge;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

final class SubmissionResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'uuid' => (string) $this->uuid,
            'form_key' => (string) $this->form_key,
            'payload' => $this->payload,
            'team_request_id' => $this->meta['team_request_id'] ?? null,
            'created_at' => $this->created_at?->toISOString(),
        ];
    }
}
'http' => [
    'resources' => [
        'submission' => \App\Http\Resources\FormForge\SubmissionResource::class,
    ],
],

Important note on queue vs sync

If the automation runs in queue mode, meta updates may not be available immediately in the submit HTTP response.

Use ->sync() when the value must be present right away.

Best practices

  • Use stable meta keys (for example team_request_id).
  • Prefer scalar or small array values for predictable serialization.
  • Do not store sensitive data in meta.