# scouthub-eventi-fe Frontend Angular per la gestione degli **eventi** Scouthub (calendario per branca, con sotto-eventi a due livelli), affianca `scouthub-attivita-fe`, `scouthub-home-fe` e `scouthub-magazzino-fe` nello stesso ecosistema. Parla con `scouthub-eventi-be` per le API e con Keycloak per l'autenticazione. Componenti standalone (nessun NgModule), routing con lazy loading per feature, Angular Material per la UI. ## Stato del progetto Le viste calendario (annuale, mensile) e il form di creazione/modifica evento sono implementati e funzionanti. L'intera app è privata (richiede login): non esiste ancora una vista pubblica del calendario. ## Struttura cartelle ``` src/app/ core/ auth/ keycloak.provider.ts provideKeycloakAngular() — login OIDC Authorization Code + PKCE auth-context.ts extractAuthContext() — ruoli + branche ("groups") dal token branca-access.ts hasBrancaAccess()/hasAnyBrancaAccess(), rispecchia assertBrancaAccess del BE require-branca-access.guard.ts guard di routing per creazione/modifica evento require-auth.guard.ts requireAuthGuard — richiede login, altrimenti avvia keycloak.login() eventi-api.service.ts client HTTP verso GET/POST/PUT /eventi (dettaglio, crea, aggiorna) utils/ colore-tipo.ts colore deterministico per "tipo" evento (hash su palette fissa) nomi-mesi.ts nomi mesi in italiano per le viste calendario vista-annuale/ feature "calendario annuale" (/vista-annuale, lazy-loaded) vista-annuale-api.service.ts client verso GET /eventi?vista=anno vista-mensile/ feature "calendario mensile" (/vista-mensile, lazy-loaded, home di default) vista-mensile-api.service.ts client verso GET /eventi?vista=mese, filtro branca lato client vista-evento/ feature "dettaglio/form evento" (/vista-evento, lazy-loaded) evento-form/ form condiviso per crea/modifica/sotto-evento src/environments/ environment.ts / environment.development.ts public/ silent-check-sso.html richiesto dal flusso check-sso silenzioso di Keycloak ``` ### Modulo di autenticazione - **Login**: `provideKeycloak` (in `keycloak.provider.ts`) usa il client pubblico `scouthub-frontend` — **condiviso con tutti gli altri frontend** (`scouthub-attivita-fe`, `scouthub-home-fe`, `scouthub-magazzino-fe`) — con Authorization Code Flow + PKCE, `onLoad: 'check-sso'` e refresh automatico del token via `withAutoRefreshToken` (logout automatico dopo 5 minuti di inattività). - **requireAuthGuard** (`core/require-auth.guard.ts`): applicato sulla route radice in `app.routes.ts`, protegge quindi tutte le sotto-route in un colpo solo (l'app non ha aree pubbliche). - **extractAuthContext** (`core/auth/auth-context.ts`): rispecchia lato client la stessa logica di `verify-token.middleware.ts` sul backend — i ruoli sono `realm_access.roles` più i ruoli sull'organizzazione attiva (claim `organization`), le branche vengono dal claim standard `groups` (path tipo `/Lupetti`, normalizzati togliendo lo slash iniziale). Non esiste ancora un claim branca dedicato. - **hasBrancaAccess / hasAnyBrancaAccess** (`core/auth/branca-access.ts`): `capo-gruppo` ha accesso in scrittura a qualunque branca dell'organizzazione; `capo-unita` solo alle branche a cui appartiene. Usate solo per nascondere via routing gli entry point non pertinenti: **il controllo autoritativo resta lato backend** (`assertBrancaAccess` su `POST`/`PUT /eventi`). - Le chiamate verso `eventiApiBaseUrl` ricevono automaticamente l'header `Authorization: Bearer ` tramite l'interceptor `includeBearerTokenInterceptor` di `keycloak-angular`, condizionato via regex sull'URL base dell'API in `app.config.ts`. ### Feature `vista-mensile` (`/vista-mensile`, home di default) Calendario del mese corrente/selezionato: carica **tutti** gli eventi del mese (radice e figli, trasversali a tutte le branche) tramite `GET /eventi?vista=mese`, e filtra lato client per branca tramite un select — così il filtro resta popolato con tutte le branche presenti nel mese anche dopo aver selezionato una branca specifica. ### Feature `vista-annuale` (`/vista-annuale`) Vista d'insieme dell'anno: per ogni giorno con almeno un evento radice, mostra un conteggio e l'elenco sintetico (titolo/tipo/branca) tramite `GET /eventi?vista=anno`. Nessun dettaglio descrizione/risorse in questa vista (aggregato leggero, coerente con quanto espone il backend). ### Feature `vista-evento` (`/vista-evento`) - `/vista-evento/:id` — dettaglio completo di un evento, con i suoi eventuali figli (2° livello) e le risorse collegate create da altri backend (`RisorsaCollegata`). - `/vista-evento/nuovo` — crea un evento radice su una branca a scelta tra quelle dell'utente (`requireCreaEventoGuard`, visibile solo a chi ha accesso ad almeno una branca). - `/vista-evento/:id/modifica` — modifica un evento esistente (`requireBrancaAccessEventoGuard`, carica prima l'evento per conoscerne la branca e poter decidere l'accesso). - `/vista-evento/:id/sotto-evento` — crea un sotto-evento del padre `:id`; il form eredita branca/vincoli di data dal genitore e blocca il campo branca. Non disponibile se `:id` è già esso stesso un sotto-evento (massimo due livelli di annidamento, imposto anche lato backend). Il form (`evento-form/`) valida che la data/ora di fine non preceda l'inizio e, in modalità sotto-evento/modifica-di-un-figlio, vincola l'intervallo selezionabile a quello del genitore; resta comunque il backend l'autorità finale su questi vincoli. ## Prerequisiti - Node.js 20+ - I servizi dell'ecosistema Scouthub in esecuzione: Keycloak e `scouthub-eventi-be` (vedi `docker-compose.yml` e `scouthub-eventi-be/README.md` nella root del repo) ## Configurazione ambiente `src/environments/environment.ts` (produzione) e `environment.development.ts` (dev, usato automaticamente da `ng serve`/`ng build --configuration development`) espongono: - `keycloakBaseUrl` — URL base dell'istanza Keycloak (default `http://localhost:8081`, coerente con `KEYCLOAK_PORT` in `.env` alla root del repo) - `keycloakRealm` — realm Keycloak (`scouthub`) - `keycloakClientId` — client pubblico condiviso già definito in `keycloak/realm-export.json` (`scouthub-frontend`) - `eventiApiBaseUrl` — URL base di `scouthub-eventi-be` (default `http://localhost:8084`) ## Collegare Keycloak in locale 1. Avviare Keycloak (e Postgres) dalla root del repo: ```bash docker compose up -d keycloak-db keycloak ``` Il realm `scouthub` viene importato automaticamente da `keycloak/realm-export.json` al primo avvio (`--import-realm`). 2. Il client pubblico `scouthub-frontend` ha `redirectUris`/`webOrigins` che includono anche `http://localhost:4204` (porta di default di questo progetto, vedi sotto) — se si cambia porta, aggiornare `keycloak/realm-export.json` di conseguenza e reimportare il realm (o aggiornarlo da console admin Keycloak). 3. `provideKeycloakAngular()` (`src/app/core/auth/keycloak.provider.ts`) inizializza il client con `onLoad: 'check-sso'`: all'avvio l'app verifica in un iframe nascosto se esiste già una sessione Keycloak, senza forzare subito un redirect di login. ## Collegare scouthub-eventi-be in locale 1. Avviare `scouthub-eventi-be` seguendo il suo README (`npm run dev`, porta di default `8084`). 2. Le richieste verso `eventiApiBaseUrl` ricevono automaticamente l'header `Authorization: Bearer ` tramite l'interceptor `includeBearerTokenInterceptor` di `keycloak-angular`, configurato in `app.config.ts`. ## Development server Questo progetto usa la porta `4204` (per non collidere con `scouthub-attivita-fe` sulla `4200`, `scouthub-home-fe` sulla `4201` e `scouthub-magazzino-fe` sulla `4203`): ```bash ng serve ``` Apri il browser su `http://localhost:4204/`. ## Build ```bash ng build ``` Artefatti di build in `dist/scouthub-eventi-fe/browser` (percorso usato anche dal `Dockerfile` multistage node→nginx). ## Test ```bash ng test ``` Esegue gli unit test con il builder `@angular/build:unit-test` (Vitest). ## Versione Angular CLI usata per lo scaffold ``` Angular CLI : 22.0.7 Angular : 22.0.8 Node.js : 24.16.0 Package Manager : npm 11.12.0 Operating System : win32 x64 ```