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 # 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 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/`, 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 `docs/contracts/`, `docs/adr/`, and `docs/evidence.md`. Superseded plans and reports are
available from Git history rather than duplicated in the working tree. 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 ## Current product shape
ThothII is a human-in-the-loop datamart builder with three independently built layers: 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 - Home: index.md
- Install and operate: - Install and operate:
- Install and first start: install/first-start.md - 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 - Local authentication: install/authentication-local.md
- Generic OIDC: install/authentication-oidc.md - Generic OIDC: install/authentication-oidc.md
- Authentik: install/authentik.md - Authentik: install/authentik.md