A API deixa de ser especifica da Scardua e passa a atender varios
clientes pela rota /v1/holmes/{cliente}/...
Camada de clientes:
- app/clientes/base.py: ClienteBase (comportamento) + ClienteConfig (dado),
separados de proposito — config sai do configs.json hoje e pode sair do
banco amanha sem o resto mudar
- app/clientes/registry.py: resolve o {cliente} da rota pra instancia
- cada cliente traz a propria conta do Holmes; o cache de token virou um
arquivo por cliente (antes era constante de modulo e dois clientes
sobrescreveriam o token um do outro)
Holmes:
- funcoes de modulo viraram a classe HolmesAPI, amarrada a uma conta
- exposta pronta em cliente.holmes (cached_property)
- as funcoes de parsing puro (extrair_*) ficaram fora da classe
Config:
- app/schemas.py: modulo folha, so pydantic. Config e services usam os
mesmos modelos sem um importar o outro
- app/config.py: so o carregamento do configs.json
- configs.json passa a ter "clientes": {"<nome>": {...}}
Compras:
- schemas aceitam o payload real do Holmes (PEDIDO_LINX vem como numero,
NUMERO NF ENTRADA so existe depois da fase da nota)
- parcelas viram dict[int, Parcela], pareando parcelaN com o vencimento
correspondente e pulando os slots vazios
- payload de saida carrega id_processo como chave de deduplicacao: o
Holmes reentrega webhook e sem isso duplica linha no destino
Criptografia:
- app/services/cripto.py: envelope AES-256-GCM + RSA-OAEP-SHA256. RSA
sozinho nao serve (cifra ~190 bytes; o payload passa disso)
- ciframos com a publica do conector e nao conseguimos desfazer
Deploy:
- Dockerfile e .dockerignore vieram da VPS pro repo
- docs/deploy.md: runbook, incluindo que --format docker e obrigatorio
(em OCI o podman ignora o HEALTHCHECK silenciosamente)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.3 KiB
Deploy — API (VPS da FLS)
Ambiente: VPS Hostinger (Debian 13), Podman rootless + Quadlet, Caddy
(proxy + TLS), user admin.
No ar: https://api-scardua.flstecnologia.tech
ℹ️ O nome
api-scarduaé legado — a API hoje atende múltiplos clientes (/v1/holmes/{cliente}/...). Renomear implica mexer junto em: nome do quadlet,Image=,ContainerName=, pasta doconfigs.json, build dir, bloco do Caddyfile e DNS. Oreverse_proxydo Caddy resolve o container peloContainerNamedentro da redefls— se um mudar sem o outro, dá 502.
Acesso à VPS
ssh vps-fls # alias -> 179.197.230.154, porta 3115, user admin
- Porta 22 é fechada no firewall. Sempre
-p 3115(ou o alias). systemctl --usersempre (rootless) — nuncasudo systemctlpros containers.- ⚠️ O
~/.ssh/configtem um BOM na primeira linha e o OpenSSH do Git Bash recusa (Bad configuration option: \357\273\277host). Contorno sem editar o arquivo:ssh -F none -i ~/.ssh/id_ed25519 -p 3115 admin@179.197.230.154
Arquitetura
- Imagem: buildada local na VPS =
localhost/api-scardua:latest(sem registry). - Container na rede
fls— só o Caddy alcança; a porta 8000 não é publicada. - Config:
configs.jsonmontado read-only de~/.config/api-scardua/configs.json. - Quadlet:
~/.config/containers/systemd/api-scardua.container. - Caddy:
api-scardua.flstecnologia.tech→api-scardua:8000, TLS automático. Caddyfile em/srv/containers/stacks/caddy/Caddyfile.
Atualizar a app
# 1. marcar rollback ANTES de qualquer coisa
ssh vps-fls 'podman tag localhost/api-scardua:latest localhost/api-scardua:rollback-$(date +%F)'
# 2. mandar o código (não tem rsync no Git Bash do Windows; tar resolve)
tar czf - --exclude='__pycache__' --exclude='*.pyc' --exclude='.ruff_cache' \
main.py app requirements.txt Dockerfile .dockerignore pyproject.toml \
| ssh vps-fls 'rm -rf ~/build/api-scardua && mkdir -p ~/build/api-scardua && tar xzf - -C ~/build/api-scardua'
# 3. buildar e reiniciar
ssh vps-fls 'cd ~/build/api-scardua && podman build --format docker -t api-scardua:latest . \
&& systemctl --user restart api-scardua'
⚠️
--format dockeré obrigatório. No formato OCI (padrão do Podman) oHEALTHCHECKdo Dockerfile é silenciosamente ignorado — e é ele que opodman auto-updateusa pra decidir rollback. Conferir depois do build:podman inspect localhost/api-scardua:latest --format '{{json .HealthCheck}}'
⚠️ Diretórios da build antiga podem estar sem bit de escrita (
dr-x------) e travar orm -rfno meio. Se acontecer:chmod -R u+rwX ~/build/api-scardua.
O configs.json da VPS é separado
Ele não vem do repo (gitignored). Vive em ~/.config/api-scardua/configs.json
e tem que ser atualizado à mão quando o formato do Settings mudar — senão o
container entra em crash-loop na validação do Pydantic, que roda no import.
cat configs.json | ssh vps-fls 'cat > ~/.config/api-scardua/configs.json && chmod 600 $_'
Rollback
ssh vps-fls '
podman tag localhost/api-scardua:rollback-<data> localhost/api-scardua:latest
systemctl --user restart api-scardua
'
Mexer no Caddy (com segurança)
cd /srv/containers/stacks/caddy
cp Caddyfile Caddyfile.bak
# editar...
podman exec caddy caddy validate --config /etc/caddy/Caddyfile # valida ANTES
podman exec caddy caddy reload --config /etc/caddy/Caddyfile # sem downtime
Comandos úteis
systemctl --user status api-scardua
podman logs -f api-scardua
podman ps --filter name=api-scardua # estado + health
podman healthcheck run api-scardua
Verificar depois de subir
curl -s -o /dev/null -w '%{http_code}\n' https://api-scardua.flstecnologia.tech/health
curl -X POST https://api-scardua.flstecnologia.tech/v1/holmes/scardua/compras/dados \
-H 'Content-Type: application/json' -d @payload-do-holmes.json
Cliente desconhecido na rota deve dar 404 (cliente 'x' nao atendido).
Evolução planejada
- Registry + CI (Forgejo Actions): publicar em
git.flstecnologia.tech, trocar o Quadlet pro alvo comAutoUpdate=registry→ deploy pull-based. - Backup do Postgres da VPS (pendência geral do servidor).