E-commerce Platform

Piattaforma e-commerce containerizzata, avviabile con un singolo comando.

Stack: Next.js 14 · PostgreSQL 16 · Prisma · Stripe · Caddy · Docker Compose


Avvio in locale (test su localhost)

Prerequisiti

  • Docker Desktop installato e avviato
  • Porta 80 libera (nessun altro web server in esecuzione)
  • Account Stripe gratuito (necessario per i pagamenti)

1. Clona il repository

git clone <url-repository>
cd ecommerce-platform

2. Crea il file .env

cp .env.example .env

Apri .env e inserisci la tua chiave Stripe test (gratuita, dalla Stripe Dashboard → API keys):

STRIPE_SECRET_KEY=sk_test_la_tua_chiave

Il resto dei valori è già preconfigurato per localhost e non va modificato.

3. Avvia la piattaforma

Senza pagamenti (admin, catalogo, email):

docker compose up -d

Con pagamenti e webhook Stripe attivi (consigliato):

docker compose --profile dev up -d

Il primo avvio richiede 510 minuti: Docker scarica le immagini, installa le dipendenze npm, compila Next.js, esegue le migrazioni e crea l'utente admin.

Segui il progresso con:

docker compose logs -f app

La piattaforma è pronta quando vedi:

✓ Ready in 91ms

4. Apri nel browser

URL Cosa trovi
http://localhost Sito pubblico (vetrina)
http://localhost/admin Dashboard amministratore
http://localhost:8025 Mailpit — cattura le email di test

5. Primo accesso admin

Vai su http://localhost/admin e accedi con:

Email:    admin@example.com
Password: Admin1234!test

Al primo accesso il sistema ti obbliga a cambiare la password.

Requisiti password: minimo 12 caratteri, almeno una maiuscola, una minuscola, un numero e un simbolo.

6. Configura il negozio (ordine consigliato)

  1. Product Types → crea un tipo di prodotto (es. "Prodotto") con gli attributi che vuoi
  2. Categories → crea le categorie
  3. Products → crea un prodotto, assegna tipo e categoria, impostalo su Published
  4. Apri http://localhost → il prodotto appare in homepage

7. Setup webhook Stripe (una tantum per macchina)

Il profilo dev include un container stripe-cli che riceve i webhook da Stripe e li inoltra all'app. Senza di esso, dopo il pagamento l'ordine resta in PENDING e nessuna email viene inviata.

Al primo avvio con --profile dev, recupera il webhook secret dai log:

docker compose logs stripe-cli | grep "webhook signing secret"

Copia il valore whsec_... nel .env:

STRIPE_WEBHOOK_SECRET=whsec_abc123...

Poi ricrea il container app per applicare la variabile (restart non ricarica il .env):

docker compose up -d --force-recreate app

Da questo momento docker compose --profile dev up -d avvia tutto inclusi i webhook — non serve altro.

8. Testa i pagamenti

Carte di test Stripe:

Carta Risultato
4242 4242 4242 4242 Pagamento riuscito
4000 0000 0000 0002 Carta rifiutata
4000 0025 0000 3155 Richiede autenticazione 3D Secure

Scadenza: qualsiasi data futura · CVC: qualsiasi 3 cifre

Verifica che tutto funzioni dopo un pagamento:

docker compose logs stripe-cli --tail=20
# deve mostrare [200] per checkout.session.completed
  1. L'ordine nel pannello admin passa da PENDING a PAID
  2. L'email di conferma appare su http://localhost:8025

9. Ferma la piattaforma

docker compose --profile dev down      # ferma tutto (con stripe-cli), i dati restano
docker compose down -v                 # ferma e cancella anche il database

Differenze tra localhost e produzione

Quattro cose cambiano quando si passa da localhost a un dominio reale.

1 — Dominio e HTTPS

Modificare una sola riga nel Caddyfile:

# localhost
localhost { ... }

# produzione
tuodominio.com { ... }

Caddy ottiene e rinnova automaticamente il certificato HTTPS tramite Let's Encrypt. Non serve nessuna configurazione SSL manuale.

2 — Variabili d'ambiente

Cinque variabili da aggiornare nel .env:

Variabile Localhost Produzione
APP_URL http://localhost https://tuodominio.com
AUTH_SECRET qualsiasi stringa openssl rand -hex 32
STRIPE_SECRET_KEY sk_test_... sk_live_...
STRIPE_WEBHOOK_SECRET dal container stripe-cli dal dashboard Stripe
SMTP_* Mailpit locale (porta 8025) provider reale (Resend, Mailgun, SendGrid…)

