# Player Management CRUD Design

## Goal

Build session-scoped player management for CourtKulture staff so they can add, view, edit, and delete players within a specific open-play session without changing backend match generation behavior. Convert app-wide flash/status alerts and destructive confirmations to SweetAlert2 as part of the same staff usability pass.

## Scope

This feature is limited to players that belong to one `OpenPlaySession`. It does not introduce a global club member directory, reusable player profiles, memberships, payments, or cross-session player history.

Existing quick-add and Reclub paste import behavior will remain available. The new management page gives staff a dedicated roster workspace for correcting details and removing players from a session.

The SweetAlert2 work covers global flash/status messages and destructive confirmations in Blade pages. Field-level validation errors remain inline beside inputs because staff need immediate form context on mobile.

## Product Behavior

Staff can open a session dashboard and choose **Manage Players**. The player management page shows all players for that session, including name, email, skill level, gender, queue/status, import source, and standings stats.

Staff can create a player from the management page using the same supported fields as quick-add:

- Display name
- Email
- Skill level
- Gender
- Optional check-in to queue

Staff can edit:

- Display name
- Email
- Skill level
- Gender

Staff can delete a player only when the player is not currently assigned to an in-progress match. Deleting a player soft-deletes the player and removes their visible queue entries through the existing queue service. If a player is actively playing, the delete request is blocked with a validation-style error message and the staff member must score or otherwise finish the match first.

Flash messages such as "Player added", "Player updated", "Player deleted", match generation status, and auth status will render through SweetAlert2 instead of Bootstrap alert blocks. Destructive actions such as player deletion will use a SweetAlert2 confirmation before form submission.

## Architecture

Player management stays nested under staff sessions because the current data model stores `open_play_session_id` directly on `players`, and queue entries, matches, and standings are session-local.

Routes will be added under the existing authenticated, verified, staff-only route group:

- `GET staff/sessions/{session}/players`
- `GET staff/sessions/{session}/players/create`
- Existing `POST staff/sessions/{session}/players`
- `GET staff/sessions/{session}/players/{player}/edit`
- `PATCH staff/sessions/{session}/players/{player}`
- `DELETE staff/sessions/{session}/players/{player}`

The `PlayerController` can remain the staff controller for this session-scoped resource. It should stay thin and delegate queue cleanup to `QueueService`. If the delete workflow becomes more than a few lines, introduce a small `PlayerManagementService` for session ownership checks, active-match checks, and deletion.

## Data Flow

Create:

1. Staff submits create form or existing quick-add form.
2. `StorePlayerRequest` validates staff authorization and per-session unique display name/email.
3. Controller creates the player with `open_play_session_id`, `import_source=manual`, and `status=active`.
4. If `check_in` is set, `QueueService::addPlayerToQueue()` marks the player as waiting.

Update:

1. Staff submits edit form.
2. `UpdatePlayerRequest` validates staff authorization, session-scoped uniqueness while ignoring the current player, skill level, and gender.
3. Controller verifies the player belongs to the session.
4. Controller updates only editable fields.

Delete:

1. Staff submits delete form.
2. Controller verifies the player belongs to the session.
3. Controller checks whether the player appears in any `in_progress` match team for the same session.
4. If active, redirect back with an error and do not delete.
5. If inactive, remove visible queue entries with `QueueService::removePlayerFromQueue()`, then soft-delete the player.

## UI Design

Add a **Manage Players** button near the Player Standings heading on the session dashboard. Do not add edit/delete buttons into the standings table; that table should stay focused on stats.

Create new staff player views:

- `resources/views/staff/players/index.blade.php`
- `resources/views/staff/players/create.blade.php`
- `resources/views/staff/players/edit.blade.php`

The index page will be mobile-first:

- Header with session name, status badge, and back-to-session link
- Primary `Add Player` action
- Mobile cards for players
- Responsive table for tablet and desktop
- Badges for skill level, gender, player status, and import source
- Edit and Delete actions per player

