Adriano 02b5180227 fix(metodo): allinea i testi degli step del Metodo ai valori voluti
Gli step del blocco Metodo (home) erano stati riscritti dal pannello ma solo nel
DB di sviluppo: il database non è versionato, quindi non erano mai arrivati in
produzione (che mostrava ancora i default del seed). Aggiornato il seed method.ts
(Check-up fisico, Insanity plan, Monitoraggio costante + testi) e aggiunta
migrazione idempotente che allinea le righe di prod ancora ai vecchi default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 16:32:44 +02:00

InsanityLab Website

Sito ufficiale di InsanityLab: vetrina aziendale, blog integrato, form di contatti e sistema di contenuti modificabili senza toccare il codice. In produzione su https://insanitylab.it.

Descrizione

Il sito è costruito su Astro 7 in modalità server (SSR) con adapter Node.js standalone, servito in un container Docker dietro Traefik (TLS Let's Encrypt automatico). I contenuti testuali e le immagini della parte vetrina sono "taggati" e salvati su SQLite: si modificano da un pannello di amministrazione o direttamente in pagina, senza deploy. Il blog è gestito internamente con editor richtext, e il form di contatti invia email tramite SMTP.

Stack tecnologico

  • Framework: Astro 7 (output server, prerender = false sulle pagine dinamiche)
  • Runtime: Node.js 22 (adapter @astrojs/node standalone)
  • Database: SQLite via better-sqlite3
  • Autenticazione: sessioni con password hashate (bcryptjs)
  • Email: Nodemailer (SMTP)
  • Editor articoli: TipTap (rich text)
  • Font: @fontsource (Montserrat, Open Sans) — nessun CDN esterno
  • Sitemap: endpoint runtime /sitemap.xml (route vetrina + articoli pubblicati)
  • Test: Vitest
  • Linguaggio: TypeScript
  • Deploy: Docker (multistage, node:22-slim) + Traefik su VPS

Funzionalità principali

  • Vetrina: home, chi siamo, training, servizi (con schede di dettaglio), blog, contatti, landing "Promo ed eventi".
  • Contenuti taggati: ogni testo/immagine ha un tag (es. home.hero.title-line-1) modificabile dal pannello o in pagina.
  • Modifica inline: chi ha i permessi può attivare l'overlay dei tag e modificare i contenuti direttamente mentre naviga il sito.
  • Blog con editor TipTap, immagini caricate, firma autore e proprietà degli articoli per ruolo.
  • Gestione utenti con tre ruoli (admin, superuser, user).
  • Form contatti con validazione, honeypot antispam, ratelimit e invio email via SMTP.

Installazione (sviluppo)

Prerequisiti

  • Node.js 18+ e npm

Setup

npm install
cp .env.example .env          # poi compila i valori reali
npm run create-user -- admin <password> admin
npm run dev                   # http://localhost:4321

Il database data/insanitylab.db viene creato al primo avvio ed è popolato automaticamente con i contenuti di default (seed) e le migrazioni idempotenti.

Comandi

Comando Descrizione
npm run dev Server di sviluppo (localhost:4321)
npm run build Build di produzione
npm run preview Anteprima locale della build
npm run start Server di produzione (node --env-file=.env)
npm run test Test con Vitest
npm run create-user Crea/aggiorna utente: -- <nome> <password> [admin|superuser|user]

Gestione contenuti

I testi e le immagini della vetrina sono blocchi taggati salvati nella tabella content_blocks. Ogni blocco ha un tag stabile (es. home.hero.title-line-1), un valore, eventuali stili predefiniti, un tipo (text / html / image) e un GUID univoco.

  • Pannello /admin/content: i blocchi sono raggruppati per pagina, con ricerca per tag o contenuto, upload delle immagini e ripristino all'originale.
  • Modifica inline: attivando "Mostra tag" dal menu utente, ogni blocco mostra un badge (nome tag + matita) che apre una finestra di modifica direttamente in pagina.
  • Componenti <T> e <TImg>: rendono i blocchi con fallback automatico al seed quando un tag non è ancora nel database.

Il seed dei contenuti è in src/data/content-seed.ts; le variazioni sui contenuti già esistenti (rinomine, testi aggiornati) si applicano tramite migrazioni idempotenti in src/lib/db.ts, così da non sovrascrivere le modifiche fatte dal pannello.

Nota tecnica: gli elementi resi dai componenti <T>/<TImg> non ereditano il data-astro-cid del componente che li usa. Uno stile scoped basato solo sulla classe (es. .hero__line) non li raggiunge: va ancorato a un contenitore che ha il cid usando :global() (es. .hero__text :global(.hero__line)).

Ruoli e accessi

Tre ruoli, con autorizzazione a matrice di prefissi in src/lib/auth.ts:

Ruolo Può fare
admin Tutto: contenuti, blog, upload, gestione utenti (/admin/users)
superuser Pannello contenuti + blog
user Solo i propri articoli del blog

Login pubblico su /login (?next sanitizzato contro open redirect). La gestione utenti (/admin/users, solo admin) consente creazione, reset password unatantum, cambio ruolo ed eliminazione, con guardie contro l'autoeliminazione e la rimozione dell'ultimo admin.

Struttura del progetto

insanitylab-website/
├── src/
│   ├── pages/            # Route Astro (vetrina, /admin, /api)
│   ├── components/       # Componenti (home/, content/, Header, Footer, …)
│   ├── layouts/          # Layout Base
│   ├── data/             # Dati statici + seed contenuti (services, trainings, site, content-seed)
│   ├── lib/              # db, auth, content, mailer, rate-limit, safe-next, env
│   ├── assets/img/       # Immagini ottimizzate da Astro
│   └── styles/           # global.css
├── data/                 # SQLite (volume in produzione)
├── uploads/              # Upload immagini (volume in produzione)
├── scripts/              # create-user, smoke test
├── astro.config.mjs      # Config Astro (site, allowedDomains, redirects)
├── compose.yaml          # Stack Docker + label Traefik
├── Dockerfile            # Build multi-stage
├── .env.example          # Template variabili d'ambiente
└── README.md

Variabili d'ambiente

Il file .env (non versionato) richiede:

Variabile Descrizione
SMTP_HOST Host SMTP (produzione: smtps.aruba.it)
SMTP_PORT Porta SMTP (465 con SSL)
SMTP_USER Casella di invio (deve coincidere con CONTACT_FROM)
SMTP_PASS Password della casella
CONTACT_FROM Mittente delle email (= SMTP_USER)
CONTACT_TO Destinatario dei messaggi del form
DB_PATH Percorso del database SQLite
UPLOADS_DIR Cartella degli upload

La posta del dominio @insanitylab.it è ospitata su Aruba; l'invio del form usa l'SMTP autenticato Aruba (smtps.aruba.it:465). Aruba impone che il mittente sia la casella autenticata, quindi CONTACT_FROM deve essere uguale a SMTP_USER.

Deploy in produzione

Il sito gira in Docker su un VPS, dietro Traefik. Lo stack è in /opt/docker/insanitylab/ (repo in src/, volumi data/ e uploads/). Aggiornamento:

cd /opt/docker/insanitylab/src
git pull
docker compose up -d --build

Le migrazioni del database (in src/lib/db.ts) sono idempotenti e girano all'avvio del container: aggiornano lo schema e i contenuti senza perdere le modifiche fatte dal pannello.

Dominio e DNS

  • Dominio ufficiale: insanitylab.it (canonico l'apex; www fa redirect 301 all'apex tramite Traefik).
  • I record A di @ e www puntano al VPS; la posta resta su Aruba (MX, SPF, webmail non vengono toccati).
  • TLS Let's Encrypt automatico via Traefik (certresolver mytlschallenge).

Attenzione dietro Traefik: allowedDomains in astro.config.mjs deve elencare i domini serviti, altrimenti Astro ignora X-Forwarded-Proto/Host e il controllo CSRF respinge i POST con 403.

Problemi comuni

better-sqlite3 non compila su npm install — servono i build tools:

  • Linux: sudo apt-get install build-essential python3
  • macOS: xcode-select --install
  • Windows: Visual Studio Build Tools

Modifiche allo <style> scoped di [slug].astro non compaiono in dev — l'HMR di Astro 7 non sempre ricompila lo stile scoped delle route dinamiche: riavviare il dev server (astro dev stop + npm run dev).

Database "locked" durante i test — assicurarsi che nessun processo stia accedendo a data/insanitylab.db.

Licenza

Proprietà di InsanityLab.

S
Description
No description provided
Readme 29 MiB
Languages
Astro 48.5%
TypeScript 46%
Shell 2.1%
JavaScript 1.6%
CSS 1.6%
Other 0.2%