3 — Server

Serve un VPS Linux con Docker installato (DigitalOcean, Hetzner, OVH, ecc.) e il record DNS del dominio puntato all'IP del server. Il comando di avvio è identico: docker compose up -d (senza --profile dev).

4 — Backup

In locale i dati si perdono con docker compose down -v. In produzione è necessario un backup automatico del database (vedi sezione Backup database) e conservare il volume uploads che contiene le immagini dei prodotti.


Deploy in produzione

Prerequisiti

  • Server Linux con Docker e Docker Compose v2 (qualsiasi VPS o cloud VM)
  • Dominio con record A puntato all'IP del server
  • Porte 80 e 443 aperte nel firewall del server
  • Account Stripe (per i pagamenti reali)
  • Account SMTP (per le email: Mailgun, Resend, SendGrid, ecc.)

1. Clona il repository sul server

git clone <url-repository>
cd ecommerce-platform

2. Crea e configura .env

cp .env.example .env
nano .env

Modifica questi valori:

# URL pubblico del sito — con https://
APP_URL=https://tuodominio.com

# Genera un segreto casuale: openssl rand -hex 32
AUTH_SECRET=incolla_qui_il_risultato_di_openssl

# Credenziali del primo admin — cambia subito dopo il primo accesso
INITIAL_ADMIN_EMAIL=admin@tuodominio.com
INITIAL_ADMIN_PASSWORD=UnaPasswordSicura1!

# Stripe — usa le chiavi live (non sk_test_)
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxx

# SMTP reale per le email
SMTP_HOST=smtp.tuoprovider.com
SMTP_PORT=587
SMTP_USER=user@tuodominio.com
SMTP_PASSWORD=la_tua_password_smtp
SMTP_FROM=noreply@tuodominio.com

DATABASE_URL non va modificato: usa già il nome del container Docker corretto.

3. Genera AUTH_SECRET

openssl rand -hex 32

Copia l'output nel campo AUTH_SECRET nel file .env.

4. Configura il dominio nel Caddyfile

Apri Caddyfile e sostituisci localhost con il tuo dominio:

