# Event Registration Flow — ALGA ARENA Esports Platform

**Date:** 2026-07-20

## Overview

Authenticated players register for events with an open registration window. Status depends on capacity, approval mode, and pricing.

---

## Prerequisites

1. User authenticated, email verified, status active
2. `player_profiles` row exists
3. `player_game_profiles` row for event's game
4. Phone number (`phone_e164`) on user or collected at registration
5. Event status = `registration_open`

---

## Routes

| Method | Route | Controller method |
|--------|-------|-------------------|
| GET | `/events/{slug}/register` | `create` |
| POST | `/events/{slug}/register` | `store` |
| GET | `/event-registrations/{registration}` | `show` |
| DELETE | `/event-registrations/{registration}` | `cancel` |
| GET | `/my-events` | `MyEventsController@index` |

**Action:** `RegisterForEventAction`, `CancelRegistrationAction`

---

## Registration Flow

```mermaid
flowchart TD
    A[GET register form] --> B{Phone valid?}
    B -->|No| C[Collect phone on POST]
    B -->|Yes| D[POST register]
    C --> D
    D --> E{Event allows registration?}
    E -->|No| F[Error: not open]
    E -->|Yes| G{Capacity full?}
    G -->|Yes + waitlist| H[Status: waitlisted]
    G -->|Yes no waitlist| I[Error: full]
    G -->|No| J{Paid event?}
    J -->|Yes| K[Status: pending_payment]
    J -->|No| L{Admin review?}
    L -->|Yes| M[Status: pending]
    L -->|No| N[Status: confirmed]
    H --> O[Record status event + notify]
    K --> O
    M --> O
    N --> O
```

---

## Initial Status Resolution

**Logic:** `RegisterForEventAction::resolveInitialStatus()`

| Condition | Initial `RegistrationStatus` |
|-----------|-------------------------------|
| Capacity full + waitlist enabled | `waitlisted` |
| Capacity full + no waitlist | Exception (rejected) |
| Paid event | `pending_payment` |
| Free + `approval_mode = admin_review` | `pending` |
| Free + automatic approval | `confirmed` |

### Payment status at registration

| Event pricing | Initial `PaymentStatus` |
|---------------|------------------------|
| Free | `not_required` |
| Paid | `pending` |

---

## Registration Record Fields

- `contact_name`, `contact_email`, `contact_phone_e164`, `contact_whatsapp`
- `player_game_profile_id` — must match event game
- `user_notes` — optional participant message
- `registered_at` — timestamp
- `confirmed_at` — set immediately if status is `confirmed`
- `waitlist_position` — assigned for waitlisted entries

---

## Status Enum Reference

**`RegistrationStatus`:**

| Value | Meaning |
|-------|---------|
| `pending` | Awaiting admin approval (free + admin_review) |
| `pending_payment` | Awaiting payment proof (paid) |
| `payment_review` | Proof submitted, admin reviewing payment |
| `confirmed` | Spot confirmed |
| `waitlisted` | Queue when full |
| `rejected` | Admin rejected |
| `cancelled` | User or system cancelled |
| `checked_in` | Event day check-in (future) |
| `attended` | Post-event (future) |
| `disqualified` | Removed from event (future) |

**Capacity-holding statuses** (`RegistrationStatusService::CAPACITY_HOLDING_STATUSES`):

`pending`, `pending_payment`, `payment_review`, `confirmed`, `checked_in`, `attended`

---

## Admin Review Flow

```
Registration status = pending
    ↓
Admin POST approve → ApproveRegistrationAction
    status → confirmed, confirmed_at set
    ↓
OR Admin POST reject → RejectRegistrationAction
    status → rejected
```

Both fire `RegistrationStatusChanged` → notifications.

---

## Waitlist Flow

```
Capacity full + waitlist → waitlisted (position assigned)
    ↓
Admin POST promote → PromoteWaitlistAction
    paid event → pending_payment
    free event → confirmed
    ↓
OR spot opens via CancelRegistrationAction
    auto PromoteWaitlistAction on next waitlisted entry
```

---

## Cancellation

**Policy:** Owner only, active status (`isActive()`)

```
DELETE /event-registrations/{registration}
    ↓
CancelRegistrationAction
    status → cancelled
    payment_status → cancelled
    If held capacity spot → auto-promote next waitlisted
```

---

## Status History

Every transition creates `event_registration_status_events` row via `RegistrationStatusService::record()`.

---

## Notifications Triggered

| Trigger | Notification class |
|---------|-------------------|
| New registration | `EventRegistrationReceivedNotification` |
| Waitlisted (new) | `EventRegistrationWaitlistedNotification` |
| Pending payment (new) | `ManualPaymentRequiredNotification` |
| Promoted from waitlist | `WaitlistPromotedNotification` |
| Confirmed | `EventRegistrationConfirmedNotification` |
| Rejected | `EventRegistrationRejectedNotification` |

See `NOTIFICATIONS.md` for full list.

---

## Duplicate Registration Prevention

`RegistrationStatusService::hasActiveRegistration()` — checks for existing active registration per user/event (use in form request validation).

---

## Form Request

**`StoreEventRegistrationRequest`** — validates contact fields, game profile ownership, duplicate checks.
