Salta al contenuto principale

19 - Deployment e DevOps: Da Docker al VPS in Produzione

L'Infrastruttura Dietro la Piattaforma Costruire una piattaforma come Play The Event non significa soltanto scrivere codice applicativo: significa anche...

Cosa ne pensi di questo articolo?

19 - Deployment e DevOps: Da Docker al VPS in Produzione
Play the EventFoto:Brett SaylesPexels

In Breve

L'Infrastruttura Dietro la Piattaforma Costruire una piattaforma come Play The Event non significa soltanto scrivere codice applicativo: significa anche...

L'Infrastruttura Dietro la Piattaforma

Costruire una piattaforma come Play The Event non significa soltanto scrivere codice applicativo: significa anche progettare un'infrastruttura che garantisca affidabilità, riproducibilità e facilità di deploy. Dall'ambiente di sviluppo locale alla VPS di produzione, ogni componente infrastrutturale è stato pensato per ridurre i tempi di deploy, minimizzare gli errori manuali e garantire che i servizi siano sempre disponibili.

Questo articolo esplora l'intero stack DevOps di Play The Event: dalla containerizzazione con Docker Compose alla configurazione Nginx con SSL, dai servizi systemd agli script di automazione, fino alla gestione delle migrazioni database e della cache Redis.

Cosa Troverai in Questo Articolo

  • Docker Compose per l'ambiente di sviluppo con MySQL, Redis, phpMyAdmin e Redis Commander
  • Nginx come reverse proxy con SSL Let's Encrypt, rate limiting e security headers
  • Servizi systemd per avvio automatico di backend e frontend
  • 18+ script Bash per deploy, avvio, stop, restart e manutenzione
  • 199 migrazioni Flyway per l'evoluzione dello schema MySQL
  • Redis con configurazione 256MB e policy allkeys-lru
  • Gestione log e monitoraggio salute dei servizi

Docker Compose: L'Ambiente di Sviluppo

L'ambiente di sviluppo di Play The Event è completamente containerizzato tramite Docker Compose. Quattro servizi orchestrati garantiscono che ogni sviluppatore possa avviare l'intero stack con un singolo comando, senza preoccuparsi di installare e configurare manualmente MySQL, Redis o i tool di amministrazione.

docker-compose.yml - Servizi di Sviluppo
version: '3.8'

services:
  # MySQL 8.4.3 - Database principale
  mysql:
    image: mysql:8.4.3
    container_name: management-events-mysql
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: management_events_db
      MYSQL_USER: events_user
      TZ: Europe/Rome
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./backend/src/main/resources/db/init:/docker-entrypoint-initdb.d
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --max_connections=200
      - --innodb_buffer_pool_size=1G
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis 7.4.1 - Cache e sessioni
  redis:
    image: redis:7.4.1-alpine
    container_name: management-events-redis
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: >
      redis-server --appendonly yes
      --maxmemory 256mb
      --maxmemory-policy allkeys-lru

  # phpMyAdmin - Gestione database via web
  phpmyadmin:
    image: phpmyadmin:5.2
    container_name: management-events-phpmyadmin
    ports:
      - "8081:80"
    depends_on:
      mysql:
        condition: service_healthy

  # Redis Commander - Gestione cache via web
  redis-commander:
    image: rediscommander/redis-commander:latest
    container_name: management-events-redis-commander
    environment:
      REDIS_HOSTS: local:redis:6379
    ports:
      - "8082:8081"
    depends_on:
      redis:
        condition: service_healthy

Alcuni aspetti chiave della configurazione Docker:

  • Health checks: sia MySQL che Redis hanno health check integrati. I servizi dipendenti (phpMyAdmin, Redis Commander) attendono che i servizi base siano pronti prima di avviarsi
  • Volumi persistenti: mysql_data e redis_data garantiscono che i dati sopravvivano al riavvio dei container
  • MySQL ottimizzato: utf8mb4 per supporto Unicode completo, innodb_buffer_pool_size=1G per prestazioni ottimali, fino a 200 connessioni simultanee
  • Redis con AOF: appendonly yes abilita la persistenza su disco. La policy allkeys-lru evita l'esaurimento della memoria eliminando le chiavi meno recentemente utilizzate

