Un sito che doveva fare due cose bene
Questo sito — quello che stai leggendo ora — è stato costruito con un obiettivo preciso: personal branding e lead generation, con una base tecnica abbastanza solida da reggere nel tempo senza bisogno di manutenzione continua.
Il vincolo principale era la semplicità operativa: deploy in un comando, contenuti gestibili senza toccare il codice, SEO tecnica corretta fin dall'inizio. Nessun CMS esterno, nessuna dipendenza da servizi terzi, nessun lock-in.
Next.js 16 App Router + MDX
La scelta di Next.js 16 con App Router non è stata scontata — avrei potuto usare Astro o un sito statico puro. Ho scelto Next.js per tre motivi: rendering ibrido (SSG per i contenuti, SSR dove serve), ecosistema maturo, e familiarità con il tooling.
JSON-LD, canonical URL e Open Graph
La SEO tecnica è stata progettata dall'inizio, non aggiunta dopo. Ogni tipo di pagina ha il suo schema JSON-LD appropriato:
Homepage — WebSite
Schema WebSite con SearchAction e ItemList per blog e portfolio. Canonical senza trailing slash, Open Graph con immagine dedicata og-image.webp (1200×630).
Articoli blog — Article
Schema Article con headline, description, author, datePublished, image per l'immagine dell'articolo, e publisher con logo che punta al logo del sito. Keywords estratte dal frontmatter MDX.
Case study — CreativeWork
Schema CreativeWork con provider, author, keywords dallo stack array del frontmatter. Immagine del progetto nel campo image.
Listing pages — ItemList
Le pagine /blog e /portfolio espongono un ItemList con tutti gli articoli/progetti indicizzati, per massimizzare la presenza nei rich results.
Il generateMetadata di Next.js costruisce dinamicamente per ogni pagina: title, description, canonical, og:url, og:image, twitter:card. Nessun meta tag scritto a mano.
Un dettaglio importante: tutti gli URL usano https://ekulos.com senza www — la coerenza tra canonical, og:url e JSON-LD è necessaria per evitare segnali contrastanti a Google.
Docker + Watchtower + GitHub Actions
Il sito gira su un home server, senza CDN né proxy cloud. Il deploy è completamente automatizzato:
Il flusso completo da commit a produzione:
`` git push origin main → GitHub Actions build + push ghcr.io → Watchtower polling (intervallo configurabile) → Container aggiornato in produzione `
Nessun SSH manuale, nessuno script da ricordare.
Cosa ho scelto di non fare
Alcune decisioni contano quanto quelle su cosa includere. CSS vanilla come sistema principale — architettura modulare con custom properties, Tailwind usato solo per utility sparse dove ha senso. Nessun framework CSS che guida le scelte architetturali: la struttura visiva è interamente in CSS modulare, più leggibile e più facile da debuggare. Nessun CMS — MDX in Git è sufficiente. Aggiungere un CMS headless avrebbe significato una dipendenza esterna, un costo mensile, e complessità senza beneficio reale. Nessun analytics di terze parti — nessun script di tracking, nessun cookie banner. Google Search Console per i dati SEO è tutto quello che serve. Static generation over server rendering — tutte le pagine sono pre-renderizzate a build time con generateStaticParams. Il server non fa lavoro a runtime, i Time to First Byte sono minimi.
"Il criterio principale era: se tra due anni devo aggiungere un articolo, quanto ci mette? La risposta deve essere: creo un file .mdx`, faccio push, deploy automatico in cinque minuti."