# Rendering full ed embedded ThothII ha una sola applicazione React, una sola build Vite e gli stessi servizi backend. «Doppio rendering» significa due modi di ospitare quella applicazione, non due versioni delle pagine e non rendering React sul server. Django renderizza il contenitore Omics; React renderizza ThothII nel browser, dentro `#root`. ## Tre decisioni indipendenti | Decisione | Configurazione | Effetto | | --- | --- | --- | | Distribuzione | `profile: local` oppure `server` | Compose, percorsi e vincoli operativi | | Presentazione | `shell.mode: full` oppure `embedded` | Proprietario di header e preferenze | | Autenticazione | `auth.yaml` local/OIDC oppure `AUTH_MODE=upstream` | Chi verifica l'identità, come arriva al backend | Il Mac usa **full + local**, con lingua iniziale inglese. L'integrazione Omics usa **embedded + upstream**, con accesso già verificato dal portale. Un server autonomo può usare **full + oidc**. Cambiare `shell.mode` non abilita un metodo di autenticazione e non modifica permessi o proprietari delle sessioni. Full con upstream può visualizzare un'identità già verificata dal proxy, ma non ha un logout ThothII disponibile: non è il profilo autonomo con login/logout. Embedded non avvia login locale o OIDC anche se il backend è configurato così; questa combinazione non realizza il login unico Omics e non va usata come fallback. ## Composizione comune ```mermaid flowchart TD CONFIG["config.js pubblico"] --> SHELL["ShellProvider"] FULL["Preferenze full nel browser"] --> SHELL HOST["Documento Omics"] --> ADAPTER["OmicsPortalAdapter: solo presentazione"] ADAPTER --> SHELL SHELL --> GATE["AuthGate: verifica GET /me"] GATE --> APP["AppShell: stesse pagine, sessioni e amministrazione"] AUTH["Backend: cookie locale/OIDC o identità upstream"] --> GATE ``` `ShellProvider` risolve la configurazione, applica lingua/tema e monta i contenuti solo dopo uno snapshot host valido in embedded. `AuthGate` verifica l'accesso; `AppShell` e le pagine non devono leggere selettori o eventi specifici di Omics. Il cambio utente smonta lo stato applicativo della precedente identità. ## Full - Header ThothII rosso Omics `#CB333B` in entrambi i temi; logo interamente chiaro. - Selettore EN/IT, tema light/dark, fullscreen e nome verificato dell'utente. - Menu del nome con logout soltanto per local/OIDC; nessuna rotellina admin. L'amministrazione resta nella navigazione applicativa, secondo i permessi. - Margine sinistro vuoto e simmetrico al destro: `max(20px, 1.5rem)`, normalmente 24px con radice a 16px. Non è una seconda sidebar di navigazione. - Lingua e tema ricordati sullo stesso origin in `localStorage`, nelle chiavi `thothii:shell:locale` e `thothii:shell:theme`. Non sono preferenze server per utente. In assenza di preferenze: `defaultLocale` e tema light. - Fullscreen usa `document.documentElement.requestFullscreen()` e `document.exitFullscreen()`: nasconde il contorno del browser dove supportato. L'icona cambia sullo stato reale, anche dopo Esc; un rifiuto mostra un errore. Non è un semplice ingrandimento CSS e non scatta automaticamente all'accesso. ## Embedded - Nessun header ThothII, selettore lingua, toggle tema, login o logout autonomo. I controlli rimangono nell'header generale Omics. - React è nello stesso documento della pagina `/kokoro/datamart-builder/`, non in un iframe. Non serve `postMessage` né un secondo protocollo di sessione. - L'adapter legge la lingua Django già confermata, osserva il tema del documento e ascolta il fullscreen reale. Le azioni rimangono di proprietà del portale. - Un contesto Omics mancante o invalido mostra un errore d'integrazione; non passa silenziosamente a full e non offre un secondo login. - Il portale assegna l'altezza disponibile sotto il proprio header: catena flex con `min-height: 0`, root contenuto e altezza applicativa vincolata al contenitore. Il contratto ThothII espone `--thoth-app-height` (fallback `100dvh`); verificare il contenitore reale, non presumere che l'intera viewport appartenga a React. Il template Omics mantiene inoltre i suoi override di compatibilità. Il reset CSS è limitato al mount React e ai popup dell'applicazione, senza richiedere CSS `@scope`. I token e i popup seguono il tema applicativo. Questo non rende indipendenti fogli di stile arbitrari caricati dal portale: la verifica del documento condiviso rimane necessaria a ogni integrazione. ## Caricamento e configurazione pubblica Il descrittore installato è la sorgente di verità. Il CLI genera `generated/frontend/config.js` e il suo mount di sola lettura nella proiezione `generated/compose.models.yaml`. Il file pubblico contiene solo `backendBaseUrl` e `shell`, mai identità, token, password o percorsi host. Va caricato **prima** del modulo React e servito senza cache. Nessuna build separata è richiesta per cambiare modalità; occorre rigenerare e applicare i mount tramite il lifecycle. L'ordine Omics è: config pubblico → override del solo prefisso API → asset dal manifest Vite. L'override deve conservare `shell`; l'adapter non configura il proxy. Il default completo di shell omessa è embedded/en/omics-portal. Il CLI normalizza anche singoli campi omessi; un oggetto `shell` scritto manualmente nel browser deve invece contenere `mode` e `defaultLocale`, altrimenti viene rifiutato. ## Lingua, continuità e dati La lingua UI traduce il testo dell'applicazione, non i contenuti di dominio. Alla creazione, la lingua UI viene acquisita come `interactionLanguage` di ripiego. Il CLI riconosce la lingua della domanda originale e salva `interaction_language` nel manifest; usa il ripiego solo per input troppo brevi, ambigui o composti da codice. Questa lingua governa domande, spiegazioni, scelte e controlli HITL. Il gate la include nei descrittori e il frontend la applica al sottoalbero dei widget, senza cambiare la lingua della navigazione. Alla ripresa vale la lingua salvata, non l'ultima scelta dell'header. Per i manifest precedenti senza campo viene riconosciuta e fissata la lingua della domanda, con la lingua workspace disponibile alla prima ripresa come ripiego. Il cambio lingua Omics invia il form Django e ricarica la pagina. ThothII conserva solo l'ID della selezione in `sessionStorage`, separato per pathname, issuer e subject. Riapre i documenti, non avvia una generazione. Bozze non inviate e modifiche non salvate richiedono conferma prima della navigazione; non sono una trascrizione salvata. La ripresa operativa resta esplicita. ## Punti di implementazione e manutenzione | Sorgente | Responsabilità | | --- | --- | | `tools/tht/internal/config/shell.go` | Normalizzazione e validazione del descrittore | | `tools/tht/internal/modelprojection/projection.go` | Config pubblico e mount generati | | `frontend/src/api/runtime-config.ts` | Validazione browser e prefisso API same-origin | | `frontend/src/shell/host/ShellProvider.tsx` | Composizione, preferenze e tema | | `frontend/src/shell/host/FullHeader.tsx` | Controlli solo full | | `frontend/src/shell/host/OmicsPortalAdapter.ts` | Conoscenza del documento Omics | | `frontend/src/auth/AuthGate.tsx` | Accesso e ricontrolli al ritorno alla pagina | | `backend/src/auth/auth.ts` e `principal.ts` | Verifica server dell'identità | Per un altro portale servono un'implementazione del [PortalAdapter](../contracts/portal-shell-adapter-v1.md), la sua registrazione nei validatori CLI/browser e nel punto di composizione, oltre al [contratto di autenticazione server](../install/authentication-upstream.md). Il nome di una classe non è un plugin caricabile dinamicamente da YAML. Procedure: [configurazione e deploy](../operations/shell-and-localization.md), [autenticazione](authentication.md), [accettazione](../testing/authentication-manual-acceptance.md).