Porte dei Servizi di Sviluppo

  • 3306 - MySQL 8.4.3 (database principale)
  • 6379 - Redis 7.4.1 (cache e sessioni)
  • 8080 - Backend Spring Boot (API REST)
  • 4200 - Frontend Angular (dev server)
  • 8081 - phpMyAdmin (gestione database)
  • 8082 - Redis Commander (gestione cache)

Nginx: Reverse Proxy con SSL

In produzione, Nginx funge da reverse proxy davanti a tutti i servizi di Play The Event. Gestisce il terminamento SSL, il routing delle richieste, la compressione gzip, il caching degli asset statici e la protezione tramite rate limiting.

nginx.conf - Configurazione Reverse Proxy
# Upstream per il backend Spring Boot
upstream backend_api {
    server localhost:8080 fail_timeout=5s max_fails=3;
    keepalive 32;
}

# Rate limiting zones
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/m;
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=10r/m;

server {
    listen 443 ssl http2;
    server_name playtheevent.com www.playtheevent.com;

    # SSL Let's Encrypt
    ssl_certificate /etc/letsencrypt/live/playtheevent.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/playtheevent.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json
               application/javascript text/xml image/svg+xml;

    # Backend API con rate limiting
    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
        proxy_pass http://backend_api;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Rate limiting stretto per login
    location /api/auth/login {
        limit_req zone=login_limit burst=5 nodelay;
        proxy_pass http://backend_api;
    }

    # Frontend Angular (SSR o static)
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Asset statici con cache lunga
    location ~* \.(js|css|png|jpg|svg|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Sicurezza a Livello di Rete

La configurazione Nginx implementa diverse strategie di protezione:

  • Rate limiting a due livelli: le API generali sono limitate a 100 richieste al minuto per IP, mentre gli endpoint di autenticazione hanno un limite molto più restrittivo di 10 richieste al minuto, con risposta HTTP 429 in caso di superamento
  • SSL con Let's Encrypt: certificati gratuiti con rinnovo automatico tramite Certbot. Lo script setup-ssl.sh automatizza la verifica DNS, l'installazione di Certbot e la generazione dei certificati
  • Security headers: protezione contro clickjacking (X-Frame-Options), MIME sniffing (X-Content-Type-Options) e XSS (X-XSS-Protection)
  • Blocco file sensibili: qualsiasi richiesta a file che iniziano con . (come .env, .git) viene bloccata automaticamente

Health Check Endpoint

Nginx espone un endpoint /health dedicato al monitoraggio esterno. Questo endpoint restituisce una risposta semplice senza toccare il backend, permettendo ai sistemi di monitoraggio di verificare che il reverse proxy sia attivo.

Health Check e Status di Nginx
# Health check endpoint (risposta diretta da Nginx)
location /health {
    access_log off;
    return 200 "healthy\n";
    add_header Content-Type text/plain;
}

# Nginx status per monitoraggio (solo localhost)
location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
}

Systemd: Servizi ad Avvio Automatico

Il backend Spring Boot e il frontend Angular vengono gestiti come servizi systemd sulla VPS Ubuntu 24.04. Questo garantisce che i servizi si riavviino automaticamente dopo un crash o un reboot del server.

play-the-event-backend.service
[Unit]
Description=Play the Event - Backend Spring Boot API
After=network.target mysql.service
Wants=mysql.service

[Service]
Type=simple
User=federicocalo
WorkingDirectory=/home/ubuntu/managementevents/backend

# Environment
Environment="JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64"
Environment="SPRING_PROFILES_ACTIVE=prod"
EnvironmentFile=/home/ubuntu/managementevents/backend/.env.prod

# Esecuzione con JAR precompilato
ExecStart=/usr/bin/java -jar target/management-events-backend.jar

# Restart policy
Restart=on-failure
RestartSec=10s
StartLimitInterval=5min
StartLimitBurst=3

# Resource limits
LimitNOFILE=65536
LimitNPROC=4096

# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=play-the-event-backend

# Security
NoNewPrivileges=true
PrivateTmp=true

# Graceful shutdown
TimeoutStopSec=30s
KillMode=mixed
KillSignal=SIGTERM

[Install]
WantedBy=multi-user.target
play-the-event-frontend.service
[Unit]
Description=Play the Event - Frontend Angular
After=network.target

[Service]
Type=simple
User=federicocalo
WorkingDirectory=/home/ubuntu/managementevents/frontend

# Environment
Environment="NODE_ENV=production"

# Angular serve (SSR o static)
ExecStart=/usr/bin/npm start

# Restart policy
Restart=on-failure
RestartSec=10s
StartLimitInterval=5min
StartLimitBurst=3

# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=play-the-event-frontend

# Security
NoNewPrivileges=true
PrivateTmp=true

# Graceful shutdown
TimeoutStopSec=15s
KillMode=mixed
KillSignal=SIGTERM

[Install]
WantedBy=multi-user.target

Aspetti importanti della configurazione systemd:

  • Dipendenze: il backend dichiara After=mysql.service e Wants=mysql.service, assicurando che MySQL sia avviato prima dell'applicazione Spring Boot
  • Restart automatico: Restart=on-failure con RestartSec=10s riavvia automaticamente il servizio dopo un crash, con un limite di 3 tentativi in 5 minuti per evitare loop infiniti
  • Variabili d'ambiente: le configurazioni sensibili sono caricate da .env.prod tramite EnvironmentFile, mantenendo le credenziali fuori dal codice sorgente
  • Sicurezza: NoNewPrivileges=true impedisce l'escalation dei privilegi, PrivateTmp=true isola la directory temporanea del servizio
  • Graceful shutdown: KillSignal=SIGTERM con KillMode=mixed invia prima un segnale di terminazione al processo principale, poi forza l'arresto dei processi figli dopo il timeout

Script di Deploy Automatizzato

Il deploy di Play The Event è gestito da una suite di 18+ script Bash che automatizzano ogni aspetto del ciclo di vita dell'applicazione sulla VPS OVHcloud.

Script di Deploy

  • deploy-all.sh
  • deploy-backend.sh
  • deploy-frontend.sh
  • deploy-analytics.sh
  • restart-all.sh
  • start-all.sh
  • stop-all.sh

Script di Setup e Manutenzione

  • setup-nginx.sh
  • setup-ssl.sh
  • setup-mysql-databases.sh
  • setup-analytics.sh
  • update-nginx-ssr.sh
  • update-vps-config.sh
  • cleanup-logs-vps.sh
  • watch-logs.sh

Il Deploy Orchestrato: deploy-all.sh

Lo script principale deploy-all.sh orchestra il deploy di tutti i servizi con supporto per esecuzione sequenziale o parallela, skip selettivo dei servizi e report dettagliato con tempi di esecuzione.

Utilizzo di deploy-all.sh
# Deploy completo (sequenziale)
./scripts/deploy-all.sh

# Deploy parallelo (più veloce)
./scripts/deploy-all.sh --parallel

# Solo frontend e analytics (salta backend)
./scripts/deploy-all.sh --skip-be

# Continua anche se un deploy fallisce
./scripts/deploy-all.sh --continue

Il flusso del deploy-all.sh include:

  1. Parsing argomenti: supporto per --parallel, --skip-be, --skip-fe, --skip-ai, --continue
  2. Deploy sequenziale o parallelo: in modalità parallela i tre servizi vengono avviati come processi background, con attesa del completamento di tutti
  3. Health check: dopo il deploy, verifica che ogni servizio risponda correttamente tramite i rispettivi endpoint di health
  4. Report finale: mostra lo stato di ogni servizio (SUCCESS, ERROR, SKIPPED) con i tempi di esecuzione

Il Deploy del Backend

Lo script deploy-backend.sh gestisce l'intero ciclo di vita del deploy backend in 8 step automatizzati:

Flusso deploy-backend.sh
# Step 1: Verifica prerequisiti (Java 21, Maven, MySQL)
# Step 2: Navigazione alla directory backend
# Step 3: Caricamento variabili da .env.prod + test connessione DB
# Step 4: Build Maven (mvnw clean package -DskipTests)
# Step 5: Verifica database e migrazioni Flyway
# Step 6: Creazione/aggiornamento servizio systemd
# Step 7: Restart servizio con verifica stato
# Step 8: Health check con retry (max 15 tentativi, 2s intervallo)

# Comandi utili post-deploy:
sudo systemctl status management-events-backend
sudo journalctl -u management-events-backend -f
curl http://localhost:8080/api/health

Gestione della VPS OVHcloud

La piattaforma gira su una VPS OVHcloud con Ubuntu 24.04. Gli script start-all.sh, stop-all.sh e restart-all.sh gestiscono l'intero ciclo di vita dei servizi sulla VPS.

Flusso di Avvio Completo (start-all.sh)
# Ordine di avvio dei servizi:

# [1/5] Verifica e avvio MySQL
systemctl start mysql
mysql -u root -e "USE management_events_system;"

# [2/5] Stop servizi esistenti (pulizia)
systemctl stop management-events-backend
systemctl stop management-events-frontend

# [3/5] Avvio backend Spring Boot
systemctl start management-events-backend
# Attesa health check su localhost:8080/api/health

# [4/5] Avvio frontend Angular
systemctl start management-events-frontend
# Attesa health check su localhost:4200

# [5/5] Verifica e reload Nginx
systemctl reload nginx
# Verifica proxy funzionante

Ordine di Avvio Critico

L'ordine di avvio è fondamentale: MySQL deve essere completamente operativo prima che il backend Spring Boot tenti di connettersi, altrimenti Flyway fallirà nell'eseguire le migrazioni. Per questo motivo start-all.sh verifica non solo che MySQL sia attivo, ma anche che il database specifico sia raggiungibile, prima di procedere con il backend.

Migrazioni Database con Flyway

Lo schema del database MySQL di Play The Event è gestito tramite 199 migrazioni Flyway versionate. Ogni modifica allo schema è una migrazione SQL numerata che viene eseguita automaticamente all'avvio del backend Spring Boot.

Struttura Migrazioni Flyway
backend/src/main/resources/db/migration/
├── V1__create_users_table.sql
├── V2__create_events_table.sql
├── V3__create_participants_table.sql
├── ...
├── V98__create_analytics_tables.sql
├── V99__create_tipologie_luogo_table.sql
├── V100__create_luoghi_table.sql
├── V101__create_festival_table.sql
├── V102__create_giornate_festival_table.sql
└── ... (199 migrazioni totali)

Flyway tiene traccia delle migrazioni già eseguite nella tabella flyway_schema_history. All'avvio, il backend confronta le migrazioni presenti nel classpath con quelle già eseguite e applica solo le nuove. Questo approccio garantisce:

  • Evoluzione incrementale: lo schema evolve gradualmente senza mai perdere dati
  • Riproducibilità: qualsiasi istanza del database può raggiungere lo stato attuale eseguendo tutte le migrazioni in ordine
  • Tracciabilità: ogni modifica allo schema è un file SQL nel repository Git, con autore, data e motivo della modifica
  • Sicurezza: le migrazioni sono idempotenti e non possono essere modificate dopo l'esecuzione (Flyway verifica il checksum)

Redis: Cache e Gestione Sessioni

Redis svolge un ruolo critico nell'architettura di Play The Event, gestendo sia la cache delle query frequenti sia le sessioni utente. La configurazione è ottimizzata per un ambiente con memoria limitata.

Configurazione Redis
# Avvio Redis con configurazione personalizzata
redis-server \
  --appendonly yes \
  --maxmemory 256mb \
  --maxmemory-policy allkeys-lru

# appendonly yes        → Persistenza AOF su disco
# maxmemory 256mb       → Limite memoria massima
# maxmemory-policy      → Eviction delle chiavi meno usate

La policy allkeys-lru (Least Recently Used) è stata scelta perché in un contesto di event management, i dati più recenti sono generalmente i più rilevanti: gli eventi attivi, le sessioni correnti e le query più frequenti hanno la priorità sulla cache di dati vecchi o poco consultati.

Utilizzi di Redis nella Piattaforma

  • Cache query: i risultati delle query più frequenti (lista eventi pubblici, dettagli evento) vengono cachati per ridurre il carico su MySQL
  • Sessioni utente: i dati di sessione sono memorizzati in Redis per supportare la scalabilità orizzontale del backend
  • Rate limiting: i contatori per il rate limiting delle API sono gestiti in Redis con TTL automatico
  • Dati temporanei: token di verifica email, codici OTP e dati di checkout Stripe con scadenza automatica

Gestione Log

La suite di script include strumenti dedicati alla gestione dei log, essenziali per il debugging in produzione e per il mantenimento dello spazio disco sulla VPS.

Watch Log in Tempo Reale

Lo script watch-logs.sh offre un menu interattivo per lo streaming dei log in tempo reale, con 9 opzioni che coprono tutti i servizi:

Menu watch-logs.sh
Seleziona quale log visualizzare:

  1) Backend (systemd journal)
  2) Backend (application log)
  3) Backend (error log)
  4) Frontend (systemd journal)
  5) Frontend (application log)
  6) Frontend (error log)
  7) Nginx (access log)
  8) Nginx (error log)
  9) Tutti i backend logs (multipli)

