diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f08bbfc --- /dev/null +++ b/.env.example @@ -0,0 +1,24 @@ +# MySQL (docker-compose) +MYSQL_ROOT_PASSWORD=rootpassword +MYSQL_DATABASE=esameits24-26 +MYSQL_USER=esameits +MYSQL_PASSWORD=esameits_password + +# Server +PORT=3011 +NODE_ENV=development + +# Database (sviluppo locale senza Docker: usa localhost) +DB_HOST=localhost +DB_PORT=3306 +DB_NAME=esameits24-26 +DB_USER=esameits +DB_PASSWORD=esameits_password + +# Auth.js +AUTH_SECRET=cambia-con-stringa-casuale-lunga +AUTH_URL=http://localhost:3011 +AUTH_TRUST_HOST=true + +# CORS — origine del frontend +FRONTEND_URL=http://localhost:5173 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6015000..007fd1e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,38 +9,32 @@ on: jobs: build: runs-on: ubuntu-latest - steps: - - name: Checkout - uses: https://github.com/actions/checkout@v4 - - - name: Setup Node.js - uses: https://github.com/actions/setup-node@v4 + - uses: https://github.com/actions/checkout@v4 + - uses: https://github.com/actions/setup-node@v4 with: node-version: "20" - - - name: Install dependencies - run: npm ci --prefer-offline - - - name: Build - run: npm run build + - run: npm ci --prefer-offline + - run: npm run build deploy: needs: build runs-on: ubuntu-latest - + timeout-minutes: 45 steps: - - name: Checkout - uses: https://github.com/actions/checkout@v4 - - - name: Deploy via SSH - uses: https://github.com/appleboy/ssh-action@v1.0.3 + - uses: https://github.com/actions/checkout@v4 + - uses: https://github.com/appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.VPS_HOST }} username: ${{ secrets.VPS_USER }} key: ${{ secrets.VPS_SSH_KEY }} + command_timeout: 30m script: | - echo "START DEPLOY" + echo "=== START $(date -Iseconds) ===" cd /root/esameits24-26backend git pull --ff-only - docker compose up -d --build \ No newline at end of file + echo "=== DOCKER BUILD $(date -Iseconds) ===" + docker compose --progress plain up -d --build + echo "=== END $(date -Iseconds) ===" + docker compose ps + echo "DEPLOY COMPLETE" diff --git a/README.md b/README.md new file mode 100644 index 0000000..f1dcb4b --- /dev/null +++ b/README.md @@ -0,0 +1,173 @@ +# Academy Aziendale — Backend + +API REST per la piattaforma formativa interna (esame ITS Web Developer Full Stack 24-26, Prova C). + +Gestisce autenticazione, catalogo corsi, assegnazioni ai dipendenti e statistiche per il Referente Academy. + +## URL produzione + +| Risorsa | URL | +|---------|-----| +| API | https://esameits24-26backend.andreavillari.it | +| Swagger UI | https://esameits24-26backend.andreavillari.it/api/docs | +| OpenAPI JSON | https://esameits24-26backend.andreavillari.it/api/docs.json | +| Health check | https://esameits24-26backend.andreavillari.it/api/health | +| Frontend | https://esameits24-26frontend.andreavillari.it | + +## Stack tecnologico + +- Node.js 20 + TypeScript (ESM) +- Express 5 +- MySQL 8 +- Auth.js (`@auth/express`) con sessione JWT e cookie +- Swagger UI per la documentazione API + +## Credenziali di test + +Password per tutti gli utenti: `Password123!` + +| Email | Ruolo | +|-------|-------| +| `admin@academy.it` | Referente Academy | +| `maria.bianchi@academy.it` | Dipendente | +| `luca.conti@academy.it` | Dipendente | +| `elena.rossi@academy.it` | Dipendente | + +## Ruoli e permessi + +| Ruolo | Accesso API | +|-------|-------------| +| **Dipendente** | Profilo, corsi (lettura), proprie assegnazioni, completamento corso | +| **Referente Academy** | Tutto il precedente + CRUD utenti/corsi/assegnazioni, statistiche | + +## Avvio con Docker (consigliato) + +### Prerequisiti + +- Docker e Docker Compose + +### Configurazione + +Crea un file `.env` nella root del backend (non committare): + +```env +MYSQL_ROOT_PASSWORD=rootpassword +MYSQL_DATABASE=esameits24-26 +MYSQL_USER=esameits +MYSQL_PASSWORD=esameits_password + +AUTH_SECRET=genera-un-segreto-lungo-e-casuale +FRONTEND_URL=http://localhost:5173 +AUTH_URL=http://localhost:3011 +AUTH_TRUST_HOST=true +``` + +### Comandi + +```bash +docker compose up -d --build +``` + +Servizi avviati: + +| Servizio | Porta locale | +|----------|--------------| +| API | http://127.0.0.1:3011 | +| MySQL | 127.0.0.1:3311 | +| phpMyAdmin | http://127.0.0.1:8086 | + +Al primo avvio, gli script in `initdb/` creano schema e dati di test. + +## Avvio in sviluppo (senza Docker) + +### Prerequisiti + +- Node.js 20+ +- MySQL 8 con database `esameits24-26` inizializzato (`initdb/01_schema.sql` e `02_seed.sql`) + +### Comandi + +```bash +npm ci +cp .env.example .env +npm run dev +``` + +Il server di default ascolta su `http://localhost:3001` (o la porta impostata in `PORT`). + +```bash +npm run build +npm start +``` + +## Variabili d'ambiente + +| Variabile | Descrizione | Esempio | +|-----------|-------------|---------| +| `PORT` | Porta HTTP del server | `3011` | +| `DB_HOST` | Host MySQL | `localhost` / `mysql` | +| `DB_PORT` | Porta MySQL | `3306` | +| `DB_NAME` | Nome database | `esameits24-26` | +| `DB_USER` | Utente MySQL | `esameits` | +| `DB_PASSWORD` | Password MySQL | — | +| `AUTH_SECRET` | Segreto per JWT Auth.js | stringa casuale lunga | +| `AUTH_URL` | URL pubblico del backend | `https://esameits24-26backend.andreavillari.it` | +| `AUTH_TRUST_HOST` | Trust proxy/host header | `true` | +| `FRONTEND_URL` | Origine CORS del frontend | `https://esameits24-26frontend.andreavillari.it` | +| `NODE_ENV` | Ambiente | `development` / `production` | + +## Endpoint principali + +| Metodo | Percorso | Note | +|--------|----------|------| +| GET | `/api/health` | Stato servizio | +| GET | `/api/docs` | Swagger UI | +| POST | `/api/auth/callback/credentials` | Login | +| POST | `/api/auth/signout` | Logout | +| GET | `/api/me` | Profilo utente autenticato | +| CRUD | `/api/utenti` | Solo Referente Academy | +| CRUD | `/api/corsi` | Lettura: tutti; scrittura: Referente | +| CRUD | `/api/assegnazioni-corsi` | Dipendente vede solo le proprie | +| PUT | `/api/assegnazioni-corsi/:id/completa` | Solo il dipendente assegnatario | +| GET | `/api/statistiche/academy` | Solo Referente Academy | + +Documentazione completa e parametri di query in Swagger. + +## Struttura progetto + +``` +src/ + auth/ Configurazione Auth.js + config/ CORS, OpenAPI, Swagger + db/ Pool MySQL + middleware/ Autenticazione e autorizzazione + routes/ Router Express + validation/ Validazione input +initdb/ Schema e seed SQL +scripts/ Script di migrazione manuale +dockerfile/ Dockerfile produzione +``` + +## Validazione errori + +Il backend restituisce errori in JSON, ad esempio: + +```json +{ + "error": "Data di scadenza non valida", + "fields": { + "dataScadenza": "La data di scadenza non può essere precedente alla data di assegnazione" + } +} +``` + +## Deploy + +Il deploy su VPS è automatizzato tramite Forgejo Actions (`.github/workflows/deploy.yml`): + +1. Build TypeScript su runner CI +2. SSH sul VPS → `git pull` → `docker compose up -d --build` + +## Autore + +Andrea Villari — esame ITS 24-26 diff --git a/src/config/cors.ts b/src/config/cors.ts index 5b63d50..749fa47 100644 --- a/src/config/cors.ts +++ b/src/config/cors.ts @@ -3,7 +3,7 @@ import cors from "cors"; const allowedOrigins = [ "http://localhost:5173", "http://127.0.0.1:5173", - "https://corrierifrontend.andreavillari.it", + "https://esameits24-26frontend.andreavillari.it", process.env.FRONTEND_URL, ].filter(Boolean) as string[];