diff --git a/docs/INFRA.md b/docs/INFRA.md new file mode 100644 index 0000000..ed6c341 --- /dev/null +++ b/docs/INFRA.md @@ -0,0 +1,90 @@ +# Infrastruttura — SmartRootsSite + +## Overview + +Sito istituzionale statico generato con **Astro 4**, deployato su **IIS / Windows Server 2016** presso Hetzner. + +- URL: https://www.smart-roots.net/ +- Cartella sul server: `C:\inetpub\wwwroot\smartroots-site\` +- Backend API: https://api.smart-roots.net/ (progetto SmartRootsServices) + +--- + +## Struttura IIS — Site `smart-roots` + +Il Site IIS `smart-roots` ha come Physical Path `C:\inetpub\wwwroot\smartroots-site\`. +Sotto di esso convivono due tipi di nodi: + +### Virtual Applications (webapp con proprio App Pool) +Sopravvivono automaticamente al cambio di Physical Path del Site. + +`/investirehub`, `/mantis`, `/motoregrafico`, `/olympiadocs`, `/reports`, `/services`, +`/smartreports`, `/smartwiki`, `/testblazor`, `/tradingview`, `/wiki`, `/zertimporter` + +### Virtual Directories (contenuto statico, nessun App Pool) +Vanno ricreate manualmente se si cambia la Physical Path del Site. +Puntano tutte a sottocartelle di `C:\inetpub\wwwroot\smart-roots.net\`. + +| Alias | Physical path | +|---|---| +| `.well-known` | `...\smart-roots.net\.well-known\` — ⚠️ necessario per rinnovo SSL | +| `allegati` | `...\smart-roots.net\allegati\` | +| `Images` | `...\smart-roots.net\Images\` | +| `Pdf` | `...\smart-roots.net\Pdf\` | +| `PricerApi` | `...\smart-roots.net\PricerApi\` | +| `PricerApp` | `...\smart-roots.net\PricerApp\` | +| `PricerApp2` | `...\smart-roots.net\PricerApp2\` | +| `video` | `...\smart-roots.net\video\` | + +--- + +## Deploy (da ripetere ad ogni aggiornamento) + +```powershell +npm run build +Copy-Item -Path "dist\*" -Destination "C:\inetpub\wwwroot\smartroots-site\" -Recurse -Force +``` + +Nessuna modifica IIS necessaria per i deploy ordinari. + +--- + +## web.config — nota critica + +Il file `public/web.config` (copiato da Astro in `dist/` durante la build) contiene: + +1. **Redirect HTTP→HTTPS** +2. **Astro static routing** — fallback catch-all che riscrive URL senza file fisico a `/{path}/index.html` +3. **httpErrors 404** — serve `/index.html` per qualsiasi 404 + +L'intera sezione `` è avvolta in: + +```xml + +``` + +**Questo wrapper è fondamentale.** Senza di esso, le regole di rewrite e il gestore 404 +vengono ereditati dalle Virtual Applications figlie, che ricevono traffico riscritto +o risposte sostituite con la homepage Astro invece dei loro contenuti. + +Sintomo senza il wrapper: endpoint dinamici delle webapp (es. `/smartreports/api/report?p=...`) +restituiscono la homepage Astro invece del contenuto atteso. + +--- + +## Pagine + +| URL | File | +|---|---| +| `/` | `src/pages/index.astro` | +| `/contatti` | `src/pages/contatti.astro` | +| `/privacy` | `src/pages/privacy.astro` | +| `/termini` | `src/pages/termini.astro` | + +## API usate dal frontend + +| Endpoint | Metodo | Scopo | +|---|---|---| +| `https://api.smart-roots.net/api/contatti` | POST | Invio form contatti | + +Il controller è in `SmartRootsServices/SRServices/Controllers/SmartRootsSite/ContattiController.cs`. diff --git a/public/web.config b/public/web.config index 6b58f41..b69f3e5 100644 --- a/public/web.config +++ b/public/web.config @@ -4,60 +4,62 @@ Da copiare nella cartella /dist dopo il build: astro build --> - + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - + + - - - - - + + + + + - + + diff --git a/src/pages/contatti.astro b/src/pages/contatti.astro index 492a4c9..cc2dfd0 100644 --- a/src/pages/contatti.astro +++ b/src/pages/contatti.astro @@ -101,10 +101,11 @@ import Footer from '../components/Footer.astro'; // ⚠️ Sostituire con l'URL reale dell'endpoint nella WebAPI const API_ENDPOINT = 'https://api.smart-roots.net/api/contatti'; - const form = document.getElementById('contact-form') as HTMLFormElement; - const submitBtn = document.getElementById('submit-btn') as HTMLButtonElement; - const okMsg = document.getElementById('form-ok') as HTMLElement; - const errMsg = document.getElementById('form-err') as HTMLElement; + const form = document.getElementById('contact-form') as HTMLFormElement; + const submitBtn = document.getElementById('submit-btn') as HTMLButtonElement; + const okMsg = document.getElementById('form-ok') as HTMLElement; + const errMsg = document.getElementById('form-err') as HTMLElement; + const errMsgDefault = errMsg.innerHTML; form.addEventListener('submit', async function (e) { e.preventDefault(); @@ -144,11 +145,17 @@ import Footer from '../components/Footer.astro'; form.reset(); okMsg.style.display = 'block'; okMsg.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + } else if (response.status === 400) { + const data = await response.json().catch(() => null); + const msg = data?.Message || 'Dati non validi. Controlla i campi e riprova.'; + errMsg.textContent = msg; + errMsg.style.display = 'block'; } else { throw new Error(`HTTP ${response.status}`); } } catch (err) { console.error('Errore invio form:', err); + errMsg.innerHTML = errMsgDefault; errMsg.style.display = 'block'; } finally { submitBtn.disabled = false;