L'opzione 9 utilizza multitail (se disponibile) per visualizzare simultaneamente log systemd, log applicativo e log errori con prefissi colorati. In assenza di multitail, uno script di fallback combina più processi tail -f con prefissi [SYSTEMD], [APP] e [ERROR].

Pulizia Automatica dei Log

Lo script cleanup-logs-vps.sh automatizza la pulizia dei log sulla VPS, scansionando le directory di log, eliminando i file e ripulendo i journal systemd più vecchi di 7 giorni.

Pulizia Log (cleanup-logs-vps.sh)
# Directory monitorate per la pulizia
LOG_DIRS=(
    "/var/log/management-events"
    "/home/ubuntu/managementevents/logs"
    "/opt/management-events/logs"
)

# Per ogni directory: conta file, calcola dimensione, elimina
# Pulisce anche journalctl logs > 7 giorni
sudo journalctl --vacuum-time=7d

# Mostra spazio disco rimanente
df -h /

Setup SSL con Let's Encrypt

Lo script setup-ssl.sh automatizza l'intera configurazione HTTPS per il dominio playtheevent.com. Il processo include la verifica DNS, l'installazione di Certbot, la generazione dei certificati e la configurazione del rinnovo automatico.

Flusso setup-ssl.sh
# Configurazione
DOMAIN="playtheevent.com"
WWW_DOMAIN="www.playtheevent.com"

