# Operação e deploy

## Variáveis reais

| Variável | Finalidade |
|---|---|
| APP_URL | Origem absoluta do domínio, sem `/` final. Configurar antes do build para SEO e antes do arranque para CSRF/links |
| DATABASE_PATH | SQLite absoluto, fora da pasta pública e preferencialmente fora do deploy |
| STORAGE_DIR | Documentos/PDF privados; nunca alias público |
| BACKUP_DIR | Destino privado dos snapshots; guardar também cópia externa |
| DRAFT_ENCRYPTION_KEY | Chave aleatória de pelo menos 32 caracteres; a rotação torna rascunhos anteriores ilegíveis |
| ADMIN_EMAILS | Destinatários administrativos separados por vírgulas |
| EMAIL_FROM | Remetente autorizado no SMTP |
| SMTP_HOST/PORT/SECURE/REQUIRE_TLS/USER/PASSWORD | Transporte SMTP. `REQUIRE_TLS=false` apenas no simulador local |
| PORT/HOSTNAME | Bind Node; por defeito 127.0.0.1:3000 |
| TRUST_PROXY | Só `true` com proxy que sobrescreve X-Real-IP e acesso direto a Node bloqueado |
| JOBS_BATCH_SIZE | Lote finito, por defeito 10, máximo 50 |
| NEW_ADMIN_PASSWORD | Apenas no comando admin:user; não guardar como credencial da aplicação |
| BACKUP_WRITES_PAUSED | Confirmação operacional para executar backup consistente |

Os comandos npm carregam `.env` se existir. O processo gerido também pode receber variáveis do alojamento. Nunca copiar `.env` entre instituições. A `.env.example` não contém segredos.

## Atualização

1. Guardar snapshot consistente (ver abaixo).
2. Instalar o novo código com `git pull`/CI numa release.
3. `npm ci` (build usa devDependencies), `npm run db:migrate`, `npm run build`.
4. Validar a release, depois reiniciar o serviço Node com `npm start` e o diretório de trabalho correto.
5. Verificar homepage, login, submissão fictícia, jobs e downloads.

Migrações são forward-only. Não existe rollback automático de schema: para regressar a uma release incompatível, parar escritas e restaurar snapshot. Não fazer `db:migrate` numa DB do CSPVF; a baseline começa numa DB vazia. A importação histórica de clientes não está incluída.

## Reverse proxy (exemplo Nginx)

Integrar no vhost HTTPS existente; certificados ficam sob responsabilidade do alojamento. Ativar Brotli se disponível ou Gzip. O Next já comprime respostas quando suportado.

```nginx
client_max_body_size 51m;
client_body_timeout 120s;
location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_read_timeout 120s;
}
```

Não ativar cache global do proxy: APIs, rascunhos e administração contêm dados pessoais. `_next/static` é versionado e recebe cache longo do Next; `public/branding`, `images` e documentos editáveis exigem revalidação. Conteúdo público estático é regenerado no build. Depois de validar HTTPS permanentemente, o alojamento pode aplicar HSTS. A CSP conserva `unsafe-inline` para bootstrap do Next e tokens CSS; não se vende como CSP com nonces. Sem scripts externos por defeito.

O limite por IP é em memória e reinicia com o processo. Sem proxy confiável, há um bucket partilhado conservador. Em produção configurar TRUST_PROXY=true **só** com o header sobrescrito e Node em loopback. O servidor limita submissões a duas simultâneas. Um proxy pode aplicar limites adicionais/conexões concorrentes a `/api/applications` para proteger memória em uploads de 50 MiB. Não existe bloqueio por IP guardado indefinidamente nem Redis.

## Cron finito

Exemplo Linux, substituindo caminho e utilizador:

```cron
* * * * * cd /srv/institution && /usr/bin/env npm run jobs >> /var/log/institution-jobs.log 2>&1
20 3 * * * cd /srv/institution && /usr/bin/env npm run maintenance -- --commit >> /var/log/institution-maintenance.log 2>&1
```

O utilizador do cron precisa do Node correto no PATH e acesso aos diretórios privados. O comando termina; não usar daemon/worker extra. Jobs sobrepostos usam claim atómico/lease, e o mesmo trabalho não é adquirido simultaneamente enquanto o lease é válido. Recuperação após falha até cinco tentativas; estado visível em `/administracao/processamento`. Guardar e rodar logs; monitorizar código de saída e trabalhos FAILED, não apenas se o cron existe.

Manutenção: remove apenas rascunhos e sessões expirados, checkpoint WAL/optimize. Não elimina candidaturas ou documentos. Os registos de jobs/auditoria não são apagados automaticamente; rever retenção de acordo com o cliente. Notas, histórico e comunicações de uma candidatura são apresentados num único detalhe; listagens de candidaturas são paginadas, detalhes não têm paginação independente.

## Backup e restauro

1. Suspender submissões e alterações administrativas e parar o processo Node e o cron/jobs.
2. `BACKUP_WRITES_PAUSED=true npm run backup`.
3. O snapshot contém `institution.sqlite` consistente (SQLite backup API), `private-files/` e manifest. Guardar uma cópia protegida fora do servidor.
4. Reiniciar serviço e cron. Backup só avança após a confirmação explícita por variável; não bloqueia a produção automaticamente.
5. Para restaurar: parar serviço/jobs, restaurar DB + ficheiros do **mesmo snapshot**, garantir proprietário/permissões, executar `PRAGMA integrity_check`, aplicar apenas migrações necessárias à versão escolhida e reiniciar.

Guardar separadamente e com segurança as chaves do ambiente; não incluir passwords no arquivo de código. A perda da chave de rascunhos impede recuperar esses rascunhos. Testar periodicamente o restauro. Não copiar SQLite ativo com `cp` ignorando WAL.

## Recursos

Um processo Node permanente por instituição, SQLite embebido, zero Redis/DB server/worker permanente. Um cron de jobs por minuto e manutenção diária opcional. Memória idle e CPU medidos localmente no relatório de performance; carga/concorrência de produção não foram simuladas. Uploads ativos aumentam RAM temporariamente; configurar limite de concorrência no proxy conforme servidor. Não é garantido um número arbitrário de sites sem capacidade adicional.
