Question Types
This document describes all question types supported by the registration workflow, including their backend implementation, frontend rendering, validation rules, and example use cases.
1. Overview
The registration workflow presents a series of questions to users during the membership or event registration process. Each question is rendered based on its type, which determines the UI component used and the validation rules applied.
1.1. Development Phases
| Phase | Period | Scope |
|---|---|---|
P1 |
Past 2 years |
Initial implementation (complete) |
P2 |
Dec 2025 - Mar 2026 |
Current work - 11 new question types |
P3 |
After Mar 2026 |
Future enhancements |
1.2. FormController Inheritance Model
Question types are registered in FormController classes that form an inheritance hierarchy:
1.3. Layer 3 Component Architecture
Questions are displayed using a Layer 3 Question Panel component that sits within the existing page structure:
-
Layer 1: Site frame (navbar + page container)
-
Layer 2: Functional area template (membership/event details panel)
-
Layer 3: Question panel (question header + person-answer table + navigation)
The question panel follows a consistent layout:
| P2 enhances the person info column to include DOB, age, gender, and category (context-dependent) in addition to the person name. |
1.4. StepCode vs UI_CODE Mapping
The backend uses StepCode to define question logic, while the frontend uses UI_CODE to determine rendering. Multiple StepCodes can map to the same UI_CODE when they share the same visual presentation but differ in business logic.
1.4.1. Base FormController Questions (Generic)
| StepCode | UI_CODE | Description | Status |
|---|---|---|---|
TXT |
TXT |
Free text with length/pattern validation |
P1 ✓ |
SEL |
SEL |
Select one option from list |
P1 ✓ |
RBO |
RAD |
Radio button options |
P1 ✓ |
BCB |
BCB |
Binary checkbox (yes/no) |
P1 ✓ |
ITC |
ITC |
Terms & conditions acceptance |
P1 ✓ |
ONE |
ONE |
Radio button single selection (pick one person) |
P1 ✓ |
CON |
CON |
Communication preference (Email/SMS/WhatsApp) |
P2 |
PHN |
PHN |
Phone with country code + number |
P2 |
EMC |
EMC |
Emergency contact (name + phone) |
P2 |
CLV |
SEL |
Select from configured custom list |
P2 |
1.4.2. MembershipFormController Questions (Membership-Specific)
| StepCode | UI_CODE | Description | Status |
|---|---|---|---|
MFA |
BCB |
Select adults for family membership |
P1 ✓ |
MFC |
BCB |
Select children for family membership |
P1 ✓ |
MFM |
ONE |
Select primary family member |
P1 ✓ |
MCS |
RAD |
Opt-in for cross-sell membership |
P1 ✓ |
1.4.3. EventFormController Questions (Event-Specific)
| StepCode | UI_CODE | Description | Status |
|---|---|---|---|
CSI |
CSI |
CSA/UCI ID number capture |
P2 |
CSM |
CSM |
Validate CSA membership status |
P2 |
CSL |
CSL |
Validate CSA racing license |
P2 |
ECA |
SEL |
Select event category (age/gender filtered) |
P2 |
ERT |
SEL |
Select race types to compete in (multi-select) |
P2 |
NSR |
ESR |
Select/replace race number |
P2 |
TSR |
ESR |
Select/replace timing tag/chip |
P2 |
2. Core Question Types
2.1. TXT - Text Input
Purpose: Capture free text responses from each person.
Backend:
-
Class:
FreeTextFormField.java -
StepCode:
TXT -
UI_CODE:
TXT
Frontend Rendering:
-
Component: Text input field per person
-
Layout: Person name on left, text input on right
Validation:
-
Required check (if configured)
-
Minimum/maximum length (
valueMin,valueMax) -
Regex pattern matching (
valuePattern)
Example Use Cases:
-
Emergency contact number
-
Medical notes
-
Special dietary requirements
DTO Example:
{
"title": "Emergency Contact Number",
"questionType": "TXT",
"required": true,
"people": [
{ "id": 1, "firstName": "Sarah", "lastName": "Smith", "answer": null },
{ "id": 2, "firstName": "Billy", "lastName": "Smith", "answer": null }
]
}
Mockup: View Text Input Mockup
2.2. SEL - Dropdown Selection
Purpose: Allow users to select one option from a predefined list per person.
Backend:
-
Class:
DropDownOptionFormField.java -
StepCode:
SEL -
UI_CODE:
SEL
Frontend Rendering:
-
Component: Dropdown/select element per person
-
Layout: Person name on left, dropdown on right
-
Options populated from
person.optionsarray
Validation:
-
Required check (if configured)
-
Answer must match one of the available options
Example Use Cases:
-
T-shirt size selection
-
School selection
-
Experience level
-
Communication preference
DTO Example:
{
"title": "T-Shirt Size",
"questionType": "SEL",
"required": true,
"people": [
{
"id": 1,
"firstName": "Sarah",
"lastName": "Smith",
"answer": null,
"options": [
{ "id": "XS", "value": "XS (Extra Small)" },
{ "id": "S", "value": "S (Small)" },
{ "id": "M", "value": "M (Medium)" },
{ "id": "L", "value": "L (Large)" },
{ "id": "XL", "value": "XL (Extra Large)" }
]
}
]
}
Mockups:
2.3. BCB - Binary Checkbox
Purpose: Capture a yes/no response per person.
Backend:
-
Class:
CheckBoxBooleanFormField.java -
StepCode:
BCB -
UI_CODE:
BCB
Frontend Rendering:
-
Component: Single checkbox per person
-
Layout: Checkbox with person name as label
-
Answer values:
"0"(unchecked) or"1"(checked)
Validation:
-
Boolean validation (answer must be "0" or "1")
-
Does NOT enforce required flag
Example Use Cases:
-
Medical conditions declaration
-
Photo consent
-
Newsletter subscription
DTO Example:
{
"title": "Medical Conditions",
"description": "Does anyone have any medical conditions we should be aware of?",
"questionType": "BCB",
"required": false,
"people": [
{
"id": 1,
"firstName": "Sarah",
"lastName": "Smith",
"answer": "0",
"options": [{ "id": "1", "value": "Yes, I have medical conditions" }]
}
]
}
Mockup: View Checkbox Mockup
2.4. ONE - Radio Single Selection
Purpose: Allow selection of exactly one person from the group.
Backend:
-
Class:
RadioButtonPickOneFormField.java -
StepCode:
ONE -
UI_CODE:
ONE
Frontend Rendering:
-
Component: Radio button group (all share same
nameattribute) -
Layout: Radio button with person name as label
-
Only one person can have answer
"1"at a time
Validation:
-
At least one person must have answer
"1"(if required) -
All other persons automatically set to
"0"
Example Use Cases:
-
Primary contact selection
-
Main account holder
-
Team captain selection
DTO Example:
{
"title": "Primary Contact Person",
"description": "Who will be the primary contact person for this membership?",
"questionType": "ONE",
"required": true,
"people": [
{ "id": 1, "firstName": "Sarah", "lastName": "Smith", "answer": "1" },
{ "id": 2, "firstName": "Billy", "lastName": "Smith", "answer": "0" }
]
}
Mockup: View Radio Selection Mockup
2.5. ITC - Terms & Conditions
Purpose: Require acceptance of terms and conditions from all members.
Backend:
-
Class:
IndemnityTermsConditionsFormField.java -
StepCode:
ITC -
UI_CODE:
ITC
Frontend Rendering:
-
Component: Master checkbox + individual checkboxes
-
Layout: Scrollable terms content, master "Accept for all", individual acceptance per person
-
Master checkbox propagates to all individual checkboxes
Validation:
-
All persons must have answer
"1"to proceed -
Does NOT enforce required flag (validation is always applied)
Special Behavior:
-
Terms text displayed in scrollable container
-
Master checkbox toggles all individual checkboxes
-
Individual checkboxes update master state
-
Not included in summary data collection
DTO Example:
{
"title": "Terms and Conditions",
"description": "Please read and accept the terms and conditions.",
"questionType": "ITC",
"required": true,
"infoURL": "https://example.com/terms",
"people": [
{ "id": 1, "firstName": "Sarah", "lastName": "Smith", "answer": "1" },
{ "id": 2, "firstName": "Billy", "lastName": "Smith", "answer": "1" }
]
}
Mockup: View Terms & Conditions Mockup
3. Membership-Specific Question Types
These question types are used specifically for family membership workflows. They render using standard UI components but have custom business logic.
3.1. MFA - Family Adult Selection
Purpose: Select which adults will be included in a family membership.
Backend:
-
Class:
MembershipAdultSelectFormField.java -
StepCode:
MFA -
UI_CODE:
BCB(renders as checkbox)
Visibility Rules:
-
Only shown for adults (18+)
-
Only shown when family membership is possible
Validation:
-
Ensures exactly 2 adults are selected for family membership
-
Not included in summary data
Example Context:
When registering multiple people and family membership pricing applies, this question allows users to select which 2 adults will be part of the family unit.
3.2. MFC - Family Child Selection
Purpose: Select which children will be included in a family membership.
Backend:
-
Class:
MembershipChildSelectFormField.java -
StepCode:
MFC -
UI_CODE:
BCB(renders as checkbox)
Visibility Rules:
-
Only shown for children (under 18)
-
Only shown when family membership is possible
Validation:
-
Children selection is optional
-
Not included in summary data
Example Context:
After selecting family adults, users can choose which children to include in the family membership at no additional cost.
3.3. MFM - Family Main Member
Purpose: Select the primary adult for the family membership.
Backend:
-
Class:
MembershipMainSelectFormField.java -
StepCode:
MFM -
UI_CODE:
ONE(renders as radio button)
Visibility Rules:
-
Only shown for selected family adults
-
Only shown after MFA step completes
Validation:
-
Exactly one main member must be selected
-
Not included in summary data
Example Context:
After selecting family adults, users must designate one as the primary member who will receive the main membership number and communications.
Mockup: View Family Main Member Mockup
4. Interactive UI Prototypes
The following interactive HTML prototypes demonstrate the visual design and interaction patterns for question screens.
| Screen | StepCode | UI_CODE | Prototype |
|---|---|---|---|
Text Input |
TXT |
TXT |
|
Binary Checkbox |
BCB |
BCB |
|
Dropdown Selection |
SEL |
SEL |
|
Dropdown (T-Shirt) |
SEL |
SEL |
|
Dropdown (School) |
SEL |
SEL |
|
Radio Single Select |
ONE |
ONE |
|
Terms & Conditions |
ITC |
ITC |
|
Family Adult Selection |
MFA |
BCB |
|
Family Child Selection |
MFC |
BCB |
|
Family Main Member |
MFM |
ONE |
| These prototypes are interactive HTML files that demonstrate the intended user experience. Navigate between screens using the Back/Next buttons. |
5. Backend Implementation Reference
5.2. Source Files
| File | Path |
|---|---|
FormField (Base) |
|
FreeTextFormField |
|
DropDownOptionFormField |
|
CheckBoxBooleanFormField |
|
RadioButtonPickOneFormField |
|
IndemnityTermsConditionsFormField |
|
MembershipAdultSelectFormField |
|
MembershipChildSelectFormField |
|
MembershipMainSelectFormField |
|
6. P2 Question Types - Generic (Base FormController)
These question types are available to both Membership and Event registration workflows.
6.1. CON - Communication Preference
Purpose: Capture preferred communication channel (Email, SMS, or WhatsApp) per person.
Backend:
-
Class:
CommunicationPreferenceFormField.java(P2) -
StepCode:
CON -
UI_CODE:
CON
Frontend Rendering:
-
Component: Toggle buttons for channel type + conditional input (email or phone)
-
Layout: Person info on left, channel selection + value input on right
-
Optional "Apply to all persons" checkbox for bulk application
Validation:
-
Channel type required (EMAIL, SMS, WHATSAPP)
-
If EMAIL: valid email format
-
If SMS/WHATSAPP: valid phone format with country code
Data Model:
{
"type": "EMAIL|SMS|WHATSAPP",
"value": "[email protected]",
"countryCode": "+27" // For SMS/WhatsApp only
}
6.2. PHN - Phone Number
Purpose: Capture phone number with country code per person.
Backend:
-
Class:
PhoneFormField.java(P2) -
StepCode:
PHN -
UI_CODE:
PHN
Frontend Rendering:
-
Component: Country code dropdown + phone number input
-
Layout: Person info on left, phone input on right
-
Default country code: +27 (South Africa)
Validation:
-
Country code required
-
Phone number format (digits, optional dashes/spaces)
Data Model:
{
"countryCode": "+27",
"number": "0821234567"
}
Mockup: View Phone Number Mockup
6.3. EMC - Emergency Contact
Purpose: Capture emergency contact name and phone number per person.
Backend:
-
Class:
EmergencyContactFormField.java(P2) -
StepCode:
EMC -
UI_CODE:
EMC
Frontend Rendering:
-
Component: Name input + phone input (reuses PHN component)
-
Layout: Person info on left, contact details on right
Validation:
-
Contact name required
-
Phone number required (reuses PHN validation)
Data Model:
{
"name": "John Doe",
"phone": {
"countryCode": "+27",
"number": "0821234567"
}
}
Mockup: View Emergency Contact Mockup
6.4. CLV - Custom List Value
Purpose: Allow selection from a configurable custom list (T-Shirt sizes, Clubs, Schools, etc.).
Backend:
-
Class:
CustomListValueFormField.java(P2) -
StepCode:
CLV -
UI_CODE:
SEL(renders as standard dropdown)
Frontend Rendering:
-
Component: Standard dropdown (reuses SEL component)
-
Layout: Person info on left, dropdown on right
-
Options populated from CustomListValue entities
Configuration:
-
ProcessStep references which CustomList to use
-
Options dynamically loaded based on list configuration
Validation:
-
Required selection from list
Data Model:
{
"customListId": 123,
"valueId": 456,
"value": "Medium"
}
7. P2 Question Types - Event-Specific (EventFormController)
These question types are specific to event registration workflows.
7.1. CSI - CSA/UCI Identification
Purpose: Capture participant’s CSA or UCI identification number.
Backend:
-
Class:
CSAIdentificationFormField.java(P2) -
StepCode:
CSI -
UI_CODE:
CSI
Frontend Rendering:
-
Component: Toggle buttons (CSA Number / UCI Number / None) + conditional number input
-
Layout: Person info (name, DOB, age, gender) on left, ID capture on right
Validation:
-
If type != NONE, number is required
-
CSA number format validation
-
UCI number format validation
Data Model:
{
"type": "CSA|UCI|NONE",
"number": "123456"
}
Mockup: View CSA Identification Mockup
7.2. CSM - CSA Membership Check
Purpose: Validate participant has valid CSA membership for event dates.
Backend:
-
Class:
CSAMembershipCheckFormField.java(P2) -
StepCode:
CSM -
UI_CODE:
CSM
Frontend Rendering:
-
Component: Status display with conditional options for non-compliant participants
-
Layout: Person info on left, status/options on right
Compliance Configuration (per-category or event level):
-
strictCompliance: If true, no deferment allowed -
dayLicenseAllowed: If true, can purchase day license
Compliance Matrix:
| Strict | Day License | Available Options |
|---|---|---|
false |
true |
Day License, Defer, Remove |
false |
false |
Defer, Remove |
true |
true |
Day License, Remove |
true |
false |
Remove only (championship events) |
Flow Logic:
-
Check CSA membership status via CSA API
-
If VALID → proceed to next step
-
If INVALID → present options based on configuration
Data Model:
{
"status": "VALID|DAY_LICENSE|DEFERRED|REMOVED",
"membershipNumber": "123456",
"dayLicenseOrderId": "order-xyz",
"deferUntil": "2026-03-15T00:00:00Z"
}
Mockup: View CSA Membership Check Mockup
7.3. CSL - CSA License Check
Purpose: Validate participant has valid racing license for discipline/event.
Backend:
-
Class:
CSALicenseCheckFormField.java(P2) -
StepCode:
CSL -
UI_CODE:
CSL
Prerequisites:
-
CSM (membership check) must be VALID or DAY_LICENSE
-
CSL always follows CSM in step order
Frontend Rendering:
-
Component: Status display with conditional options (similar to CSM)
-
Layout: Person info (including category) on left, status/options on right
Flow Logic:
-
Verify CSM status (implicit membership requirement)
-
Check racing license for discipline on event dates via CSA API
-
If VALID → proceed
-
If INVALID → present options (same as CSM)
Data Model:
{
"status": "VALID|DAY_LICENSE|DEFERRED|REMOVED",
"licenseNumber": "RC-2025-1234",
"discipline": "Road Cycling",
"dayLicenseOrderId": "order-xyz",
"deferUntil": "2026-03-15T00:00:00Z"
}
Mockup: View CSA License Check Mockup
7.4. ECA - Event Category Selection
Purpose: Select event category based on participant age/gender.
Backend:
-
Class:
EventCategoryFormField.java(P2) -
StepCode:
ECA -
UI_CODE:
SEL(renders as dropdown with special logic)
Frontend Rendering:
-
Component: Dropdown (extends SEL) with filtered options
-
Layout: Person info on left, category dropdown on right
-
Special handling for no eligible categories
Logic:
-
Filter categories by participant’s age and gender
-
If 0 matching → Show "Remove participant" option
-
If 1 matching → Auto-select, show confirmation
-
If 2+ matching → User must select
Data Model:
{
"categoryId": 123,
"categoryName": "Elite Men 35-39"
}
7.5. ERT - Event Race Type Selection
Purpose: Select which races participant will compete in (multi-select).
Backend:
-
Class:
EventRaceTypeFormField.java(P2) -
StepCode:
ERT -
UI_CODE:
SEL(multi-select variant)
Frontend Rendering:
-
Component: Multi-select checkbox list
-
Layout: Person info on left, race type checkboxes on right
-
Options filtered by selected category
Validation:
-
At least one race type required
Data Model:
{
"raceTypes": [
{ "id": 1, "name": "Scratch Race" },
{ "id": 2, "name": "Match Sprint" },
{ "id": 4, "name": "Elimination" }
]
}
7.6. NSR - Number Select/Replacement
Purpose: Select preferred race number or request replacement.
Backend:
-
Class:
NumberSelectFormField.java(P2) -
StepCode:
NSR -
UI_CODE:
ESR(shared Equipment Select/Replace component)
Frontend Rendering:
-
Component: ESR (Equipment Select/Replace) - shared with TSR
-
Layout: Person info on left, equipment options on right
-
Header text configurable per equipment type
Logic:
-
Shows participant’s previously assigned numbers from past events
-
Allows selection of existing number or request for new/replacement
Data Model:
{
"action": "USE_EXISTING|REPLACEMENT|NEW",
"selectedNumberId": 123,
"numberValue": "127",
"replacementReason": "Lost number board"
}
7.7. TSR - Tag Select/Replacement
Purpose: Select preferred timing tag/chip or request replacement.
Backend:
-
Class:
TagSelectFormField.java(P2) -
StepCode:
TSR -
UI_CODE:
ESR(shared Equipment Select/Replace component)
Frontend Rendering:
-
Component: ESR (Equipment Select/Replace) - shared with NSR
-
Layout: Person info on left, equipment options on right
-
Header text configurable per equipment type
Logic:
-
Shows participant’s previously assigned timing tags
-
Allows selection of existing tag, request replacement, or rental
Data Model:
{
"action": "USE_EXISTING|REPLACEMENT|RENTAL|NEW",
"selectedTagId": 456,
"tagNumber": "A001234",
"replacementReason": "Tag expired"
}
8. Answer Data Migration (P2)
P2 introduces structured JSON answers to support complex data types.
8.1. Storage Design
-
Column:
data_valueincreased from VARCHAR(100) to VARCHAR(500) -
Format: JSON strings parsed using typed DTOs
8.2. Backward Compatibility
| Data Type | P1 Storage | P2 Storage | Detection |
|---|---|---|---|
TXT, BCB, SEL |
|
Same |
Not JSON |
CON, PHN, EMC, etc. |
N/A |
|
Starts with |
8.3. Answer DTOs
// PHN - Phone Number
public record PhoneAnswer(
String countryCode,
String number
) {}
// CON - Communication Preference
public record CommunicationPreferenceAnswer(
CommunicationType type, // EMAIL, SMS, WHATSAPP
String value,
String countryCode // Optional, for SMS/WhatsApp
) {}
// CSI - License Identification
public record LicenseAnswer(
LicenseType type, // CSA, UCI, NONE
String number // Optional, null for NONE
) {}
// EMC - Emergency Contact
public record EmergencyContactAnswer(
String name,
PhoneAnswer phone
) {}
9. Related Documentation
-
Process Flow - Overall registration process workflow
-
Screen Designs - SCR-005 Registration Questions specification
-
Functional Overview - System capabilities
-
P2 Design Journal - Design decisions and rationale