Case study web app — gestionale HR

200 persone,
quattro fogli Excel,
zero controllo.

Un'azienda tech in rapida crescita gestiva presenze, ferie, performance review e reportistica HR su strumenti disconnessi. Ho progettato e sviluppato una web app interna su misura: un'unica piattaforma, tre livelli di accesso, dati in tempo reale — e un team HR che ha recuperato il 60% del proprio tempo.

ClienteSettore tech (NDA)
Team200+ dipendenti
Anno2025
TipoWeb App interna
app.hrplatform.io/dashboard
Dashboard HR
Panoramica · Luglio 2025
LIVE
PRESENTI
187
su 214 totali
FERIE HOY
12
approvate
REVIEW
34
in scadenza
ORE ADMIN
−60%
vs anno prec.
PRESENZE · ULTIMI 6 MESI
Feb
Mar
Apr
Mag
Giu
Lug
RICHIESTE FERIE
L
L. Rossi
✓ ok
M
M. Bianchi
⏳ att.
A
A. Ferrari
✓ ok

Case study gestionale HR React Laravel

150 persone gestite
con tre strumenti che non si parlano.

L'azienda — una software house italiana in forte crescita — aveva raggiunto i 150 dipendenti quando il team HR ha alzato la mano: il sistema non reggeva più. Le presenze venivano registrate su un foglio Google condiviso, le richieste di ferie arrivavano via email, le performance review erano gestite su un file Excel per reparto e i report mensili per la direzione richiedevano due giornate di lavoro manuale per essere assemblati da fonti diverse.

Con l'arrivo dei successivi 60 dipendenti — portando il team a oltre 200 persone — il caos era destinato a diventare ingestibile. Quattro HR manager spendevano il 60% del loro tempo su attività amministrative ripetitive invece di concentrarsi su recruiting, benessere e sviluppo delle persone.

Non serviva un software HR generico da configurare in mille modi: serviva uno strumento pensato esattamente per i loro processi, integrato con i sistemi esistenti e abbastanza semplice da essere adottato da tutti i dipendenti senza formazione.

«Ogni lunedì mattina spendevo due ore a controllare chi era in ferie, chi in smart working e chi aveva ore straordinarie da recuperare. Due ore su dati che avrebbero dovuto essere visibili in un secondo.»

— HR Manager, chiamata di kickoff
Progetto Web App HR interna — presenze, ferie, performance, report
Stack React 18 + TypeScript · Laravel 11 · MySQL · Redis
Accessi Admin HR · Manager · Dipendente (RBAC)
Integrazioni Slack · Google Calendar · Export PDF/CSV
Durata 11 settimane
Tag
React TypeScript Laravel RBAC data viz PDF export Slack API

Requisiti piattaforma HR aziendale

Un'unica fonte di verità.
Tre livelli di accesso.

Gestione presenze e timbrature in tempo reale

Ogni dipendente deve poter segnare entrata, uscita e modalità (ufficio / smart working / trasferta) da qualsiasi dispositivo. L'HR vede lo stato dell'intero team aggiornato al minuto, con alert automatici per assenze non giustificate.

Workflow ferie e permessi con approvazione multi-livello

Il dipendente richiede ferie dalla propria area. La richiesta va al manager diretto (primo livello) e poi all'HR (secondo livello). Notifica Slack automatica a ogni passaggio di stato. Calendario condiviso per visualizzare le assenze del team prima di approvare.

Performance review strutturata con cicli configurabili

L'HR configura i cicli di review (semestrale / annuale), gli obiettivi per ruolo e i template di valutazione. Manager e dipendente compilano le rispettive sezioni in modo asincrono. I risultati aggregati alimentano la dashboard della direzione.

Reportistica automatica con export PDF e CSV

I report mensili (presenze, ore straordinarie, ferie residue, headcount per reparto) devono generarsi in un click — non in due giorni. Export in PDF brandizzato per la direzione e CSV per il payroll. Schedulazione automatica con invio email ogni primo del mese.

RBAC granulare: Admin HR, Manager, Dipendente

