Files
GTI_GERENCIADOR_FISCAL/README.md
T

78 lines
5.3 KiB
Markdown

# painel-clientes-web
Painel administrativo (FastAPI + Jinja2) para gestão de `CLIENTE`, `CLIENTE_CONTATO` e geração manual de chave de licenciamento no MySQL do sistema legado.
Proteções: login por sessão em toda rota (cookie assinado — ver seção "Login e permissões" abaixo), CSRF via cookie de duplo envio (`app/csrf.py` — todo formulário que muda estado embute o mesmo token do cookie `csrf_token`, definido pelo middleware em `app/main.py`) e a lista de clientes é paginada (100 por página), com busca e ordenação por código/razão/fantasia/CNPJ.
`CODIGO` de cliente não aceita duplicado (bloqueio duro, sem bypass) e o formulário de novo cliente já sugere o próximo código sequencial (editável). Só `CODIGO`, `CNPJ`, `RAZAO` e `FANTASIA` são obrigatórios — os campos de contrato (implantação, mensalidade, juros, datas) podem ficar em branco e recebem default (0,00 / data de hoje).
`CLIENTE` tem uma coluna `ATIVO` (criada no banco de dev — **precisa ser criada manualmente em produção também**, `ALTER TABLE` completo no início de `app/db/clientes.py`) que controla o filtro de status da listagem (Ativos/Inativos/Todos, padrão Ativos). Sem essa coluna, a listagem quebra com erro 500. O `DEFAULT 1` do `ALTER TABLE` é intencional: todo cliente cadastrado antes da migração nasce como Ativo.
A rota `/log` mostra o histórico de ações do painel (tabela `LOG_PAINEL`, criada no banco de dev — **precisa ser criada manualmente em produção também**, DDL no início de `app/db/log.py`) e, se `N8N_API_URL`/`N8N_API_KEY` estiverem configuradas (`.env.example`), os últimos envios automáticos de chave via WhatsApp (lidos da Data Table `pagamentos_processados` do n8n, somente leitura).
## Login e permissões
O painel usa login por sessão (cookie assinado, `app/session.py`) — não é
mais HTTP Basic Auth. Defina `SESSION_SECRET` no `.env` (`.env.example`
tem o exemplo); sem isso, uma chave é gerada em memória a cada start do
processo, o que derruba todas as sessões ativas a cada restart (funciona,
só incomoda).
Cada funcionário (`FUNCIONARIO_PAINEL`, criada no banco de dev — **precisa
ser criada manualmente em produção também**, DDL no início de
`app/db/funcionarios.py`) tem um perfil: **admin** (gerencia outros
funcionários em `/funcionarios`: cadastra, edita, redefine senha,
ativa/desativa, promove/rebaixa perfil) ou **padrão** (sem acesso a
`/funcionarios`). Se `FUNCIONARIO_PAINEL` já existir de uma instalação
anterior sem a coluna `PERFIL`, rode o `ALTER TABLE FUNCIONARIO_PAINEL ADD
COLUMN PERFIL ...` (DDL completo em `app/db/funcionarios.py`) — **precisa
ser rodado manualmente em produção também**; sem essa coluna, todo login
falha com erro 500 (a query de autenticação seleciona `PERFIL`, que não
existe na tabela antiga). O `DEFAULT 'ADMIN'` desse `ALTER TABLE` é
intencional: todo funcionário cadastrado antes da migração vira admin
automaticamente. O sistema nunca deixa ficar sem nenhum admin ativo —
rebaixar ou desativar o último admin é bloqueado.
Qualquer usuário logado troca a própria senha em **Minha conta**
(`/minha-conta`), pedindo a senha atual antes de trocar.
`ADMIN_USER`/`ADMIN_PASSWORD` (`.env.example`) continuam funcionando como
conta de bootstrap, sempre com perfil admin — é com ela que você entra a
primeira vez para cadastrar o primeiro funcionário, e serve de plano B se
a tabela ficar vazia. Login checa primeiro o admin do `.env`, depois
`FUNCIONARIO_PAINEL` (só contas com `ATIVO=1`).
## Rodando localmente (sem Docker)
1. Instale as dependências de desenvolvimento:
```
pip install -r requirements-dev.txt
```
2. Defina as variáveis de ambiente necessárias (`ADMIN_USER`, `ADMIN_PASSWORD`, `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `SESSION_SECRET` — veja `.env.example`) diretamente no shell antes de subir a aplicação. `SESSION_SECRET` é opcional em dev — sem ela, uma chave aleatória é gerada em memória a cada start (sessões caem a cada restart); defina um valor fixo em produção. **Importante:** apesar de `python-dotenv` estar nas dependências, nada no código chama `load_dotenv()` hoje — um arquivo `.env` sozinho NÃO é lido automaticamente fora do Docker. Exporte as variáveis manualmente (ex.: `set -a; source .env; set +a` no bash, ou `$env:...` no PowerShell) ou defina-as por outro meio.
3. Rode a aplicação:
```
uvicorn app.main:app --reload
```
4. Rodando direto na máquina (fora de container), use `DB_HOST=127.0.0.1` (porta `3307`, a mesma do container de dev `licenciamento-mysql-dev`).
## Rodando os testes
```
pytest -v
```
Os testes usam defaults definidos em `tests/conftest.py` (equivalentes ao `.env.example`) e incluem testes de integração que precisam do container MySQL de dev (`licenciamento-mysql-dev`, `127.0.0.1:3307`) rodando.
## Rodando via Docker
1. Copie o arquivo de exemplo de variáveis de ambiente e edite `ADMIN_PASSWORD` (e demais valores, se necessário):
```
cp .env.example .env
```
2. Suba o container:
```
docker compose up -d --build
```
O `docker-compose.yml` já usa `env_file: .env` e mapeia `host.docker.internal` para o host (via `extra_hosts`), então o valor padrão `DB_HOST=host.docker.internal` do `.env.example` funciona também em hosts Docker Linux, não só no Docker Desktop (Windows/Mac).
3. A aplicação fica disponível em `http://localhost:8010`.