From f33d29fe7b2bd4a4b02d2f1e2e9fbdc9bcf1eb9c Mon Sep 17 00:00:00 2001 From: Javaxman Date: Fri, 24 Apr 2026 20:59:53 +0200 Subject: [PATCH 1/2] Rende operativa la pagina news e sostituisce il README starter con un runbook di progetto. Allinea la documentazione a setup, deploy Cloudflare e gestione contatti per supportare il go-live. Made-with: Cursor --- README.md | 145 +++++++++++++++++++++++-------------------- src/pages/news.astro | 31 +++++++-- 2 files changed, 102 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index a6105e9..c256778 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,71 @@ -# Astro Starter Kit: Minimal +# NexStudio Website Runbook -```sh -npm create astro@latest -- --template minimal -``` +Sito istituzionale NexStudio basato su Astro, con deploy su Cloudflare e form contatti protetto da Turnstile. -> ๐Ÿง‘โ€๐Ÿš€ **Seasoned astronaut?** Delete this file. Have fun! +## Obiettivo del repository -## ๐Ÿš€ Project Structure +- Presentazione aziendale e servizi (homepage e pagine legali). +- Entry point unico per richieste commerciali e supporto. +- Base pronta per contenuti multilingua IT/EN/TH. +- Pipeline di deploy stabile su Cloudflare. -Inside of your Astro project, you'll see the following folders and files: +## Stack tecnico -```text -/ -โ”œโ”€โ”€ public/ -โ”œโ”€โ”€ src/ -โ”‚ โ””โ”€โ”€ pages/ -โ”‚ โ””โ”€โ”€ index.astro -โ””โ”€โ”€ package.json -``` +- Astro + Tailwind CSS +- Adapter Cloudflare (`@astrojs/cloudflare`) +- Sitemap (`@astrojs/sitemap`) +- Form backend su endpoint `/api/contact` +- Turnstile + Resend per anti-spam e invio email -Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. +## Struttura essenziale -There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components. +- `src/pages/`: pagine pubbliche e route API (`src/pages/api/contact.ts`) +- `src/components/`: componenti UI condivisi +- `src/data/`: contenuti testuali e configurazioni pagine +- `public/`: asset statici (loghi, immagini, robots) +- `.env.example`: variabili locali di riferimento -Any static assets, like images, can be placed in the `public/` directory. +## Prerequisiti -## ๐Ÿงž Commands +- Node.js 20+ +- npm 10+ +- Account Cloudflare (Pages/Workers + Turnstile) +- Account Resend (API key + sender verificato) -All commands are run from the root of the project, from a terminal: +## Avvio locale -| Command | Action | -| :------------------------ | :----------------------------------------------- | -| `npm install` | Installs dependencies | -| `npm run dev` | Starts local dev server at `localhost:4321` | -| `npm run build` | Build your production site to `./dist/` | -| `npm run preview` | Preview your build locally, before deploying | -| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | -| `npm run astro -- --help` | Get help using the Astro CLI | +1. Installazione dipendenze: + - `npm install` +2. Copia variabili di ambiente: + - copia `.env.example` in `.env` +3. Avvio sviluppo: + - `npm run dev` +4. Se Vite resta in cache incoerente: + - `npm run dev:fresh` -## ๐Ÿ‘€ Want to learn more? +## Comandi utili -Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). +- `npm run dev`: sviluppo locale +- `npm run dev:fresh`: reset cache `.vite` e `.astro` + avvio dev server +- `npm run build`: build produzione +- `npm run preview`: preview locale della build +- `npm run deploy:cf`: build + deploy con wrangler su output Astro -## Cloudflare deploy notes +## Configurazione contatti -If you deploy with Wrangler in CI/Cloudflare, build first and deploy using Astro's generated Worker config: +Variabili pubbliche (frontend): -- Build command: `npm run build` -- Deploy command: `npm run deploy:cf` - -This avoids entrypoint errors like `@astrojs/cloudflare/entrypoints/server` not found. - -## Contact form configuration - -Set these variables for the website contact form. - -Public (frontend): - -- `PUBLIC_CONTACT_FORM_ACTION_URL` (default `/api/contact`) -- `PUBLIC_CONTACT_FORM_SUCCESS_REDIRECT` (absolute URL for `_next`) -- `PUBLIC_CONTACT_FORM_MAILTO` (fallback only if `ACTION_URL` is empty) +- `PUBLIC_CONTACT_FORM_ACTION_URL` (default consigliato: `/api/contact`) +- `PUBLIC_CONTACT_FORM_SUCCESS_REDIRECT` (URL assoluto della pagina post-submit) +- `PUBLIC_CONTACT_FORM_MAILTO` (fallback se action URL non disponibile) - `PUBLIC_CONTACT_TURNSTILE_SITE_KEY` -Server-side (Cloudflare runtime / local `.env`): +Variabili server (Cloudflare/local): -- `CONTACT_FORM_MODE` (`dev` or `live`) +- `CONTACT_FORM_MODE` (`dev` oppure `live`) - `CONTACT_FORM_RESEND_API_KEY` -- `CONTACT_FORM_FROM_EMAIL` (verified sender in Resend, recommended `no-reply@nexstudio.com`) -- `CONTACT_FORM_TO_EMAIL` (default recipient inbox or alias, recommended `info@nexstudio.com`) +- `CONTACT_FORM_FROM_EMAIL` (consigliato: `no-reply@nexstudio.ai`) +- `CONTACT_FORM_TO_EMAIL` (default destinatario, es. `info@nexstudio.ai`) - `CONTACT_FORM_TO_EMAIL_SUPPORT` - `CONTACT_FORM_TO_EMAIL_PRIVACY` - `CONTACT_FORM_TO_EMAIL_SECURITY` @@ -76,29 +74,40 @@ Server-side (Cloudflare runtime / local `.env`): - `CONTACT_FORM_TO_EMAIL_HR` - `CONTACT_TURNSTILE_SECRET_KEY` -Mode behavior: +Comportamento: -- `dev`: accepts form and logs payload server-side (no real email send) -- `live`: verifies Turnstile (if secret configured) and sends via Resend API +- `dev`: accetta submit e scrive payload nei log (senza invio reale) +- `live`: valida Turnstile e invia email via Resend -Department routing: +## Deploy Cloudflare -- the contact form includes a department selector -- if a department-specific env is set, the email is routed to that recipient -- otherwise it falls back to `CONTACT_FORM_TO_EMAIL` +Impostazioni consigliate: -Suggested operational use: +- Build command: `npm run build` +- Deploy command: `npm run deploy:cf` -- `info@...` for prospects and generic clarifications (non-clients) -- `support@...` for existing customers -- `no-reply@...` as sender for newsletters and automated communications +Questa configurazione evita errori tipo: +`The entry-point file at "@astrojs/cloudflare/entrypoints/server" was not found.` -Copy `.env.example` to `.env` for local development and configure the same keys in Cloudflare Pages/Workers for production. +## Dominio e sicurezza -## Production domain - -- Official domain: `https://nexstudio.ai` -- Keep Turnstile widget hostnames aligned with: +- Dominio ufficiale: `https://nexstudio.ai` +- Hostname Turnstile da mantenere allineati: - `nexstudio.ai` - - `www.nexstudio.ai` (if used) - - `localhost` (for local testing) + - `www.nexstudio.ai` (se usato) + - `localhost` (test locale) +- Accesso pre-go-live gestito con Cloudflare Zero Trust Access + +## Stato operativo attuale + +- Issue #1 (contact form live): implementata +- Issue #2 (anti-spam Turnstile): implementata +- Issue #3 (SEO base): implementata (sitemap, robots, canonical/OG/Twitter) +- Issue #4: in avanzamento (contenuti non placeholder) +- Issue #5: da completare (localizzazione reale IT/EN/TH) + +## Note operative + +- Per modifiche non minori usare branch dedicato (`feat/*`, `fix/*`) e merge su `main` dopo verifica. +- Evitare commit su `main` per attivita complesse. +- Rigenerare eventuali API key esposte e aggiornare subito i secret su Cloudflare. diff --git a/src/pages/news.astro b/src/pages/news.astro index a1a0e1d..b01f530 100644 --- a/src/pages/news.astro +++ b/src/pages/news.astro @@ -6,13 +6,32 @@ import SubpageLayout from '../layouts/SubpageLayout.astro'; title="Novitร  โ€” NexStudio" description="Novitร , release e articoli da NexStudio." heading="Novitร " - lead="Hub comunicazioni: collegate qui il vostro blog CMS, oppure elencate manualmente le notizie." + lead="Aggiornamenti ufficiali su piattaforma, compliance, infrastruttura e contenuti editoriali." > -

