# DEPLOY PROD — Assistente RH (CT 121 `assistente`, 10.0.30.248)

Instalação feita a 24/09/2026, a partir dos passos realmente executados. O CT
de dev (117, 192.168.69.150) continua só com o Sabichão e as pastas de dev; este
CT só com o Sabichão (CT 107) e as pastas de prod.

## 1. Proxmox de prod (10.0.30.10)

NAS montada no host (conta `assistente`, credenciais em `/etc/cifs/assistente.cred`, 600):

```
//10.0.30.79/Processos  /mnt/assistente-processos  cifs credentials=/etc/cifs/assistente.cred,ro,vers=3.0,iocharset=utf8,uid=100033,gid=100033,file_mode=0440,dir_mode=0550,noserverino,_netdev,x-systemd.automount,x-systemd.idle-timeout=600 0 0
//10.0.30.79/Assistente /mnt/assistente-rh         cifs credentials=/etc/cifs/assistente.cred,vers=3.0,iocharset=utf8,uid=100033,gid=100033,file_mode=0664,dir_mode=0775,noserverino,_netdev,x-systemd.automount,x-systemd.idle-timeout=600 0 0
```

(uid/gid 100033 = `www-data` dentro do CT não privilegiado.)

CT criado com:

```bash
pct create 121 local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst --hostname assistente \
  --cores 2 --memory 4096 --swap 1024 --rootfs local-lvm:20 \
  --net0 name=eth0,bridge=vmbr0,firewall=1,gw=10.0.30.1,ip=10.0.30.248/24 --nameserver 10.0.30.1 \
  --unprivileged 1 --features nesting=1 --onboot 1 --ssh-public-keys <chave claude> \
  --mp0 /mnt/assistente-processos,mp=/mnt/processos,ro=1 --mp1 /mnt/assistente-rh,mp=/mnt/assistente
```

## 2. Dentro do CT 121

- Pacotes: `nginx mariadb-server php-fpm php-cli php-bcmath php-curl php-gd php-intl php-mbstring php-mysql php-xml php-zip php8.4-opcache composer unzip git curl fontconfig libreoffice-writer-nogui qpdf poppler-utils rsync cron`.
- `timedatectl set-timezone Europe/Lisbon`.
- Utilizador `claude` (grupo `www-data`, sem sudo) para deploy; app em `/var/www/assistente` (`claude:www-data`, 2775); `storage` e `bootstrap/cache` de `www-data`.
- Fonte Aptos **oficial** (Microsoft Aptos Fonts 4.40, `download.microsoft.com`, licença permite instalar em qualquer número de equipamentos próprios, sem redistribuição) em `/usr/local/share/fonts/aptos`, `fc-cache -f`. O mesmo zip substituiu no CT 117 as cópias tiradas do Office (antigas em `/root/aptos-office-antiga`). Processo 15 pelo LibreOffice com a fonte oficial: 15 páginas, igual ao Word.
- MariaDB: BD `assistente`, utilizador `assistente@localhost` (password só no `.env`).
- nginx: `/etc/nginx/sites-available/assistente` (root `public/`, `server_tokens off`, `nosniff`, `X-Frame-Options SAMEORIGIN`), `default` removido. Só HTTP na LAN (como dev).
- Fila: `deploy/assistente-queue.service` em `/etc/systemd/system/`, `enable --now`.
- Chaves do wrapper geradas NO CT (nunca saem): `/opt/assistente/.ssh/assistente_{consulta,apply}` (`www-data`, 600).

## 3. `.env` de prod (campos que diferem de dev)

```
APP_ENV=production
APP_DEBUG=false
APP_URL=http://10.0.30.248
APP_TIMEZONE=Europe/Lisbon
LOG_STACK=daily
LOG_LEVEL=info
WRAPPER_HOST=10.0.30.253
WRAPPER_CHAVE_CONSULTA=/opt/assistente/.ssh/assistente_consulta
WRAPPER_CHAVE_APPLY=/opt/assistente/.ssh/assistente_apply
WRAPPER_APPLY_ATIVO=prod       # desde 24/09/2026 (secção 5)
CONTRATOS_MODELOS_PATH="/mnt/assistente/Modelos contratos"
CONTRATOS_SAIDA_PATH="/mnt/assistente/Contratos Feitos"
CONTRATOS_CONVERSOR=word
```

Sem `FICHAS_PROCESSOS_PATH_TESTE` (só dev). `.env` `claude:www-data` 640.

## 4. Backups

- `/opt/db-backup/{backup.sh,targets.sh}` + `/etc/cron.d/db-backup` (02:30), como nos outros CTs (`/root/db-backup/targets/121.sh` no host).
- `CTS` do `/root/db-backup/aggregate.sh` passou a incluir `121` (cópia anterior em `aggregate.sh.bak-2026-09-24`). O pull cifrado de dev (05:00) apanha-o sem mudanças.
- Restauro testado a 24/09/2026 (BD ainda vazia): 21/21 tabelas, 23/23 migrações; BD temporária apagada. Repetir com dados depois dos primeiros casos.

## 5. CT 107 (Sabichão prod) — FEITO 24/09/2026 (autorizado pelo utilizador)