The create and edit pages will use simple Bootstrap forms matching the existing CourtKulture branding and button styles. Primary submit buttons use `btn btn-cq btn-cq-active`; secondary navigation uses `btn btn-outline-secondary`; destructive delete actions use `btn btn-outline-danger`.

## SweetAlert2 Alert Design

Add SweetAlert2 as an npm dependency and import it from `resources/js/app.js`.

Use a small shared JavaScript bridge:

- Read flash payloads from `data-cq-flash-status` and `data-cq-flash-errors` attributes rendered by layouts.
- Show success/info messages with CourtKulture-friendly SweetAlert2 styling.
- Show form-level error summaries with an error icon.
- Attach confirmation behavior to forms marked with `data-cq-confirm`.
- Submit the form only after staff confirm the SweetAlert2 prompt.

Existing Bootstrap alert blocks in staff/login/auth-session status areas should be removed or replaced with hidden data containers. Inline validation feedback such as `.invalid-feedback` and `<x-input-error>` stays in place.

## Validation And Error Handling

Validation rules:

- `display_name`: required, string, max 255, unique inside the session
- `email`: nullable, valid email, max 255, unique inside the session
- `skill_level`: required, one of `beginner`, `intermediate`, `advanced`
- `gender`: required, one of `male`, `female`, `unspecified`
- `check_in`: nullable boolean on create only

Update validation must ignore the current player for uniqueness.

Cross-session player access must be blocked. If a staff member attempts to edit, update, or delete a player through the wrong session URL, return 404.

Delete of a player in an in-progress match must redirect back with a clear error message.

Flash and form-level errors should be exposed to SweetAlert2 through escaped JSON in Blade. Do not concatenate untrusted message strings into executable JavaScript.

## Security

All routes remain behind `auth`, `verified`, and `staff` middleware. Form Requests authorize only staff users. Blade forms include CSRF tokens. Update and delete actions must explicitly ensure the player belongs to the session before modifying data.

Deletion is soft-delete only. This preserves match and standings history and reduces accidental data loss.

SweetAlert2 is the only new dependency. No secrets or external services are required.

## Testing

Add feature coverage for:

- Staff can view the session player management page.
- Staff can open create and edit forms.
- Staff can update player details.
- Update rejects duplicate display name/email within the same session.
- Same display name/email can exist in a different session.
- Non-staff users cannot access player management routes.
- Cross-session player edit/update/delete returns 404.
- Deleting a waiting player removes visible queue entries and soft-deletes the player.
- Deleting a player in an in-progress match is blocked.
- Session dashboard shows the Manage Players entry point.
- Staff layout exposes success/error flash payloads for SweetAlert2 without rendering Bootstrap alert blocks.
- Player delete forms expose SweetAlert2 confirmation attributes.

Run:

- `php artisan test`
- `npm run build`

## Affected Files

Likely modified files:

- `routes/web.php`
- `app/Http/Controllers/Staff/PlayerController.php`
- `app/Http/Requests/Staff/StorePlayerRequest.php`
- `resources/js/app.js`
- `resources/views/staff/sessions/show.blade.php`
- `resources/views/layouts/staff.blade.php`
- `resources/views/auth/login.blade.php`
- `resources/views/components/auth-session-status.blade.php`
- `resources/css/app.css`
- `package.json`
- `package-lock.json`

Likely new files:

- `app/Http/Requests/Staff/UpdatePlayerRequest.php`
- `resources/views/staff/players/index.blade.php`
- `resources/views/staff/players/create.blade.php`
- `resources/views/staff/players/edit.blade.php`
- `tests/Feature/StaffPlayerManagementTest.php`

Optional new file if controller logic needs extraction:

- `app/Services/PlayerManagementService.php`

## Out Of Scope

- Global member/player directory
- Player profile photos
- Player merge/dedupe tools
- CSV file upload
- Bulk edit
- Matchmaking algorithm changes
- Public live view changes