Tre ruoli distinti con permessi configurabili. L'Admin HR vede tutto e può modificare qualsiasi record. Il Manager vede e approva solo il suo team. Il Dipendente accede solo ai propri dati. I permessi vengono controllati sia lato frontend che lato API — nessuna fiducia implicita nel client.

Sfide tecniche gestionale risorse umane

Dati sensibili, logica complessa,
zero margine d'errore.

Una piattaforma HR gestisce dati personali, buste paga, valutazioni riservate. Ogni bug non è un fastidio — è un problema legale o di fiducia. Le sfide tecniche erano architetturali prima ancora che di codice.

01

RBAC: permessi coerenti tra API e UI

Il rischio classico è avere un'UI che nasconde i bottoni ma un'API che risponde comunque a richieste non autorizzate. Ho implementato un sistema di policy Laravel (Gate + Policy) che viene consumato sia dal backend che esposto come endpoint /me/permissions, così il frontend React costruisce dinamicamente la UI senza duplicare la logica dei permessi.

02

Concorrenza sulle richieste di ferie

Due manager approvano la stessa richiesta in contemporanea, oppure un dipendente invia due richieste sovrapposte nello stesso periodo. Soluzione: transazioni MySQL con lock SELECT ... FOR UPDATE sulla tabella dei saldi ferie, più validazione lato API che controlla i giorni disponibili residui all'interno della stessa transazione atomica.

03

Report PDF con dati aggregati in tempo reale

Generare un PDF con 200 dipendenti, presenze mensili e ore aggregate richiedeva fino a 45 secondi — troppo per una risposta HTTP sincrona. Soluzione: job asincrono in coda Laravel Horizon (Redis), notifica Slack/email quando il report è pronto, file temporaneo su storage S3-compatible con URL firmato valido 24 ore.

04

Sincronizzazione bidirezionale con Google Calendar

Le ferie approvate devono apparire sul calendario aziendale Google senza creare duplicati o conflitti se il dipendente le modifica da entrambi i lati. Ho implementato un webhook Google Calendar che aggiorna il database e un job schedulato di riconciliazione ogni 15 minuti che risolve i conflitti tenendo come fonte di verità la piattaforma HR.

05

GDPR: separazione dei dati sensibili di performance

Le valutazioni di performance sono dati sensibili che non possono essere accessibili all'intero team HR — solo al responsabile diretto e al dipendente interessato, più l'admin con accesso auditato. Ho strutturato una tabella separata con crittografia a livello di campo (AES-256) per i commenti narrativi, con chiave derivata dall'ID utente autorizzato.

Processo sviluppo web app HR

11 settimane,
dal foglio Excel al go-live.

Settimane 1–2
Discovery: mappare i processi reali, non quelli teorici

Ho condotto interviste separate con i 4 HR manager, 6 manager di reparto e 10 dipendenti campione. Obiettivo: capire come venivano davvero gestite presenze e ferie — non come avrebbero dovuto essere gestite. Sono emersi 14 micro-processi informali (messaggi WhatsApp, promemoria su Notion personali, email cc a tutta la catena) che nessun requisito scritto avrebbe catturato. Questi processi sono diventati i casi limite da gestire nel sistema.

→ Deliverable: mappa processi AS-IS · 14 edge case documentati · wireframe navigazione
Settimane 3–5
Backend: API Laravel, RBAC e modello dati

Ho costruito il backend Laravel con autenticazione Sanctum, sistema RBAC con Policy granulari e le tre entità core: presenze, richieste ferie e cicli di performance review. Ogni endpoint restituisce i permessi dell'utente corrente nell'header della risposta, così il frontend React non deve fare chiamate separate per capire cosa mostrare. Database MySQL con 22 migration, indici ottimizzati per le query di reportistica aggregata.

→ 38 endpoint REST · 22 migration · 65 test PHPUnit · Sanctum + RBAC
Settimane 6–8
Frontend React: dashboard, workflow e data viz

Interfaccia React 18 con TypeScript, React Query per la gestione dello stato server e Recharts per i grafici. Ho costruito tre layout distinti per i tre ruoli — Admin HR, Manager, Dipendente — che si adattano dinamicamente ai permessi ricevuti dall'API. Il workflow ferie è stato il modulo più complesso: stati multipli (bozza → inviata → approvazione manager → approvazione HR → approvata/rifiutata) con notifica Slack a ogni transizione.

