feat(form-builder): add PersonProvisioner with race-safe firstOrCreate (WS-6)
PersonProvisioner reads bindings from schema_snapshot (RFC Q6) and provisions Persons via lockForUpdate + firstOrCreate (RFC Q8). Person is event-scoped (Person::$organisationScopeColumn = 'event_id'), so the lookup matches by (email, event_id) — cross-event submissions never collide. Throws PersonProvisioningException on misconfiguration (failsafe — publish guards should prevent these at config time): no_transaction, no_event, no_identity_key, identity_key_missing_value, no_crowd_type. Snapshot enrichment: FormFieldBindingService::toApplicatorShape + FormSubmissionService snapshot now adds a 'bindings' (plural) key with binding id, merge_strategy, trust_level, is_identity_key. Singular 'binding' key kept for legacy webhook / GDPR readers. Includes RFC V4 state-injection concurrency test asserting recovery semantics under lockForUpdate windows. Refs: RFC-WS-6.md §3 (Q6, Q8), §4 (V4) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Providers;
|
||||
|
||||
use App\FormBuilder\Bindings\BindingTypeRegistry;
|
||||
use App\FormBuilder\Bindings\PersonProvisioner;
|
||||
use App\FormBuilder\Purposes\PurposeRegistry;
|
||||
use App\Models\Company;
|
||||
use App\Models\CrowdList;
|
||||
@@ -90,6 +91,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
|
||||
$this->app->singleton(PurposeRegistry::class);
|
||||
$this->app->singleton(BindingTypeRegistry::class);
|
||||
$this->app->singleton(PersonProvisioner::class);
|
||||
|
||||
// Telescope is a dev-only debugging dashboard. Three-layer
|
||||
// defense keeps it out of production: composer `dont-discover`
|
||||
|
||||
Reference in New Issue
Block a user