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>
115 lines
4.3 KiB
Markdown
115 lines
4.3 KiB
Markdown
# 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 do `configs.json`, build dir, bloco do
|
||
> Caddyfile e DNS. O `reverse_proxy` do Caddy resolve o container pelo
|
||
> `ContainerName` dentro da rede `fls` — se um mudar sem o outro, dá **502**.
|
||
|
||
## Acesso à VPS
|
||
|
||
```bash
|
||
ssh vps-fls # alias -> 179.197.230.154, porta 3115, user admin
|
||
```
|
||
|
||
- Porta 22 é **fechada** no firewall. Sempre `-p 3115` (ou o alias).
|
||
- `systemctl --user` sempre (rootless) — **nunca** `sudo systemctl` pros containers.
|
||
- ⚠️ O `~/.ssh/config` tem um **BOM** na primeira linha e o OpenSSH do Git Bash
|
||
recusa (`Bad configuration option: \357\273\277host`). Contorno sem editar o
|
||
arquivo:
|
||
```bash
|
||
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.json` montado 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
|
||
|
||
```bash
|
||
# 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) o
|
||
> `HEALTHCHECK` do Dockerfile é **silenciosamente ignorado** — e é ele que o
|
||
> `podman auto-update` usa pra decidir rollback. Conferir depois do build:
|
||
> ```bash
|
||
> podman inspect localhost/api-scardua:latest --format '{{json .HealthCheck}}'
|
||
> ```
|
||
|
||
> ⚠️ Diretórios da build antiga podem estar **sem bit de escrita** (`dr-x------`)
|
||
> e travar o `rm -rf` no 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.
|
||
|
||
```bash
|
||
cat configs.json | ssh vps-fls 'cat > ~/.config/api-scardua/configs.json && chmod 600 $_'
|
||
```
|
||
|
||
## Rollback
|
||
|
||
```bash
|
||
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)
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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 com `AutoUpdate=registry` → deploy pull-based.
|
||
- Backup do Postgres da VPS (pendência geral do servidor).
|