Commit Graph

9 Commits

Author SHA1 Message Date
e17fc7c2f4 chore: remove dead legacy form-data migration commands
MigrateLegacyFormsData and VerifyFormsDataIntegrity exist to migrate the
pre-form-builder registration_form_fields / registration_field_templates
/ person_field_values tables into the current form_* tables. Those
legacy tables have been dropped from the dev database (verified via the
2026_04_20 drop_remaining_legacy_registration_tables migration), which
means the migrator's top-of-handle() guard always short-circuits the
run. The verify command is only reachable via
MigrateLegacyFormsData::verify() — also dead with its caller gone.

CLAUDE.md delete > adapt. These commands would also break the WS-5d
commit 5 column drop: MigrateLegacyFormsData:225 writes \$rff->options
straight to form_fields.options, which will not exist after commit 5.
Cleaning up before WS-5d starts keeps the dev tree consistent throughout
the refactor.

The two stale comment references in FormBuilderDevSeeder (header docblock
and seedSubmissionsForEvent docblock) plus the migration docblock that
mentions the migrator self-skip behaviour are scrubbed in the same
commit so no orphan references remain.

No production data exists; no migration safety net is being removed.

Tests: 1158 → 1158 green (no test coverage existed for these commands;
they were truly orphaned).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 01:58:19 +02:00
079d10975b refactor(form-builder): strict validator + drop form_fields.conditional_logic JSON column
WS-5c commit 3 of 4. FormRequests (Store/Update) now reject bad
conditional_logic trees at the HTTP boundary — the `after()` hook
unwraps the `show_when` envelope, normalises legacy `{all|any: [...]}`
group shape to the service's internal form, and delegates to
`FormFieldConditionalLogicService::assertSpecsValid()`. Unknown
operators, root conditions, empty groups, and unknown field_slug
references produce a 422 with a readable error before any write.

`form_fields.conditional_logic` JSON column dropped. FormField model
`$fillable` and `$casts` no longer mention the column; factory default
no longer writes `null` to it. Snapshot fixtures in the dev seeder and
the legacy-forms migration command keep `conditional_logic` in their
snapshot JSON shape — that's the schema_snapshot contract, not the DB
column.

FormFieldController now maps InvalidConditionalLogicSpecException to
422 alongside FrozenSchemaException / CyclicDependencyException.

Rollback path: roll back WS-5c commits 1–3 together. Partial rollback
(drop-column reversed but backfill still applied) is not a supported
state — matching the WS-5a/b precedent on the family's full-rollback
contract.

Tests: 6 new (strict FormRequest rejection cases + JSON-column drop
assertion). Rollback step counts in WS-5a/b migration tests bumped +1
for the drop_conditional_logic_json_column migration. Baseline
1142 → 1148 green (3085 → 3099 assertions).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 00:03:21 +02:00
d494478c08 feat(form-builder): form_field_configs relational table + non-validation key split + drop validation_rules JSON columns 2026-04-24 22:42:35 +02:00
800b1b6c01 feat(form-builder): FormFieldValidationRuleService + legacy backfill + snapshot + library row-copy 2026-04-24 22:12:08 +02:00
61719bf8bf refactor(form-builder): pre-publish check reads form_field_bindings; drop binding JSON columns 2026-04-24 20:09:27 +02:00
1a87871e94 feat(form-builder): extend public form backend for S3a PR 2
- 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>
2026-04-23 18:54:58 +02:00
79d834cb1d feat(seeder): dev event_registration schema with draft + submitted submissions exercising FORM-02 (§31.10)
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>
2026-04-17 21:58:42 +02:00
a3ca596362 S2a: purge legacy Form Builder PHP code and routes 2026-04-17 18:43:00 +02:00
021a3cd079 refactor(seeders): move DevSeeder to new form-builder structure
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>
2026-04-17 14:08:43 +02:00