Add scouthub-eventi-fe
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
# 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 <token>` 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 <token>` 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
|
||||
```
|
||||
Reference in New Issue
Block a user