# Step 1: Verifica DNS
#   - Recupera IP della VPS (curl ifconfig.me)
#   - Verifica che il dominio punti all'IP corretto (dig +short)
#   - Controlla sia @ che www

# Step 2: Installazione Certbot
sudo apt install -y certbot python3-certbot-nginx

# Step 3: Generazione certificati
sudo certbot --nginx \
    -d playtheevent.com \
    -d www.playtheevent.com \
    --email admin@playtheevent.com \
    --agree-tos

# Step 4: Verifica rinnovo automatico (cron)
sudo certbot renew --dry-run

Monitoraggio e Health Check

Il sistema di monitoraggio di Play The Event verifica la salute di tutti i servizi dopo ogni deploy e può essere eseguito su richiesta.

Health Check dei Servizi
# Health check integrato nel deploy-all.sh:

# Backend - verifica risposta HTTP 200
curl -s -o /dev/null -w "%{http_code}" \
    http://localhost:8080/api/health

# Frontend SSR - verifica risposta HTTP 200/301/302
curl -s -o /dev/null -w "%{http_code}" \
    http://localhost:4200

# Analytics - verifica risposta HTTP 200
curl -s -o /dev/null -w "%{http_code}" \
    http://localhost:8001/health

# Nginx - verifica proxy funzionante
curl -s https://playtheevent.com/health

