Needed by the Fiscal's searchable client combobox (search by name/code/CNPJ). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
33 KiB
GTI Gerenciador — Discovery Técnico (v1)
Nota crítica de escopo, apurada nesta missão: "GTI Gerenciador" é o nome comercial/de produção do repositório
painel-clientes-web. Não existe um projeto separado com esse nome — confirmado com o usuário após uma busca read-only que não encontrou nenhuma pasta*gerenciador*emD:\PROJETOSnem em10.0.10.117. O sistema real é um painel de gestão de clientes/licenciamento (cadastro de clientes, funcionários, geração de chave de reativação, log de auditoria) — não um gerenciador de frota/RMM com Agents Windows, heartbeat, jobs e blockers, como o briefing da missão presumia. As seções abaixo refletem o sistema real; onde o briefing pedia algo que não existe (ex.: módulo de Agents), isso é dito explicitamente, não inventado.
1. Identidade do repositório
PROJECT_NAME=painel-clientes-web ("GTI Gerenciador" em produção)
REPOSITORY_PATH=D:\PROJETOS\BLOQUEIO SGV\painel-clientes-web
CURRENT_BRANCH=master
HEAD_COMMIT=ce718f7ac22a583fd8c5d3a23415a19dcfc31291 (2026-08-20)
WORKING_TREE_STATUS=limpo (só ../.claude/ não rastreado, fora do repo)
GIT_REMOTE=nenhum configurado — repositório só local, nunca teve push
Estrutura principal (app/):
routers/: auth, clientes, contatos, funcionarios, log, minha_conta, chave_manualdb/: clientes, contatos, funcionarios, log, chaves, connection — SQL cru via PyMySQL, sem ORMtemplates/: Jinja2 server-rendered (base.html + uma página por rota)static/: CSS puro + JS vanilla inlineauth.py,csrf.py,session.py,senha.py,rate_limit.py,n8n_client.py,gerador_chave.py,cnpj_lookup.pydocs/,docs/superpowers/specs|plans— specs e planos de cada feature (fluxo de desenvolvimento assistido por IA usado neste projeto)
Não há pasta frontend/, migrations/ (Alembic) ou deployment/ separada — é
um monólito único, com deploy manual (não há migrations/; mudanças de schema
são ALTER TABLE manuais documentadas em docstring + README).
2. Stack da aplicação
BACKEND_FRAMEWORK=FastAPI
BACKEND_LANGUAGE=Python
BACKEND_VERSION=3.12 (imagem Docker python:3.12-slim)
FRONTEND_TYPE=server-rendered
FRONTEND_FRAMEWORK=Jinja2Templates (FastAPI)
FRONTEND_BUILD_CHAIN=nenhuma (sem bundler/npm — CSS/JS estáticos escritos à mão)
DATABASE=MySQL 5.7
ORM=nenhum (PyMySQL cru, SQL parametrizado manualmente)
MIGRATION_TOOL=nenhum (ALTER TABLE manual, documentado em docstring do módulo + README.md)
CACHE=nenhum
QUEUE=nenhuma
BACKGROUND_JOBS=nenhum (tudo síncrono, request/response)
WEBSERVER=uvicorn (ASGI, standalone — sem gunicorn na frente)
APPLICATION_SERVER=uvicorn[standard]==0.30.6
Dependências (requirements.txt, todas pinadas por auditoria de segurança de
2026-08-15): fastapi==0.115.6, uvicorn[standard]==0.30.6, jinja2==3.1.6,
python-multipart==0.0.20, PyMySQL==1.1.1, python-dotenv==1.0.1,
httpx==0.27.2 (usado só para chamar a API do n8n).
Classificação: monolito único, server-rendered, sem frontend separado.
3. Funcionalidades atuais
| MODULE_NAME | PURPOSE | MAIN_ROUTES | MAIN_TABLES | DEPENDENCIES |
|---|---|---|---|---|
| Clientes | CRUD de clientes (CNPJ, contato, status ativo/inativo) | /clientes, /clientes/{id}, /clientes/{id}/alternar-ativo |
CLIENTE |
cnpj_lookup.py (consulta CNPJ externa) |
| Contatos | Contatos por cliente (nome/telefone/e-mail) | rotas aninhadas sob /clientes/{id} |
CLIENTE_CONTATO |
— |
| Funcionários | Usuários do painel (login/senha/perfil ADMIN|PADRAO) | /funcionarios |
FUNCIONARIO_PAINEL |
senha.py (scrypt) |
| Gerador de chave | Gera chave de reativação/liberação (cifra própria) | /gerador-chave, /gerador-chave/gerar |
— (sem persistência própria) | gerador_chave.py |
| Log | Auditoria de ações do painel + espelho de envios automáticos do n8n | /log, /log/limpar (admin) |
LOG_PAINEL |
n8n_client.py (lê Data Table do n8n via API, não escreve) |
| Autenticação | Login humano (admin de ambiente + funcionários) | /login, /logout |
FUNCIONARIO_PAINEL + ADMIN_USER/ADMIN_PASSWORD (env) |
session.py, csrf.py |
| Minha conta | Trocar a própria senha | /minha-conta |
FUNCIONARIO_PAINEL |
— |
Não existe: módulo de servidores, agentes, backups, monitoramento, inventário ou "integrações" no sentido do briefing original — o sistema é puramente sobre clientes/licenciamento, não sobre gestão de infraestrutura de terceiros.
4. Autenticação e autorização
AUTH_MODEL=cookie de sessão assinado por HMAC-SHA256 (chave própria em session.py,
não é JWT de biblioteca) + cookie CSRF de double-submit
USER_TABLE=FUNCIONARIO_PAINEL (login, hash de senha, PERFIL)
ROLE_MODEL=dois perfis fixos: ADMIN e PADRAO (sem granularidade por permissão)
PERMISSION_MODEL=checagem direta de perfil nas rotas (Depends(exigir_admin) vs
Depends(exigir_login)) — não é RBAC configurável
- Existe também um login "raiz" fora da tabela: usuário/senha vindos de
ADMIN_USER/ADMIN_PASSWORD(variáveis de ambiente), comparação direta — serve de acesso de emergência independente do banco. - Senha de funcionário:
scrypt(stdlib do Python, sem bcrypt/argon2/passlib). - Sessão: HMAC-SHA256 sobre payload com
login,nome,perfil,exp— validade de 12 horas, sem refresh automático (expira, força novo login). - CSRF: cookie
csrf_token(HttpOnly) + campo hidden em todo formulário POST, comparados no servidor (double-submit). - Logout: limpa cookie de sessão.
Reuso por GTI Fiscal: o modelo de sessão (HMAC próprio) é simples e
replicável, mas está fortemente amarrado a este processo Python específico
(chave HMAC em memória do processo/env, sem endpoint de validação exposto
para outro serviço consumir). Reuso real exigiria extrair isso para um
serviço de auth compartilhado ou aceitar duplicar a lógica — não há hoje um
"SSO" ou endpoint /auth/validar pronto para outro backend chamar.
5. Banco de dados
DB_ENGINE=MySQL
DB_VERSION=5.7 (imagem Docker mysql:5.7)
DB_HOST_MODEL=container único (gtisoftw-mysql), sem replicação/cluster
DB_NAME=gtisoftw_clientes_dev (nome de dev usado também em produção — dívida
histórica de nomenclatura, não um ambiente de teste real)
MIGRATION_HEAD=n/a (sem Alembic/ferramenta — ALTER TABLE manual documentado)
Tabelas principais conhecidas: CLIENTE, CLIENTE_CONTATO,
FUNCIONARIO_PAINEL, LOG_PAINEL (+ tabelas do sistema legado
licenciamento-n8n que compartilham o mesmo banco, fora do escopo direto do
painel). Total de ~9 tabelas segundo o dump de referência mais recente
(Banco para Prod/README-DEPLOY-PROXMOX.md).
- Volume de dados: pequeno — ~209 clientes, 127 contatos (dump de referência).
- Pool/connections: sem pool —
PyMySQLabre e fecha conexão por request (get_connection()/conn.close()a cada operação), aceitável no volume atual mas não escalaria bem sob concorrência alta. - Backup: não encontrei rotina de backup automatizada no servidor (sem
cron de dump, sem script de backup do container) — só existe o
procedimento manual documentado em
Banco para Prod/README-DEPLOY-PROXMOX.mdpara popular/restaurar a partir de um dump. - Persistência: volume Docker nomeado (
gtisoftw_mysql_data, implícito pelo compose deBanco para Prod/), não bind-mount.
CAN_GTI_FISCAL_SHARE_DATABASE=requires_analysis
| Opção | Vantagens | Riscos |
|---|---|---|
| A) Mesmo PostgreSQL, schemas separados | Simples de administrar (1 backup, 1 instância), sem novo processo de banco | GTI Fiscal quer PostgreSQL, este ambiente só roda MySQL 5.7 — não é "mesmo Postgres", seria instalar um segundo motor de banco do zero |
| B) Bancos lógicos separados no mesmo motor | N/A aqui pelo mesmo motivo acima | — |
| C) PostgreSQL separado no mesmo host | Cada stack usa o motor que já foi desenhado para ela, sem gambiarra de schema | Mais um processo residente numa VM que já está com RAM apertada (ver §22) |
Dado que GTI Fiscal foi desenhado para PostgreSQL e este ambiente só tem MySQL, a opção realista é C) PostgreSQL próprio no mesmo host (se houver recursos — ver §22) — não há cenário realista de "compartilhar" o banco atual entre os dois sistemas.
6. Ambiente de execução
HOSTNAME=srvbd
OS=Ubuntu 24.04.4 LTS
KERNEL=Linux 6.8.0-137-generic
VIRTUALIZATION_VISIBLE=kvm (systemd-detect-virt)
CONTAINER_OR_VM=VM (QEMU/KVM — "Standard PC (i440FX + PIIX, 1996)", vendor QEMU)
Confirmado como VM dentro de um host Proxmox: a pasta local
Banco para Prod/README-DEPLOY-PROXMOX.md (deste mesmo repositório) documenta
explicitamente o processo de deploy do banco "na VM/LXC do Proxmox" — este
servidor (10.0.10.117) é essa VM.
CPU_CORES=2
RAM_TOTAL=1.9 GiB
RAM_AVAILABLE=~1.2 GiB (742 MiB em uso, 1.0 GiB em buff/cache)
DISK_TOTAL=8.1 GiB (partição raiz)
DISK_FREE=1.4 GiB (82% em uso)
LOAD=0.08, 0.02, 0.01 (ociosa)
UPTIME=36 dias
Só leitura — nenhum comando de escrita executado.
7. Docker / containers
DOCKER_VERSION=29.7.2
COMPOSE_VERSION=v5.4.0
| NAME | IMAGE | STATUS | PORTS | NETWORKS |
|---|---|---|---|---|
painel-clientes-web-painel-1 |
painel-clientes-web-painel (build local) |
Up 4 semanas | 0.0.0.0:80->8000/tcp |
default + bancoparaprod_default (externa) |
gtisoftw-mysql |
mysql:5.7 |
Up 5 semanas | 0.0.0.0:3306->3306/tcp |
bancoparaprod_default (dedução — mesmo network externo usado pelo painel) |
docker-compose.yml do painel (em /home/administrador/painel-clientes-web/):
services:
painel:
build: .
ports: ["80:8000"]
env_file: [.env]
networks: [default, bancoparaprod_default]
restart: unless-stopped
networks:
bancoparaprod_default:
external: true
O container do MySQL vem de um compose separado (Banco para Prod/,
network bancoparaprod_default criada por ele, consumida como externa pelo
painel) — os dois projetos/composes são independentes, unidos só pela network
Docker compartilhada. Sem healthcheck explícito em nenhum dos dois serviços.
8. Recursos usados atualmente
painel-clientes-web-painel-1: CPU 0.12% RAM 78.8 MiB
gtisoftw-mysql: CPU 0.07% RAM 199.4 MiB
CURRENT_RESOURCE_PRESSURE=baixa em CPU (2 vCPU quase ociosos); MODERADA em RAM
(só a folga não-cache é ~200-400MiB reais depois
de reservar o que o SO/buffers já usam) e ALTA em
disco (82% da partição raiz de 8GB já ocupado)
HEADROOM_ESTIMATE=CPU: folgado. RAM: ~1.2GiB "available" reportado pelo
kernel, mas isso conta cache reclamável — para uma
segunda aplicação Python + segundo banco (Postgres) a
margem real é apertada, não confortável. Disco: crítico
— só 1.4GiB livres, qualquer novo serviço com imagem
Docker própria (Postgres + Hub FastAPI) provavelmente
não cabe sem aumentar o disco da VM antes.
9. Portas e rede
| SERVICE | LISTEN_ADDRESS | PORT | EXPOSED_EXTERNALLY | PURPOSE |
|---|---|---|---|---|
| painel-clientes-web (uvicorn) | 0.0.0.0 | 80 | sim (direto, sem proxy na frente) | HTTP da aplicação |
| MySQL | 0.0.0.0 | 3306 | sim | Banco relacional |
| SSH | 0.0.0.0 | 22 | sim | Administração |
| systemd-resolved | 127.0.0.53/127.0.0.54 | 53 | não | DNS local |
Nenhuma porta foi aberta ou alterada — apenas listadas via ss -tlnp.
10. Acesso web
CURRENT_URL=http://10.0.10.117/ (IP direto, porta 80)
DOMAIN=nenhum domínio público configurado
HTTPS=não (confirma pendência já registrada na auditoria de segurança de
2026-08-15: "falta de TLS em produção é pendência aceita
conscientemente")
TLS_PROVIDER=n/a
Fluxo real: Internet/rede interna → 10.0.10.117:80 → uvicorn (direto). Não
há DNS/Cloudflare nem qualquer camada intermediária.
11. Reverse proxy
REVERSE_PROXY_TYPE=NENHUM instalado (nginx/caddy/traefik ausentes no host)
REVERSE_PROXY_LOCATION=n/a
TLS_TERMINATION=n/a
PROXY_TARGET=n/a
Isso é uma lacuna relevante para a integração: hoje não existe onde
configurar /fiscal ou fiscal.dominio — seria preciso instalar um reverse
proxy do zero (Caddy é o mais barato em RAM para esta VM apertada) antes de
sequer cogitar rotear dois serviços por hostname/porta 80/443 únicos.
12. Firewall e exposição
PUBLICLY_EXPOSED_PORTS=22 (SSH), 80 (aplicação), 3306 (MySQL)
MySQL está exposto publicamente (0.0.0.0:3306), não só em loopback/rede
interna — isso já era uma pendência independente desta missão, mas relevante
para decidir se um segundo banco (Postgres do GTI Fiscal) repete o mesmo
padrão ou é mantido só em rede interna Docker. Não alterei nenhuma regra.
13. Backup
BACKUP_STATUS=inexistente como rotina automatizada
RESTORE_PROCEDURE=manual, documentado (Banco para Prod/README-DEPLOY-PROXMOX.md)
— restaura a partir de dump SQL versionado no repo local,
não a partir de um backup do estado de produção atual
LAST_BACKUP_IF_VISIBLE=não há evidência de nenhum backup de produção
rodado — dumps encontrados localmente são snapshots
pontuais feitos manualmente (ex.:
dump-gtisoftw_clientes_dev-20260806_104136.sql)
14. Logs / observabilidade
LOGGING_MODEL=stdout do container (docker logs), mais LOG_PAINEL (tabela de
auditoria de ações do painel, não logs técnicos)
MONITORING_MODEL=nenhum (sem Prometheus/Grafana/Loki/Zabbix — nada instalado
no host além do sysstat padrão do Ubuntu)
Eventos do GTI Fiscal (heartbeat, jobs, blockers) não têm onde se integrar hoje — não existe stack de observabilidade centralizada nesta VM para "encaixar" nele.
15. Serviços do sistema
systemd: só serviços padrão do Ubuntu + Docker daemon. Nenhum serviço systemd customizado para o painel (ele roda viarestart: unless-stoppeddo próprio Docker, não via unit systemd).cron: só as entradas padrão do Ubuntu (cron.hourly/daily/weekly/monthlyvia anacron) — nenhum job customizado do projeto.- Sem Windows services (host é Linux).
16. Deploy atual
DEPLOY_PROCEDURE=manual, via script Python ad-hoc (paramiko/SFTP) rodado pelo
desenvolvedor: empacota o repo local em .tar.gz (excluindo
docker-compose.yml e .env de produção), sobe por SFTP,
extrai por cima do diretório existente na VM, roda
"docker compose build" (com retry manual em caso de timeout
do registro Docker Hub) e "docker compose up -d". Migração
de schema (quando há) é um ALTER TABLE manual rodado à parte,
documentado no docstring do módulo Python afetado.
ROLLBACK_PROCEDURE=NÃO documentado/automatizado — não há tag de imagem
anterior preservada nem processo de reverter; reverter
exigiria checkout de um commit anterior local e repetir
o deploy manual.
Não há CI/CD, GitHub Actions, ou pipeline — é 100% manual, disparado por uma pessoa a cada mudança.
17. Estrutura do frontend
- Layout:
app/templates/base.html— sidebar fixa com navegação (ícones SVG inline), área de conteúdo à direita, tema claro/escuro vialocalStorage+ atributodata-temano<html>. - Templates: um arquivo Jinja2 por página, todos estendendo
base.htmlvia{% block conteudo %}. Sem componentização (sem includes/macros reutilizáveis além do layout base). - CSS: um único
app/static/estilo.css, variáveis CSS para cores (tema claro/escuro), sem framework (sem Tailwind/Bootstrap). - Identidade visual: logo GTI (
logo-gti-256x256.png), paleta escura por padrão com acento laranja — a UI já é rotulada "GTI" na sidebar ("Painel de Clientes"). - Auth nos templates:
request.state.usuario(setado por middleware) controla o que aparece na sidebar (ex.: "Funcionários" só para admin).
CAN_ADD_FISCAL_MENU=sim, tecnicamente simples — é só adicionar um <a> na
sidebar de base.html com a mesma checagem de
request.state.usuario.eh_admin, IF o Fiscal virar rota
deste mesmo processo FastAPI (Opção A da seção 20)
CAN_REUSE_LAYOUT=sim, mas exigiria portar o CSS de tema claro/escuro e a
sidebar para dentro do stack do GTI Fiscal (que hoje
também é Jinja2 — compatível em princípio) SE a integração
for Opção C (backend separado, UI incorporada)
CAN_REUSE_AUTH=parcialmente — ver §4: o modelo é simples de replicar/portar,
mas não existe hoje um serviço de auth desacoplado para
"importar" sem duplicar código
18. APIs e integrações
Inventário de rotas por módulo (ver §3). Não há uma "API" no sentido REST
externo — todas as rotas retornam HTML (exceto /gerador-chave/gerar, que
retorna JSON, chamado via fetch() do próprio frontend do painel). Não há
autenticação por token/Bearer em lugar nenhum — só cookie de sessão.
Integração externa existente: app/n8n_client.py — chama a API REST de uma
instância n8n (N8N_API_URL/N8N_API_KEY via env) para ler (não
escrever) uma Data Table de envios automáticos de chave, exibida em /log.
É a única integração "tipo API" que este sistema tem.
Não existe conceito de client/server/installation/agent no
sentido do GTI Fiscal — o mais próximo é CLIENTE (empresa/licenciada), que
é uma entidade de negócio/cobrança, não de infraestrutura técnica (não
tem hostname, IP, SO, ou qualquer atributo de "servidor monitorado").
19. Modelo de cliente/servidor
CLIENTE = empresa licenciada (CODIGO, RAZAO, FANTASIA, CNPJ, ATIVO,
DIA_VENCIMENTO) — chave primária ID (int), CODIGO é o
identificador de negócio usado no gerador de chave
CLIENTE_CONTATO = contatos humanos daquele cliente (nome/telefone/e-mail),
FK CLIENTE_ID
Não existem EMPRESA (é o mesmo que CLIENTE), SERVIDOR, INSTALAÇÃO,
nem AGENT neste sistema.
Comparando com o GTI Fiscal (tenant/client, installation_id, agent_id,
hostname, contexto de empresa): a única sobreposição conceitual real é
cliente/empresa — CLIENTE.CNPJ poderia, em teoria, ser a chave de
correlação entre "quem é o cliente" nos dois sistemas (mesmo CNPJ = mesma
empresa), mas isso exigiria um design explícito de correlação (ex.: o Fiscal
guardar o CLIENTE_ID ou CODIGO deste sistema como referência externa) —
não existe isso hoje, seria trabalho novo de integração, não algo pronto
para reaproveitar.
20. Possível integração do GTI Fiscal
Opção A — Mesmo processo/aplicação (GTI Fiscal como módulo interno do FastAPI existente): exigiria portar o Fiscal de FastAPI+PostgreSQL+Alembic próprios para dentro deste monolito Python+MySQL+SQL-cru — descartaria a stack já pronta do Fiscal (Postgres, migrations, auth de Agent via Bearer). Alto retrabalho, alto acoplamento, alto risco de regressão no painel de clientes hoje estável. Não recomendado.
Opção B — Serviço separado na mesma máquina (dois processos FastAPI independentes, dois bancos, roteados por porta ou subdomínio): mais fiel à arquitetura já pronta do Fiscal (Postgres, migrations Alembic, auth de Agent por Bearer token — nada disso precisa mudar). Exige: instalar PostgreSQL nesta VM, instalar um reverse proxy (inexistente hoje — §11), e — dado o disco em 82% de uso (§22) — provavelmente aumentar o disco da VM antes.
Opção C — Backend Fiscal separado + UI incorporada no Gerenciador: o Fiscal mantém seu backend/API de Agents isolado (bom para segurança — Agents externos batendo Bearer token não precisam tocar no mesmo processo do painel), mas a tela humana ("Resumo", "Agents/Servidores", "Blockers", "Jobs") é servida a partir do processo do painel, chamando o backend do Fiscal internamente (rede Docker) e renderizando com o mesmo layout Jinja2 já existente (§17). Combina isolamento de falha (Fiscal fora do ar não derruba o painel de clientes) com a experiência visual unificada que o usuário quer.
21. Recomendação
Opção B para o backend (times/dados isolados) combinada com a fachada de UI da Opção C, na prática: dois processos FastAPI + dois bancos (MySQL do painel, PostgreSQL do Fiscal) na mesma VM/rede Docker, sem misturar código Python nem schemas — e, quando fizer sentido visualmente, o painel ganha um item de menu "Fiscal" que ou (a) faz proxy/iframe para o serviço do Fiscal rodando noutra porta/subpath via reverse proxy, ou (b) mais elegante: o próprio Hub FastAPI do Fiscal serve suas páginas Jinja2 reaproveitando o CSS do painel (arquivo estático compartilhado ou copiado), ficando visualmente idêntico sem juntar os dois processos.
Critérios que pesaram:
- Baixa manutenção / isolamento de falhas: times/schemas separados evitam que um bug do Fiscal (ex.: processamento de 500k produtos) afete o painel de clientes em produção, que hoje é estável.
- Segurança: Agents Windows externos autenticam via Bearer contra o backend do Fiscal — não faz sentido esse tráfego externo passar pelo mesmo processo/sessão-cookie do painel administrativo interno.
- Reaproveitamento real disponível: só a máquina (VM), a rede Docker e, superficialmente, o CSS/layout são reaproveitáveis hoje — banco, auth e modelo de dados não são, então forçar Opção A jogaria fora o trabalho já feito na stack do Fiscal sem ganho real.
- Pré-requisito bloqueante: nada disso cabe sem antes resolver o disco (82% cheio) e decidir sobre reverse proxy — ver §22-23.
22. Capacidade da máquina
CAN_HOST_GTI_FISCAL_ON_SAME_MACHINE=false, no estado atual da VM (sem
aumentar disco/RAM primeiro)
Considerando a carga alvo do briefing (Hub FastAPI + PostgreSQL + 100 Agents iniciais + 500k produtos + event logs + blockers + jobs) contra o que esta VM tem hoje:
- CPU: 2 vCPU, carga atual quase zero — folga real, não é o gargalo.
- RAM: 1.9GiB total, dos quais ~940MiB já em uso por SO+containers
atuais. PostgreSQL sozinho, com um volume de 500k produtos + índices, tende
a querer bem mais que a folga restante para não sofrer com cache pequeno
(
shared_buffers/effective_cache_sizeficariam artificialmente baixos). 100 Agents com heartbeat periódico é tráfego leve por si, mas soma-se ao processo do Hub. Risco real de troca/swap sob carga. - Disco: 8.1GiB total, 1.4GiB livres (82% usado). Uma imagem PostgreSQL + o próprio volume de dados (500k produtos, mesmo que compactos, mais índices, mais WAL) muito provavelmente não cabe nesse espaço livre atual, ainda mais somado à imagem Docker do Hub FastAPI. Este é o gargalo mais crítico e imediato, antes mesmo de RAM.
NEEDS_PROXMOX_RESOURCE_INFO=true
O que falta, especificamente (só visível a partir do host Proxmox, não de dentro da VM):
- Quanto de CPU/RAM/disco físico está livre no host Proxmox para aumentar
esta VM (ou criar uma segunda) — de dentro da VM não dá pra saber se o
host tem folga para um
pvesm resize/qm resizedo disco de 8→20GB+, por exemplo. - Política de backup/snapshot do Proxmox para esta VM (indiretamente relevante para §13 — se o Proxmox já faz snapshot no nível de hypervisor, isso muda a análise de "backup inexistente").
- Se há outras VMs/LXCs no mesmo host Proxmox concorrendo pelos mesmos recursos físicos (I/O de disco compartilhado principalmente).
23. Conflitos potenciais
PORT_CONFLICTS=nenhum imediato — Fiscal pode usar outra porta (8001, por
exemplo); porta 80 já está tomada pelo painel
DATABASE_CONFLICTS=nenhum — motores diferentes (MySQL vs PostgreSQL) não
colidem, mas cada um consome memória/disco próprios
NETWORK_CONFLICTS=nenhum — network Docker externa (bancoparaprod_default)
pode ser reaproveitada ou uma nova criada, sem colisão
DOMAIN_CONFLICTS=n/a — não há domínio configurado hoje para nenhum dos dois
DEPENDENCY_CONFLICTS=nenhum a nível de processo (processos Python isolados
em containers separados não compartilham
dependências) — mas concorrem por RAM/disco da
mesma VM (ver §22)
AUTH_CONFLICTS=nenhum tecnicamente (mecanismos diferentes, cookie de sessão
vs Bearer de Agent, não colidem) — mas também não se somam:
um usuário logado no painel não fica "logado" automaticamente
no Fiscal sem um esforço explícito de integração de auth
24. O que pode ser reutilizado
REUSABLE_COMPONENTS=
- Máquina/VM (10.0.10.117) — há folga de CPU, mas não de disco (ver §22)
- Rede Docker (bancoparaprod_default ou nova network dedicada)
- CSS/identidade visual (app/static/estilo.css + logo GTI) — copiável para
o Fiscal se ele também for Jinja2
- Padrão de deploy manual via SFTP/docker compose (mesmo processo humano já
usado, sem precisar inventar um novo fluxo de deploy)
- Conceito de correlação por CNPJ entre CLIENTE (aqui) e tenant/client (lá),
SE for desenhado explicitamente — não existe pronto
25. O que deve ficar separado
SHOULD_REMAIN_ISOLATED=
- Banco de dados (MySQL do painel vs PostgreSQL do Fiscal — motores
diferentes, sem cenário real de compartilhar)
- Autenticação de Agent (Bearer token) — não deve passar pelo mesmo
middleware de sessão-cookie do painel administrativo
- Migrations (Alembic do Fiscal vs ALTER TABLE manual do painel — misturar
processos de schema é fonte garantida de erro operacional)
- Processo do Hub FastAPI do Fiscal — mantê-lo como processo próprio
(Opção B/C) preserva o isolamento de falha que o painel de clientes tem
hoje (37 dias de uptime sem intervenção)
26. Segurança
Achados relevantes (todos já visíveis publicamente ou já documentados em auditoria anterior deste mesmo projeto — nada novo exposto aqui):
- MySQL exposto publicamente na porta 3306 (
0.0.0.0), não restrito a rede interna/loopback — ver §12. - Sem TLS/HTTPS em produção — tráfego HTTP puro na porta 80, incluindo login (pendência já registrada conscientemente em memória de projeto anterior — não uma novidade desta auditoria).
.envde produção existe e não foi lido (só variáveis específicas necessárias, viagreppontual, nunca o arquivo inteiro) — nenhuma senha, token ou secret aparece neste relatório.- Auth de funcionário usa
scrypt(adequado); auth "raiz" viaADMIN_USER/ADMIN_PASSWORDem variável de ambiente, comparação direta (sem hashing) — aceitável para uma única conta de emergência, mas vale nota para quem for desenhar auth compartilhada com o Fiscal. - Nenhuma correção foi feita — só relatado, como pedido.
27. Artefato
Este arquivo: docs/GTI_GERENCIADOR_DISCOVERY_V1.md, dentro do repositório
painel-clientes-web. Não commitado — a missão pediu regime read-only;
o arquivo fica no working tree local para o usuário revisar e decidir se
versiona.
28. Confirmação — nada foi alterado
Nenhum código, banco, container, proxy, firewall ou configuração foi
modificado nesta missão. Todos os comandos no servidor foram de leitura
(hostnamectl, uptime, free, df, docker ps, docker stats, ss,
systemctl list-units, find, ls, cat de arquivos não sensíveis,
crontab -l). A única tentativa que exigiria credencial adicional (contar
tabelas via mysql -uroot) falhou por falta de acesso e não foi insistida.
Relatório final (resumo estruturado)
STATUS=discovery concluído, read-only, nenhuma alteração feita
PROJECT_NAME=painel-clientes-web ("GTI Gerenciador" é o nome comercial —
confirmado com o usuário, não é um projeto separado)
REPOSITORY_PATH=D:\PROJETOS\BLOQUEIO SGV\painel-clientes-web
BRANCH=master
HEAD=ce718f7ac22a583fd8c5d3a23415a19dcfc31291
WORKTREE=limpo
BACKEND=FastAPI (Python 3.12) + PyMySQL, sem ORM
FRONTEND=Jinja2 server-rendered, sem build chain
DATABASE=MySQL 5.7 (gtisoftw_clientes_dev), sem migrations formais
AUTH_MODEL=cookie de sessão HMAC-SHA256 próprio (12h) + CSRF double-submit;
login de funcionário (FUNCIONARIO_PAINEL, scrypt) + login raiz
via env
HOSTNAME=srvbd
OS=Ubuntu 24.04.4 LTS
VIRTUALIZATION=KVM (VM dentro de Proxmox, confirmado por doc local do projeto)
CPU=2 vCPU (ocioso)
RAM=1.9GiB total (~940MiB em uso)
DISK_FREE=1.4GiB de 8.1GiB (82% usado — CRÍTICO)
DOCKER=29.7.2 / Compose v5.4.0
CONTAINERS=painel-clientes-web-painel-1 (up 4 semanas), gtisoftw-mysql (up 5 semanas)
CURRENT_URL=http://10.0.10.117/ (IP direto, sem domínio)
DOMAIN=nenhum
HTTPS=não
REVERSE_PROXY=nenhum instalado
PUBLIC_PORTS=22 (SSH), 80 (app), 3306 (MySQL — exposto publicamente)
BACKUP=inexistente como rotina automatizada; só restore manual documentado
MONITORING=inexistente (sem Prometheus/Grafana/Loki)
CLIENT_MODEL=CLIENTE (empresa licenciada, negócio/cobrança) — sem conceito
de servidor/instalação/agente técnico
SERVER_MODEL=não existe
AGENT_MODEL=não existe
CAN_REUSE_AUTH=parcial (modelo simples, mas não desacoplado/exposto para
outro serviço consumir sem duplicar código)
CAN_REUSE_CLIENT_MODEL=parcial (CNPJ como chave de correlação possível,
exigiria design novo de integração)
CAN_REUSE_SERVER_MODEL=n/a (não existe)
CAN_REUSE_LAYOUT=sim (CSS/Jinja2 portável se o Fiscal também for Jinja2)
CAN_HOST_GTI_FISCAL_ON_SAME_MACHINE=false no estado atual (disco em 82%,
RAM apertada) — viável DEPOIS de
aumentar disco (e provavelmente RAM)
da VM
NEEDS_PROXMOX_RESOURCE_INFO=true (capacidade física do host Proxmox para
redimensionar esta VM; política de
backup/snapshot no nível de hypervisor; outras
VMs concorrendo pelo mesmo host)
RECOMMENDED_INTEGRATION_MODE=B (backend separado, mesma VM/rede Docker) +
fachada visual estilo C (menu "Fiscal" no
painel, reaproveitando layout/CSS)
RECOMMENDATION_REASON=isolamento de falha e de auth (Agents Bearer não devem
passar pelo processo/sessão do painel), motores de
banco incompatíveis (MySQL vs Postgres) inviabilizam
Opção A, e só máquina+rede+CSS são reaproveitáveis de
verdade hoje
PORT_CONFLICTS=nenhum
DATABASE_CONFLICTS=nenhum (motores diferentes)
AUTH_CONFLICTS=nenhum tecnicamente, mas também nenhuma integração pronta
REUSABLE_COMPONENTS=VM/rede Docker, CSS/identidade visual, processo de
deploy manual já estabelecido
SHOULD_REMAIN_ISOLATED=banco de dados, auth de Agent, migrations, processo
do Hub FastAPI do Fiscal
GTI_FISCAL_INTEGRATION_PREREQUISITES=
1. Aumentar disco da VM (crítico — 82% usado hoje, não cabe Postgres+dados)
2. Confirmar/aumentar RAM disponível junto ao Proxmox
3. Instalar reverse proxy (Caddy é o mais leve) — hoje não existe nenhum
4. Decidir domínio/subdomínio (nenhum configurado hoje)
5. Desenhar (não implementar ainda) a correlação CLIENTE.CNPJ ↔ tenant do
Fiscal, se a intenção for cruzar dados de cliente entre os dois sistemas
6. Resolver a exposição pública do MySQL (3306) antes de repetir o padrão
com um segundo banco
RISKS=
- Disco cheio (82%) é bloqueante técnico imediato, não é só "atenção"
- MySQL público na 3306 é uma exposição já existente, independente desta
missão, mas relevante para não repetir o padrão
- Sem backup automatizado hoje — somar um segundo banco sem resolver isso
primeiro dobra a superfície de risco de perda de dados
- Sem TLS — Agents do Fiscal batendo HTTPS externo precisarão de reverse
proxy com certificado, que hoje não existe nesta VM
NEXT_STEP=levantar capacidade real do host Proxmox (item bloqueante
NEEDS_PROXMOX_RESOURCE_INFO) e decidir se a VM atual cresce ou se
uma segunda VM é criada especificamente para o Fiscal — só depois
disso faz sentido detalhar a Opção B/C escolhida em um plano de
implementação
VERDICT=Integração é viável e recomendável na forma B+C (backend separado,
UI visualmente unificada), mas NÃO deve começar antes de resolver
disco/RAM da VM e decidir sobre reverse proxy — do contrário, o
Fiscal nasce competindo por recursos com um painel de clientes que
hoje está estável e em produção real.