Accesso e ruoli
Questa pagina descrive chi può fare cosa dopo il login. Per il flusso SSO e i token JWT vedi Autenticazione SSO.
Modello di autorizzazione
L'ACL UI non è più basata su check hard-coded sul ruolo JWT. Dopo il login (e al refresh di sessione) il frontend carica:
GET /v1/auth/policies → PoliciesService
Il payload espone flag booleani per risorsa/azione (persons.create, teams.update, leaveRequests.show, …). Quella mappa è la single source of truth per:
- guard di route (
requirePolicy,policyChildGuard,teamDetailGuard) - visibilità voci sidebar (
requiresPolicy) - gating in template (
*appPolicy) - computed di comodo (
canManageTeams,canManageProjects,canManageUsers, …)
Il ruolo nel JWT (RoleEnum) resta solo display / ingresso in dashboard (authGuard + isAuthorized()). Le decisioni ACL usano le policies.
flowchart LR
Login[Login / restore session] --> PS[PoliciesService.load]
PS --> API["GET /v1/auth/policies"]
API --> Map[Policies map]
Map --> G[Route guards]
Map --> S[Sidebar]
Map --> D["*appPolicy / can()"]
Ruoli disponibili (JWT)
| Ruolo | Codice (RoleEnum) |
Nota |
|---|---|---|
| Executive | EXECUTIVE |
Di solito policies complete |
| Executive Support | EXECUTIVE_SUPPORT |
Allineato all'Executive |
| Scrum Master | SCRUM_MASTER |
Tipicamente team + leave |
| Product Owner | PRODUCT_OWNER |
Tipicamente progetti + leave |
| Nessun ruolo | NO_ROLE |
authGuard blocca la dashboard |
I flag effettivi dipendono dalle permission policies lato backend (collaboration type × ruolo), non solo dal codice ruolo.
Guard sulle route
| Guard | Tipo | Effetto |
|---|---|---|
authGuard |
canActivate |
Login + dashboard: sessione e ruolo valido |
policyChildGuard |
canActivateChild |
Su clients / buyers / buyer-contracts: richiede rispettivamente clients.show, buyers.show, buyerContracts.show |
requirePolicy("leaveRequests.show") |
canActivate |
Su /permissions |
teamDetailGuard |
canActivate |
Su /teams/:id: richiede canManageTeams() |
positionGuard / businessUnitGuard |
canDeactivate |
Annulla stato "aggiunta in corso" uscendo dalle tab |
Nota: il dettaglio progetto (/projects/:id) non ha route guard. Le azioni di scrittura usano PoliciesService.canManageProjects() in UI.
Visibilità sidebar
SidebarComponent filtra le voci con requiresPolicy:
| Voce | Policy richiesta |
|---|---|
| Gestione risorse (Candidature, …) | jobApplications.show |
| Partnership e contratti | clients.show |
| Richieste e permessi | leaveRequests.show |
Le altre voci (People, team, progetti, form, FAQ, settings) restano visibili; le azioni di scrittura all'interno delle pagine sono gated da policies specifiche o *appPolicy.
Matrice funzionalità ↔ policies (sintesi)
| Funzionalità | Lettura (tipica) | Scrittura / gestione (tipica) |
|---|---|---|
| Directory People | persons.show |
Creazione: persons.create (canManageUsers); archiviazione: persons.archive |
| Dettaglio utente | persons.show / sezioni |
Update sezioni: policies persons.* + isSelf per il proprio profilo |
| Teams — elenco | Tutti in dashboard | Creazione/gestione: teams.create / canManageTeams() |
| Team detail | canManageTeams() (route guard) |
Stesse write policies team |
| Progetti — elenco | Tutti in dashboard | Creazione: projects.create / canManageProjects() (inclusi campi stato progetto in dialog) |
| Project detail | Tutti in dashboard | Modifica/eliminazione e card «Stato del progetto»: canManageProjects() (people sempre sola lettura) |
| Candidature | jobApplications.show |
Update/status: policies jobApplications.* |
| Clienti / Fornitori / Contratti | *.show + policyChildGuard |
Policies CRUD dedicate |
| Permessi (leave) | leaveRequests.show |
Solo visualizzazione (sync Libemax) |
| Skills / Posizioni / BU | Tutti | Write: policies skills / positions / businessUnits |
| Form feedback / straordinari | Tutti | Tutti (invio Zapier) |
Per il dettaglio esatto dei flag vedi src/models/policies.ts e la risposta di /auth/policies.
Direttiva *appPolicy
@if (true) {
<button *appPolicy="'persons.create'">Aggiungi</button>
}
PolicyDirective mostra il template solo se PoliciesService.can(policy) è true; si ricalcola quando le policies vengono caricate.
| Funzionalità | Lettura | Scrittura / gestione |
|--------------|---------|----------------------|
| Directory People | Tutti | Aggiunta persona: executive |
| Dettaglio utente | Tutti (con limiti su email) | Executive o self (con limiti per sezione) |
| Teams — elenco | Tutti | Creazione team: EX/SM |
| Team detail | EX/SM (route guard) | EX/SM |
| Progetti — elenco | Tutti | Creazione: EX/PO |
| Project detail | Tutti | Modifica/eliminazione: EX/PO |
| Candidature | Executive (sidebar) | Executive |
| Clienti / Fornitori / Contratti | Executive (route guard) | Executive |
| Permessi (leave) | EX/EXS/SM/PO | Solo visualizzazione (sync Libemax) |
| Skills / Posizioni / BU | Tutti | Executive |
| Form feedback / straordinari | Tutti | Tutti (invio) |
| Firma digitale | Tutti | — |
| FAQ | Tutti | Executive / Executive Support (via policy contents.*, vedi nota) |
Nota — permessi via PoliciesService: l'editing FAQ non usa AuthService.isExecutive()/RoleEnum come le altre righe della tabella, ma il sistema di policy più granulare esposto da GET /v1/auth/policies (PoliciesService, direttiva *appPolicy). Le chiavi contents.create / contents.update / contents.delete sono assegnate lato backend (tipicamente a Executive ed Executive Support) e determinano la visibilità delle azioni di scrittura nella pagina FAQ. Dettaglio in FAQ.
File di riferimento
| File | Ruolo |
|---|---|
src/models/policies.ts |
Tipi Policies, PolicyKey, EMPTY_POLICIES |
src/services/policies.service.ts |
Load, can(), computed di comodo |
src/directives/policy.directive.ts |
*appPolicy |
src/guards/policy.guard.ts |
requirePolicy, policyChildGuard |
src/guards/teams.guard.ts |
teamDetailGuard |
src/services/auth.service.ts |
Sessione, JWT, isSelf, bootstrap policies |
src/utils/sidebar-items.ts |
requiresPolicy sulle voci menu |