Prenotazioni APRA
Sistema per prenotare uffici e sale riunioni nella sede aziendale, sviluppato durante il percorso di alternanza scuola-lavoro in APRA S.p.A. Un'app Flutter multipiattaforma davanti, un'API REST in .NET dietro, il tutto in container su un server Linux.
- Contesto
- PCTO in APRA S.p.A.
- Anno
- 2026
- Ruolo
- Sviluppo completo, frontend e backend
- Stack
- Flutter · ASP.NET Core · PostgreSQL · Docker
- Stato
- In esecuzione su server di prova
Descrizione del progetto
I dipendenti prenotano una postazione o una sala riunioni; il sistema distingue tre livelli di utente con permessi crescenti.
- Standard — accesso, prenotazione, gestione delle proprie prenotazioni, cambio password.
- Admin — in piu': anagrafica dipendenti, gestione di uffici e sale, tutte le prenotazioni, statistiche di utilizzo.
- Superadmin — in piu': promozione e retrocessione degli amministratori.
La schermata principale e' una piantina unificata che mostra lo stato di ogni spazio (libero, parzialmente occupato, occupato) con filtri per tipo, piano e numero minimo di posti. Il calendario permette di creare una prenotazione trascinando sull'orario: in giornata singola, su un intervallo di date o ricorrente su determinati giorni della settimana.
Tech stack
Architettura client-server classica: il frontend parla con il backend via HTTP scambiando JSON. In produzione Nginx fa da reverse proxy: la radice serve l'applicazione Flutter compilata per il web, il percorso /api/ viene inoltrato all'API in ascolto nel container.
| Runtime | .NET 10 |
|---|---|
| Framework | ASP.NET Core, pattern Minimal API |
| ORM | Entity Framework Core con provider Npgsql |
| Database | PostgreSQL 16 |
| Frontend | Flutter, un solo progetto per web, Android e Windows |
| Autenticazione | JWT firmati HS256, password con BCrypt |
| Infrastruttura | Docker Compose + Nginx su Debian |
Gli endpoint sono registrati come funzioni, senza classi controller: ogni percorso e' una funzione con i suoi ingressi e la sua risposta. Le tabelle sono definite come classi C# e le migrazioni vengono generate da quelle e applicate all'avvio, quindi il database si allinea da solo al codice senza script SQL scritti a mano.
Tutto il backend e' containerizzato: un container per l'API, uno per il database e uno per l'interfaccia di amministrazione del database. I dati vivono in un volume nominato, cosi' ricostruire i container non cancella nulla.
Problema risolto
In sede le sale riunioni si prenotavano con il metodo piu' vecchio del mondo: chiedere. Il risultato erano riunioni con due gruppi davanti alla stessa porta, sale bloccate da prenotazioni mai disdette e nessun modo di sapere quali spazi fossero davvero usati.
La richiesta dell'azienda era vedere lo stato reale degli spazi a colpo d'occhio e prenotare in pochi secondi, dal computer o dal telefono. Da qui due scelte: la piantina come schermata principale, perche' una mappa si legge piu' in fretta di un elenco, e Flutter al posto di un framework solo web, perche' la stessa base di codice doveva servire il browser dei dipendenti e l'app sul telefono senza scriverla due volte.
Dal mio lato serviva un'altra cosa: un progetto vero, con un committente vero, portato fino a girare su un server e non fino al tasto Esegui.
Le procedure
Essendo un progetto aziendale, il modo di lavorare era parte della consegna quanto il codice.
- Raccolta dei requisiti — incontro iniziale con il tutor aziendale per capire chi usa il sistema e cosa deve poter fare. Da li' sono usciti i tre livelli di utente e le regole sui permessi.
- Analisi e modello dei dati — prima le entita' e le relazioni (spazi, dipendenti, prenotazioni, ricorrenze), poi il codice. Le tabelle sono nate su carta e sono diventate classi C#.
- Sviluppo a incrementi — prima l'autenticazione, poi la prenotazione singola, poi intervalli e ricorrenze, infine amministrazione e statistiche. Ogni pezzo funzionante prima di passare al successivo.
- Versionamento — repository Git con un branch dedicato alla versione containerizzata, tenuto separato da quello di sviluppo locale finche' il deployment non era stabile.
- Verifica — prove sui casi limite: prenotazioni sovrapposte, ricorrenze che cadono su giorni gia' occupati, utente retrocesso mentre e' collegato, token scaduto.
- Messa in esecuzione — accesso al server via SSH, build delle immagini, avvio con Docker Compose, configurazione di Nginx come reverse proxy e verifica che i dati sopravvivessero alla ricostruzione dei container.
- Consegna — presentazione del funzionamento al tutor e documentazione delle procedure di avvio e aggiornamento, perche' il progetto dovesse restare utilizzabile anche senza di me.
Sul fronte dell'applicazione le procedure principali sono tre e sono tutte tracciate: creazione di una prenotazione con controllo di conflitto prima della conferma, promozione o retrocessione di un amministratore riservata al superadmin, e cambio password con reimpostazione forzata al primo accesso.
Nozioni apprese
- Cosa significa “andare in produzione” — e' il primo progetto che ho portato fino al deployment vero: SSH sul server, build dei container, reverse proxy, volumi persistenti. Prima di questo, per me, mandare in produzione finiva con il tasto Esegui.
- Docker non e' un dettaglio — separare API, database e strumenti in container distinti, e capire che il volume nominato e' l'unica ragione per cui ricostruire tutto non cancella i dati.
- Autenticazione con token — firmare un JWT, farlo scadere, verificarlo a ogni richiesta e non salvare mai una password in chiaro: BCrypt, con il suo costo di calcolo, esiste apposta.
- Migrazioni invece di SQL a mano — il database che si allinea al codice all'avvio dell'applicazione elimina un'intera categoria di errori da “ho dimenticato di aggiornare la tabella sul server”.
- Una base di codice, tre piattaforme — lo stesso progetto Flutter che produce web, Android e Windows, con le differenze concentrate in pochi punti.
- Lavorare per qualcun altro — un requisito dato da un'azienda non si negozia riscrivendolo: si chiarisce prima e si rispetta dopo. E' la differenza piu' grande rispetto ai progetti personali.