Event Registration
1. Overview
The Event Registration workflow enables users to register participants for events such as races, tournaments, and competitions. It follows the Phase 2 Registration Design with implementation-specific details for event scenarios.
Key Features:
-
Multi-participant Registration - Register multiple people in a single transaction
-
LinkedPerson Integration - Select from existing linked persons
-
Order-based System - Creates Order entity for payment tracking
-
Payment Gateway Integration - Redirect to payment portal after registration
-
Cancellation Support - Cancel registrations with refund rules (Phase 2)
2. Event Concepts
2.1. Event Entities
Event
Defines the overall competition or activity:
-
Name, description, dates
-
Location and venue
-
Organizer (Organisation)
-
Registration open/close dates
-
Status (upcoming, active, completed, cancelled)
Race
Specific category or distance within an event:
-
Name (e.g., "10km Run", "21km Half Marathon")
-
Distance, difficulty level
-
Age restrictions
-
Maximum participants
-
Price per participant
EventParticipant
Individual participant registration:
-
Links Person to Race
-
Stores participant-specific details
-
Tracks registration status
-
References Order for payment
-
Can include additional participant information (bib number, start time, etc.)
Order
Payment transaction container:
-
Groups multiple EventParticipants
-
Tracks payment status
-
Links to buyer (Person via userKey)
-
Total amount
-
Payment gateway reference
3. Registration Flow by Step
This section details each step from the Phase 2 Registration Design as it applies to event registration.
3.1. Step 1: Identity Selection
|
Phase 2 Enhancement: Identity Selection is a new capability being introduced. Current implementation uses URL parameters for user identification. |
3.1.1. Current Implementation (URL-Based Access)
Route Pattern:
/register
Query Parameters:
| Parameter | Description | Required | Example |
|---|---|---|---|
|
Event ID to register for |
Yes |
|
|
Organisation ID (organizer) |
Yes |
|
|
User key (security context) |
Optional |
|
Example URLs:
https://app.example.com/register?eventId=42&orgId=8&userKey=abc123xyz
https://app.example.com/register?eventId=42&orgId=8
Session vs URL userKey:
-
If
userKeyprovided in URL → Use URL parameter (external link scenario) -
If no
userKeyin URL → Use sessionuserKey(logged-in user scenario)
3.1.2. Phase 2: OIDC Authentication
When OIDC authentication is configured for the tenant, users will be presented with a choice:
-
Authenticate - Sign in via OIDC provider to access existing profile
-
Continue Anonymously - Proceed without authentication
See Identity Selection in the Phase 2 design for details.
3.2. Step 2: Registration Overview
The Registration Overview displays the event details and linked persons for selection.
Component: RegistrationComponent
File: src/main/webapp/app/entities/registration/list/registration.component.ts
3.2.1. Component Structure
export class RegistrationComponent implements OnInit, OnDestroy {
persons: IPersonSelect[] = [];
selectForm!: FormGroup;
selectCount = 0;
isLoading = false;
isSaving = false;
_eventId: number | undefined;
event: IEvent | undefined;
_organisationId: number | undefined;
organisation: IOrganisation | undefined;
_userKey: string | undefined;
principal: IPerson | undefined;
sessionUserId: boolean = true;
}
3.2.2. Initialization
ngOnInit(): void {
this.selectForm = this.fb.group({
selection: this.fb.array([]),
});
// Subscribe to checkbox changes for count
this.selectionChangeSubscription = this.selectForm.valueChanges
.subscribe(data => {
const arr: boolean[] = data.selection;
this.selectCount = arr.reduce((n, checkbox) =>
(checkbox ? n + 1 : n), 0);
});
this.handleNavigation();
}
3.2.3. Navigation Handler
protected handleNavigation(): void {
combineLatest([this.activatedRoute.data, this.activatedRoute.queryParamMap])
.subscribe(([data, params]) => {
const eventId = params.get('eventId');
if (eventId) {
this.eventId = +eventId;
}
const organisationId = params.get('orgId');
if (organisationId) {
this.organisationId = +organisationId;
}
const userKey = params.get('userKey');
if (userKey) {
this.userKey = userKey;
this.sessionUserId = false;
} else {
this.userKey = this.sessionService.getUserKey();
this.sessionUserId = true;
}
this.loadPage(pageNumber, true);
});
}
API Endpoints Called:
-
GET /api/events/{id}- Load event details -
GET /api/organisations/{id}- Load organisation details -
GET /api/people/userkey/{userkey}- Load or create principal person
3.2.4. Loading LinkedPersons
loadPage(page?: number, dontNavigate?: boolean): void {
const pageToLoad: number = page ?? this.page ?? 1;
if (this.organisationId && this.userKey) {
this.isLoading = true;
this.personService.getAllLinkedOrgUsersByPrincipal(
this.userKey,
this.organisationId
).subscribe(
(res: EmbeddedLinkedPersonDTO[]) => {
this.isLoading = false;
this.persons = res;
this.selectForm.setControl('selection', this.buildSelection());
},
() => {
this.isLoading = false;
this.onError();
}
);
}
}
API Endpoint: GET /api/people/linked?userKey={key}&organisationId={orgid}
Response:
[
{
"id": 1,
"firstName": "John",
"lastName": "Smith",
"dateOfBirth": "1985-03-15",
"gender": "MALE",
"email": "[email protected]",
"contactNumber": "0821234567"
},
{
"id": 3,
"firstName": "Billy",
"lastName": "Smith",
"dateOfBirth": "2010-11-03",
"gender": "MALE",
"email": null,
"contactNumber": null
}
]
3.2.6. Existing Registration Status
|
Phase 2 Enhancement: The Registration Overview will clearly show if any person is already registered for this event. See Registration Overview in the Phase 2 design. |
For persons already registered:
-
Display "Registered" status
-
Show bib number if assigned
-
If current user was the payer, show link to view order/payment/invoice details
3.2.7. Event Cancellation
|
Phase 2 Enhancement: Event cancellation with refund rules is a new capability. See Registration Overview in the Phase 2 design. Outstanding Requirements:
|
For events, users will be able to cancel existing registrations:
-
Select registered person
-
Request cancellation
-
System applies configured refund rules
-
Refund processed (if applicable)
-
Registration status updated to cancelled
3.3. Step 3: Link Person
The Link Person step allows users to add participants to their profile.
See LinkedPerson Management for complete details on the person search, matching, and linking workflow.
Add Person Button:
<a routerLink="/linked-person/search">
<button type="button" class="btn btn-primary">
<fa-icon icon="plus"></fa-icon>
Add Person
</button>
</a>
Flow:
-
User clicks "Add Person"
-
Navigate to
/linked-person/search -
User searches/creates person
-
Person is linked to principal
-
Return to
/registerwith updated person list
3.3.1. Form Array for Selection
buildSelection(clear?: boolean): FormArray<FormControl<boolean | null>> {
const arr = this.persons.map(person => {
return this.fb.control(!clear ? !!person.selected : false);
});
return this.fb.array(arr);
}
get selectionControl(): FormArray<FormControl<boolean | null | undefined>> {
return this.selectForm.get('selection') as FormArray;
}
Validation:
get canRegister(): boolean {
return !!this.event &&
this.selectForm.valid &&
this.selectCount > 0 &&
!this.isLoading &&
!this.isSaving;
}
3.4. Step 4: Registration Details
|
Phase 2 Enhancement: Event registration will support process-driven questions similar to membership registration. Current implementation uses direct registration without questions. |
3.4.1. Current Implementation (Direct Registration)
Event registration currently bypasses the question workflow and proceeds directly to registration submission.
3.4.2. Phase 2: Question Workflow
For Phase 2, event registration will support:
-
Category Selection - Choose race category for each participant
-
Personal Information - Emergency contact, medical conditions (if not already captured)
-
Event-Specific Questions - T-shirt size, transport requirements, etc.
-
Legal Acceptance - Event indemnity, terms and conditions
The question workflow will use the same ProcessDefinition system as membership registration. See Process Flow Integration for details.
3.5. Step 5: Order Creation
Upon completing Registration Details, the system commits the registration to the admin-service:
-
EventParticipant records created (status: Pending Payment)
-
Order created with line items:
-
Event entry fee per participant
-
Additional fees (if applicable)
-
-
Order status set to Unpaid
The order details are then used to either display a reference number for manual payment or create a corresponding WooCommerce order for online payment.
See Order Creation in the Phase 2 design for complete details on the order creation process and payment callbacks.
3.6. Step 6: Payment
3.6.1. Registration Submission
register(value: boolean[]) {
if (this.canRegister) {
const participants: IParticipantCandidate[] = [];
this.selectionControl.value.forEach((checkbox, i) => {
if (!!checkbox) {
const person: IPerson = this.persons[i];
const participant: IParticipantCandidate = {
id: null,
person
};
participants.push(participant);
}
});
const order: NewOrder = {
id: null,
organisation: this.organisation ?? null,
buyer: { id: null, userKey: this.userKey ?? null },
};
const registration: IEventParticipantRegistration = {
event: this.event!,
participants,
order,
};
this.isSaving = true;
this.registrationService.register(registration).subscribe(
(res: HttpResponse<IEventParticipantRegistration>) => {
this.log.debug('Registration', res.body);
this.clear();
this.isSaving = false;
if (res.body?.infoURL) {
location.href = res.body.infoURL;
}
},
() => {
this.clear();
this.isSaving = false;
}
);
}
}
3.6.2. Registration Model
export interface IParticipantCandidate extends NewEventParticipant {
questions?: IQuestion[];
answer?: string;
valid?: boolean;
message?: string;
}
export interface IEventParticipantRegistration {
event: IEvent;
participants: IParticipantCandidate[];
order?: IOrder | NewOrder;
phase?: string;
title?: string;
message?: string;
infoURL?: string;
questionType?: string;
}
3.6.3. Request Payload Example
{
"event": {
"id": 42,
"name": "Marathon 2024",
"startDate": "2024-06-15T08:00:00Z"
},
"participants": [
{
"id": null,
"person": {
"id": 3,
"firstName": "Billy",
"lastName": "Smith",
"dateOfBirth": "2010-11-03",
"gender": "MALE"
}
}
],
"order": {
"id": null,
"organisation": {
"id": 8,
"name": "Running Club"
},
"buyer": {
"id": null,
"userKey": "abc123xyz"
}
}
}
API Endpoint: POST /api/event-participants/register
3.6.4. Backend Processing
Backend Flow:
-
Validate Registration
-
Check event registration is open
-
Verify person eligibility
-
Check age restrictions for race
-
Verify maximum participants not exceeded
-
-
Create EventParticipant Records
-
One EventParticipant per selected person
-
Link to Race (derived from Event)
-
Assign bib numbers (if applicable)
-
Set status to PENDING_PAYMENT
-
-
Create Order
-
Calculate total amount (participants × race price)
-
Generate order reference
-
Link to Organisation
-
Store buyer userKey
-
-
Payment Integration
-
If amount > 0, generate payment URL
-
Include order reference and return URL
-
Return infoURL in response
-
-
Free Registration
-
If amount = 0, mark participants as REGISTERED
-
Send confirmation email
-
No payment redirect needed
-
3.6.5. Registration Response
{
"event": {
"id": 42,
"name": "Marathon 2024"
},
"participants": [
{
"id": 1523,
"person": {
"id": 3,
"firstName": "Billy",
"lastName": "Smith"
},
"bibNumber": "B1523",
"status": "PENDING_PAYMENT"
}
],
"order": {
"id": 892,
"reference": "ORD-892-2024",
"totalAmount": 350.00,
"status": "PENDING"
},
"infoURL": "https://payment.gateway.com/pay?reference=ORD-892-2024&amount=350.00&return=https://app.example.com/registration/payment-return"
}
3.6.6. Online Payment (WooCommerce)
Payment Redirect:
if (res.body?.infoURL) {
location.href = res.body.infoURL;
}
Payment Gateway URL Example:
https://payment.gateway.com/pay?
reference=ORD-892-2024&
amount=350.00&
return=https://app.example.com/registration/payment-return&
cancel=https://app.example.com/registration/payment-cancel
3.6.7. Manual Payment
|
Phase 2 Enhancement: Manual payment is a new capability being introduced. See Payment in the Phase 2 design. |
Manual payment will be available for registration desk scenarios at events:
-
System generates reference number with QR code
-
User presents QR code to staff at registration desk
-
Staff scans/enters reference on registration system
-
Staff captures: amount, payment method, outcome
-
Registration completes upon payment confirmation
3.6.8. Payment Return
Return URL: /registration/payment-return
Query Parameters:
| Parameter | Description | Example |
|---|---|---|
|
Order reference |
|
|
Payment status |
|
|
Gateway transaction ID |
|
Backend Processing on Return:
-
Verify payment status with gateway
-
Update Order status
-
Update EventParticipant status
-
Send confirmation email
-
Display success/failure message
3.7. Step 7: Confirmation & Notifications
3.7.1. Immediate Confirmation
Upon successful payment:
-
EventParticipant records marked as REGISTERED
-
Bib numbers assigned (if applicable)
-
Confirmation displayed with registration details
-
Confirmation email sent
Confirmation Display:
Registration Successful!
Billy Smith - Bib Number: B1523
You will receive your race pack at:
Race Expo: March 14, 2024, 10:00-18:00
Centurion Mall
Race Start: March 15, 2024, 07:00
Good luck!
3.7.2. Scheduled Notifications
|
Phase 2 Enhancement: Scheduled notifications are managed by long-running processes. See Confirmation & Notifications in the Phase 2 design. |
For events, scheduled notifications include:
-
Registration confirmation with event details
-
Event location and directions (closer to event date)
-
Program updates and changes
-
Pre-event reminders (day before, morning of)
-
Post-event results and certificates
4. Error Handling
4.1. Validation Errors
Client-Side:
-
No event loaded → Disable register button
-
No persons selected → Disable register button
-
Form invalid → Display validation messages
Server-Side:
{
"phase": "VALIDATION_ERROR",
"title": "Registration Error",
"message": "One or more participants are not eligible for this event",
"participants": [
{
"id": null,
"person": { "id": 3, "firstName": "Billy", "lastName": "Smith" },
"valid": false,
"message": "Participant is under minimum age requirement (18 years)"
}
]
}
Error Display:
<div *ngIf="registration.phase === 'VALIDATION_ERROR'" class="alert alert-danger">
<h4>{{ registration.title }}</h4>
<p>{{ registration.message }}</p>
<ul>
<li *ngFor="let p of registration.participants">
<span *ngIf="!p.valid">
{{ p.person.firstName }} {{ p.person.lastName }}: {{ p.message }}
</span>
</li>
</ul>
</div>
4.2. Registration Failures
Common Failure Scenarios:
| Scenario | Cause | Resolution |
|---|---|---|
Event Full |
Maximum participants reached |
Show waitlist option |
Registration Closed |
Outside registration window |
Display event information only |
Duplicate Registration |
Person already registered |
Show existing registration |
Payment Gateway Down |
External service unavailable |
Allow registration, mark as pending payment |
Network Error |
Connection timeout |
Show retry button, preserve selection |
4.3. Loading States
<div *ngIf="isLoading" class="text-center">
<div class="spinner-border" role="status">
<span class="sr-only">Loading persons...</span>
</div>
</div>
<div *ngIf="isSaving" class="text-center">
<div class="spinner-border" role="status">
<span class="sr-only">Processing registration...</span>
</div>
</div>
5. Integration Points
5.1. LinkedPerson Workflow
Event registration integrates with LinkedPerson management:
-
User accesses registration URL
-
System loads linked persons for user
-
User can add more persons via LinkedPerson workflow
-
User selects participants from linked persons
-
Registration creates EventParticipant records
5.2. Order System
Event registration creates Order entities:
-
Order - Container for transaction
-
OrderLine - Individual line items (one per participant)
-
Payment - Payment record after gateway processing
See Financial Entities for details.
5.3. Email Notifications
Registration Confirmation:
-
Sent after successful registration (free events)
-
Sent after successful payment (paid events)
-
Includes participant details, event information
-
Includes payment receipt (if applicable)
Payment Receipt:
-
Sent after successful payment
-
Includes order reference, amount paid
-
Itemized list of participants