Il report finale del deploy mostra una vista chiara dello stato:

Report di Deploy
╔════════════════════════════════════════════╗
║          REPORT DEPLOY                     ║
╚════════════════════════════════════════════╝

Stato Servizi:

  ✓ Backend     SUCCESS  (2m 34s)
  ✓ Frontend    SUCCESS  (1m 12s)
  ✓ Analytics   SUCCESS  (45s)

Tempo totale: 4m 31s

URL di accesso:
  • Frontend: https://playtheevent.com
  • API: https://playtheevent.com/api
  • Analytics: http://localhost:8001/docs

Riepilogo dell'Infrastruttura

Stack Infrastrutturale Completo

  • VPS: OVHcloud Ubuntu 24.04 LTS
  • Containerizzazione: Docker Compose per lo sviluppo (MySQL 8.4.3, Redis 7.4.1, phpMyAdmin, Redis Commander)
  • Web Server: Nginx come reverse proxy con SSL Let's Encrypt, rate limiting e compressione gzip
  • Process Manager: systemd per avvio automatico e restart on-failure di backend e frontend
  • Database: MySQL 8.4.3 con 199 migrazioni Flyway versionate
  • Cache: Redis 7.4.1 con 256MB, policy allkeys-lru, persistenza AOF
  • Automazione: 18+ script Bash per deploy, setup, manutenzione e monitoraggio
  • SSL: Let's Encrypt con rinnovo automatico tramite Certbot

