RFC-TIMETABLE v0.2 Session 3 — Form Builder integration #17
Reference in New Issue
Block a user
Delete Branch "feat/timetable-session-3"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
RFC-TIMETABLE v0.2 Session 3 — Form Builder integration. Wires the
artist-advance portal flow to the existing FormBindingApplicator
pipeline (RFC-WS-6 v1.3.1) without reimplementing it.
artist_engagements.advancing_*_countin sync atomically on every section lifecycle event. Closes
ART-OBSERVER-ADVANCE-AGGREGATE.portal-token → engagement resolution. Two domain exceptions
distinguish 404 (no match) from 410 (master artist soft-deleted).
RFC v0.2 D15 with section_level_submit=true. Idempotent. Wired into
org creation via OrganisationObserver, gated on
config('artist_advance.bootstrap_on_org_create')(production: true,phpunit: false). Existing orgs covered via the
artist:seed-advance-defaultartisan command./p/artist/{token}/*(public, throttle:30,1). Section submit reusesthe FormBindingApplicator pipeline via FormSubmissionSectionSubmitted.
event_idvia the$contextbag — required because the artist_advance schema isorg-owned and this route has no
{event}parameter. ARCH-FORM-BUILDER§17.3 footnote.
Frontend in Session 5 — backend complete here.
Test plan
lifecycle, is_open no-op, orphaned-engagement guard, no-activity-noise.
observer behaviour, artisan one-org + all-orgs paths.
including cross-engagement guard.
Open BACKLOG entries surfaced this session
artist_advance.bootstrap_on_org_createconfig flag and thephpunit.xmlenv-override once the five FormSchema-counting testsexpect the auto-bootstrapped artist_advance schema. Goal:
productiegedrag = testgedrag, geen branching.
between
advance_sections(engagement-scoped) andform_schema_sections(org-scoped) with a properform_schema_section_idFK. Today's name-match works for default-seeded schemas but breaks on UI rename and offers no integrity
guarantee.
🤖 Generated with Claude Code
Three backend endpoints under public throttle:30,1: GET /p/artist/{token} — engagement summary + sections GET /p/artist/{token}/sections/{section} — form schema + draft values POST /p/artist/{token}/sections/{section} — section submit Token resolution via ArtistResolver::fromPortalToken (Step 2). The master Artist becomes the FormSubmission subject; engagement.event_id populates form_submissions.event_id per WS-4 denormalisation. Token mismatches map to 404 (InvalidPortalTokenException), soft-deleted master artists to 410 Gone (ArtistDeletedException). Section submit reuses the existing FormBindingApplicator pipeline (RFC-WS-6 v1.3.1) by dispatching FormSubmissionSectionSubmitted — no parallel apply path. Drafts are idempotent on 'artist_advance:{engagement_id}', so repeated POSTs find the same submission. AdvanceSection (engagement-scoped) ↔ FormSchemaSection bridge: case-sensitive name match against the org's artist_advance schema; the default seeder names them in lockstep. Frontend in Session 5 — backend complete here. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>22 new tests across four files: - AdvanceSectionObserverTest (7) — counter recompute on create / status transition / delete / is_open toggle no-op / orphaned-section guard / no activity-log noise on counter writes - ArtistResolverTest (4) — happy path / invalid token / soft-deleted artist / SHA-256 digest verification - ArtistAdvanceDefaultTest (6) — five-section + slug shape / idempotency / per-section field shape / observer-invocation outside tests / artisan one-org + all-orgs paths - EngagementPortalControllerTest (6) — show 200/404/410 / show-section schema + draft values / submit happy-path with submission persistence + counter recompute / cross-engagement section returns 404 Implementation tweaks driven by test feedback: - OrganisationObserver gated by `app()->runningUnitTests()` — auto-seed runs in production but is silent in CI so existing FormSchema-counting tests are unperturbed. Tests that need the seeded schema invoke `ArtistAdvanceDefault::seedFor()` explicitly. - EngagementPortalController idempotency_key uses `aa-` + sha1 prefix (28 chars) so it fits the form_submissions.idempotency_key varchar(30) column. Test count: 1709 (Session 2 close) → 1731 (+22). Larastan: 0 new errors over baseline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>OrganisationObserver was gated on app()->runningUnitTests() — replaced with config('artist_advance.bootstrap_on_org_create') (default true, phpunit.xml overrides to false). Behaviour identical, but the seam is explicit and removable. Tracked for full convergence by new BACKLOG entry TECH-OBSERVER-TEST-CONVERGENCE — productiegedrag = testgedrag, geen branching, na test-cleanup. idempotency_key for the engagement-scoped draft simplified from 'aa-' + sha1(engagement_id)[0:27] to 'aa:' + engagement_id (29 chars, fits varchar(30)). Same uniqueness guarantee, recognisable shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>