# Spec di design — Fase 3.3: Giocatore (auto-iscrizione + dashboard)

**Data:** 2026-06-12 · **Stato:** deciso in autonomia · **Autore:** Claude
**Base:** F3.0 (schema), F3.1 (engine), F3.2 (service layer eventi + admin). Master spec §1/§9.

---

## 1. Obiettivo e ambito
Dare al **giocatore loggato** due cose: **auto-iscriversi** agli eventi con iscrizioni aperte, e una **dashboard personale** (le mie iscrizioni, le mie partite, la mia classifica nei gironi correnti, il mio storico ranking).

**Dentro:**
- Auto-iscrizione: lista eventi in stato `iscrizioni` + bottone "Iscriviti" (crea `eventRegistration` stato `richiesta`; l'admin conferma in F3.2).
- Dashboard giocatore arricchita: sezioni "I miei eventi", "Le mie partite" (con link app + esito), "Le mie classifiche", "Il mio ranking".

**Fuori:** notifiche (F3.6), calendario con date/avvio automatico (le date partita si gestiscono in F3.2/F3.6), claim allo storico (richiede migrazione F3.5).

## 2. Decisioni d'impianto (autonome)
1. **Player dal User**: ogni vista giocatore parte da `getPlayerByUserId(locals.user.id)` (già esistente da F2b). Se manca il player (caso raro), self-heal come in /profilo.
2. **Auto-iscrizione → `richiesta`**: il giocatore chiede; l'admin conferma (coerente con F3.2). Niente auto-conferma in V1 (l'admin gestisce capienza/coda).
3. **Service dedicato** `src/lib/server/players/player-view.ts`: `listOpenEvents()`, `getPlayerOverview(playerId)` (iscrizioni + partite + classifiche + ranking). Riusa le tabelle; query mirate.
4. **Dashboard come hub giocatore**: arricchisco `/dashboard` (già esistente) invece di creare nuove rotte, mantenendo profilo/logout. Le partite mostrano: serie/girone, avversari, `linkAppCge`, stato, e (se conclusa) la posizione.
5. **Iscrizione idempotente**: `registerPlayer` (F3.2) già impedisce doppie iscrizioni (unique eventId+playerId) → messaggio pulito.

## 3. Architettura
- **`src/lib/server/players/player-view.ts`**:
  - `listOpenEvents(): Promise<{ id; slug; nome; tipo }[]>` — eventi `stato='iscrizioni'`.
  - `getPlayerOverview(playerId): Promise<{ iscrizioni; partite; classifiche; ranking }>`:
    - iscrizioni: `eventRegistration` del player + evento (nome, slug, stato della registrazione).
    - partite: `matchParticipant` del player → `match` (stato, nGiocatori, linkAppCge) → `girone` (livello) → `event` (nome), + gli avversari (altri partecipanti).
    - classifiche: `standing` del player → girone/evento (puntiTorneo, posizione).
    - ranking: righe `ranking` del player (storico per stagione, ordinate).
- **Route**:
  - `/dashboard/+page.server.ts` — arricchito: carica player + overview + open events.
  - `/dashboard/+page.svelte` — sezioni; bottoni "Iscriviti" (form action) per gli eventi aperti.
  - **Action** `iscriviti` in `/dashboard/+page.server.ts`: `registerPlayer(eventId, playerId, 'richiesta')`.

## 4. Test
- **Integration** `player-view.integration.test.ts`: crea evento+player+iscrizione+partita+standing+ranking → `getPlayerOverview` ritorna le sezioni corrette; `listOpenEvents` filtra per stato. Cleanup.
- Gate: check/build verdi; dashboard monta.

## 5. Note (da validare)
- Auto-iscrizione = `richiesta` (admin conferma). Se l'organizzazione vuole auto-conferma, è un flag.
- Le date/orari delle partite e l'avvio non sono in F3.3 (gestione in F3.2 admin / F3.6 notifiche).
</content>