→ React 18 · TypeScript · React Query · Recharts · Slack Webhook API
Settimana 9
Motore reportistica: PDF asincrono e schedulazione

Ho costruito il generatore di report con Laravel Horizon (Redis) per la gestione delle code. Ogni report mensile viene generato come job in background: aggrega dati da 4 tabelle, compone il PDF con DomPDF (template brandizzato con logo e palette aziendale), lo carica su MinIO (S3-compatible self-hosted), genera un URL firmato con scadenza 24h e notifica via email e Slack. Il job schedulato scatta automaticamente il primo di ogni mese alle 07:00.

→ Laravel Horizon · Redis · DomPDF · MinIO · job schedulato
Settimane 10–11
UAT, migrazione dati storici e go-live graduale

Due settimane di User Acceptance Testing con 20 utenti campione (5 per ruolo). Ho migrato 18 mesi di dati storici da 3 fogli Excel diversi con uno script PHP di normalizzazione. Go-live graduale per reparto: prima il team Engineering (40 persone), poi Marketing e Sales, infine tutti. Periodo di doppio binario di 2 settimane con i vecchi sistemi ancora attivi in sola lettura. Zero incidenti al go-live completo.

→ 20 utenti UAT · migrazione 18 mesi dati · rollout 3 fasi · zero downtime

Soluzione tecnica: RBAC e dashboard React

Tre moduli, un'unica piattaforma.
Zero silos.

La piattaforma è costruita attorno a tre moduli indipendenti ma perfettamente integrati, ognuno progettato partendo dal workflow reale degli utenti — non da un modello astratto.

Modulo 01 / 03

Timbrature e presenze — dashboard in tempo reale

Ogni dipendente accede da browser o mobile e seleziona la modalità del giorno (ufficio, smart working, trasferta, malattia). Il sistema registra l'orario e aggiorna la dashboard HR in tempo reale tramite polling ogni 60 secondi con React Query. I manager vedono solo il proprio team; l'Admin HR vede tutto con filtri per reparto, sede e modalità. Le anomalie (assenza non giustificata entro le 10:00) generano un alert automatico Slack al manager responsabile.

// Hook React per presenze real-time con React Query function useTeamPresenze( teamId: string ) { return useQuery({ queryKey: ['presenze', teamId], queryFn: () => api.get(`/teams/${teamId}/presenze/oggi`), refetchInterval: 60_000, // polling ogni 60s staleTime: 30_000, // permessi già nel payload — nessuna call extra select: (data) => data.filter( (p) => hasPermission(p, 'view') ), }); }
Modulo 02 / 03

Workflow ferie — da 3 email a 1 click

La richiesta ferie passa attraverso 5 stati con transizioni esplicite e notifiche automatiche. Prima di inviare, il dipendente vede in tempo reale il calendario del proprio team per evitare sovrapposizioni critiche. Il manager riceve una notifica Slack con link diretto all'approvazione — senza doversi loggare per trovare la richiesta. Se non risponde entro 48 ore, l'HR riceve un promemoria. Il 94% delle richieste viene ora processato entro 24 ore, contro i 3–5 giorni del processo precedente.

Stato richiesta ferie
Richiesta inviata
Approvata dal manager
In attesa HR ← ora
Approvazione finale
Modulo 03 / 03

Performance review — strutturata, asincrona, riservata

L'HR configura il ciclo di review: periodo, template di valutazione per ruolo (da Junor a Lead), obiettivi aziendali di riferimento e scadenze. Manager e dipendente compilano le rispettive sezioni in modo indipendente — nessuno vede la valutazione dell'altro finché entrambe non sono chiuse. I commenti narrativi vengono cifrati a livello di campo (AES-256) con chiave derivata dall'ID della review, così anche un accesso diretto al database non espone i testi. I risultati aggregati — rating medi per reparto, distribuzione delle valutazioni, trend rispetto al ciclo precedente — alimentano la dashboard della direzione con grafici Recharts interattivi.

