docs: add guarded server upgrade runbook
Publish documentation / publish (push) Successful in 1m20s

This commit is contained in:
Codex
2026-09-04 17:37:26 +02:00
parent eba6148511
commit ad744f0212
3 changed files with 712 additions and 1 deletions
+6 -1
View File
@@ -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:
@@ -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/<installation-id>/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 `<PUBLIC_URL>/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)
+1
View File
@@ -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