tuodominio.com {
    handle /uploads/* {
        root * /srv
        file_server
    }
    encode gzip zstd
    reverse_proxy app:3000
}

5. Avvia

docker compose up -d

Attendi che l'app sia pronta:

docker compose logs -f app
# attendi: ✓ Ready in ...ms

Il sito è live su https://tuodominio.com.

6. Configura il webhook Stripe

Nel dashboard Stripe → Webhooks, aggiungi un endpoint:

URL endpoint:  https://tuodominio.com/api/webhooks/stripe

Eventi da ascoltare:
  - checkout.session.completed
  - payment_intent.succeeded
  - payment_intent.payment_failed

Copia il Signing secret (whsec_...) nel .env come STRIPE_WEBHOOK_SECRET, poi ricrea il container per applicarlo:

docker compose up -d --force-recreate app

7. Primo accesso e configurazione negozio

  1. Vai su https://tuodominio.com/admin
  2. Accedi con le credenziali del .env
  3. Cambia la password quando richiesto
  4. Configura il negozio in questo ordine:
    • Settings → nome negozio, logo, colori
    • Product Types → tipi di prodotto con attributi personalizzati
    • Categories → categorie prodotto
    • Products → aggiungi i tuoi prodotti
    • Admin Users → aggiungi altri amministratori se necessario

Porte di rete

Porte da aprire nel firewall del server (produzione)

Porta Protocollo Servizio Perché è necessaria
80 TCP Caddy (HTTP) Redirect automatico HTTP → HTTPS e rinnovo certificati Let's Encrypt (ACME challenge)
443 TCP Caddy (HTTPS) Traffico web principale — sito pubblico e pannello admin

Solo queste due porte devono essere aperte verso l'esterno. Tutto il resto è interno a Docker.

Porte interne (rete Docker — non esporre al pubblico)

Porta Servizio Note
3000 Next.js (app) Accessibile solo da Caddy tramite reverse_proxy app:3000
5432 PostgreSQL (db) Accessibile solo dall'app tramite DATABASE_URL
1025 Mailpit SMTP Accessibile solo dall'app per l'invio email

Porta solo per sviluppo locale (non aprire in produzione)

Porta Servizio Note
8025 Mailpit UI Interfaccia web per ispezionare le email di test — non deve mai essere esposta in produzione

Riepilogo comandi firewall (UFW — Ubuntu/Debian)

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw deny 8025/tcp
sudo ufw enable
sudo ufw status

Aggiornamenti

git pull
docker compose build app
docker compose up -d

Le migrazioni del database vengono applicate automaticamente all'avvio.


Backup database

Dump manuale:

docker compose exec db pg_dump -U ecommerce ecommerce > backup_$(date +%Y%m%d_%H%M%S).sql

Ripristino:

cat backup_XXXXXXXX_XXXXXX.sql | docker compose exec -T db psql -U ecommerce ecommerce

Backup automatico giornaliero (aggiungi al crontab del server con crontab -e):

0 3 * * * cd /percorso/ecommerce-platform && docker compose exec -T db pg_dump -U ecommerce ecommerce | gzip > /backups/ecommerce_$(date +\%Y\%m\%d).sql.gz

Problemi comuni

Il build impiega molto tempo al primo avvio È normale. npm install + compilazione Next.js richiedono 510 minuti la prima volta. I build successivi sono molto più veloci grazie alla cache Docker.

http://localhost non risponde (502 Bad Gateway) L'app è ancora in fase di avvio. Aspetta qualche secondo e ricarica. Controlla lo stato con:

docker compose logs -f app

Errore "port 80 already in use" Un altro servizio usa la porta 80 (Apache, Nginx, ecc.). Fermalo o cambia la porta nel docker-compose.yml.

L'ordine resta in PENDING dopo il pagamento Il container stripe-cli non è in esecuzione o STRIPE_WEBHOOK_SECRET non è configurato. Verifica:

docker compose --profile dev ps        # stripe-cli deve essere "running"
docker compose logs stripe-cli --tail=10

Se il whsec_... manca nel .env, segui lo step 7 del setup locale.

Le variabili del .env non vengono applicate dopo la modifica docker compose restart non ricarica il .env. Usa sempre:

docker compose up -d --force-recreate app

Dimentico la password admin Resetta direttamente nel database:

# genera hash bcrypt per la nuova password
docker compose exec app node -e "
const bcrypt = require('bcryptjs');
bcrypt.hash('NuovaPassword1!', 12).then(h => console.log(h));
"
# aggiorna nel db
docker compose exec db psql -U ecommerce ecommerce -c \
  "UPDATE \"User\" SET \"passwordHash\"='HASH_QUI', \"mustChangePassword\"=true WHERE email='admin@example.com';"

Struttura del progetto

ecommerce-platform/
├── docker-compose.yml       Orchestrazione: db, app, caddy, mailpit, stripe-cli (profilo dev)
├── Caddyfile                Reverse proxy — modifica qui il dominio
├── .env                     Variabili d'ambiente (non committare)
├── .env.example             Template da copiare
└── app/
    ├── Dockerfile           Build multi-stage Next.js
    ├── entrypoint.sh        Sequenza avvio: migrazioni → admin → server
    ├── prisma/
    │   └── schema.prisma    Schema database completo
    ├── scripts/
    │   └── bootstrap-admin.ts  Crea il primo OWNER se non esiste
    └── src/
        ├── app/             Pagine Next.js (App Router)
        │   ├── admin/       Dashboard admin (protetta per ruolo)
        │   ├── api/         API routes (auth, prodotti, ordini, webhook)
        │   └── (storefront) Homepage, catalogo, carrello, checkout
        ├── components/      Componenti React riutilizzabili
        └── lib/             Auth, Prisma client, Stripe, email

Variabili d'ambiente

Variabile Descrizione Locale Produzione
APP_URL URL pubblico del sito http://localhost https://tuodominio.com
DATABASE_URL Connessione PostgreSQL invariato invariato
AUTH_SECRET Segreto sessioni (min 32 char) qualsiasi openssl rand -hex 32
INITIAL_ADMIN_EMAIL Email primo admin qualsiasi la tua email
INITIAL_ADMIN_PASSWORD Password primo admin qualsiasi sicura
STRIPE_SECRET_KEY Chiave Stripe sk_test_... sk_live_...
STRIPE_WEBHOOK_SECRET Segreto webhook Stripe dal container stripe-cli dal dashboard Stripe
SMTP_HOST Server SMTP mailpit provider reale
SMTP_PORT Porta SMTP 1025 587
SMTP_USER Utente SMTP vuoto obbligatorio
SMTP_PASSWORD Password SMTP vuoto obbligatorio
SMTP_FROM Mittente email qualsiasi noreply@tuodominio.com
S
Description
No description provided
Readme 1 MiB
Languages
TypeScript 98.7%
Dockerfile 0.6%
Shell 0.5%
JavaScript 0.2%