78 lines
5.3 KiB
Markdown
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`.
|