- Quando avrete contenuti da pubblicare (release di prodotto, note di - conformitร , eventi), potete sostituire questa pagina con una raccolta - articoli Astro, un redirect verso Medium/Substack, o un headless CMS. +

+ Stato editoriale: canale attivo. Le prossime pubblicazioni verranno aggiornate su questa pagina con frequenza periodica.

+ +

Programma editoriale

+ + +

Canali di distribuzione

+ +

Archivio

-

Nessuna news pubblicata per il momento.

+

+ In questa fase il sito e in pre-lancio operativo. Il primo blocco di news verra pubblicato con il go-live ufficiale. +

+

+ Per richieste stampa, partnership o approfondimenti tecnici e possibile usare il form nella sezione + Contatti. +

-- 2.49.0 From ddab32d3efc31e0f937326f479a6c9697d71ac76 Mon Sep 17 00:00:00 2001 From: Javaxman Date: Fri, 24 Apr 2026 21:32:15 +0200 Subject: [PATCH 2/2] Riduce il routing del contact form pubblico a info, privacy e careers. Allinea backend, configurazione env e documentazione al nuovo modello vetrina con destinatari meno granulari. Made-with: Cursor --- .env.example | 7 ++----- README.md | 20 +++++++++++++++----- src/data/home/cta.ts | 12 ++++-------- src/pages/api/contact.ts | 9 +++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.env.example b/.env.example index aef0b21..e3ce163 100644 --- a/.env.example +++ b/.env.example @@ -7,10 +7,7 @@ CONTACT_FORM_MODE=dev CONTACT_FORM_RESEND_API_KEY= CONTACT_FORM_FROM_EMAIL=no-reply@nexstudio.com CONTACT_FORM_TO_EMAIL=info@nexstudio.com -CONTACT_FORM_TO_EMAIL_SUPPORT=support@nexstudio.com +CONTACT_FORM_TO_EMAIL_INFO=info@nexstudio.com CONTACT_FORM_TO_EMAIL_PRIVACY= -CONTACT_FORM_TO_EMAIL_SECURITY= -CONTACT_FORM_TO_EMAIL_ETHICS= -CONTACT_FORM_TO_EMAIL_LEGAL= -CONTACT_FORM_TO_EMAIL_HR= +CONTACT_FORM_TO_EMAIL_CAREERS= CONTACT_TURNSTILE_SECRET_KEY= diff --git a/README.md b/README.md index c256778..3a175f8 100644 --- a/README.md +++ b/README.md @@ -66,12 +66,9 @@ Variabili server (Cloudflare/local): - `CONTACT_FORM_RESEND_API_KEY` - `CONTACT_FORM_FROM_EMAIL` (consigliato: `no-reply@nexstudio.ai`) - `CONTACT_FORM_TO_EMAIL` (default destinatario, es. `info@nexstudio.ai`) -- `CONTACT_FORM_TO_EMAIL_SUPPORT` +- `CONTACT_FORM_TO_EMAIL_INFO` (opzionale, override esplicito per area "info") - `CONTACT_FORM_TO_EMAIL_PRIVACY` -- `CONTACT_FORM_TO_EMAIL_SECURITY` -- `CONTACT_FORM_TO_EMAIL_ETHICS` -- `CONTACT_FORM_TO_EMAIL_LEGAL` -- `CONTACT_FORM_TO_EMAIL_HR` +- `CONTACT_FORM_TO_EMAIL_CAREERS` - `CONTACT_TURNSTILE_SECRET_KEY` Comportamento: @@ -79,6 +76,19 @@ Comportamento: - `dev`: accetta submit e scrive payload nei log (senza invio reale) - `live`: valida Turnstile e invia email via Resend +Routing pubblico consigliato (portale vetrina): + +- `info`: informazioni generali/commerciali +- `privacy`: richieste privacy e diritti interessato +- `careers`: candidature e collaborazioni + +Indirizzi consigliati portale: + +- `info@nexstudio.ai` +- `privacy@nexstudio.ai` +- `careers@nexstudio.ai` +- `no-reply@nexstudio.ai` (solo invio comunicazioni/newsletter, non destinazione inbound) + ## Deploy Cloudflare Impostazioni consigliate: diff --git a/src/data/home/cta.ts b/src/data/home/cta.ts index 746f3a1..1ead7e6 100644 --- a/src/data/home/cta.ts +++ b/src/data/home/cta.ts @@ -30,7 +30,7 @@ export const cta = { nameLabel: 'Nome', companyLabel: 'Azienda (opzionale)', countryLabel: 'Paese', - departmentLabel: 'Reparto', + departmentLabel: 'Area', emailLabel: 'Email', messageLabel: 'Scrivi qui il tuo messaggio', submitLabel: 'Invia messaggio', @@ -54,13 +54,9 @@ export const cta = { fieldEmail: 'email', fieldMessage: 'message', departmentOptions: [ - { value: 'general', label: 'Generale' }, - { value: 'support', label: 'Support' }, - { value: 'privacy', label: 'Privacy / DPO' }, - { value: 'security', label: 'Security / Incident Response' }, - { value: 'ethics', label: 'Segnalazioni confidenziali (Ethics)' }, - { value: 'legal', label: 'Legal' }, - { value: 'hr', label: 'HR' }, + { value: 'info', label: 'Informazioni generali e commerciali' }, + { value: 'privacy', label: 'Privacy' }, + { value: 'careers', label: 'Careers / Collaborazioni' }, ], }, } as const; diff --git a/src/pages/api/contact.ts b/src/pages/api/contact.ts index f69dd38..2d86cf7 100644 --- a/src/pages/api/contact.ts +++ b/src/pages/api/contact.ts @@ -82,12 +82,9 @@ async function sendWithResend(apiKey: string, fromEmail: string, toEmail: string function resolveDepartmentRecipient(runtimeEnv: RuntimeEnv, defaultRecipient: string, department: string): string { const normalized = department.trim().toLowerCase(); const map: Record = { - support: readEnv('CONTACT_FORM_TO_EMAIL_SUPPORT', runtimeEnv), + info: readEnv('CONTACT_FORM_TO_EMAIL_INFO', runtimeEnv) || defaultRecipient, privacy: readEnv('CONTACT_FORM_TO_EMAIL_PRIVACY', runtimeEnv), - security: readEnv('CONTACT_FORM_TO_EMAIL_SECURITY', runtimeEnv), - ethics: readEnv('CONTACT_FORM_TO_EMAIL_ETHICS', runtimeEnv), - legal: readEnv('CONTACT_FORM_TO_EMAIL_LEGAL', runtimeEnv), - hr: readEnv('CONTACT_FORM_TO_EMAIL_HR', runtimeEnv), + careers: readEnv('CONTACT_FORM_TO_EMAIL_CAREERS', runtimeEnv), }; return map[normalized] || defaultRecipient; } @@ -111,7 +108,7 @@ export const POST: APIRoute = async ({ request, locals, url }) => { const company = required(form.get('company')); const email = required(form.get('email')); const country = required(form.get('country')); - const department = required(form.get('department')) || 'general'; + const department = required(form.get('department')) || 'info'; const message = required(form.get('message')); if (!name || !email || !country || !message) { -- 2.49.0