# Player Profile Flow — ALGA ARENA Esports Platform

**Date:** 2026-07-20

## Overview

Every registered user gets a `player_profiles` row automatically. Profiles are the anchor for game profiles, records, videos, and event registrations.

---

## 1. Registration → Profile Creation

**Route:** `POST /register`  
**Controller:** `Auth\RegisteredUserController`  
**Action:** `RegisterUserAction` → `CreatePlayerProfileOnRegistration`

### Flow

```
User submits registration form
    ↓
RegisterUserAction (DB transaction)
    ├── Create User (role=user, status=active, terms_accepted_at=now)
    ├── Normalize phone (optional) via PhoneNormalizationService
    └── CreatePlayerProfileOnRegistration
            └── PlayerProfile (display_name, country, timezone, amateur, public, 0% complete)
    ↓
Email verification required (MustVerifyEmail)
    ↓
User can access authenticated routes after verify + active middleware
```

### User fields set at registration

- `public_id`, `username`, `display_name`, `email`, `password`
- `country_code`, `preferred_locale`, `timezone`
- Optional phone → `phone_country_code`, `phone_number`, `phone_e164`

### Player profile defaults

- `player_level`: `amateur`
- `profile_visibility`: `public`
- `profile_completion_percentage`: `0`
- `status`: `active`

---

## 2. Profile View (Public)

**Route:** `GET /players/{playerProfile}`  
**Controller:** `ProfileController@show`  
**Policy:** `PlayerProfilePolicy@view` (always allowed)

### Behavior

- Loads profile with user, social links, languages, game profiles, records, videos
- Maps DB data to frontend array shape via `toPlayerArray()` for Blade compatibility
- Uses `user.username` as public slug in the view model
- Avatar/cover from `profiles` disk with fallbacks to static assets
- Still injects mock feed slice from `MockDataService` (3 items) — partial preview integration

**Route binding:** `PlayerProfile` resolves by `public_id` (UUID), not username.

---

## 3. Profile Edit

**Routes:**

| Route | Controller | Purpose |
|-------|------------|---------|
| `GET /profile/edit` | ProfileController@edit | Redirects to settings account tab |
| `GET /settings/{tab}` | SettingsController@index | account \| security \| notifications |
| `POST /settings/profile` | SettingsController@updateProfile | Update profile fields |
| `POST /settings/password` | SettingsController@updatePassword | Change password |
| `POST /settings/phone` | SettingsController@updatePhone | Update E.164 phone |

**Action:** `UpdatePlayerProfileAction`  
**Policy:** `PlayerProfilePolicy@update` (owner only)

### Updatable fields (via settings)

- User: `display_name`, `username` (via form requests)
- Profile: `bio`, `country_code`, `city`, `looking_for_team`, avatar/cover uploads via `UploadProfileImageAction`

Phone updates clear `phone_verified_at` until re-verified (verification not implemented in MVP).

---

## 4. Profile Completion

`profile_completion_percentage` column exists but automated calculation is not fully wired in all code paths — defaults to `0` at registration. Frontend may display the field from `ProfileController` mapping.

---

## 5. Related Flows (downstream)

| Feature | Requires profile |
|---------|------------------|
| Player game profiles | Yes — `PlayerGameProfileController` |
| Records | Yes — `PlayerRecordPolicy@create` |
| Videos | Yes — `PlayerVideoPolicy@create` |
| Event registration | Yes — `RegisterForEventAction` throws if missing |

---

## 6. Admin Visibility

**Route:** `GET /admin/player-profiles`  
**Controller:** `Admin\PlayerProfileController@index`  
Read-only listing for admins; no edit/suspend at profile level (user suspend is on `Admin\UserController`).

---

## Sequence Diagram

```mermaid
sequenceDiagram
    participant U as User
    participant R as RegisteredUserController
    participant A as RegisterUserAction
    participant P as CreatePlayerProfileOnRegistration
    participant DB as Database

    U->>R: POST /register
    R->>A: execute(data)
    A->>DB: INSERT users
    A->>P: execute(user, data)
    P->>DB: INSERT player_profiles
    A-->>R: User
    R-->>U: Redirect + verify email notice

    Note over U,DB: After email verified

    U->>ProfileController: GET /players/{public_id}
    ProfileController->>DB: Load profile + relations
    ProfileController-->>U: Blade view (mapped array)
```

---

## Models & Relationships

```
User
 └── hasOne PlayerProfile
       ├── hasMany PlayerSocialLink
       ├── hasMany PlayerLanguage
       ├── hasMany PlayerPreference
       ├── hasMany PlayerGameProfile
       ├── hasMany PlayerRecord
       └── hasMany PlayerVideo
```

---

## Known Limitations

1. Public profile URL uses UUID `public_id`, not `@username` slug — differs from preview routes (`/preview/profile/{slug}`).
2. Profile feed section still uses mock data.
3. `verified` / `premium` badges hardcoded `false` in view mapper.
4. Phone verification timestamp stored but SMS/OTP verification not implemented.