1. Wrapper instalado pelo `install.sh` com `ALVO=prod FROM_IP=10.0.30.248`, release `20260924110956` (anterior `20260922160526` fica em `releases/`; reverter = `ln -sfn` do `bin/current`). `inserir.php`/`portal_lookup.php`/`fichas_email.php` copiados da skill `inserir-funcionario`. `wkhtmltopdf` já existia em `/usr/local/bin`.
2. `authorized_keys` só com as duas chaves do CT 121 (`from="10.0.30.248"`, `command=` do wrapper, sem PTY/forwarding). Cópia anterior em `/root/authorized_keys.assistente.bak-20260924` no CT 107.
3. Chave de consulta de prod do CT 117 retirada (linha do `authorized_keys` e ficheiros em `/home/claude/.ssh` do CT 117). Dev fica só com dev.
4. CT 121: `WRAPPER_APPLY_ATIVO=prod`. Verificado: `consulta.alvo` = prod, 18 zonas, 95 processos na fila de contratos, `Aplicador::ambiente()` = prod com confirmação remota OK; contrato do processo 465 redigido pelo Word (15 páginas, 69 s), NÃO publicado.
5. Utilizador da app: `ru1p3dro` (Rui Pedro), único.

Nenhuma alteração à BD do Sabichão de prod.

## 6. Atualizar o código (deploy normal)

```bash
export COPYFILE_DISABLE=1
rsync -a --chmod=Dug=rwx,Do=rx,Fug=rw,Fo=r -e "ssh -i $HOME/.ssh/id_ed25519_claude" \
  --exclude vendor --exclude node_modules --exclude .env --exclude storage \
  --exclude bootstrap/cache --exclude tests --exclude phpunit.xml \
  /Volumes/www/assistente/app/ claude@10.0.30.248:/var/www/assistente/
# depois, como root no host 10.0.30.10:
pct exec 121 -- bash -c 'cd /var/www/assistente; runuser -u claude -- composer install --no-dev --optimize-autoloader --no-interaction; runuser -u www-data -- php artisan migrate --force; runuser -u www-data -- php artisan config:clear; runuser -u www-data -- php artisan view:clear; systemctl restart php8.4-fpm assistente-queue'
```

Nunca `config:cache` (os testes não correm aqui, mas mantém-se a regra de dev). Nunca correr a suite Pest em prod.

## 7. Verificar

1. `curl -s -o /dev/null -w '%{http_code}' http://10.0.30.248/login` → 200.
2. Na app, barra lateral mostra a pill do ambiente (OFF até à secção 5, depois PROD).
3. `LeitorClient::saude()` a partir do CT → `word: disponivel` (verificado 24/09/2026).

## 8. Reverter

- App: `pct stop 121` (nada mais depende dele); a skill do Claude continua como via manual.
- Backups: repor `aggregate.sh.bak-2026-09-24`.
- NAS: remover as 2 linhas do `/etc/fstab` do host.

## 9. Atualizações

- **24/09/2026 14:20** — app atualizada (commits até 5631319: portal dos dados na leitura com procura por nome, classificador do verso do CC, concelho/distrito, data de início = admissão, máscara de datas, "Confirmar em branco", comando `fichas:comparar-modelos`); migração `2026_09_24_000003`. CT 107: wrapper release `20260924141729` (acrescenta `consulta.portal_por_nome`, só leitura); anterior `20260924110956` em `releases/`. Mini: leitor com `modelo` por pedido e `/v1/classificar-documento`; Gemma 4 carregado.
- **24/09/2026 (noite)** — porte das regras OCR do Sabichão (classificação, CC frente/verso, acentos, cartões PSP, morada, IBAN, habilitações; commits f648aa5..5cd1bcb, revisto pelo Codex). Sem migrações nem `.env`. Leitor do mini: modelo por omissão Gemma 4 26B A4B QAT.
- **25/09/2026** — correções do uso real: especialidades desmarcadas ao guardar, ações bloqueadas com alterações por guardar, verso do CC sem MRZ, morada (andar em maiúsculas, ponto de abreviatura, vírgula), leituras alternativas normalizadas, nome do modelo, zona 1 editável, visualizador fixo e PDFs a 300 DPI (commits edc9bc9..7cbfaf1). Sem migrações. Caso 1 (Cristóvão): VIG marcado e aprovação anulada (feita sem o VIG); caso 2 relido (v3). Revisão Codex pendente (sem quota).
- **25/09/2026 (tarde)** — botão "Fazer contrato" na ficha inserida e pesquisa na lista de contratos (commit 3d8b1dc). Sem migrações. Revisão Codex pendente.
- **28/09/2026** — mini mudou para o IP temporário 192.168.69.231: plist do leitor (--host) e LEITOR_URL dos CT 117 e 121 atualizados; Gemma recarregado no LM Studio. Reverter quando o IP definitivo voltar.
- **28/09/2026** — Regerar/Guardar e regerar dos contratos passam pela fila, página atualiza-se sozinha (commit d6cfccd). Sem migrações. Revisão Codex pendente.
- **28/09/2026 (2)** — filiação "Pai e Mãe", val_rc nunca em branco (recurso 2025-01-01), origem "sem submissão no portal" (commits d46dc9a, b3b7731, 0a4e0a8). Sem migrações. Casos 172122 e 136029 relidos. Revisão Codex pendente.