Nota GDPR: i dati di performance rientrano nella categoria dei dati che richiedono misure di sicurezza rafforzate ai sensi dell'art. 25 GDPR (privacy by design). La cifratura a livello di campo è una misura tecnica documentata nel registro dei trattamenti dell'azienda.

Stack tecnologico React TypeScript Laravel

Scelte deliberate,
non casuali.

React 18 + TypeScript
Laravel 11
MySQL 8
Redis + Horizon
React Query
Recharts
Slack Webhook API
Google Calendar API
DomPDF
MinIO (S3)
PHPUnit + Pest
Vite + ESBuild

Perché Laravel e non Node.js?

Laravel ha un sistema di Policy e Gate mature per il RBAC, un ORM (Eloquent) che gestisce bene le relazioni complesse tra team, ruoli e permessi, e Laravel Horizon per le code — tutto già integrato e testato. Costruire lo stesso sistema su Node.js avrebbe richiesto di assemblare librerie separate con meno garanzie di coerenza. Per una web app interna con dati sensibili, la maturità dell'ecosistema conta.

Perché React Query e non Redux?

Lo stato dell'applicazione è quasi interamente stato server: dati che vivono nel backend e devono essere sincronizzati. React Query gestisce cache, refetch, ottimismo UI e invalidazione in modo dichiarativo — senza il boilerplate di Redux. Il risultato è un'interfaccia che sembra real-time con la semplicità di una chiamata API.

Risultati gestionale HR: -60% ore amministrative

Il team HR ha smesso
di fare gli amministratori.

Dati rilevati a 3 mesi dal go-live completo (tutti i 214 dipendenti sulla piattaforma), confrontati con il periodo equivalente dell'anno precedente.

−60%
Ore admin HR
Da 18h a 7h/settimana per persona
−83%
Errori presenze
Da 34 a 6 correzioni manuali/mese
94%
Ferie processate <24h
Prima: 3–5 giorni medi
5 min
Generazione report mensile
Prima: 2 giorni lavorativi
98%
Adoption rate
214/214 dipendenti attivi dopo 30gg
4.7/5
Soddisfazione utenti
Survey interna post go-live

«Il primo report mensile generato in automatico è arrivato il primo settembre alle 07:01. Ho aperto Slack e ho visto la notifica. Ho quasi pianto.»

— Head of HR, 3 mesi dopo il go-live

Learnings sviluppo web app HR

Cosa porterei
nel prossimo progetto.

Intervistare gli utenti finali prima di scrivere una riga di codice non è overhead — è risparmio. I 14 processi informali emersi nelle interviste hanno evitato altrettanti bug in produzione. Ogni ora di discovery ha risparmiato almeno 3 ore di sviluppo e testing.

Il RBAC deve vivere nel backend, non nell'UI. Nascondere un bottone nel frontend non è sicurezza — è cosmesi. Il sistema di Policy Laravel che espone i permessi come dato ha permesso di avere un'UI che si adatta dinamicamente senza duplicare logica di autorizzazione nel codice React.

Il go-live graduale per reparto vale sempre la complessità aggiuntiva. Lanciare prima solo con Engineering (40 persone) ha permesso di trovare 3 bug critici di UX — non di codice — che avrebbero impattato tutti i 214 utenti se fossimo andati live in un colpo solo.

I job asincroni cambiano l'esperienza utente in modo sproporzionato. Spostare la generazione del PDF da sincrona (45 secondi di attesa) ad asincrona (notifica quando pronto) ha portato il rating di soddisfazione del modulo reportistica da 3.1 a 4.8 su 5 — a parità di output finale.

Il periodo di doppio binario è fondamentale per la fiducia. Tenere i vecchi Excel attivi in sola lettura per 2 settimane dopo il go-live ha azzerato la resistenza al cambio: gli utenti potevano "controllare" che i dati fossero giusti. Nessuno è tornato al vecchio sistema dopo la prima settimana.

Hai un processo interno che merita uno strumento su misura?

Excel e email vanno bene finché non cresci. Poi servono strumenti che crescono con te.