# Manuali d'uso delle applicazioni GTS

Toolkit condiviso per generare il manuale d'uso di una qualsiasi app del portale:
screenshot reali catturati da un browser headless e impaginati in un PDF.
Le app che lo usano tengono solo la propria configurazione e il proprio testo.

## Preparare la macchina (una volta sola, per server)

Serve Node 18 o superiore, un Chromium headless e `pdftoppm` (solo se il manuale
deve includere la stampa PDF di un documento).

```bash
# RHEL / CentOS / Rocky 9
dnf -y install atk at-spi2-atk at-spi2-core gtk3 mesa-libgbm alsa-lib \
  libXcomposite libXdamage libXrandr libXcursor libXi libXtst cups-libs \
  pango cairo nss nspr libdrm libxkbcommon liberation-fonts poppler-utils

cd /opt/gts/shared/doc/manuale
npm install
npx playwright install chromium
```

Su Debian/Ubuntu bastano `npx playwright install --with-deps chromium` (li'
`--with-deps` funziona, usa apt) e `apt install poppler-utils`.

Prova che sia tutto a posto: `node capture.mjs -h` deve stampare l'uso.

## Il comando: un manuale nuovo, da zero

```bash
cd /opt/gts/shared/doc/manuale
GTS_USER=<utente> GTS_PASS=<password> node nuovo.mjs <app>
```

`<app>` e' il codice o il nome con cui l'applicazione compare nel portale
(`rda`, oppure `"Richieste di Acquisto"`). Il comando fa tutto da solo:

