- Seed AVAILABILITY_PICKER and SECTION_PRIORITY demo fields in the
event_registration showcase, and augment seedEchtFeesten with a
parent-level VOLUNTEER time slot pair + a standard registration-
visible section whose name duplicates a child section so the
PublicFormController dedup path is exercised end-to-end.
- Validate SECTION_PRIORITY value shape in FormValueService: arrays of
{ section_id, priority } with unique section_ids + priorities in 1..5,
max 5 entries, and section_ids scoped to the schema's event tree
(parent + children). Error envelope is the standard VALIDATION_FAILED
FieldValidationException shape so the portal renders errors next to
the field.
- Enrich admin-facing FormSubmissionResource with a nested identity_match
block mirroring the PublicFormSubmissionResource contract (status only;
leaves room for future matched_user_id / confidence).
- Lock in the FORM-05 stub contract with 6 tests against the existing
TriggerPersonIdentityMatchOnFormSubmit listener (no new listener was
needed — the current one already writes 'pending' for public
event_registration submissions per ARCH §31.1).
- 24 new backend assertions across seeder, shape validation, listener
state matrix, and resource serialisation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sprint 0.5. Extends FormBuilderDevSeeder (additive) so that after
`migrate:fresh --seed` the dev org has:
- one published public-token-enabled event_registration schema anchored
to the primary festival (Echt Feesten 2026) with a curated 5-field
set (HEADING / SELECT / CHECKBOX_LIST / TAG_PICKER / TEXTAREA) —
mirrors the subset Bert needs to eyeball via the portal and verify
§31.10 sync with;
- one draft submission (partial fill: shirtmaat + dieetwensen) for the
first approved person with user_id — the TAG_PICKER is deliberately
absent so this submission does NOT fire the listener;
- one submitted submission for the next approved person, with
TAG_PICKER values = the first 3 active person_tags by sort_order.
The submission is pushed through FormSubmissionService::submit so
FormSubmissionSubmitted fires, SyncTagPickerSelectionsOnSubmit runs,
and user_organisation_tags receives 3 self_reported rows.
Queue-connection contract: production runs QUEUE_CONNECTION=redis, so
the listener would queue and not execute before the seeder returns.
The seeder temporarily flips queue.default to sync for the submit()
call so Bert sees the synced tags immediately after `--seed`.
Console output matches the Sprint 0.5 spec: public URL for GET-testing
+ a line naming the submitter and the sync result count.
Wired from DevSeeder::seedEchtFeesten() behind an
app()->environment('local', 'testing', 'development') guard (belt-and-
suspenders on top of DatabaseSeeder's existing local gate).
Collateral fix: FormSubmissionService::submit() stored signed fractional
seconds into the unsigned `submission_duration_seconds` column. Carbon
3's diffInSeconds returns signed floats when `opened_at` is earlier than
now, which MySQL rejects. Wrapped with abs() + int cast. No test
expectations relied on the sign so 857 tests remain green.
Verified via tinker after `migrate:fresh --seed`:
fields_count = 5, submissions_count = 2 (1 draft + 1 submitted),
values on submitted = 4, self_reported tags for submitter = 3,
PublicFormSchemaResource returns all 5 fields on the public token.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds UserObserver::created() that firstOrCreate's a user_profiles row
for every User. Registered in AppServiceProvider alongside PersonObserver.
Covers DevSeeder (3 scattered User::create sites: DatabaseSeeder super admin,
DevSeeder org staff, DevSeeder volunteer users) and all future creation
paths (invite/register/import) with zero per-caller boilerplate.
New FormBuilderDevSeeder seeder class holds canonical 16-field registration
template (borrowed from the legacy RegistrationFieldTemplateService list so
test data stays recognisable). Produces per-org:
- 16 form_templates (system, schema_snapshot per ARCH §4.6.1)
- 1 FormSchema per event (event_registration, owner=event, draft_single
mode, is_published mirrors event.status lifecycle)
- 16 FormFields per schema
- 1 FormSubmission per person whose status ∈ applied/approved/no_show
(same rule as MigrateLegacyFormsData), with 6 realistic FormValues each
DevSeeder::run() now wraps the whole seed body in
ActivityLog::suppressed(...) so the ~80 field creates + ~277 submission
lifecycle triggers don't flood activity_log. Also removes the legacy
RegistrationFieldTemplateService::seedSystemTemplates call — the 16
system templates now land directly in form_templates.
Post-seed totals (dev DB):
5 form_schemas, 80 form_fields, 277 form_submissions, 1662 form_values,
16 form_templates, 270 user_profiles (1:1 with users).
forms:verify-data-integrity on freshly seeded DB: exit 0.
php artisan test: 910/910.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>