Parent
#237
What to build
Implement the Application enrollment method: participant fills a dynamic form, enrollment goes to pending, organizer approves or rejects in Admin panel.
Dynamic form schema:
events_enrollment_policies.application_form_schema stores a JSONB array defining form fields
- Schema structure:
[{type: "text|textarea|select|checkbox", label: "...", required: bool, options?: [...]}]
- Filament form builder in Admin for organizer to define questions when creating/editing the policy
- App panel renders the form dynamically from the schema using Filament form components
Modify EnrollUserAction (application path):
- When
enrollment_method = 'application':
- Validates submitted data against the form schema
- Creates enrollment with status
pending, stores answers in application_data (JSONB)
- Records transition (from=null, to=pending, triggered_by=user)
- Does NOT check capacity yet (only checked on approval)
Action: ApproveApplicationAction
- Validates: enrollment status must be
pending
- Checks capacity (with
lockForUpdate) — if full + has_waitlist → waitlisted, if full + no waitlist → reject approval
- Transitions to
confirmed (or waitlisted), sets confirmed_at
- Records transition (triggered_by=admin, actor_user_id=organizer)
- Dispatches
EnrollmentConfirmed domain event
Action: RejectApplicationAction
- Validates: enrollment status must be
pending
- Transitions to
rejected, stores rejection_reason
- Records transition (triggered_by=admin, actor_user_id=organizer, reason=rejection_reason)
Admin panel:
- "Pending Applications" view/filter on enrollments — shows application_data in a readable format
- "Approve" and "Reject" actions (reject requires reason text field)
- Application data displayed in enrollment detail view
App panel:
- Dynamic form rendered from policy schema when user clicks "Apply"
- Shows "Application pending" status with submitted data (read-only)
- Shows "Rejected" status with rejection reason when applicable
Acceptance criteria
Blocked by
Parent
#237
What to build
Implement the Application enrollment method: participant fills a dynamic form, enrollment goes to
pending, organizer approves or rejects in Admin panel.Dynamic form schema:
events_enrollment_policies.application_form_schemastores a JSONB array defining form fields[{type: "text|textarea|select|checkbox", label: "...", required: bool, options?: [...]}]Modify
EnrollUserAction(application path):enrollment_method = 'application':pending, stores answers inapplication_data(JSONB)Action:
ApproveApplicationActionpendinglockForUpdate) — if full + has_waitlist →waitlisted, if full + no waitlist → reject approvalconfirmed(orwaitlisted), setsconfirmed_atEnrollmentConfirmeddomain eventAction:
RejectApplicationActionpendingrejected, storesrejection_reasonAdmin panel:
App panel:
Acceptance criteria
pendingandapplication_datapopulatedconfirmed(orwaitlistedif full)rejectedwith reason storedBlocked by