Add full shell, replaceable Omics adapter and bilingual interaction

Implement approved specification #32 and tickets #33-#37. Keep host authentication server-verified and pin session interaction language. Compile scoped base selectors for browser compatibility and retain full gutters during CSS pruning.
This commit is contained in:
Codex
2026-09-13 14:26:39 +02:00
parent 2d1b714ebe
commit d8a29bfbdd
207 changed files with 8570 additions and 2164 deletions
@@ -0,0 +1,129 @@
# Full shell, Omics e interfaccia bilingue — verifica
Data: 2026-09-13. Specifica: [Full shell, integrazione Omics e interfaccia bilingue](../plans/2026-09-13-full-shell-spec.md).
I cinque ticket e le loro dipendenze sono elencati nel [piano](../plans/2026-09-13-full-shell-and-portal-integration.md).
## Risultato
- Configurazione pubblica generata dal descrittore installato; full ed embedded
usano la stessa immagine frontend. Sul Mac: `full`, locale iniziale `en`.
- Header full con lingua, tema, fullscreen reale e menu utente/logout; rail sinistro
vuoto di almeno 20 px. Nessuna rotellina amministrativa.
- Embedded senza header locale; `OmicsPortalAdapter` incapsula l'osservazione del
portale. Identità e autorizzazioni rimangono verificate dal server.
- Cataloghi EN/IT, traduzioni dei controlli delle griglie, grafici e SQL adattati
al tema. I contenuti di dominio rimangono invariati.
- `interaction_language` fissata nel manifest: cattura alla creazione, mantenimento
alla ripresa e assegnazione atomica del valore workspace per sessioni precedenti.
- Continuità della selezione al reload, nessuna ripresa automatica del modello e
protezione delle bozze non inviate.
La [guida operativa](../operations/shell-and-localization.md) descrive configurazione,
accesso, estensione ad altri portali/lingue e checklist di deploy.
## Verifiche automatiche
| Livello | Esito |
| --- | --- |
| CLI nativa Go | `go test ./...`: 21 package verificati |
| Harness Python | 1290 passati, 1 saltato, 6 L2 esclusi |
| Gate Pi JavaScript | 205 passati |
| Frontend | suite completa: 755 passati in 90 file; regressione CSS prebuild superata |
| Backend | suite completa Node 24: 1397 passati, 40 saltati |
| Omics Docker isolato | 15 test Django/integrazione passati; controlli JavaScript del browser inclusi |
| Cataloghi | 1666 messaggi italiani, 1701 riferimenti statici; conflitti e interpolazioni verificati |
| Build | frontend, backend/typecheck e documentazione MkDocs strict verificati; regressione CSS eseguita automaticamente prima della build frontend |
La suite backend richiede Node 24. Sul Mac il percorso Homebrew `node@24`
risolveva a Node 25; è stato usato esplicitamente Node 24.16.0 già presente in NVM,
senza modificare il runtime globale. Un test preesistente sul timeout di arresto
di un processo è fallito sotto carico parallelo ed è passato isolatamente;
la verifica finale usa un solo worker.
I test coprono comportamenti pubblici e confini approvati: manifest filesystem e
PostgreSQL, CLI, Fastify, processo Pi simulato, stream SSE, shell e widget React,
template/autorizzazione Omics. Non è stata avviata una nuova generazione L2 contro
il modello remoto o il DWH operativo. Il controllo statico dei cataloghi non è
una prova di traduzione di ogni possibile messaggio diagnostico esterno.
## Standards
Revisione indipendente rispetto al punto iniziale ThothII
`2d1b714ebe31419d712e9c3324a5e171d5f0317d` e Omics `aff7581`.
Due violazioni concrete del contratto: bozze dei gate non protette dal reload e
selezione di sessioni altrui persa per gli amministratori. Entrambe corrette e
riesaminate dal revisore indipendente. La protezione resta attiva anche durante
un invio e dopo un errore HTTP, fino all'accettazione e allo smontaggio del widget.
Nessun ulteriore rilievo concreto sul codice Omics o sulle euristiche di manutenibilità.
Esito finale del revisore: approvato, zero rilievi aperti.
## Spec
Quattro rilievi: i due precedenti, più verifica dell'identità mancante dopo una
riconnessione SSE riuscita ed errori deterministici dello stream non tradotti.
Le correzioni includono test di regressione e sono state riesaminate dal revisore
indipendente. Sono tradotti anche gli errori sanitizzati di avvio e le notifiche
deterministiche dei gate già localizzate nella lingua fissata della sessione.
Esito finale del revisore: tutti e quattro i rilievi chiusi, nessun nuovo rilievo
o ampliamento ingiustificato dell'ambito.
Riepilogo iniziale: Standards 2 rilievi P2; Spec 4 rilievi P2. Gli assi restano
separati; i rilievi comuni non rappresentano ulteriori difetti distinti.
Riepilogo finale: Standards 0 aperti; Spec 0 aperti.
## Collaudo visivo
Il collaudo con l'account locale autenticato ha trovato tre difetti non visibili
nei test DOM dei componenti:
1. Il contenitore CSS `@scope` includeva l'intero livello base Tailwind e nel browser
integrato non applicava i token. Il CSS era servito con HTTP 200, ma il font
effettivo era Times e `--background` risultava vuoto. L'isolamento del reset
è ora compilato in selettori ordinari, senza modificare gli stili del portale.
Il browser applica Manrope e i token light/dark corretti. Revisione indipendente
del CSS compilato: nessuna perdita di isolamento individuata.
2. La classe full costruita per interpolazione faceva eliminare il token del
margine dalla build Tailwind. Nomi di classe letterali e una regressione sulla
presenza di `--thot-shell-gutter` rendono il requisito verificabile nella build.
3. Le griglie amministrative caricavano il tema CSS preesistente insieme al nuovo
tema automatico della libreria. Griglie amministrative e anteprime ora usano
un solo sistema CSS con i token della shell, eliminando il conflitto. I token
vengono applicati anche ai contenitori di tema interni creati da AG Grid,
che altrimenti sovrascriverebbero i colori ereditati.
Questi controlli sono stati eseguiti prima del commit di consegna. Il nuovo test
`scripts/scoped-base.test.mjs` viene eseguito dal comando `prebuild` anche in Docker.
Le prove di lingua/tema non hanno modificato dati del catalogo o avviato sessioni.
## Installazione locale e recupero
Il binario nativo aggiornato è installato in `/usr/local/bin/tht`.
Il descrittore locale, non versionato, è
`deploy/psd/thothii-installation.yaml`; `installation generate` ha prodotto:
```javascript
window.__THOTHII_CONFIG__ = {"backendBaseUrl":"/api","shell":{"mode":"full","defaultLocale":"en"}};
```
Il progetto Docker locale è `thothii-18998cca7b0a`; l'aggiornamento riguarda soltanto
core/frontend. Database, Qdrant, embedding e volumi persistenti restano invariati.
Le immagini precedenti sono conservate come
`thothii-core:before-full-shell-20260913` e
`thothii-frontend:before-full-shell-20260913`.
Binario e descrittore precedenti sono in `/private/tmp/thothii-shell-install.8idNoC`
(copia temporanea locale, non backup permanente).
Il sorgente Omics aggiornato è registrato nel commit locale `95154e1`.
Nessun push o deploy sul server di produzione è stato eseguito. Il collaudo
operativo sul server resta una fase del normale rilascio, seguendo la guida.
Core/frontend locali aggiornati e healthy; `/api/health` restituisce 200,
`/config.js` espone full/en e `/api/auth/config` conferma l'accesso locale.
Con l'account locale autenticato sono stati controllati header, cambio EN/IT,
light/dark, menu utente/logout, ingresso/uscita fullscreen tramite pulsante e
margini effettivi di 24 px. I test automatici coprono logout e sincronizzazione
con `fullscreenchange`, compreso il ritorno allo stato normale. L'uscita tramite
tasto Esc nativo resta da provare in un browser desktop ordinario: il comando
di tastiera automatizzato del browser integrato non l'ha riprodotta. Nessuna
promessa di collaudo completo del browser del server è implicita in queste prove.
Le preferenze locali sono state riportate a inglese e tema chiaro.
@@ -0,0 +1,195 @@
# Revisione della semplificazione della shell
Data: 2026-09-13. Oggetto: piano full/embedded, ADR 0021–0022 e contratto
Portal Shell Adapter v1. Questa è una revisione con raccomandazioni: non modifica il
codice applicativo né sostituisce automaticamente i contratti accettati.
## Valutazione
La separazione tra shell, autenticazione e lingua delle sessioni è corretta. La
semplificazione precedente ha però mantenuto un protocollo di comunicazione non
necessario per il montaggio corrente e ha lasciato ambigue alcune condizioni di
compatibilità. Raccomando un adapter che osservi il documento già condiviso con
Omics, riutilizzi l'autenticazione esistente e non imponga un nuovo bridge al portale.
La revisione considera il sorgente locale di ThothII e Omics Portal al commit
`aff7581`, già ottenuto con il pull richiesto. Non certifica quali immagini,
configurazioni o modifiche siano attualmente attive sul server.
## Problemi individuati e correzioni raccomandate
### 1. Il cambio lingua senza ricaricamento non corrisponde a Omics
In `templates/partials/topbar.html:74–87`, Omics usa il form Django `set_language`
con `onchange="this.form.submit()"`. La lingua cambia attraverso una nuova pagina
renderizzata dal server. Il criterio 2 del contratto v1 promette invece aggiornamenti
senza ricaricamento per tutte le preferenze.
Raccomandazione: rispettare il comportamento del portale. In full, lingua e tema
cambiano immediatamente. In embedded, il tema cambia immediatamente e la lingua
segue il normale ricaricamento Omics. Evitare di intercettare il form per cambiare
solo ThothII: lascerebbe header, sidebar e testi Django nella lingua precedente.
Il ricaricamento va verificato durante una sessione attiva e con modifiche non
salvate: deve essere possibile ritrovare la sessione senza avviare una nuova
generazione; eventuali bozze richiedono una protezione dalla navigazione. Lo stato
persistito del workflow non equivale alla conservazione automatica della bozza UI
o del flusso di messaggi in memoria. Questa verifica è necessaria anche mantenendo
il protocollo a eventi del piano precedente.
### 2. Un protocollo ready/state non è necessario nello stesso documento
`templates/kokoro/datamart_builder.html` monta React in `#root`, nello stesso
documento dell'header. L'adapter può ottenere direttamente:
- lingua effettivamente renderizzata: `data-lang` del selettore
`.omics-language-select`;
- tema: attributo `data-bs-theme` sull'elemento `html`;
- fullscreen: stato del documento e relativo evento del browser.
Un'osservazione limitata all'attributo del tema e un listener del fullscreen
coprono gli aggiornamenti attuali. La lingua viene riletta quando Django restituisce
la pagina. Questi selettori e dettagli devono comparire soltanto dentro
`OmicsPortalAdapter`, con test basati sul template reale.
Attenzione: `templates/base.html:3` contiene oggi `lang="en"` fisso; quell'attributo
non è una fonte attendibile per la lingua Omics. Se in futuro il portale espone la
lingua su un attributo dedicato del punto di montaggio, si modifica soltanto l'adapter.
La proposta elimina due eventi personalizzati, la versione del protocollo, il
timeout di avvio e il rischio che il messaggio iniziale parta prima del listener.
L'osservazione va installata prima di consegnare lo snapshot iniziale; la funzione
di disiscrizione rimuove tutte le risorse. L'assenza dei dati Omics attesi produce
un errore di integrazione comprensibile, senza attivare la shell full.
Il costo accettato è una dipendenza esplicita dal piccolo contratto DOM Omics,
confinata nell'adapter. Un secondo portale potrà fornire gli stessi dati usando
un'altra implementazione, anche con un diverso trasporto. Non occorre costruirla ora.
### 3. `authenticated` duplica uno stato che il server già verifica
`kokoro/datamart_catalog_views.py:49` e `nginx/nginx.conf:69` verificano l'accesso
Omics e trasmettono al backend identità e autorizzazioni normalizzate. ThothII
ottiene già l'utente tramite `/me`. Non serve un ulteriore login né un flag nel
documento che dichiari l'utente autenticato.
Il logout Omics attuale è una navigazione (`topbar.html:118`), non un evento di
revoca. Un click sul link non prova che il logout sia stato completato; inoltre,
un flag inviato una volta non rileva la scadenza della sessione o un logout in
un'altra scheda.
Raccomandazione: togliere `authenticated` dallo snapshot visivo. La verifica
dell'accesso rimane nel percorso di autenticazione esistente. In embedded,
perdita dell'accesso significa chiudere i dati protetti e demandare il rientro
al portale, senza mostrare il form di login ThothII.
Serve verificare la gestione dei rifiuti Omics: l'endpoint di autorizzazione
restituisce attualmente 403 anche quando l'accesso non è disponibile, mentre
`frontend/src/api/client.ts` pulisce automaticamente lo stato su 401. Un 403
ordinario può anche significare che manca il permesso per una sola operazione;
non va trasformato indiscriminatamente in logout. La verifica `/me` deve
distinguere la perdita di accesso all'applicazione dal rifiuto di una sua funzione.
`frontend/src/stream/useSessionStream.ts` esegue già un controllo di autenticazione
quando il collegamento eventi fallisce: riutilizzare quel percorso. Non promettere
revoca istantanea di una connessione già aperta in un'altra scheda sulla sola base
di `auth_request` o di un evento nella pagina corrente. Il contratto deve dichiarare
quando l'accesso viene ricontrollato e verificare anche il ritorno a una scheda
rimasta aperta.
In full sul Mac resta il login locale esistente. Il logout backend esiste già
(`backend/src/auth/routes.ts:355`): il lavoro riguarda il collegamento all'header
e la pulizia della UI. Per installazioni full con OIDC va consentito anche quel
logout; oggi `AuthGate` lo espone soltanto per `mode === "local"`. La revoca della
sessione ThothII non va descritta come logout globale dal fornitore d'identità.
### 4. Il default embedded contraddice l'adapter obbligatorio
Il piano dichiara compatibilità con descrittori senza `shell`, ma il contratto
richiede `adapter` in embedded. Inoltre, pretendere un nuovo bridge renderebbe
inutilizzabile la vecchia pagina Omics finché non fosse aggiornata.
Raccomandazione: risolvere i valori in un unico punto di configurazione:
- assenza di `shell`: embedded con adapter Omics predefinito;
- embedded senza `adapter`: `omics-portal`;
- full: nessun adapter istanziato;
- nome adapter sconosciuto: errore esplicito di configurazione.
L'adapter che legge lo stato già esistente rende questa compatibilità concreta.
Sul Mac rimangono espliciti `mode: full` e `defaultLocale: en`. La proiezione
pubblica può usare il `config.js` già presente; non serve un nuovo servizio di
configurazione. Va verificato anche il prefisso API `/datamart-builder/api` nel
montaggio Omics: il default frontend `/api` non basta a dimostrare che il deploy
funzioni. Prima si aggiorna il lettore del descrittore, poi il file installato,
poiché il lettore corrente rifiuta chiavi sconosciute.
### 5. Fullscreen e dark mode hanno già elementi riutilizzabili
ThothII possiede già token scuri in `frontend/src/index.css:67`, attivati anche da
`data-bs-theme="dark"`. Il lavoro è completarne la copertura e verificare contrasto,
form, menu e finestre, riutilizzando questi token.
Omics cambia la classe `fullscreen-enable` al click (`static/js/app.js:702`)
prima di conoscere il risultato. Il ramo di uscita usa metodi storici e non
contiene `document.exitFullscreen()`. Non va copiato nella shell full: l'icona
deve seguire lo stato effettivo, compresi Esc e richieste rifiutate. La correzione
equivalente dell'header Omics appartiene al suo modulo UI, non a un secondo
controllo fullscreen dentro ThothII embedded.
La fascia vuota sinistra si realizza con una misura CSS condivisa, almeno 20 px,
bilanciata con lo spazio destro. Non richiede un modulo di navigazione vuoto.
Poiché il documento è condiviso, verificare anche che stili globali ThothII e
contenuti sovrapposti non alterino header e sidebar del portale: il template Omics
contiene già correzioni per reset CSS e altezza `100vh`.
## Elementi da conservare
La lingua dell'interfaccia, quella delle domande al revisore e quella dei contenuti
del workspace hanno proprietari e durate diverse. Conservare la separazione di
ADR 0022: semplificarla in un'unica preferenza globale introdurrebbe errori in
ripresa e nei workspace italiani.
Precisare tre regole d'implementazione:
- una nuova sessione salva il locale UI effettivamente risolto, dopo il fallback
delle traduzioni;
- una sessione esistente conserva la propria lingua anche se un altro revisore
usa un'interfaccia diversa;
- per manifest precedenti senza campo lingua, usare la lingua del workspace come
criterio di compatibilità e fissarla alla prima ripresa con un aggiornamento
idempotente. Non dedurla dalla lingua del browser del nuovo revisore. La lingua
storica esatta non è ricostruibile se il workspace è stato cambiato nel frattempo.
L'i18n resta il lavoro trasversale principale: include pagine amministrative,
errori, accessibilità e testi deterministici dei widget, anche quelli costruiti
fuori da React. Aggiungere soltanto i cataloghi dell'header non soddisfa la richiesta.
Il modello deve ricevere la lingua dal manifest autorevole, senza tradurre a
posteriori payload delle decisioni, SQL o contenuti del workspace.
## Struttura raccomandata
Un solo controller di shell alimenta l'interfaccia. In full gestisce preferenze
locali e header; in embedded riceve `{ locale, theme, fullscreen }` da un
`PortalAdapter.subscribe(...)`. I componenti applicativi usano quello stato e
non conoscono Omics. Nessun registro dinamico di plugin, protocollo di comandi o
controller separato per ciascun pulsante.
L'autenticazione continua a usare il modulo esistente, con presentazione dell'accesso
coerente con la shell. L'integrazione con un futuro portale richiede anche che il
suo lato server soddisfi il contratto di identità verificata: sostituire una classe
JavaScript non può da solo sostituire l'autenticazione server. Documentare insieme
l'adapter UI e la configurazione server Omics, senza introdurre nuove dipendenze
Omics nel workflow o nelle pagine ThothII.
## Verifiche necessarie prima della consegna
Verificare full sul Mac con default inglese, accesso/logout, tema e fullscreen;
embedded sul template Omics, con preferenze già impostate prima del montaggio,
cambio tema e lingua, Esc, assenza di header ThothII e descrittore precedente.
Verificare nuova sessione, ripresa, manifest precedente, ricaricamento durante
la revisione e perdita dell'accesso con collegamento eventi attivo.
Sono verifiche del comportamento, non motivi per costruire un'infrastruttura
generica. Questa revisione si basa sull'ispezione del sorgente; non sono stati
eseguiti test runtime né modificati i due applicativi.