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,101 @@
# ADR 0021 — Shell separati e adapter sostituibile per il portale
- Stato: accettato
- Data: 2026-09-13
## Decisione
ThothII espone due modalità di installazione, selezionate da `shell.mode`:
- `embedded` (default): ThothII è ospitato da Omics Portal. Non renderizza alcun header e
riceve dal portale lingua, tema e fullscreen. L'accesso resta verificato dal server.
- `full`: ThothII è autonomo. Renderizza il proprio header, con selettore lingua, tema,
fullscreen e nome utente. Il click sul nome apre il logout. Non mostra mai la rotellina o
altri comandi amministrativi del portale. Mantiene un rail vuoto a sinistra di almeno 20 px.
Il fatto che la shell sia `full` è distinto dallo stato `fullscreen`: la prima decide quale
contenitore viene renderizzato, il secondo indica se è attiva la Fullscreen API del browser.
L'icona passa da “entra in fullscreen” a “torna alla modalità normale”; anche `Esc` aggiorna lo
stato visualizzato.
La configurazione installata resta semplice e retrocompatibile. Sul Mac di sviluppo il profilo
locale userà:
```yaml
shell:
mode: full
defaultLocale: en
```
Il deploy sul server userà invece:
```yaml
shell:
mode: embedded
adapter: omics-portal
```
`defaultLocale` indica la lingua iniziale della shell full; in embedded la fonte autorevole resta
il portale.
L'adapter è l'unico confine tra ThothII e il portale. La sua interfaccia pubblica è volutamente
profonda e minima: consegna solo snapshot dello stato, senza esporre comandi, token, identità o
dettagli di trasporto.
```ts
export type HostShellState = {
locale: string; // BCP-47, inizialmente it/en
theme: "light" | "dark";
fullscreen: boolean;
};
export interface PortalAdapter {
subscribe(
onState: (state: HostShellState) => void,
onError: (error: Error) => void,
): () => void;
}
```
`OmicsPortalAdapter` è l'implementazione corrente. Un adapter per un altro portale potrà
sostituirlo senza modificare shell, i18n o workflow. In `full` l'adapter non viene istanziato:
lo stato è gestito internamente dalla shell.
Per l'integrazione oggi operativa, che monta la SPA direttamente nel DOM di Omics Portal,
l'adapter legge la lingua effettiva dal selettore Omics, osserva l'attributo del tema e ascolta
il fullscreen del documento. Selettori e osservatori restano privati dell'implementazione Omics.
La lingua segue il normale ricaricamento Django; tema e fullscreen cambiano nella pagina aperta.
La revisione approvata del 2026-09-13 elimina il precedente handshake a eventi: non servono
messaggi personalizzati, versioni di trasporto o timeout di avvio. Un futuro adapter potrà usare
un diverso trasporto senza modificare l'interfaccia applicativa.
Se `shell` o l'adapter embedded sono omessi, si usa `embedded` con `omics-portal`. Questo default
supporta il documento Omics esistente; nomi adapter sconosciuti o dati host mancanti producono
un errore esplicito, senza attivare la shell full.
## Confini che restano invariati
L'identità e l'autorizzazione del backend non vengono ricostruite nel browser. In embedded,
Omics Portal continua a gestire login e logout e la catena server-side `auth_request` continua a
fornire i principal header già previsti. Lo stato UI non dichiara l'utente autenticato: il modulo
di accesso usa la verifica backend esistente anche alla riconnessione e al ritorno alla pagina.
Un rifiuto su una singola operazione non equivale automaticamente alla perdita dell'accesso.
La lingua UI e la lingua di interazione con il modello restano separate dalla lingua del
workspace; il relativo contratto è in [ADR 0022](0022-separate-ui-locale-from-session-interaction-language.md).
## Alternative scartate
- Duplicare l'header di Omics in embedded: crea due fonti di stato e incompatibilità visive.
- Spargere controlli `if embedded/full` nei componenti: lega ogni pagina al portale.
- Trasmettere utente o token nel bridge: aumenta superficie e accoppia UI e autenticazione.
- Introdurre un protocollo completo request/response: non aggiunge funzionalità richiesta.
- Usare `profile` per distinguere le shell: `profile` descrive la topologia dell'installazione,
non la sua presentazione.
## Conseguenze
La soluzione richiede un adapter nel frontend che osserva il documento condiviso e mantiene la
logica di shell locale a ThothII. Il backend non necessita di un nuovo protocollo di autenticazione
o di una nuova sessione browser. Un nuovo portale deve soddisfare anche il contratto server di
identità fidata: la sola sostituzione della classe UI non sostituisce quel contratto.
@@ -0,0 +1,51 @@
# Separate UI locale from session interaction language
status: accepted
ThothII distinguishes three language concepts:
- `workspace.language` remains the language of workspace-owned documents, descriptions and Evidence;
- `ui_locale` controls deterministic ThothII chrome such as labels, form help, placeholders, errors,
accessibility text and review-widget chrome;
- `interaction_language` is persisted in a session and controls model-generated questions,
explanations and reviewer proposals.
The initial locale catalog supports Italian and English and uses extensible BCP-47 language tags.
Missing deterministic translations fall back to English. The selected UI locale supplies the default
interaction language when a new session is created. A resumed session always uses its persisted
interaction language; changing the host or full-shell UI locale must not silently rewrite an existing
session or make its model output switch language mid-workflow.
The distinction is required because the current workspace contract already uses `language` for
content and the PSD workspace is Italian. Reusing that field for a browser preference would make a
visual choice mutate domain content semantics. The model receives the session interaction language
through the session/Pi workflow context. SQL, identifiers, database values and other technical
artifacts remain governed by their existing contracts and are not translated as UI strings.
In `full`, the local shell owns `ui_locale` and supplies it when starting a new session. In
`embedded`, the host adapter is authoritative for `ui_locale`; ThothII applies host changes to
deterministic UI immediately while preserving the interaction language of any active session.
We considered using only `workspace.language`, using only a global browser locale, and translating
the model output after generation. The first conflates domain content with UI preference; the second
cannot preserve a session's language or follow the host portal; and the third would be unsafe for
structured reviewer decisions and would not control the model's reasoning or proposal language.
## Considered Options
- One mutable `language` field for workspace, UI and session was rejected because the fields have
different owners and lifecycles.
- Client-only translation of reviewer choices was rejected because choices can be generated by the
model and must be requested in the intended language.
- An English-only deterministic chrome was rejected because embedded and full installations must
follow the selected host/user language.
## Consequences
- Session creation and the persisted manifest gain an explicit interaction-language value.
- Legacy manifests without that value use the workspace language, pinned idempotently on first
resume; the browser locale must not determine this compatibility value.
- Resume must read that value from the manifest and must not accept a new locale as an override.
- The workflow prompt contract and deterministic reviewer-widget builders need a locale-aware input.
- Frontend strings need a catalog and stable keys; backend events should expose stable codes where
the frontend is responsible for localization.
+110
View File
@@ -0,0 +1,110 @@
# Portal Shell Adapter v1
Contratto minimo della presentazione embedded. La revisione approvata il 2026-09-13
sostituisce il precedente trasporto a eventi personalizzati con l'osservazione del
documento condiviso. Non trasferisce identità, token o stato di autenticazione.
## Configurazione
Sul Mac:
```yaml
shell:
mode: full
defaultLocale: en
```
Sul server Omics:
```yaml
shell:
mode: embedded
adapter: omics-portal
```
Se `shell` o `mode` sono omessi, la modalità è embedded. L'adapter embedded
predefinito è `omics-portal`; un nome sconosciuto è un errore di configurazione.
Full non istanzia adapter. `defaultLocale` inizializza full; in embedded il locale
proviene dal portale. L'autenticazione si configura separatamente dalla shell.
## API applicativa
```ts
export type PortalSnapshot = {
locale: string;
theme: "light" | "dark";
fullscreen: boolean;
};
export interface PortalAdapter {
subscribe(
onState: (state: PortalSnapshot) => void,
onError: (error: Error) => void,
): () => void;
}
```
Una sottoscrizione installa gli osservatori e consegna lo snapshot iniziale senza
richiedere messaggi all'altro applicativo. Gli aggiornamenti contengono snapshot
completi e validati. La disiscrizione elimina tutti i listener e osservatori.
La lingua viene risolta tramite i cataloghi UI, con fallback inglese.
## Implementazione Omics
L'integrazione monta React nel documento Django, non in un iframe.
| Dato | Fonte privata dell'adapter | Aggiornamento |
| --- | --- | --- |
| Locale | `data-lang` del selettore `.omics-language-select` | nuova pagina Django dopo `set_language` |
| Tema | `data-bs-theme` su `html` | osservazione limitata a quell'attributo |
| Fullscreen | stato effettivo del documento | evento del browser, inclusa uscita con Esc |
L'attributo `lang` storicamente fisso a `en` nel template base non deve essere
usato come surrogato della lingua selezionata. Leggere il valore renderizzato dal
server evita anche di anticipare un cambio lingua prima che il form abbia successo.
L'assenza del contesto host atteso produce un errore di integrazione; non abilita
controlli locali. Non si introducono eventi `ready/state`, handshake, timeout,
versioni dei messaggi o comandi duplicati. Selettori e dettagli Omics non devono
essere letti dai componenti applicativi.
## Proprietà per modalità
| Funzione | Full | Embedded |
| --- | --- | --- |
| Header | ThothII | solo Omics |
| Lingua | selettore locale | selettore Omics, normale reload Django |
| Tema | toggle locale light/dark | stato Omics |
| Fullscreen | controllo locale, stato reale | controllo Omics, stato reale |
| Login/logout | autenticazione ThothII configurata | autenticazione Omics esistente |
| Nome utente | header ThothII | header Omics |
| Rotellina amministrativa | mai | eventuale comando del portale |
## Accesso e continuità
Il server Omics verifica l'accesso a Datamart Builder e il proxy trasmette i
principal header normalizzati al backend ThothII. La UI usa `/me`; non effettua
un secondo login. Un altro portale deve soddisfare anche questo contratto server,
oltre a fornire una nuova implementazione dell'adapter UI.
Il logout del portale segue la sua navigazione. Una perdita di accesso rilevata
dal server chiude lo stato protetto; un 403 di una singola operazione non equivale
automaticamente a logout. La riconnessione degli eventi e il ritorno alla pagina
ricontrollano l'accesso. Non si garantisce revoca istantanea di una connessione
aperta in un'altra scheda attraverso il solo controllo iniziale del proxy.
Il cambio lingua può ricaricare la pagina: conservare la selezione della sessione,
proteggere le modifiche non salvate e non avviare una nuova generazione al reload.
Non si conserva una trascrizione integrale nel browser. La lingua della sessione
rimane quella registrata nel manifest, secondo ADR 0022.
## Sostituzione e verifiche
Un nuovo adapter può usare un diverso documento o trasporto, ma deve rispettare
la stessa sottoscrizione e mantenere la conoscenza del portale nella propria
implementazione. Non occorre implementare ora iframe o un secondo portale.
Verificare snapshot prima/dopo il montaggio, tema, fullscreen con Esc, cleanup,
contesto host mancante, assenza di header ThothII embedded, accesso singolo,
locale dopo reload e compatibilità del prefisso API. Full deve funzionare senza
alcun elemento Omics presente.
+186
View File
@@ -0,0 +1,186 @@
# Shell, autenticazione e lingue
Questa guida accompagna la [specifica approvata](../plans/2026-09-13-full-shell-spec.md)
e il [contratto Portal Shell Adapter](../contracts/portal-shell-adapter-v1.md).
## Scegliere il contenitore
La modalità della shell è indipendente dal profilo di distribuzione e dal metodo
di autenticazione. Un server può ospitare full; un ambiente locale può ospitare
embedded per provare un'integrazione.
Per questo Mac, nel descrittore installato:
```yaml
shell:
mode: full
defaultLocale: en
```
Per il server Omics:
```yaml
shell:
mode: embedded
adapter: omics-portal
```
L'assenza di `shell` conserva embedded con adapter Omics. Un nome adapter
sconosciuto è un errore, non una richiesta di fallback a full. Full ignora
l'adapter Omics riconosciuto e non lo istanzia. Un locale ben formato per cui non
esiste ancora un catalogo usa l'inglese nell'interfaccia.
`defaultLocale` è il valore iniziale, non un vincolo che annulla ogni scelta
dell'utente. Full ricorda lingua e tema nel browser; embedded segue soltanto
Omics. Le preferenze non modificano il descrittore installato.
## Applicare una modifica all'installazione
Aggiornare prima il binario nativo `tht`: le versioni precedenti rifiutano la
sezione `shell`. Modificare poi il descrittore e generare le proiezioni:
```bash
tht --installation /percorso/assoluto/thothii-installation.yaml installation generate
```
Il comando non avvia né arresta servizi. Genera anche
`generated/frontend/config.js`, che contiene configurazione pubblica, e il
relativo mount Compose. Non modificare a mano i file generati. `tht start`
rigenera le proiezioni nel normale percorso di avvio.
Applicare il normale processo di aggiornamento dei container dell'installazione.
Se si usa un launcher Compose personalizzato, deve includere la proiezione
Compose generata e ricreare il frontend quando cambia la configurazione. Il
fingerprint della configurazione pubblica permette a Compose di rilevare il cambio.
La stessa immagine frontend supporta entrambe le modalità.
Controllare il `config.js` effettivamente servito, che non deve essere memorizzato
in cache. In full la route API ordinaria è `/api`; Omics imposta nel template il
prefisso same-origin `/datamart-builder/api`, mantenendo le altre impostazioni.
## Accesso in parole semplici
In Omics l'utente effettua l'accesso al portale come oggi. Quando sceglie
Datamart Builder, il server controlla che possa usarlo e comunica a ThothII chi è.
ThothII apre l'applicazione per quella persona: non presenta un altro login e non
crea una seconda sessione browser. Le password non vengono trasmesse a ThothII.
Il nome e il comando Esci rimangono nell'header del portale.
Sul Mac full, ThothII presenta il proprio login locale. Dopo l'accesso mostra il
nome nell'header; il menu del nome contiene il logout. Riutilizza gli utenti e
la configurazione di accesso dell'installazione. Full supporta anche un'eventuale
autenticazione OIDC configurata; il suo logout termina la sessione ThothII, non
promette di disconnettere l'utente da tutti gli altri servizi OIDC.
I controlli server restano autorevoli. Un errore su una singola operazione non
deve cancellare automaticamente l'accesso all'intera applicazione. Un rifiuto
della verifica dell'utente chiude invece lo stato protetto. L'accesso viene
ricontrollato anche al ritorno alla pagina e quando il collegamento eventi deve
riconnettersi. Questo non equivale a una revoca istantanea di ogni connessione
già aperta in altre schede.
## Contratto server Omics
Il percorso corrente usa il controllo Django della capability
`datamart_builder.access`, la subrequest nginx `auth_request` e gli header
normalizzati `X-Thoth-Principal-Issuer`, `X-Thoth-Principal-Subject`,
`X-Thoth-Principal-Display-Name` e `X-Thoth-Is-Admin`. Il browser non può
scegliere queste identità: il proxy ricava gli header dal controllo server e
sostituisce quelli eventualmente forniti dal client.
Mantenere il backend configurato per l'autenticazione upstream e i suoi controlli
di autorizzazione. Non esporre un percorso alternativo che permetta al browser
di raggiungerlo aggirando quel controllo. Non introdurre token nel documento,
negli eventi UI o nella configurazione pubblica.
## Come funziona l'adapter
`OmicsPortalAdapter` è il solo modulo frontend che conosce il documento Omics.
Legge il `data-lang` del selettore lingua, osserva `data-bs-theme` e ascolta lo
stato fullscreen del documento. Fornisce snapshot `{ locale, theme, fullscreen }`
al controller di shell. Non invia comandi al portale e non usa un handshake.
La pagina Omics deve continuare a esporre il selettore
`select.omics-language-select` con la lingua renderizzata nel suo `data-lang`, e
il tema light/dark nell'attributo di `html`. Il selettore lingua usa il normale
form Django; non occorre convertirlo in una richiesta asincrona.
Per un altro portale, implementare la stessa sottoscrizione e selezionare il
nuovo adapter nel punto di composizione. Le pagine, l'i18n e il workflow non
devono acquisire riferimenti al nuovo portale. Sul lato server, il nuovo
contenitore deve anche fornire un'identità verificata conforme al contratto
upstream. Cambiare una classe JavaScript non sostituisce quel requisito.
## Lingue e sessioni
Ci sono tre scelte distinte:
| Scelta | Dove viene conservata | Cosa influenza |
| --- | --- | --- |
| Lingua UI | preferenza full o stato Omics | label, form, messaggi e controlli |
| Lingua di interazione | `interaction_language` nel manifest | nuove domande, spiegazioni e scelte del modello |
| Lingua workspace | configurazione del workspace | documenti, descrizioni e contenuti di dominio |
La creazione web acquisisce la lingua UI prima delle operazioni asincrone e la
invia come `interactionLanguage`. Un cambio successivo non modifica quella
richiesta. La ripresa legge il manifest e non usa il locale del browser come
override. SQL, identificatori, valori e citazioni dei contenuti rimangono invariati.
Per sessioni precedenti senza `interaction_language`, la prima ripresa fissa la
lingua del workspace in modo idempotente. Se il workspace era stato modificato
nel frattempo, non esiste una registrazione da cui ricostruire con certezza la
vecchia lingua: il criterio di compatibilità è quella disponibile alla ripresa.
Il cambio lingua di Omics ricarica la pagina. ThothII ricorda soltanto l'identificatore
della sessione per utente e pagina, senza salvare una trascrizione nel browser.
Il recupero riapre il pannello dei documenti; la ripresa operativa è esplicita e
non avvia una generazione soltanto perché la pagina è stata ricaricata. Le bozze
non inviate e le modifiche amministrative richiedono protezione dalla navigazione.
## Aggiungere e verificare traduzioni
I messaggi inglesi fungono da identificatori gettext-style e fallback. I
cataloghi italiani sono divisi per area per agevolarne la manutenzione. Usare
`useI18n()` nei componenti e interpolazioni nominate, evitando concatenazioni
che rendano impossibile cambiare l'ordine delle parole. Non chiamare il traduttore
su SQL, testi del modello o descrizioni del workspace.
Per una nuova lingua aggiungere il catalogo, registrarlo nel risolutore e renderlo
disponibile nel selettore full. Il portale deve fornire il relativo locale. La
lingua delle sessioni è già esplicita e non richiede una nuova struttura del manifest.
Le traduzioni dei controlli della griglia provengono dal catalogo ufficiale della
stessa versione di AG Grid.
```bash
cd frontend
npm run check:i18n
npx tsc -b
npx vitest run
```
Il controllo dei cataloghi segnala messaggi statici mancanti, interpolazioni
incompatibili e traduzioni discordanti. Non può provare da solo la copertura di
tutti i messaggi dinamici: completarlo con i test delle pagine e la verifica visiva.
La build verifica anche il CSS effettivamente generato: il reset Tailwind viene
limitato al mount React e ai suoi popup con selettori ordinari, senza richiedere
supporto browser a `@scope`. Mantenere letterali le classi dei due modi della shell
per conservarle durante la rimozione del CSS inutilizzato. Le griglie usano il tema
CSS esistente con i token light/dark; non mescolarlo con la nuova Theming API di AG Grid.
## Verifica prima del deploy server
Provare l'apertura dal menu Omics con un utente autorizzato e uno senza accesso;
verificare assenza di un secondo login e di header ThothII, italiano/inglese già
selezionati prima dell'apertura, tema, fullscreen e uscita con Esc. Ripetere con
un menu o un form aperto, una bozza non inviata e una sessione esistente.
Verificare perdita dell'accesso, ritorno alla scheda e riconnessione degli eventi;
distinguere questi casi dal rifiuto di una sola operazione. Controllare che una
ripresa conservi la lingua salvata e che il reload non avvii una nuova generazione.
Eseguire i test Omics nel suo ambiente Docker e includere gli aggiornamenti
dei template, degli asset e dei cataloghi Django nel suo normale rebuild.
La verifica del codice e i test locali non costituiscono un deploy sul server
di produzione. Usare il normale processo di rilascio per applicare entrambe le
revisioni e annotare immagini, descrittore e revisioni realmente installate.
@@ -0,0 +1,91 @@
# Piano — Full shell e integrazione con il portale
Stato: implementazione completata e installata sul Mac; deploy server non eseguito.
Esiti e limiti del collaudo: [rapporto di verifica](../reports/2026-09-13-full-shell-implementation.md).
Specifica consolidata: [Full shell, integrazione Omics e interfaccia bilingue](2026-09-13-full-shell-spec.md),
pubblicata come [specifica su Gitea](https://git.tylconsulting.it/mptyl/ThothII/issues/32).
Ticket approvati: [Full sul Mac](https://git.tylconsulting.it/mptyl/ThothII/issues/33),
[Embedded Omics](https://git.tylconsulting.it/mptyl/ThothII/issues/34),
[Sessioni bilingui](https://git.tylconsulting.it/mptyl/ThothII/issues/35),
[Traduzione completa](https://git.tylconsulting.it/mptyl/ThothII/issues/36),
[Consegna verificata](https://git.tylconsulting.it/mptyl/ThothII/issues/37).
Le dipendenze sono registrate anche nativamente sul tracker.
## Obiettivo
Aggiungere una shell autonoma `full` mantenendo compatibile l'integrazione corrente `embedded`
con Omics Portal. La complessità del portale deve restare confinata a un `PortalAdapter`.
## Regole definitive
- `embedded` è il default e non renderizza alcun header ThothII.
- La configurazione installata su questo Mac imposta `shell.mode: full` e
`shell.defaultLocale: en`.
- Il deploy server imposta `shell.mode: embedded` e `shell.adapter: omics-portal`.
- `full` renderizza header, rail sinistro vuoto di almeno 20 px e logout locale.
- Fullscreen è uno stato separato dalla shell: il pulsante entra/esce dalla Fullscreen API e
l'icona riflette anche l'uscita con `Esc`.
- Full include lingua, tema `light/dark`, fullscreen e nome utente; non include la rotellina
amministrativa.
- Embedded riceve dal portale solo `locale`, `theme` e `fullscreen`; il server verifica l'accesso.
- Login e logout embedded restano responsabilità di Omics Portal.
- La lingua UI è separata dalla lingua di interazione fissata nella sessione.
## Sequenza di implementazione
### 1. Configurazione e stato shell
- Aggiungere `shell.mode`, `shell.defaultLocale` e `shell.adapter` al descrittore di
installazione, mantenendo `embedded` come default quando `shell` non è presente.
- Proiettare nel runtime frontend solo configurazione non segreta.
- Centralizzare lo stato shell in un controller; i componenti non devono leggere direttamente
il portale.
### 2. Adapter e bridge Omics
- Implementare `PortalAdapter` con la sola API `subscribe`.
- Implementare `OmicsPortalAdapter` osservando il documento condiviso, secondo il contratto rivisto.
- Leggere il locale dal selettore renderizzato da Django, osservare il tema e ascoltare il fullscreen.
- Conservare il cambio lingua tramite reload Omics e il percorso server di autenticazione esistente.
- Validare snapshot e cleanup; in caso di errore mostrare un messaggio di integrazione in
embedded, senza fallback a controlli locali.
### 3. i18n e lingua del modello
- Introdurre cataloghi UI estendibili, inizialmente `it` e `en`, con fallback inglese.
- Usare il locale corrente per le nuove sessioni.
- Persistire nel manifest la lingua di interazione e usarla per domande, spiegazioni e scelte
del revisore; una ripresa conserva quella lingua.
- Non tradurre SQL, identificatori o contenuti del workspace.
### 4. Shell full
- Renderizzare header solo in `full`.
- Collegare selettore lingua, tema, fullscreen, nome utente e logout alle funzioni già esistenti
o equivalenti del frontend/backend.
- Implementare il cambio icona e la sincronizzazione con `fullscreenchange`.
- Applicare il rail sinistro vuoto con larghezza base semplice e non inferiore a 20 px.
### 5. Verifica
- Unit test per validazione adapter, cambio stato, fallback locale e regole di sessione.
- Test frontend per entrambe le shell, logout full e fullscreen con `Esc`.
- Test backend per il passaggio della lingua nelle nuove sessioni e la conservazione in resume.
- Test di integrazione Omics per preferenze iniziali, tema, fullscreen, locale dopo reload e accesso.
- Build frontend/backend, suite harness e build documentale.
## Fuori ambito
- Cambiare il proxy/authentication chain già operativo.
- Passare a iframe o introdurre `postMessage`.
- Trasferire token o oggetti utente nel browser bridge.
- Aggiungere una shell `system` per il tema o un terzo tema.
- Implementare un adapter per un secondo portale: deve solo essere possibile sostituire quello
Omics tramite la stessa interfaccia.
## Gate di approvazione
L'implementazione è approvabile quando il codice rispetta il [contratto v1](../contracts/portal-shell-adapter-v1.md),
la modalità embedded non mostra header proprio e la modalità full non dipende da Omics Portal.
+99
View File
@@ -0,0 +1,99 @@
# Full shell, integrazione Omics e interfaccia bilingue
## Problem Statement
ThothII è utilizzabile nel contenitore di Omics Portal, ma quando viene avviato
autonomamente deve offrire i comandi generali che oggi appartengono al portale.
Gli utenti devono poter scegliere italiano o inglese per l'interfaccia e per le
nuove conversazioni con il modello, senza modificare la lingua dei contenuti del
workspace. L'integrazione server deve conservare l'accesso già effettuato in Omics.
## Solution
Due modalità di installazione: Full Thoth Shell con header autonomo e Embedded
Thoth Shell pilotata dall'header del portale. Sul Mac si installa full con inglese
predefinito. Un Portal Shell Adapter sostituibile concentra le conoscenze Omics;
l'autenticazione utilizza i percorsi già esistenti. La lingua di interazione
rimane fissata per tutta la durata di una sessione, comprese le riprese.
## User Stories
1. As an operatore, I want scegliere full o embedded durante l'installazione, so that il contenitore corrisponda al luogo di utilizzo.
2. As an operatore Mac, I want full con inglese predefinito, so that l'applicazione sia autonoma appena aperta.
3. As an operatore di un'installazione precedente, I want mantenere embedded senza aggiungere configurazioni obbligatorie, so that un aggiornamento non interrompa l'integrazione Omics.
4. As an utente full, I want un header con lingua, tema, fullscreen e nome utente, so that i comandi generali siano sempre raggiungibili.
5. As an utente full, I want una fascia sinistra vuota di almeno 20 px bilanciata con lo spazio destro, so that il contenuto abbia margini coerenti.
6. As an utente full, I want nessuna rotellina amministrativa del portale, so that il contenitore mostri solo i comandi richiesti.
7. As an utente full, I want aprire il logout dal nome utente, so that possa terminare il mio accesso.
8. As an utente locale, I want usare le credenziali ThothII esistenti, so that non debba configurare Omics.
9. As an utente full con OIDC, I want terminare la sessione ThothII, so that il logout non sia limitato al login locale.
10. As an utente Omics, I want aprire Datamart Builder già autenticato, so that non debba effettuare un secondo accesso.
11. As an utente embedded, I want un solo header fornito da Omics, so that non compaiano comandi duplicati.
12. As an utente embedded, I want che login e logout siano gestiti dal portale, so that l'accesso sia coerente con le altre pagine.
13. As an utente embedded, I want che ThothII recepisca le preferenze già impostate prima dell'apertura, so that lingua e tema siano subito corretti.
14. As an utente, I want scegliere light o dark, so that la leggibilità corrisponda alle condizioni ambientali.
15. As an utente, I want leggere form, menu, errori e finestre anche in dark, so that il tema sia completo.
16. As an utente full, I want entrare in fullscreen del browser, so that il browser lasci spazio all'applicazione.
17. As an utente, I want vedere l'icona di uscita quando il fullscreen è attivo e l'icona iniziale dopo Esc, so that il comando rappresenti lo stato effettivo.
18. As an utente, I want un messaggio comprensibile se il browser rifiuta il fullscreen, so that il controllo non mostri uno stato inesistente.
19. As an utente, I want tutte le label e i testi non generati dal modello in italiano o inglese, so that possa usare l'applicazione nella lingua scelta.
20. As an utente assistito da lettore di schermo, I want nomi accessibili e messaggi tradotti, so that i controlli siano utilizzabili quanto quelli visivi.
21. As an utente embedded, I want il cambio lingua segua il normale ricaricamento Omics, so that tutta la pagina condivida la lingua.
22. As an revisore, I want ritrovare la sessione dopo quel ricaricamento e proteggere le modifiche non salvate, so that non perda il lavoro.
23. As an revisore, I want le nuove domande e scelte del modello nella lingua UI selezionata, so that l'interazione sia comprensibile.
24. As an revisore, I want riprendere una sessione nella sua lingua originale, so that le preferenze del nuovo browser non cambino il workflow.
25. As an revisore di sessioni precedenti, I want una regola stabile per i manifest privi della lingua di interazione, so that le riprese restino prevedibili.
26. As an responsabile dei dati, I want conservare lingua e contenuto di workspace, SQL, identificatori e valori, so that una preferenza UI non alteri i dati.
27. As an manutentore, I want aggiungere cataloghi per altre lingue con fallback inglese, so that l'i18n sia estendibile.
28. As an integratore, I want sostituire OmicsPortalAdapter con un altro adapter della stessa interfaccia, so that un nuovo portale non richieda modifiche alle pagine o al workflow.
29. As an utente il cui accesso scade, I want che lo stato protetto venga chiuso e il rientro segua il contenitore, so that non compaia un login ThothII in embedded.
30. As an operatore, I want documentazione accurata di configurazione, autenticazione, adapter, migrazione e verifiche, so that il deploy server sia ripetibile.
## Implementation Decisions
- La configurazione installata distingue topologia, autenticazione e shell. Shell omessa significa embedded con adapter Omics predefinito; adapter sconosciuti sono errori espliciti. Full non istanzia adapter.
- La configurazione frontend pubblica contiene soltanto dati non segreti e usa il meccanismo runtime esistente, compreso il prefisso API necessario al montaggio Omics.
- Un controller di shell espone preferenze e stato; i componenti non accedono direttamente al portale.
- L'interfaccia PortalAdapter offre una sottoscrizione con snapshot iniziale, aggiornamenti, errori e disiscrizione. Lo snapshot contiene locale, tema light/dark e fullscreen.
- L'implementazione Omics legge la lingua effettivamente renderizzata dal selettore, osserva il tema sul documento e ascolta il fullscreen del browser. Non introduce handshake, eventi personalizzati o polling per le preferenze. Il contratto DOM è privato dell'adapter.
- Il montaggio resta nello stesso documento. Nessun header o comando locale di autenticazione/presentazione viene introdotto in embedded.
- Il server resta autorevole per identità e autorizzazioni. Il bridge UI non trasmette token, utente o flag authenticated. La catena di identità fidata esistente viene conservata.
- I rifiuti di accesso all'applicazione devono essere distinti dai 403 relativi a una singola operazione. Ricontrollare l'accesso alla riconnessione e al ritorno alla pagina; non promettere revoca istantanea di altre schede tramite il solo proxy.
- Full riutilizza login e logout esistenti, preserva le protezioni dalle modifiche non salvate e abilita il logout anche per sessioni ThothII OIDC. Il logout globale dall'identity provider non è implicito.
- Fullscreen è indipendente dalla modalità full. L'icona segue lo stato effettivo e le richieste rifiutate sono gestite. I token dark esistenti vengono completati, con verifica dei contenuti sovrapposti e dell'isolamento degli stili embedded.
- L'i18n utilizza cataloghi estendibili EN/IT con fallback inglese, comprese label, aiuti, placeholder, accessibilità, errori e widget deterministici. I payload tecnici restano stabili.
- La lingua di interazione viene scelta dal locale UI risolto, salvata nel manifest e propagata al contesto del modello. Resume non accetta override dal browser.
- Le sessioni precedenti prive del campo usano la lingua del workspace come compatibilità; il valore viene fissato alla prima ripresa mediante aggiornamento idempotente. Non si pretende di ricostruire una lingua storica non registrata.
- Il cambio lingua Omics mantiene la navigazione Django. La selezione della sessione deve sopravvivere alla navigazione; le modifiche non salvate devono essere protette, senza avviare una nuova generazione implicitamente.
## Testing Decisions
I punti di verifica erano già approvati nel piano: comportamento della shell e
dell'accesso dall'interfaccia, contratto pubblico dell'adapter, creazione/ripresa
tramite API e CLI del workflow, configurazione d'installazione e integrazione
Omics. Non si richiede una nuova approvazione degli stessi punti.
- Test comportamentali: stato osservabile, testo e controlli accessibili, permessi e lingua persistita; evitare metodi privati o asserzioni sull'organizzazione interna.
- Riutilizzare i test AuthGate/AppShell con API simulate al confine HTTP, quelli delle route sessioni e quelli pubblici del repository/CLI del workflow.
- Verificare adapter con un documento equivalente al template reale, preferenze iniziali, aggiornamenti e cleanup; includere montaggio ripetuto.
- Verificare nuova sessione, resume con lingua UI diversa, manifest precedente e input locale invalido; il contesto fornito al modello deve contenere la lingua persistita.
- Verificare fullscreen con ingresso, uscita, Esc e rifiuto; entrambe le modalità con dark, form e menu aperti.
- Verificare accesso embedded senza secondo login, scadenza/403, riconnessione degli eventi e ritorno a una scheda; verificare logout full e protezione dei dati di un utente precedente.
- Typecheck e test mirati durante lo sviluppo; suite complete alla fine, build documentale e prova browser proporzionata. Non usare chiamate reali al modello per i test deterministici.
## Out of Scope
- Deploy sul server di produzione o modifica delle credenziali.
- Seconda implementazione per un portale futuro, iframe e protocollo postMessage.
- Nuovo sistema di autenticazione, propagazione di token nel browser o logout globale OIDC.
- Tema system, ingresso automatico in fullscreen, rotellina amministrativa nell'header full.
- Traduzione di SQL, dati, identificatori o contenuti del workspace; traduzione a posteriori delle decisioni generate dal modello.
- Persistenza di una trascrizione integrale delle conversazioni.
## Further Notes
La revisione della semplificazione del 2026-09-13 è stata approvata dall'utente e
prevale sui dettagli superati del primo contratto a eventi. La specifica consolida
le decisioni senza riaprire l'intervista. Le modifiche vengono revisionate sui due
assi Standards/Spec e committate sul branch corrente, preservando i cambiamenti
preesistenti estranei a questa funzionalità.
@@ -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.