Files
crewli/api/config/form_builder.php
bert.hausmans 6b5111ce43 feat(form-builder): ApplyBindings listener chain with two-transaction pattern (WS-6)
ApplyBindingsOnFormSubmit (sync) wraps the applicator in DB::transaction
and writes apply_status post-commit. On exception: outer catch records
FormSubmissionActionFailure in a separate transaction (survives inner
rollback), marks apply_status=failed, swallows so siblings keep running
(RFC Q3, Q4). When ApplyBindings provisions a Person on a previously
no-subject submission, the listener also writes subject_type/subject_id
back so TriggerPersonIdentityMatchOnFormSubmit (next sync listener) can
find the freshly-provisioned subject.

ApplyBindingsOnFormSectionSubmitted (queued, feature-flagged) ready
for ARTIST_ADVANCE activation per RFC Q10.

Listener chain on FormSubmissionSubmitted explicitly registered in
AppServiceProvider::boot for deterministic ordering (RFC Q1):
ApplyBindings → IdentityMatch → queued siblings.

FormBindingApplicator dropped 'final readonly' to 'class' so listener
tests can subclass it for throw-path coverage; constructor properties
remain readonly individually.

Refs: RFC-WS-6.md §3 (Q1, Q3, Q4, Q10)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 13:18:30 +02:00

88 lines
2.5 KiB
PHP

<?php
declare(strict_types=1);
/*
|--------------------------------------------------------------------------
| Form Builder — general configuration
|--------------------------------------------------------------------------
|
| Tunable limits, webhook policy, captcha, retention and feature flags for
| the universal form builder. See ARCH-FORM-BUILDER.md §22.7 for rationale.
|
*/
return [
'limits' => [
'max_fields_per_schema' => 100,
'max_filterable_fields_per_schema' => 20,
'max_options_per_field' => 100,
'max_submissions_per_public_schema_per_ip_per_hour' => 5,
],
'webhooks' => [
'allowlist_domains' => [],
'blocklist_ips' => [
'127.0.0.0/8',
'10.0.0.0/8',
'172.16.0.0/12',
'192.168.0.0/16',
'169.254.169.254/32',
],
'timeout_seconds' => 10,
'max_attempts' => 5,
],
'file_uploads' => [
'default_allowed_mime_types' => ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'],
'default_max_size_mb' => 5,
],
'search_index' => [
'max_chars' => 10000,
],
'captcha' => [
'provider' => 'turnstile',
'site_key' => env('TURNSTILE_SITE_KEY'),
'secret_key' => env('TURNSTILE_SECRET_KEY'),
'required_for_purposes' => ['public_complaint', 'public_press_request'],
],
'public_submitter_ip_retention_days' => 30,
'user_profile_settings_whitelist' => [
'ui.theme',
'ui.sidebar_collapsed',
'ui.time_format',
'notifications.email_digest',
'notifications.shift_reminders',
'notifications.event_updates',
],
'custom_field_types' => [],
'validation_callbacks' => [],
'features' => [
'webhooks' => false, // dispatcher arrives in S6
'i18n_runtime' => false, // runtime resolution later
'retention_job' => false, // scheduler task later
],
/**
* RFC-WS-6 §3 (Q10) — section-level binding apply runtime gate.
*
* REMOVAL TRIGGER: enable when ARTIST_ADVANCE feature work begins
* (post-S5). At enablement: set FORM_BUILDER_SECTION_APPLY=true,
* write section-scoped tests, activate the dispatch path in
* FormSubmissionService, remove this flag and the early-return
* guard from ApplyBindingsOnFormSectionSubmitted::handle().
*
* Tracking: BACKLOG.md → ARTIST-ADV-SECTION-APPLY
*/
'section_apply_enabled' => env('FORM_BUILDER_SECTION_APPLY', false),
];