L'infrastruttura di Play The Event dimostra come anche un progetto gestito da un singolo sviluppatore possa avere un livello di automazione e affidabilità paragonabile a team più grandi, grazie a script ben strutturati, servizi systemd e una configurazione Nginx solida.

Il codice sorgente è disponibile su GitHub.

Domande frequenti

Come funziona la containerizzazione con Docker Compose nell'ambiente di sviluppo di Play The Event?

L'ambiente di sviluppo di Play The Event è completamente containerizzato tramite Docker Compose, che garantisce che ogni sviluppatore possa avviare l'intero stack con un singolo comando.

Quali sono le strategie di protezione implementate nella configurazione Nginx?

La configurazione Nginx implementa diverse strategie di protezione, tra cui il terminamento SSL, il routing delle richieste, la compressione gzip, il caching degli asset statici e la protezione tramite rate limiting.

Come funziona la gestione dei log in tempo reale con lo script Watch Log?

Lo script Watch Log offre un menu interattivo per lo streaming dei log in tempo reale, con 9 opzioni che coprono tutti i servizi, tra cui l'opzione di utilizzare multitail per visualizzare simultaneamente log systemd, log applicativo e log errori.

Come viene gestita la migrazione del database MySQL con Flyway?

Lo schema del database MySQL di Play The Event è gestito tramite 199 migrazioni Flyway versionate, che vengono eseguite automaticamente all'avvio del backend Spring Boot. Flyway tiene traccia delle migrazioni già eseguite e applica solo le nuove.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti