679 lines
21 KiB
JSON
679 lines
21 KiB
JSON
{
|
||
"openapi": "3.0.3",
|
||
"info": {
|
||
"title": "API Gestione Rimborsi Spese Aziendali",
|
||
"version": "1.0.0",
|
||
"description": "Backend prova pratica S5 – Gestione rimborsi spese aziendali"
|
||
},
|
||
"servers": [
|
||
{
|
||
"url": "http://localhost:3003",
|
||
"description": "Sviluppo locale"
|
||
}
|
||
],
|
||
"tags": [
|
||
{ "name": "Sistema", "description": "Health check" },
|
||
{ "name": "Autenticazione", "description": "Login e sessione Auth.js" },
|
||
{ "name": "Utenti", "description": "Registrazione e profilo" },
|
||
{ "name": "Categorie", "description": "Categorie di spesa" },
|
||
{ "name": "Rimborsi", "description": "Richieste di rimborso" },
|
||
{ "name": "Statistiche", "description": "Report amministrativi" }
|
||
],
|
||
"components": {
|
||
"securitySchemes": {
|
||
"cookieAuth": {
|
||
"type": "apiKey",
|
||
"in": "cookie",
|
||
"name": "authjs.session-token",
|
||
"description": "Cookie di sessione impostato dopo il login. In produzione il nome può essere __Secure-authjs.session-token."
|
||
}
|
||
},
|
||
"schemas": {
|
||
"Error": {
|
||
"type": "object",
|
||
"properties": {
|
||
"error": { "type": "string" }
|
||
},
|
||
"required": ["error"]
|
||
},
|
||
"Message": {
|
||
"type": "object",
|
||
"properties": {
|
||
"message": { "type": "string" }
|
||
},
|
||
"required": ["message"]
|
||
},
|
||
"Ruolo": {
|
||
"type": "string",
|
||
"enum": ["DIPENDENTE", "RESPONSABILE_AMMINISTRATIVO"]
|
||
},
|
||
"StatoRichiesta": {
|
||
"type": "string",
|
||
"enum": ["IN_ATTESA", "APPROVATA", "RIFIUTATA", "LIQUIDATA"]
|
||
},
|
||
"Utente": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": { "type": "integer" },
|
||
"nome": { "type": "string" },
|
||
"cognome": { "type": "string" },
|
||
"email": { "type": "string", "format": "email" },
|
||
"ruolo": { "$ref": "#/components/schemas/Ruolo" }
|
||
},
|
||
"required": ["id", "nome", "cognome", "email", "ruolo"]
|
||
},
|
||
"UtenteSintetico": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": { "type": "integer" },
|
||
"nome": { "type": "string" },
|
||
"cognome": { "type": "string" }
|
||
},
|
||
"required": ["id", "nome", "cognome"]
|
||
},
|
||
"RegistrazioneInput": {
|
||
"type": "object",
|
||
"required": ["nome", "cognome", "email", "password", "confermaPassword"],
|
||
"properties": {
|
||
"nome": { "type": "string", "example": "Mario" },
|
||
"cognome": { "type": "string", "example": "Rossi" },
|
||
"email": { "type": "string", "format": "email", "example": "mario.rossi@azienda.it" },
|
||
"password": { "type": "string", "format": "password" },
|
||
"confermaPassword": { "type": "string", "format": "password" },
|
||
"ruolo": { "$ref": "#/components/schemas/Ruolo" }
|
||
}
|
||
},
|
||
"RegistrazioneResponse": {
|
||
"type": "object",
|
||
"properties": {
|
||
"message": { "type": "string" },
|
||
"utente": { "$ref": "#/components/schemas/Utente" }
|
||
},
|
||
"required": ["message", "utente"]
|
||
},
|
||
"CategoriaSpesa": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": { "type": "integer" },
|
||
"descrizione": { "type": "string" }
|
||
},
|
||
"required": ["id", "descrizione"]
|
||
},
|
||
"Rimborso": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": { "type": "integer" },
|
||
"dataInserimento": { "type": "string", "format": "date-time" },
|
||
"dataSpesa": { "type": "string", "format": "date" },
|
||
"categoriaId": { "type": "integer" },
|
||
"categoria": { "type": "string" },
|
||
"importo": { "type": "number" },
|
||
"descrizione": { "type": "string" },
|
||
"riferimentoGiustificativo": { "type": "string", "nullable": true },
|
||
"stato": { "$ref": "#/components/schemas/StatoRichiesta" },
|
||
"dipendenteId": { "type": "integer" },
|
||
"dipendenteNome": { "type": "string" },
|
||
"dataValutazione": { "type": "string", "format": "date-time", "nullable": true },
|
||
"responsabileValutazioneId": { "type": "integer", "nullable": true },
|
||
"responsabileNome": { "type": "string", "nullable": true },
|
||
"motivazioneRifiuto": { "type": "string", "nullable": true },
|
||
"dataLiquidazione": { "type": "string", "format": "date-time", "nullable": true }
|
||
},
|
||
"required": [
|
||
"id",
|
||
"dataInserimento",
|
||
"dataSpesa",
|
||
"categoriaId",
|
||
"categoria",
|
||
"importo",
|
||
"descrizione",
|
||
"stato",
|
||
"dipendenteId",
|
||
"dipendenteNome"
|
||
]
|
||
},
|
||
"RimborsoInput": {
|
||
"type": "object",
|
||
"required": ["dataSpesa", "categoriaId", "importo", "descrizione"],
|
||
"properties": {
|
||
"dataSpesa": { "type": "string", "format": "date", "example": "2025-06-01" },
|
||
"categoriaId": { "type": "integer", "example": 1 },
|
||
"importo": { "type": "number", "minimum": 0.01, "example": 45.5 },
|
||
"descrizione": { "type": "string", "example": "Pranzo di lavoro con cliente" },
|
||
"riferimentoGiustificativo": { "type": "string", "nullable": true, "example": "FATT-2025-001" }
|
||
}
|
||
},
|
||
"RifiutaInput": {
|
||
"type": "object",
|
||
"properties": {
|
||
"motivazione": { "type": "string", "nullable": true, "example": "Manca il giustificativo" }
|
||
}
|
||
},
|
||
"StatisticaRimborso": {
|
||
"type": "object",
|
||
"properties": {
|
||
"mese": { "type": "string", "example": "2025-06" },
|
||
"categoria": { "type": "string" },
|
||
"numeroRichieste": { "type": "integer" },
|
||
"totaleRichiesto": { "type": "number" },
|
||
"totaleApprovato": { "type": "number" },
|
||
"totaleLiquidato": { "type": "number" }
|
||
},
|
||
"required": [
|
||
"mese",
|
||
"categoria",
|
||
"numeroRichieste",
|
||
"totaleRichiesto",
|
||
"totaleApprovato",
|
||
"totaleLiquidato"
|
||
]
|
||
},
|
||
"CsrfResponse": {
|
||
"type": "object",
|
||
"properties": {
|
||
"csrfToken": { "type": "string" }
|
||
},
|
||
"required": ["csrfToken"]
|
||
}
|
||
},
|
||
"responses": {
|
||
"Unauthorized": {
|
||
"description": "Autenticazione richiesta",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Error" }
|
||
}
|
||
}
|
||
},
|
||
"Forbidden": {
|
||
"description": "Operazione non consentita per il ruolo corrente",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Error" }
|
||
}
|
||
}
|
||
},
|
||
"NotFound": {
|
||
"description": "Risorsa non trovata",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Error" }
|
||
}
|
||
}
|
||
},
|
||
"BadRequest": {
|
||
"description": "Richiesta non valida",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Error" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"paths": {
|
||
"/api/health": {
|
||
"get": {
|
||
"tags": ["Sistema"],
|
||
"summary": "Health check",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Servizio attivo",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "object",
|
||
"properties": {
|
||
"status": { "type": "string", "example": "ok" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"/api/auth/csrf": {
|
||
"get": {
|
||
"tags": ["Autenticazione"],
|
||
"summary": "Ottieni token CSRF per login/logout",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Token CSRF",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/CsrfResponse" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"/api/auth/callback/credentials": {
|
||
"post": {
|
||
"tags": ["Autenticazione"],
|
||
"summary": "Login con email e password",
|
||
"description": "Invia i dati come application/x-www-form-urlencoded. Imposta il cookie di sessione in caso di successo.",
|
||
"requestBody": {
|
||
"required": true,
|
||
"content": {
|
||
"application/x-www-form-urlencoded": {
|
||
"schema": {
|
||
"type": "object",
|
||
"required": ["csrfToken", "email", "password"],
|
||
"properties": {
|
||
"csrfToken": { "type": "string" },
|
||
"email": { "type": "string", "format": "email" },
|
||
"password": { "type": "string", "format": "password" },
|
||
"redirect": { "type": "string", "example": "false" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": { "description": "Login riuscito" },
|
||
"401": { "description": "Credenziali non valide" }
|
||
}
|
||
}
|
||
},
|
||
"/api/auth/signout": {
|
||
"post": {
|
||
"tags": ["Autenticazione"],
|
||
"summary": "Logout",
|
||
"requestBody": {
|
||
"required": true,
|
||
"content": {
|
||
"application/x-www-form-urlencoded": {
|
||
"schema": {
|
||
"type": "object",
|
||
"required": ["csrfToken"],
|
||
"properties": {
|
||
"csrfToken": { "type": "string" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": { "description": "Logout effettuato" }
|
||
}
|
||
}
|
||
},
|
||
"/api/utenti/register": {
|
||
"post": {
|
||
"tags": ["Utenti"],
|
||
"summary": "Registrazione nuovo utente",
|
||
"requestBody": {
|
||
"required": true,
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/RegistrazioneInput" }
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"201": {
|
||
"description": "Utente registrato",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/RegistrazioneResponse" }
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"409": {
|
||
"description": "Email già registrata",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Error" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"/api/utenti/me": {
|
||
"get": {
|
||
"tags": ["Utenti"],
|
||
"summary": "Profilo utente corrente",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Profilo utente",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Utente" }
|
||
}
|
||
}
|
||
},
|
||
"401": { "$ref": "#/components/responses/Unauthorized" }
|
||
}
|
||
}
|
||
},
|
||
"/api/utenti/dipendenti": {
|
||
"get": {
|
||
"tags": ["Utenti"],
|
||
"summary": "Elenco dipendenti",
|
||
"description": "Solo per RESPONSABILE_AMMINISTRATIVO",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Lista dipendenti",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": { "$ref": "#/components/schemas/UtenteSintetico" }
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"403": { "$ref": "#/components/responses/Forbidden" }
|
||
}
|
||
}
|
||
},
|
||
"/api/categorie-spesa": {
|
||
"get": {
|
||
"tags": ["Categorie"],
|
||
"summary": "Elenco categorie di spesa",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Lista categorie",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": { "$ref": "#/components/schemas/CategoriaSpesa" }
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": { "$ref": "#/components/responses/Unauthorized" }
|
||
}
|
||
}
|
||
},
|
||
"/api/rimborsi": {
|
||
"get": {
|
||
"tags": ["Rimborsi"],
|
||
"summary": "Elenco richieste di rimborso",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"parameters": [
|
||
{
|
||
"name": "stato",
|
||
"in": "query",
|
||
"schema": { "$ref": "#/components/schemas/StatoRichiesta" }
|
||
},
|
||
{
|
||
"name": "categoriaId",
|
||
"in": "query",
|
||
"schema": { "type": "integer" }
|
||
},
|
||
{
|
||
"name": "mese",
|
||
"in": "query",
|
||
"description": "Formato YYYY-MM",
|
||
"schema": { "type": "string", "pattern": "^\\d{4}-\\d{2}$", "example": "2025-06" }
|
||
},
|
||
{
|
||
"name": "dipendenteId",
|
||
"in": "query",
|
||
"schema": { "type": "integer" }
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Lista rimborsi",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": { "$ref": "#/components/schemas/Rimborso" }
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"401": { "$ref": "#/components/responses/Unauthorized" }
|
||
}
|
||
},
|
||
"post": {
|
||
"tags": ["Rimborsi"],
|
||
"summary": "Crea nuova richiesta di rimborso",
|
||
"description": "Solo per DIPENDENTE",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"requestBody": {
|
||
"required": true,
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/RimborsoInput" }
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"201": {
|
||
"description": "Richiesta creata",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Rimborso" }
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"403": { "$ref": "#/components/responses/Forbidden" }
|
||
}
|
||
}
|
||
},
|
||
"/api/rimborsi/{id}": {
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"required": true,
|
||
"schema": { "type": "integer" }
|
||
}
|
||
],
|
||
"get": {
|
||
"tags": ["Rimborsi"],
|
||
"summary": "Dettaglio richiesta di rimborso",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Dettaglio rimborso",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Rimborso" }
|
||
}
|
||
}
|
||
},
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"403": { "$ref": "#/components/responses/Forbidden" },
|
||
"404": { "$ref": "#/components/responses/NotFound" }
|
||
}
|
||
},
|
||
"put": {
|
||
"tags": ["Rimborsi"],
|
||
"summary": "Modifica richiesta (solo stato IN_ATTESA)",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"requestBody": {
|
||
"required": true,
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/RimborsoInput" }
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Richiesta aggiornata",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Rimborso" }
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"403": { "$ref": "#/components/responses/Forbidden" },
|
||
"404": { "$ref": "#/components/responses/NotFound" }
|
||
}
|
||
},
|
||
"delete": {
|
||
"tags": ["Rimborsi"],
|
||
"summary": "Elimina richiesta (solo stato IN_ATTESA)",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Richiesta eliminata",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Message" }
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"403": { "$ref": "#/components/responses/Forbidden" },
|
||
"404": { "$ref": "#/components/responses/NotFound" }
|
||
}
|
||
}
|
||
},
|
||
"/api/rimborsi/{id}/approva": {
|
||
"put": {
|
||
"tags": ["Rimborsi"],
|
||
"summary": "Approva richiesta",
|
||
"description": "Solo RESPONSABILE_AMMINISTRATIVO. La richiesta deve essere IN_ATTESA.",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"required": true,
|
||
"schema": { "type": "integer" }
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Richiesta approvata",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Rimborso" }
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"403": { "$ref": "#/components/responses/Forbidden" }
|
||
}
|
||
}
|
||
},
|
||
"/api/rimborsi/{id}/rifiuta": {
|
||
"put": {
|
||
"tags": ["Rimborsi"],
|
||
"summary": "Rifiuta richiesta",
|
||
"description": "Solo RESPONSABILE_AMMINISTRATIVO. La richiesta deve essere IN_ATTESA.",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"required": true,
|
||
"schema": { "type": "integer" }
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/RifiutaInput" }
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Richiesta rifiutata",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Rimborso" }
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"403": { "$ref": "#/components/responses/Forbidden" }
|
||
}
|
||
}
|
||
},
|
||
"/api/rimborsi/{id}/liquida": {
|
||
"put": {
|
||
"tags": ["Rimborsi"],
|
||
"summary": "Liquida richiesta approvata",
|
||
"description": "Solo RESPONSABILE_AMMINISTRATIVO. La richiesta deve essere APPROVATA.",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"required": true,
|
||
"schema": { "type": "integer" }
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Richiesta liquidata",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/Rimborso" }
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"403": { "$ref": "#/components/responses/Forbidden" }
|
||
}
|
||
}
|
||
},
|
||
"/api/statistiche/rimborsi": {
|
||
"get": {
|
||
"tags": ["Statistiche"],
|
||
"summary": "Statistiche rimborsi aggregate",
|
||
"description": "Solo RESPONSABILE_AMMINISTRATIVO",
|
||
"security": [{ "cookieAuth": [] }],
|
||
"parameters": [
|
||
{
|
||
"name": "mese",
|
||
"in": "query",
|
||
"description": "Formato YYYY-MM",
|
||
"schema": { "type": "string", "pattern": "^\\d{4}-\\d{2}$", "example": "2025-06" }
|
||
},
|
||
{
|
||
"name": "categoriaId",
|
||
"in": "query",
|
||
"schema": { "type": "integer" }
|
||
},
|
||
{
|
||
"name": "dipendenteId",
|
||
"in": "query",
|
||
"schema": { "type": "integer" }
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Statistiche aggregate",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": { "$ref": "#/components/schemas/StatisticaRimborso" }
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"403": { "$ref": "#/components/responses/Forbidden" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|