Il commit 1522d97 ha spostato la freccia "→" dei bottoni promo nel CSS
(::after) e il maiuscolo in text-transform, cambiando il seed in minuscolo
senza freccia. Ma il seed è INSERT OR IGNORE: sui DB esistenti (produzione)
le righe restavano a "LE NOSTRE PROPOSTE →" / "ACQUISTA →", e il ::after
avrebbe prodotto una doppia freccia.
Aggiunge una migrazione guardata dal vecchio valore (idempotente, non tocca
le righe modificate dal pannello) che le allinea al seed corrente. Verificata
su copia del DB di produzione: frecce corrette e 40 edit del pannello intatti.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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 rich‑text, e il form di contatti invia email tramite SMTP.
Stack tecnologico
- Framework: Astro 7 (output
server,prerender = falsesulle pagine dinamiche) - Runtime: Node.js 22 (adapter
@astrojs/nodestandalone) - 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 (multi‑stage,
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 anti‑spam, rate‑limit 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 ildata-astro-ciddel 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 una‑tantum, cambio ruolo ed eliminazione, con guardie contro l'auto‑eliminazione 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;
wwwfa redirect 301 all'apex tramite Traefik). - I record A di
@ewwwpuntano 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:
allowedDomainsinastro.config.mjsdeve elencare i domini serviti, altrimenti Astro ignoraX-Forwarded-Proto/Hoste 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.