diff --git a/docs/plans/2026-08-22-longevity-interfaccia.md b/docs/plans/2026-08-22-longevity-interfaccia.md new file mode 100644 index 0000000..95f255c --- /dev/null +++ b/docs/plans/2026-08-22-longevity-interfaccia.md @@ -0,0 +1,405 @@ +# Longevity — l'interfaccia: piano di implementazione + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** dare una faccia al fascicolo del cliente — il questionario che si compila in pagina e il referto che il cliente legge, col radar a sette assi. + +**Architecture:** pagine Astro dentro il sito esistente, sotto `/longevity/`, con un layout dedicato e un foglio di stile prefissato. Il contenuto statico è Astro; React solo dove serve interattività vera — il questionario a blocchi e il radar. I dati arrivano dal motore già costruito, mai da query scritte nelle pagine. + +**Tech Stack:** Astro, React, recharts (già in casa), better-sqlite3, vitest. Nessuna dipendenza nuova. + +**Spec:** `docs/specs/2026-08-21-longevity-design.md` + +**Piani precedenti, già eseguiti:** `2026-08-21-longevity-strato-dati.md` e `2026-08-22-longevity-motore.md`. Lo strato dati e il motore esistono, sono testati, e nessuna pagina li usa ancora. + +## Global Constraints + +- Branch **`feat/longevity`**. `main` non si tocca, non si deploya, non si pusha senza che Adriano lo chieda. +- **Nessuna dipendenza npm nuova.** +- Test in `tests/longevity/`, eseguiti con `npm test`. Codice e commenti in italiano. +- ⚠️ **La suite parte con un rosso che non è nostro:** `tests/modifiche-agosto.test.ts` (test del sito disallineato su `main`, fuori perimetro). L'atteso è **1 fallito pre-esistente**, il resto verde. Non ripararlo. +- ⚠️ **`npx tsc --noEmit` deve restare pulito.** In questo lavoro il tipo è il meccanismo di sicurezza: un typecheck rosso è un cancello che nessuno guarda più. +- **Nessun dato reale di persone** nelle fixture. + +## Le due regole di prodotto che l'interfaccia non può violare + +**1. Un punteggio insufficiente non si mostra come numero.** Il motore restituisce un tipo che nel ramo insufficiente **non ha il campo `valore`**: la pagina non ha da dove prenderlo. Ma la barriera finisce lì — la tabella dei punteggi è letta da una funzione tipata (`leggiScore`), e **le pagine devono usare quella**, mai una query propria. Una `SELECT valore FROM score` scritta in una pagina riapre il buco. + +**2. Il colore non giudica il corpo.** Niente semaforo verde/giallo/rosso sui punteggi: il servizio è premium ma **non clinico**, e un rosso su «Composizione Corporea» detto a una persona è un giudizio, non un'informazione. I punteggi si esprimono con l'**intensità** del colore d'accento del sito. L'unico colore di segnale — il mattone `#b05a4e` già presente nel foglio di Stress Index — è riservato ai **valori fuori range**, che segnalano un problema **della misura**, non della persona. + +## Il gesto che questa interfaccia deve avere + +Il radar mostra **quello che sappiamo** come area piena, e dove la misura non basta lascia un **perimetro tratteggiato** con, sotto, cosa manca per completarlo. Non un buco, non un errore: un invito. + +Regge tre cose insieme — la regola di prodotto («tratteggiato, mai un numero pieno fasullo»), la leva commerciale che il cliente voleva per il livello avanzato, e una posizione onesta: *non ti diciamo un numero che non sappiamo*. + +⚠️ **Con i dati di oggi sei assi su sette saranno tratteggiati**, perché nel registro c'è solo il questionario e i test fisici arrivano col piano degli import. È atteso: chi guarda la prima dashboard non deve scambiarlo per un guasto. + +## Struttura dei file + +| File | Responsabilità | +|---|---| +| `src/layouts/Longevity.astro` | layout della piattaforma: intestazione, niente header pubblico | +| `src/styles/longevity.css` | stile prefissato `.lg`, globale (deve raggiungere le isole React) | +| `src/pages/longevity/questionario.astro` | la pagina del questionario | +| `src/components/longevity/Questionario.tsx` | isola React: quattro blocchi, validazione, invio | +| `src/pages/api/longevity/questionario.ts` | endpoint che salva una compilazione | +| `src/pages/longevity/io.astro` | il referto del cliente | +| `src/components/longevity/Radar.tsx` | isola React: il radar a sette assi col tratteggio | +| `src/components/longevity/MacroScore.astro` | le tre carte dei macro-score | +| `src/lib/longevity/vista.ts` | ciò che serve alle pagine, letto dal motore | + +--- + +### Task 1: Il guscio — layout, stile, e una rotta che risponde + +**Files:** +- Create: `src/layouts/Longevity.astro`, `src/styles/longevity.css`, `src/pages/longevity/index.astro` +- Test: `tests/longevity/pagine.test.ts` + +**Interfaces:** +- Consumes: `isProtectedPath`, `canAccessAdminPath` da `src/lib/auth.ts` +- Produces: il layout `Longevity.astro` con `title` e `crumbs`, e le classi `.lg-*` + +**Il modello da seguire:** `src/layouts/StressIndex.astro` e `src/styles/stress-index.css`. Leggili prima di scrivere. Il foglio di stile va **globale e prefissato**, non in `