From ad744f0212b34119b7d2d112462c1bff50b92896 Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 4 Sep 2026 17:37:26 +0200 Subject: [PATCH] docs: add guarded server upgrade runbook --- PROJECT_STATE.md | 7 +- .../server-upgrade-gitea-workspace-v2.md | 705 ++++++++++++++++++ mkdocs.yml | 1 + 3 files changed, 712 insertions(+), 1 deletion(-) create mode 100644 docs/operations/server-upgrade-gitea-workspace-v2.md diff --git a/PROJECT_STATE.md b/PROJECT_STATE.md index 70498ec2..385e6860 100644 --- a/PROJECT_STATE.md +++ b/PROJECT_STATE.md @@ -1,12 +1,17 @@ # ThothII — Project State -Last updated: 2026-09-02. +Last updated: 2026-09-04. This file is the short operational snapshot. Stable commands and the architecture mental model live in `AGENTS.md`; current design and runtime contracts live under `docs/architecture/`, `docs/contracts/`, `docs/adr/`, and `docs/evidence.md`. Superseded plans and reports are available from Git history rather than duplicated in the working tree. +The guarded server migration from a legacy checkout to the schema-v2 installation, Gitea source, +Authentik, internal catalog/embedding services, and the PSD workspace repository is documented in +`docs/operations/server-upgrade-gitea-workspace-v2.md`. Treat its operator gates and rollback +requirements as mandatory; do not replace the running server stack in place. + ## Current product shape ThothII is a human-in-the-loop datamart builder with three independently built layers: diff --git a/docs/operations/server-upgrade-gitea-workspace-v2.md b/docs/operations/server-upgrade-gitea-workspace-v2.md new file mode 100644 index 00000000..6ea22a1a --- /dev/null +++ b/docs/operations/server-upgrade-gitea-workspace-v2.md @@ -0,0 +1,705 @@ +# Upgrade del server alla configurazione ThothII v2 + +Questo runbook è il passaggio di consegne per il Codex che opererà sul server remoto. Porta una +installazione precedente alla configurazione corrente di ThothII senza modificare Authentik o il +DWH esterno e senza cancellare lo stack precedente durante il primo cutover. + +La procedura si applica a `main` quando contiene almeno il commit +`eba6148511675fc6a187aabb69a975adc5e3c542`. Deve essere presente anche questo file. Il commit +minimo è un controllo di sicurezza, non un invito a fermarsi a quella revisione: installare sempre +la `origin/main` approvata dall'operatore. + +## Regole non negoziabili + +- Eseguire prima l'intero inventario in sola lettura e consegnarlo all'operatore. +- Non stampare mai password, token, chiavi private, cookie, file `.env` o contenuti dei Docker + secret. Nei report sono ammessi solo percorsi, nomi delle variabili e valori non segreti. +- Non usare `set -x`, credenziali dentro URL Git, `http.sslVerify=false`, `docker compose down -v`, + `docker volume rm`, `git reset --hard` o pulizie ricorsive. +- Non inventare l'indirizzo IP di `git.tylconsulting.it` e non aggiungerlo a `/etc/hosts` senza un + valore e un fingerprint TLS forniti dall'amministratore. +- Non sovrascrivere la vecchia configurazione. Creare una nuova installation ID e mantenere + configurazione, immagini, container e volumi precedenti fino all'accettazione scritta. +- Fermarsi a ogni **Gate operatore**. Il Codex prepara evidenze e comandi esatti; l'operatore + autorizza backup con segreti, fermo dello stack, cambio del reverse proxy e rimozioni. +- Il DWH resta read-only e diretto. Nessuna migrazione o DDL deve essere eseguita sul DWH. + +## Cosa contiene la nuova release + +Il confine informale “da auth in poi” non coincide con un singolo commit Git. OIDC/Authentik e il +CLI host `tht` fanno parte del contratto che il nuovo server deve rispettare, ma la tranche promossa +da `f5861526` a `eba61485` riguarda soprattutto: + +- Database Management e il catalogo metadati isolato nel PostgreSQL interno `catalog-db`; +- sincronizzazione di tabelle, colonne e relazioni, generazione descrizioni e flag di sensibilità; +- Installation Model Catalog schema v2 come unica sorgente authored per modelli e provider; +- workspace schema v4 e proiezioni runtime generate; +- Qdrant per gli indici del workspace e Ollama per il solo modello di embedding; +- analisi locale deterministica delle colonne sensibili, con NER CPU opzionale; +- hardening delle proiezioni e stabilizzazione dei gate di test pre-deploy. + +La topologia base attesa è: + +| Servizio | Funzione | Persistenza | +| --- | --- | --- | +| `frontend` | UI React | nessuna persistenza propria | +| `core` | Fastify, Pi RPC e catalog API | volumi settings, Pi, registry, secrets e sessioni | +| `catalog-db` | PostgreSQL del catalogo metadati | volume `catalog-data` | +| `catalog-migrate` | migrazioni esplicite del catalogo | job one-shot, deve terminare con exit 0 | +| `qdrant` | indice vettoriale workspace | volume `qdrant-data` | +| `embedding` | Ollama interno per embedding | volume `embedding-models` | +| `embedding-model-init` | scarica/verifica il modello | job one-shot, deve terminare con exit 0 | + +`catalog-db` non è il DWH. Non pubblica porte sull'host e usa credenziali runtime e migrator +separate. Ollama non controlla le password utente: l'autenticazione resta OIDC tramite Authentik. + +Il PostgreSQL per le **sessioni** è un'altra funzione ancora. L'overlay +`deploy/compose.session-server.yaml.example` è esplicitamente opt-in: non abilitarlo durante questo +upgrade salvo decisione separata dell'operatore e presenza di un database sessioni già +provisionato. L'introduzione richiesta qui è soltanto `catalog-db`. + +## Stato finale desiderato + +Sono due repository distinti e non devono essere confusi: + +| Uso | Remote atteso | Branch | Trasporto | +| --- | --- | --- | --- | +| codice applicativo ThothII, remote `origin` | `https://git.tylconsulting.it/mptyl/ThothII.git` | `main` | HTTPS | +| workspace PSD, `workspaceRepository` | `git@github.com:mptyl/tht-workspace-psd.git` | `main` | SSH | + +Il riferimento locale approvato usa il workspace precedente e questi default di modello: + +- sessione: `zai/glm-5.3`; +- generazione metadati: `zai/glm-5.3`; +- embedding: `ollama/qwen3-embedding:0.6b`, 1024 dimensioni. + +Non copiare i file generati locali. La sorgente authored è il nuovo +`thothii-installation.yaml`; i file Pi, settings, catalogo runtime e Compose derivati vengono +rigenerati da `tht`. + +## 0. Preparare le variabili di lavoro + +Usare percorsi assoluti reali. I valori seguenti sono esempi e vanno sostituiti dopo l'inventario: + +```bash +THTII_REPO=/absolute/path/to/ThothII +THTII_GITEA_URL=https://git.tylconsulting.it/mptyl/ThothII.git +THTII_MIN_COMMIT=eba6148511675fc6a187aabb69a975adc5e3c542 +THTII_NEW_ID=psd-server-v2 +THTII_WORKSPACE_REMOTE=git@github.com:mptyl/tht-workspace-psd.git +THTII_WORKSPACE_BRANCH=main +THTII_OLD_INSTALLATION=/absolute/path/to/legacy/thothii-installation.yaml +THTII_NEW_INSTALLATION=/absolute/path/to/ThothII/deploy/psd-server-v2/thothii-installation.yaml +THTII_NEW_ENV=/absolute/path/to/ThothII/deploy/psd-server-v2/operator.env +THTII_BACKUP_ARCHIVE=/protected/backups/thothii-pre-v2-YYYYMMDD.zip +THTII_SECRETS_FILE=/protected/thothii-v2/thothii.secrets +THTII_PI_AUTH_FILE=/protected/thothii-v2/pi-auth.json +THTII_CATALOG_RUNTIME_PASSWORD=/protected/thothii-v2/catalog-runtime-password +THTII_CATALOG_MIGRATOR_PASSWORD=/protected/thothii-v2/catalog-migrator-password +THTII_WORKSPACE_SSH_KEY=/protected/thothii-v2/workspace-deploy-key +THTII_WORKSPACE_KNOWN_HOSTS=/protected/thothii-v2/workspace-known-hosts +THTII_PUBLIC_URL=https://thothii.example.invalid +THTII_AUTH_ISSUER=https://authentik.example.invalid/application/o/thothii/ +THTII_AUTH_CLIENT_ID=replace-with-approved-client-id +THTII_AUTHENTIK_URL=https://authentik.example.invalid +``` + +Definire inoltre, senza pubblicarne il contenuto: + +- percorso del descriptor e comando di avvio della vecchia installazione; +- installation ID, Compose project, porte e reverse-proxy route correnti; +- percorsi protetti per secret bundle, Pi auth, chiave SSH GitHub e `known_hosts`; +- Public URL, issuer, client ID, URL Authentik e nomi dei gruppi; +- host, porta, database, utente e CA del binding diretto DWH; +- directory persistenti e directory backup della nuova installazione. + +**Esito richiesto:** tutte le variabili indicano target esistenti o percorsi nuovi approvati; nessun +valore segreto compare nel terminale condiviso. + +## 1. Inventario in sola lettura del server + +Non fare ancora fetch, checkout, stop o modifica di remote. Dal checkout esistente raccogliere: + +```bash +cd "$THTII_REPO" +git status --short --branch +git branch --show-current +git rev-parse HEAD +git remote -v +git tag --points-at HEAD +docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}' +docker volume ls +df -h +tht version --json +``` + +Se `tht` non esiste ancora, registrarlo come assente senza installarlo in questo passo. Individuare +anche i container realmente appartenenti al vecchio stack, i loro image ID, i volumi montati e il +comando esatto che oggi li avvia. Non assumere nomi dai file della nuova release. + +Raccogliere in forma redatta: + +1. configurazione Authentik attuale: Public URL, issuer, client ID, callback, claim gruppi e gruppi + ruolo; non leggere in output client secret o API token; +2. binding DWH diretto: tipo `postgres_direct`, endpoint, database e utente; non stampare password; +3. remote, branch e revisione del vecchio workspace; +4. stato delle sessioni e directory dati che devono essere conservate; +5. spazio disponibile per immagini, volume Ollama, Qdrant, catalogo e backup. + +Se il worktree è sporco o contiene configurazioni non committate, fermarsi: descrivere file e +proprietario delle modifiche, senza fare stash, reset o checkout. + +**Esito richiesto:** un report redatto identifica vecchio stack, dati, immagini, rete, Authentik, +DWH e workspace; il worktree è pulito oppure l'operatore ha risolto esplicitamente le differenze. + +## 2. Rendere Gitea raggiungibile e assegnarlo a `origin` + +“Impostare Gitea come origin” e “risolvere il dominio Gitea” sono due operazioni diverse. Verificare +prima DNS e TLS: + +```bash +getent hosts git.tylconsulting.it +curl --fail --silent --show-error --head https://git.tylconsulting.it/ +``` + +Se `getent` non è disponibile, usare il resolver diagnostico già installato, per esempio +`dig +short git.tylconsulting.it`. Se il nome non risolve, fermarsi e chiedere la correzione DNS o +la mappatura IP ufficiale. Se TLS fallisce per una CA interna, installare la CA fornita +dall'amministratore nel trust store; non disabilitare la verifica. + +Quando rete e TLS sono validi, registrare l'URL corrente di `origin` nel report e configurare Gitea: + +```bash +cd "$THTII_REPO" +git remote get-url origin +git remote set-url origin "$THTII_GITEA_URL" +git remote -v +git ls-remote --exit-code origin refs/heads/main +``` + +Se `origin` non esiste, usare `git remote add origin "$THTII_GITEA_URL"` al posto di +`set-url`. Se serve autenticazione HTTPS, configurare il credential helper o il token nel secret +store del server; non inserire il token nell'URL o nella shell history. + +**Esito richiesto:** `origin` mostra l'URL Gitea esatto per fetch e push e `ls-remote` restituisce +`refs/heads/main`. Non eseguire push dal server. + +## 3. Fare fetch e aggiornare `main` senza perdere il rollback + +Con worktree pulito: + +```bash +cd "$THTII_REPO" +git fetch --prune origin +git branch rollback/server-pre-v2-YYYYMMDD HEAD +git switch main +git merge --ff-only origin/main +git merge-base --is-ancestor "$THTII_MIN_COMMIT" HEAD +test -f docs/operations/server-upgrade-gitea-workspace-v2.md +git status --short --branch +git rev-parse HEAD +``` + +Sostituire `YYYYMMDD` con la data reale e registrare hash precedente, rollback branch e nuovo hash. +Un merge non fast-forward, un file mancante o il fallimento di `merge-base` sono condizioni di stop. +Non risolvere divergenze con reset o rebase sul server. + +**Esito richiesto:** `main` coincide con la `origin/main` approvata, contiene il commit minimo e il +runbook, e il rollback branch punta ancora al vecchio HEAD. + +## 4. Salvare vecchia installazione, dati e immagini + +### Gate operatore A — custodia del backup + +Prima di leggere o archiviare secret, presentare l'elenco esatto dei file e volumi da salvare e +ottenere l'autorizzazione. Il backup deve stare fuori dal repository, su storage protetto, con +permessi restrittivi e checksum registrato separatamente. + +Se il vecchio CLI espone `backup` e accetta il suo descriptor, usare il percorso esplicito: + +```bash +umask 077 +tht --installation "$THTII_OLD_INSTALLATION" backup \ + --output "$THTII_BACKUP_ARCHIVE" --include-secrets --yes --drain +sha256sum "$THTII_BACKUP_ARCHIVE" +``` + +Se il vecchio formato non è accettato, usare la procedura di backup già approvata sul server. Non +improvvisare un archivio ricorsivo di `/srv` o della root. Il backup deve includere almeno: + +- descriptor, env non segreto, configurazione auth canonica, secret bundle, Pi auth e certificati; +- repository/configurazione workspace precedente e sessioni persistite; +- inventario di container, reti, volumi, mount, image name e image ID; +- configurazione del reverse proxy necessaria a ripristinare il servizio. + +Conservare anche le immagini effettivamente in uso: assegnare tag di rollback agli image ID +espliciti identificati al passo 1 oppure salvarli in un archivio Docker protetto. Non selezionare +immagini tramite glob. Il nuovo build può riutilizzare gli stessi tag mentre i container vecchi +continuano a funzionare. + +Il backup integrato va considerato sufficiente per un volume solo se il suo manifest lo elenca e la +procedura di restore è stata verificata. In questa migrazione il nuovo `catalog-data` nasce vuoto; +non esiste quindi un vecchio catalogo da importare. Per upgrade successivi, il catalogo PostgreSQL +dovrà avere un dump consistente esplicito se il backup corrente non lo comprende. + +**Esito richiesto:** archivio, checksum, immagini di rollback e comando di ripristino sono +verificati; nessun vecchio container o volume è stato eliminato. + +## 5. Installare il CLI corrente e creare una installation v2 affiancata + +Dal nuovo checkout: + +```bash +cd "$THTII_REPO" +./scripts/install-tht.sh +tht version --json +``` + +Preparare fuori dal repository file protetti distinti per: + +- secret bundle applicativo; +- Pi auth; +- password runtime e migrator di `catalog-db`; +- chiave privata e `known_hosts` del repository workspace GitHub. + +Le due password del catalogo devono essere casuali, non vuote e diverse. I file devono essere +leggibili solo dall'operatore autorizzato. Nel secret bundle servono i riferimenti approvati per i +provider (`ZAI_API_KEY` e, se mantenuto, `DEEPSEEK_API_KEY`) e per Authentik +(`THT_OIDC_CLIENT_SECRET`, `THT_AUTHENTIK_API_TOKEN`), mai i valori nel descriptor YAML. + +Verificare l'accesso SSH al workspace con la chiave e il file `known_hosts` approvati. Non costruire +`known_hosts` accettando alla cieca il primo fingerprint restituito dalla rete: + +```bash +ssh-keygen -F github.com -f "$THTII_WORKSPACE_KNOWN_HOSTS" +GIT_SSH_COMMAND="ssh -i $THTII_WORKSPACE_SSH_KEY -o IdentitiesOnly=yes -o UserKnownHostsFile=$THTII_WORKSPACE_KNOWN_HOSTS" \ + git ls-remote --exit-code "$THTII_WORKSPACE_REMOTE" refs/heads/main +``` + +Creare la configurazione server in modalità `configure-only`; il profilo server richiede root per +creare la proiezione auth con UID/GID del container. La versione corrente di `setup` non scrive +ancora i due path catalogo nell'env generato: passarli all'ambiente del comando per validare +Compose, quindi aggiungerli subito a `operator.env` nel passo successivo. + +```bash +cd "$THTII_REPO" +sudo env \ + THT_CATALOG_RUNTIME_PASSWORD_SOURCE="$THTII_CATALOG_RUNTIME_PASSWORD" \ + THT_CATALOG_MIGRATOR_PASSWORD_SOURCE="$THTII_CATALOG_MIGRATOR_PASSWORD" \ + tht setup --configure-only \ + --installation-id "$THTII_NEW_ID" \ + --profile server \ + --workspace-remote "$THTII_WORKSPACE_REMOTE" \ + --workspace-branch "$THTII_WORKSPACE_BRANCH" \ + --workspace-access ssh \ + --secrets-file "$THTII_SECRETS_FILE" \ + --pi-auth-file "$THTII_PI_AUTH_FILE" \ + --git-ssh-key-file "$THTII_WORKSPACE_SSH_KEY" \ + --git-known-hosts-file "$THTII_WORKSPACE_KNOWN_HOSTS" \ + --auth-mode oidc \ + --auth-public-url "$THTII_PUBLIC_URL" \ + --auth-issuer "$THTII_AUTH_ISSUER" \ + --auth-client-id "$THTII_AUTH_CLIENT_ID" \ + --auth-authentik-base-url "$THTII_AUTHENTIK_URL" \ + --auth-user-group 'TOT Users' \ + --auth-admin-group 'TOT Admin' +``` + +Se sul server i gruppi hanno nomi diversi, usare i nomi verificati al passo 1. Non indovinarli. +Registrare il descriptor prodotto, normalmente +`deploy//thothii-installation.yaml`, e usarlo esplicitamente in ogni comando +successivo. Aggiungere all'`operator.env` generato, usando un editor che non stampi i valori: + +```dotenv +THT_CATALOG_RUNTIME_PASSWORD_SOURCE=/protected/thothii-v2/catalog-runtime-password +THT_CATALOG_MIGRATOR_PASSWORD_SOURCE=/protected/thothii-v2/catalog-migrator-password +THT_CATALOG_SYNC_TIMEOUT_MS=600000 +``` + +I valori a destra devono essere i percorsi assoluti reali preparati sopra. Verificare che +`THTII_NEW_INSTALLATION` e `THTII_NEW_ENV` corrispondano ai file appena creati. + +**Esito richiesto:** esistono descriptor schema v2, env operatore e directory auth canonica/runtime +della nuova installation; lo stack precedente è ancora in esecuzione. + +## 6. Allineare il descriptor alla configurazione locale approvata + +Il `setup` genera un catalogo modelli valido ma generico. Sostituire il suo blocco `modelCatalog` +con questo riferimento corrente, soltanto dopo aver verificato che il server raggiunga gli endpoint +necessari: + +```yaml +modelCatalog: + defaults: + session: zai/glm-5.3 + metadataGeneration: zai/glm-5.3 + embedding: + id: ollama/qwen3-embedding:0.6b + dimensions: 1024 + providers: + deepseek: + authentication: + mode: pi_auth + session: + mode: pi_builtin + models: + deepseek-v4-pro: + session: {} + deepseek-v4-flash: + session: {} + deepseek-metadata: + authentication: + mode: secret_env + apiKeyEnv: DEEPSEEK_API_KEY + metadataGeneration: + litellmProvider: deepseek + models: + deepseek-v4-pro: + label: DeepSeek V4 Pro + metadataGeneration: {} + deepseek-v4-flash: + label: DeepSeek V4 Flash + metadataGeneration: {} + zai: + endpoint: + baseUrl: https://api.z.ai/api/coding/paas/v4 + authentication: + mode: secret_env + apiKeyEnv: ZAI_API_KEY + session: + mode: openai_compatible + metadataGeneration: + litellmProvider: openai + models: + glm-5.3: + label: GLM 5.3 + session: + reasoning: true + contextWindow: 200000 + maxTokens: 131072 + metadataGeneration: {} + local-qwen: + endpoint: + baseUrl: https://ml-aritmolab.policlinicosandonato.it/v1 + authentication: + mode: none + session: + mode: openai_compatible + metadataGeneration: + litellmProvider: openai + models: + qwen3.6-35b-a3b: + label: AritmoLab Qwen 3.6 35B A3B + session: + reasoning: false + input: [text] + cost: {input: 0, output: 0, cacheRead: 0, cacheWrite: 0} + contextWindow: 131072 + maxTokens: 16384 + compatibility: + supportsDeveloperRole: false + supportsReasoningEffort: false + supportsStore: false + maxTokensField: max_tokens + metadataGeneration: + disableThinking: true +``` + +Controllare inoltre: + +- `profile: server` e `projectDirectory` uguale al checkout reale; +- `workspaceRepository` uguale alla riga PSD della tabella iniziale; +- `authentication.configDirectory` nella nuova directory canonica; +- `authentication.runtimeProjection` in una directory separata, con `uid: 10001` e `gid: 10001`; +- un solo override Git SSH; +- nessun riferimento a vecchi `deploy/pi/models.json`, `deploy/pi/settings.json` o model metadata + nel workspace; +- nessun overlay session PostgreSQL salvo approvazione separata. + +La proiezione Compose dell'auth runtime è automatica: non aggiungere manualmente +`deploy/compose.auth-runtime-projection.yaml` agli override. Se un endpoint di modello non è +raggiungibile dal server, fermarsi e chiedere quale provider mantenere; non cambiare silenziosamente +i default. + +Aggiornare l'env operatore usando `deploy/env/server.env.example` come checklist. Devono essere +valorizzati almeno i percorsi `THT_CATALOG_RUNTIME_PASSWORD_SOURCE`, +`THT_CATALOG_MIGRATOR_PASSWORD_SOURCE`, `THT_DATA_ROOT`, `THT_PI_STATE_ROOT`, +`THT_WORKSPACE_REGISTRY_ROOT`, `THT_BACKUP_ROOT`, le sorgenti auth/Git e le porte. Le directory +persistenti della nuova installation non devono coincidere accidentalmente con quelle legacy. + +**Esito richiesto:** descriptor e env contengono soltanto configurazione non segreta, puntano ai +secret file protetti e descrivono esattamente workspace, auth e modelli approvati. + +## 7. Verificare Authentik senza ricrearlo + +Se Public URL resta invariato, non creare una seconda applicazione/provider in Authentik. Il +provider esistente deve avere: + +- callback esatta `/api/auth/oidc/callback`; +- scope `openid profile email`; +- claim `groups` non vuoto come array JSON; +- gruppi applicativi attesi, normalmente `TOT Users` e `TOT Admin`; +- token del service account con sola lettura dei gruppi. + +Configurare o rigenerare soltanto la configurazione canonica della nuova installation: + +```bash +sudo tht --installation "$THTII_NEW_INSTALLATION" auth configure \ + --mode oidc \ + --public-url "$THTII_PUBLIC_URL" \ + --issuer "$THTII_AUTH_ISSUER" \ + --client-id "$THTII_AUTH_CLIENT_ID" \ + --authentik-base-url "$THTII_AUTHENTIK_URL" \ + --user-group 'TOT Users' \ + --admin-group 'TOT Admin' +tht --installation "$THTII_NEW_INSTALLATION" auth status --json +``` + +Il comando non riceve secret come argomenti: li risolve dai riferimenti nel secret bundle. La nuova +directory `auth-state` può partire vuota. Le vecchie sessioni browser non devono essere migrate e +gli utenti dovranno autenticarsi di nuovo dopo il cutover. + +**Esito richiesto:** lo status redatto indica `mode: oidc`, URL e gruppi corretti; nessun secret è +presente in YAML, argomenti, log o report. + +## 8. Preflight e preparazione dei servizi interni + +`tht start` rigenera le proiezioni e avvia i servizi, ma non esegue il job esplicito +`catalog-migrate`. Preparare quindi immagini e servizi interni con la stessa identità Compose della +nuova installation mentre il vecchio frontend/core sono ancora attivi. + +Per prima cosa validare il descriptor e il render Compose: + +```bash +tht --installation "$THTII_NEW_INSTALLATION" update --check-only +``` + +Questo comando carica e valida il descriptor; dopo la modifica del `modelCatalog`, la proiezione +generata da `setup` resta intenzionalmente precedente fino a `tht start`. Non usare `doctor` come +gate in questo momento: i servizi sono fermi e il suo controllo di drift deve ancora fallire. Il +gate completo viene eseguito al passo 10, dopo che `start` ha rigenerato la proiezione. + +Calcolare il Compose project name con la stessa regola del CLI e costruire l'array dei file. Questo +blocco è esatto per il descriptor atteso, che ha il solo override Git SSH. Se nel descriptor ci sono +altri override approvati, inserirli nello stesso ordine subito dopo `compose.git-ssh.yaml`; non +ometterli e non aggiungere l'overlay sessioni per comodità. + +```bash +THTII_NEW_INSTALLATION=$(realpath "$THTII_NEW_INSTALLATION") +THTII_INSTALL_DIR=$(dirname "$THTII_NEW_INSTALLATION") +THTII_COMPOSE_PROJECT="thothii-$(printf '%s' "$THTII_NEW_INSTALLATION" | sha256sum | cut -c1-12)" +THTII_COMPOSE=( + docker compose + --project-name "$THTII_COMPOSE_PROJECT" + --project-directory "$THTII_REPO" + --env-file "$THTII_NEW_ENV" + -f "$THTII_REPO/compose.yaml" + -f "$THTII_REPO/deploy/compose.server.yaml" + -f "$THTII_REPO/deploy/compose.git-ssh.yaml" + -f "$THTII_INSTALL_DIR/generated/compose.models.yaml" + -f "$THTII_REPO/deploy/compose.auth-runtime-projection.yaml" +) +"${THTII_COMPOSE[@]}" config --quiet +``` + +Non stampare il render completo. Costruire le immagini e avviare soltanto i servizi interni privi +di porte host: + +```bash +"${THTII_COMPOSE[@]}" build core frontend +"${THTII_COMPOSE[@]}" up --detach catalog-db qdrant embedding +"${THTII_COMPOSE[@]}" run --rm catalog-migrate +"${THTII_COMPOSE[@]}" run --rm embedding-model-init +"${THTII_COMPOSE[@]}" ps --all +``` + +Il comando `catalog-migrate` deve terminare con exit 0 prima che `core` venga avviato. Anche +`embedding-model-init` deve terminare con exit 0 e lasciare il modello nel volume della nuova +installation. Questi comandi non pubblicano la nuova applicazione e non toccano i volumi legacy. + +Confermare inoltre che il server abbia accesso in uscita necessario al primo pull del modello +Ollama e spazio sufficiente per `embedding-models`. Qdrant e `catalog-db` devono restare sulla rete +Compose privata, senza porte host pubblicate. + +L'overlay NER `deploy/compose.sensitivity-ner.yaml` non è richiesto per il primo avvio. La policy +deterministica funziona senza NER. Abilitare il modello CPU soltanto con la procedura e i gate in +[Analisi locale della sensibilità](sensitivity-analysis.md). + +**Esito richiesto:** render Compose valido, immagini costruite, `catalog-db` healthy, migrazione exit +0, Qdrant/Ollama healthy e modello embedding inizializzato; `core` e `frontend` nuovi sono ancora +fermi. + +## 9. Cutover controllato + +### Gate operatore B — finestra di manutenzione + +Presentare prima: + +- hash release, descriptor nuovo e risultato del preflight; +- comando esatto per fermare e riavviare il vecchio stack; +- comando di rollback, image ID conservati e durata stimata; +- porte e route del reverse proxy che resteranno invariate o verranno cambiate. + +Dopo approvazione, bloccare nuove attività applicative e fermare solo lo stack legacy con il comando +registrato al passo 1. Non rimuoverne container o volumi. Avviare quindi la nuova installation: + +```bash +tht --installation "$THTII_NEW_INSTALLATION" start +``` + +Il primo avvio deve: + +1. rigenerare le proiezioni del model catalog aggiornato; +2. riutilizzare le immagini costruite e il catalogo già migrato al passo 8; +3. confermare healthy `catalog-db` e Qdrant; +4. avviare Ollama ed eseguire/verificare `embedding-model-init` per + `qwen3-embedding:0.6b`; +5. avviare `core` soltanto dopo le dipendenze richieste; +6. avviare `frontend` sulla bind address prevista per il reverse proxy. + +Non interrompere il primo pull perché è lento se log e avanzamento restano regolari. In caso di +errore, raccogliere soltanto i log sanitizzati: + +```bash +tht --installation "$THTII_NEW_INSTALLATION" status +tht --installation "$THTII_NEW_INSTALLATION" logs +``` + +`embedding-model-init` è one-shot: `exited (0)` è lo stato corretto, non un guasto. Il job +`catalog-migrate` è stato eseguito con `run --rm`, quindi fa fede l'exit 0 registrato al passo 8. +Qualsiasi exit diverso da zero blocca il cutover. + +**Esito richiesto:** servizi persistenti healthy/running, job one-shot terminati con exit 0 e +reverse proxy diretto alla nuova UI; i volumi legacy esistono ancora. + +## 10. Verificare autenticazione e runtime + +Eseguire: + +```bash +tht --installation "$THTII_NEW_INSTALLATION" status +tht --installation "$THTII_NEW_INSTALLATION" doctor --json +tht --installation "$THTII_NEW_INSTALLATION" auth status --json +tht --installation "$THTII_NEW_INSTALLATION" auth check +tht --installation "$THTII_NEW_INSTALLATION" pi test +``` + +Dal browser verificare: + +1. redirect ad Authentik e ritorno alla callback corretta; +2. login di un membro `TOT Users`; +3. accesso amministrativo soltanto a un membro `TOT Admin`; +4. logout e nuova autenticazione; +5. assenza di loop OIDC, cookie error o `502` del reverse proxy. + +È previsto che le sessioni browser precedenti non siano più valide. Non è previsto modificare +issuer, client o gruppi per aggirare un errore: diagnosticare prima callback, claim e secret refs. + +**Esito richiesto:** `doctor`, `auth check` e `pi test` passano e i due ruoli Authentik sono mappati +correttamente. + +## 11. Ripuntare e materializzare il workspace PSD + +Il vecchio workspace runtime non è una sorgente da copiare. La nuova installation deve clonare e +validare il repository Git approvato: + +```text +git@github.com:mptyl/tht-workspace-psd.git, branch main, access ssh +``` + +Nella UI amministrativa, nell'ordine: + +1. usare **Update workspace repository** per fetch/clone e validazione; +2. selezionare il workspace PSD; l'ID atteso è `psd-clinical`, ma confermarlo dal catalogo + `thoth-workspaces.yaml` anziché forzarlo; +3. usare **Validate workspace source**; +4. aprire **Database Management** e creare/aggiornare il database del workspace; +5. configurare il binding `postgres_direct` con gli stessi endpoint, ruolo read-only e CA già + approvati sul server; reinserire la password nel secret store write-only, non nel repository; +6. eseguire **Test workspace connections**; +7. eseguire una sincronizzazione completa dello schema nel nuovo catalogo; +8. selezionare quel workspace come workspace globale dell'installation. + +Poi verificare e materializzare con il CLI: + +```bash +tht --installation "$THTII_NEW_INSTALLATION" workspace inspect \ + --workspace psd-clinical --json +tht --installation "$THTII_NEW_INSTALLATION" workspace preprocess run \ + --workspace psd-clinical --json +``` + +Se il preprocess restituisce un run ID interrotto, usare il suo `--resume RUN` soltanto dopo aver +diagnosticato la causa. Non lanciare run paralleli. Il preprocess DWH materializza gli artifact +runtime; il preprocess Evidence ricostruisce l'indice Qdrant con l'embedding fisso. Le nuove sessioni +pinzano la revisione Git attiva del workspace. + +Non copiare nel nuovo descriptor i legacy `harness/workspaces/*.yaml` come catalogo authored e non +trasferire vecchi indici vettoriali incompatibili. Il repository workspace schema v4 definisce +database ed Evidence; binding, segreti e selezione attiva restano locali all'installation. + +**Esito richiesto:** `workspace inspect` mostra repository, branch e revisione PSD corretti; test +DWH diretto, schema sync e preprocess completo terminano con successo; Qdrant contiene la nuova +generazione Evidence. + +## 12. Accettazione finale + +Prima di dichiarare concluso l'upgrade, consegnare una checklist con evidenze redatte: + +- `git rev-parse HEAD` uguale alla release approvata e worktree pulito; +- `origin` uguale al Gitea ThothII e workspace remote uguale al GitHub PSD; +- `tht doctor --json`, `auth check` e `pi test` senza errori; +- `catalog-db`, Qdrant, Ollama, core e frontend healthy; +- `catalog-migrate` ed `embedding-model-init` terminati con exit 0; +- login Authentik utente/admin verificato; +- binding DWH diretto read-only verificato; +- catalogo sincronizzato e preprocess workspace completato; +- una nuova sessione di prova crea artifact e usa la revisione workspace attiva; +- backup, checksum, rollback branch e immagini legacy ancora disponibili; +- nessun secret aggiunto al repository o ai log condivisi. + +### Gate operatore C — fine osservazione + +Non rimuovere ancora stack, immagini, volumi o backup legacy. La loro eliminazione è un'attività +successiva e distruttiva, autorizzata soltanto dopo un periodo di osservazione e un backup completo +della nuova installazione che includa esplicitamente anche il catalogo PostgreSQL. + +## Rollback + +Eseguire il rollback se il nuovo stack non diventa healthy, Authentik non completa il login, il DWH +diretto non passa il test o il workspace non si materializza entro la finestra approvata. + +1. Raccogliere `status` e log sanitizzati della nuova installation. +2. Fermarla senza volumi: + + ```bash + tht --installation "$THTII_NEW_INSTALLATION" stop + ``` + +3. Ripristinare i tag immagine legacy dagli image ID/tag conservati se il nuovo build li ha + sostituiti. +4. Riportare il checkout al rollback branch soltanto se il comando legacy legge file dal checkout: + + ```bash + cd "$THTII_REPO" + git switch rollback/server-pre-v2-YYYYMMDD + ``` + +5. Riavviare il vecchio stack con il comando esatto registrato al passo 1. +6. Ripristinare la route reverse proxy precedente se era cambiata. +7. Verificare vecchia UI, Authentik e DWH; non montare i nuovi volumi nel vecchio stack. +8. Lasciare intatti i volumi della nuova installation per l'analisi post-mortem. + +**Esito richiesto:** il servizio precedente è nuovamente disponibile con i suoi dati originali e +la nuova installazione è ferma ma ispezionabile. + +## Riferimenti operativi + +- [Installazione e primo avvio](../install/first-start.md) +- [Authentik](../install/authentik.md) +- [OIDC generico](../install/authentication-oidc.md) +- [Operazioni workspace](workspaces.md) +- [Configurazione dei modelli Pi](../general/pi-configuration.md) +- [Contesti Docker](../installazione-docker-4-contesti.md) +- [Database Management](database-management.md) +- [Analisi locale della sensibilità](sensitivity-analysis.md) diff --git a/mkdocs.yml b/mkdocs.yml index 49d3101f..dd5488e4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -46,6 +46,7 @@ nav: - Home: index.md - Install and operate: - Install and first start: install/first-start.md + - Server upgrade from legacy release: operations/server-upgrade-gitea-workspace-v2.md - Local authentication: install/authentication-local.md - Generic OIDC: install/authentication-oidc.md - Authentik: install/authentik.md