1. trova la scheda dell'app nel portale e ne ricava **codice e societa'**
   (se e' pubblicata per piu' societa' lo dice e chiede `--soc N`);
2. crea `/opt/gts/<app>/doc/manuale/` e ci scrive `manuale.json`;
3. controlla che nessuna voce di menu scriva al solo caricamento (`preflight`);
4. cattura le schermate di tutte le voci di `menu.xml`;
5. **scrive il testo** descrivendo ogni schermata con i filtri, le colonne e i
   comandi trovati davvero nella pagina;
6. impagina `manuale.pdf`.

Opzioni: `--soc N`, `--base <url>`, `--titolo "..."`, `--cartella P`.

**Il server non e' cablato da nessuna parte.** Si prova l'installazione locale:
`http://127.0.0.1`, poi https, poi `localhost`. Si parte dall'indirizzo IPv4 di
proposito — `localhost` risolve in IPv6 e il server vedrebbe arrivare `::1`, che
le app con restrizione per indirizzo (`gts_app_config["localnetwork"]`)
rifiutano con "accesso non consentito". Se nulla risponde,
`nuovo.mjs` chiede l'URL. In alternativa `--base <url>` o `GTS_BASE=<url>`, che
viene propagato a tutti i passi della catena. Anche i `manuale.json` non
contengono il server, se non quando lo si indica apposta: gli stessi file
funzionano quindi su qualsiasi macchina in cui l'applicazione sia installata.

Il testo generato e' una base onesta ma meccanica: descrive *cosa* c'e' in ogni
schermata, non *perche'*. Si rifinisce a mano `manuale.html` e si rifa' il solo PDF.

## Portare un manuale al livello di rda e hq

Il testo generato descrive le schermate; i manuali curati spiegano i procedimenti.
Per colmare il divario senza rifare l'indagine a mano:

```bash
node dossier.mjs /opt/gts/<app>/doc/manuale     # -> dossier.md
```

Il dossier raccoglie dai sorgenti dell'app il materiale su cui si scrive: mappa
del menu, campi per schermata, messaggi di validazione (cioe' i campi davvero
obbligatori e quando), legende dei codici, permessi con i file che li usano,
azioni dei comandi con le transizioni di stato, integrazioni esterne.
`nuovo.mjs` lo genera gia' da solo. Come usarlo: **PROCEDURA.md**, che elenca
l'ordine dei capitoli e le regole di stesura.

## I singoli passi

Servono per rigenerare un manuale gia' esistente, o per ripetere solo un pezzo:

```bash
node preflight.mjs /opt/gts/<app>/doc/manuale     # controllo preventivo
GTS_USER=<utente> GTS_PASS=<password> node capture.mjs /opt/gts/<app>/doc/manuale
node verifica.mjs /opt/gts/<app>/doc/manuale      # nessuno screenshot vuoto?
node dossier.mjs  /opt/gts/<app>/doc/manuale      # materiale per scrivere a mano
node testo.mjs    /opt/gts/<app>/doc/manuale      # riscrive il testo (--forza per sovrascrivere)
node topdf.mjs    /opt/gts/<app>/doc/manuale      # ricostruisce il PDF
```

Ogni script accetta `-h`. `SOLO=06-griglia,12-riga` rigenera solo quelle
schermate; `GTS_BASE=<url>` punta a un server diverso da quello
del config (che di norma non lo indica: vale `http://127.0.0.1`): la cattura e' pura navigazione HTTP, quindi **una sola postazione
puo' generare i manuali di tutte le app raggiungibili in rete**, senza
installare nulla altrove.

## Cosa mette l'app

```
<app>/doc/manuale/
  manuale.json     configurazione (sotto)
  manuale.html     il testo del manuale, con <img src="img/..."/>
  img/             screenshot generati
  manuale.pdf      il risultato
```

Il foglio di stile e' condiviso: l'HTML lo linka come
`../../../shared/doc/manuale/manuale.css`.

## manuale.json

| chiave | a cosa serve |
|---|---|
| `base`, `app`, `soc` | server, codice applicazione e id societa'. **La scheda del portale si cerca per codice+societa'**, non per etichetta: la stessa etichetta si ripete su societa' diverse. |
| `titolo` | intestazione delle pagine del PDF |
| `daHome` | `true` (default se `daMenu` e' attivo): aggiunge le schermate raggiungibili dalle card della home (`hb_bs4_labels2`), che spesso non sono in `menu.xml` |
| `daMenu` | `true`: visita da sola tutte le voci di `menu.xml` (inventario gia' dichiarato dall'app, servito da Apache senza autenticazione). `false`: solo le `scene`. |
| `cercaAuto` | `false` per non premere il pulsante "Ricerca" delle pagine di menu (di default lo preme: senza, molte griglie restano vuote) |
| `saltaVoci` | voci di menu da non visitare |
| `righeMax` | righe di tabella oltre le quali la figura viene troncata |
| `nomi` | rinomina le tre schermate fisse (`login`, `portale`, `home`) |
| `sfoca` | offuscamento: `colonne` (per intestazione), `campi` (per id), `parole` (nomi di aziende o persone, ovunque compaiano), `selettori`, `celleMiste` (nominativo mescolato ad altro testo nella stessa cella), `perPagina` (regole extra, incluso `theDa` per le griglie con i nomi come intestazioni di colonna) |
| `variabili` | valori ricavati a runtime (es. l'id di un documento esistente) da usare come `{nome}` nelle scene |
| `scene` | schermate non raggiungibili dal menu: `pagina`, `pre`, `attendi`, `azione`, `attesa`, `righe`, `clip`/`clipJs`, `fullPage`, `pdf` |

## Regole da rispettare

- **Sola lettura.** La cattura apre pagine e pannelli e li richiude: non deve mai
  premere Salva, Registra, Autorizza, Invia o Elimina. Le schermate di conferma si
  fotografano aperte, mai confermate.
- **Passare dal portale.** E' `gate.php` a impostare applicazione e societa', e con
  esse la connessione al db e i permessi. Andare diretti su `entry.php` lascia il
  contesto di un'altra app: elenchi vuoti e funzioni "non autorizzate".
- **Lanciare `preflight.mjs` su un'app nuova.** La cattura da menu e' cieca: se una
  voce punta a una pagina che scrive gia' al caricamento va messa in `saltaVoci`.
- **Verificare l'offuscamento.** `capture.mjs` conta gli elementi sfocati per ogni
  scatto e segnala con `!!` le occorrenze delle `parole` rimaste leggibili: quel
  contatore deve restare a zero.
- **Niente credenziali nei file.** Utente e password si passano come variabili
  d'ambiente al momento del lancio.

## Comandi pronti, app per app

Sempre da `/opt/gts/shared/doc/manuale`. Rigenerano screenshot **e** PDF:

```bash
# RDA - Richieste Di Acquisto (testo scritto a mano, 25 schermate)
GTS_USER=<utente> GTS_PASS=<password> node capture.mjs /opt/gts/rda/doc/manuale && node topdf.mjs /opt/gts/rda/doc/manuale

# HQ - Amministrazione GTS (testo scritto a mano, 30 schermate)
GTS_USER=<utente> GTS_PASS=<password> node capture.mjs /opt/gts/hq/doc/manuale && node topdf.mjs /opt/gts/hq/doc/manuale

# qualsiasi altra app, manuale completo da zero
GTS_USER=<utente> GTS_PASS=<password> node nuovo.mjs <app>
```

Per rda e hq si usa `capture.mjs` e non `nuovo.mjs` perche' il loro testo e'
scritto a mano: `nuovo.mjs` non lo sovrascrive comunque (`testo.mjs` rifiuta di
sostituire un `manuale.html` esistente senza `--forza`).

Se serve solo ricostruire il PDF dopo aver modificato il testo, basta
`node topdf.mjs <cartella>`. Per rifare una singola schermata:
`SOLO=<nome> ... node capture.mjs ...`.
