APvenda é um sistema em desenvolvimento para controle de produtos, marcas e categorias, com evolução prevista para operação de PDV, incluindo abertura e fechamento de caixa e registro de vendas.
Este README registra o contexto específico do produto. Padrões técnicos, stack compartilhada e orientações detalhadas para IA ficam em .specs/.
O objetivo inicial do APvenda é manter uma base organizada de cadastros para apoiar a operação futura de venda presencial.
Nesta fase, o sistema prioriza:
- produtos;
- marcas;
- categorias de produtos.
Esses cadastros devem preparar a base para etapas posteriores de PDV, em que o sistema passará a registrar caixa, vendas, itens vendidos e movimentações financeiras.
- Cadastro e manutenção de produtos.
- Cadastro e manutenção de marcas.
- Cadastro e manutenção de categorias.
- Estrutura técnica inicial para evolução dos módulos de PDV.
- Abertura e fechamento de caixa.
- Registro de vendas.
- Controle dos itens vendidos.
- Movimentações de caixa.
- Relatórios operacionais básicos.
Entidades centrais desta fase:
Produto: item comercializado no PDV.Marca: fabricante, linha ou identificação comercial associada ao produto.Categoria: classificação usada para organizar produtos.
Entidades previstas para as próximas fases:
Caixa: sessão operacional de caixa.Venda: registro principal de uma venda realizada.ItemVenda: item vinculado a uma venda.Receber: registro financeiro (conta a receber) vinculado a uma venda.MovimentoCaixa: entrada, saída ou ajuste financeiro do caixa.
Stack padrão conforme .specs/00-contexto-geral.md:
- Backend: Java 25, Spring Boot 4, PostgreSQL, Liquibase, Logback e QueryDSL.
- Frontend: Angular 21, Node 24, Bootstrap 5, FontAwesome 7, ngx-ui-loader, ngx-toastr, ngx-mask e ng-select.
.
├── backend/ # Aplicação backend Spring Boot
├── frontend/ # Aplicação frontend Angular
├── .specs/ # Especificações técnicas e padrões usados por IA
├── .cruds/ # YAMLs operacionais para geração de CRUDs do projeto
├── mise.toml # Versões de ferramentas usadas no ambiente local
└── README.md # Contexto específico do APvenda
Pontos de entrada principais:
- backend:
backend/src/main/java/com/github/andrepenteado/venda/VendaApplication.java; - configurações backend:
backend/src/main/resources/application.yamlebackend/src/main/resources/application-dev.yaml; - migrações Liquibase:
backend/src/main/resources/db/changelog/; - frontend:
frontend/src/main.ts; - rotas e configurações frontend:
frontend/src/app/app.routes.tsefrontend/src/app/config/.
Versões esperadas pelo mise.toml:
- Java:
corretto-25.0.1.8.1; - Maven:
4.0.0-rc-5; - Node:
24.13.0.
Backend:
cd backend
mvn spring-boot:runFrontend:
cd frontend
npm install
npm startBuild e testes:
cd backend
mvn test
mvn packagecd frontend
npm run build
npm testO backend usa PostgreSQL. Antes de rodar localmente, revise as configurações de banco, SSO e CORS em application.yaml e application-dev.yaml.
Para implementar funcionalidades, manter CRUDs ou orientar assistentes de IA, use .specs/ como fonte de padrões técnicos.
Arquivos mais relevantes:
.specs/00-contexto-geral.md: stack, regras gerais e critérios globais..specs/orquestrador.md: fluxo esperado para geração assistida por IA..specs/*.md: regras específicas de backend, frontend, banco, telas e checklist.
YAMLs operacionais de CRUD devem ficar em .cruds/, fora de .specs/.
- Cadastros base: produtos, marcas e categorias.
- Base de PDV: abertura, fechamento e movimentações de caixa.
- Vendas: registro de venda, itens, totalizadores e consulta de produtos.
- Operação: relatórios de vendas, relatórios de caixa e indicadores básicos.
O PDV é a tela de operação de venda presencial. Não é um CRUD: não possui YAML em .cruds/ e não segue o fluxo de geração assistida. Esta seção define o comportamento esperado da tela e os dados persistidos.
Registrar uma venda de forma ágil, operada inteiramente por teclado, sem necessidade de mouse, com a lista de itens exibida em formato de cupom. Nesta fase o PDV grava apenas a venda e seus itens; o fluxo de caixa (abertura, fechamento e movimentações) ainda não é implementado.
- A tela abre com o foco no campo de pesquisa de produto.
- A pesquisa é um
ng-selectcom autocompletar: conforme se digita parte do nome ou o código de barras, abre-se um combo com os produtos que casam com o termo (busca no servidor). - As
Setasnavegam pela lista do combo. Selecionar comEnteradiciona o produto direto ao carrinho (quantidade1); selecionar com o mouse apenas move o foco para o campo quantidade (com o preço exibido e a quantidade1). - Com o foco na quantidade, ajusta-se o valor e
Enteradiciona o produto ao carrinho e devolve o foco para a pesquisa. - O campo quantidade fica desabilitado enquanto não houver produto selecionado.
- O campo preço de venda fica sempre desabilitado (apenas exibição).
F2: foco no campo de pesquisa de produto.F3: foco no campo quantidade, quando habilitado.Del: entra no modo de navegação dos itens do carrinho;Seta acima/Seta abaixoselecionam o item eEnterconfirma a exclusão.F6: abre o modal de vínculo de cliente.Ctrl + D: remove o vínculo de cliente (quando houver cliente vinculado).F10: abre o modal de pagamento.- No modal de pagamento:
F7foca a forma de pagamento,F8os juros,F9o desconto eEscvolta (fecha o modal). Ctrl + F11: finaliza a venda (exige ao menos um item; funciona também a partir do modal de pagamento).Esc: sai do modo de exclusão e fecha os modais (cliente, pagamento e impressão).Ctrl + C: cancela a venda a qualquer momento (o cancelamento exige confirmação, então não copia nem cancela por engano).F4: imprime o comprovante (ver "Impressão do comprovante").- Exclusão de item e cancelamento da venda exibem popup de confirmação; no cancelamento, a opção padrão é Não (evita cancelar por engano ao pressionar
Enter).
No modal de impressão, [Ctrl + P] imprime e [Esc] fecha.
O pagamento acontece em um modal, aberto pelo botão [F10] Pagar (ou pela tecla F10), exigindo ao menos um item no carrinho:
- O modal tem os campos: Forma de pagamento (
F7), Juros (%) (F8) e Desconto (%) (F9) — inteiros, em percentual, aplicados sobre o total — e Valor a pagar (somente exibição, calculado em tempo real no frontend:total+total×juros% −total×desconto%). - Finalizar (
Ctrl + F11, botão do modal): o frontend envia itens, juros, desconto e forma de pagamento em uma única chamada; o backend consolida e valida os itens, grava aVenda, osItemVendae um únicoReceberjá quitado e baixa o estoque. Ao concluir, abre o modal de impressão com o cabeçalhoVENDA #NNN(id gerado).
A lista de itens fica em um card entre o formulário de produto e a barra de ações, em tabela Bootstrap alinhada ao visual do restante do sistema:
- colunas
Produto(miniatura da foto e nome),Quantidade(com a unidade),Valor UnitárioeValor Total; - cabeçalho do card com o cliente vinculado e um badge com o contador de itens;
- o card tem altura fixa: quando os itens ultrapassam o limite, a tabela rola dentro do card (como um dbrowse), com o cabeçalho fixo (
sticky); - rodapé do card com o total da venda em destaque;
- o modo de exclusão (
Del) destaca a linha selecionada (table-warning).
- A impressão usa o componente reutilizável
venda-imprimir(pages/venda/imprimir/), compartilhado com o relatório de vendas e a consulta de venda. F4abre um modal Bootstrap com o comprovante, a qualquer momento da venda; ao finalizar, o modal abre automaticamente. (A teclaPrint/PrtScé capturada pelo sistema operacional para captura de tela e não é confiável no navegador; por issoF4.)- No modal,
[Ctrl + P]imprime e[Esc]fecha. OCtrl + Pusa a impressão nativa do navegador, imprimindo apenas o conteúdo do modal: via@media print, o restante da tela e os próprios botões do modal ficam ocultos (classed-print-nonedo Bootstrap). - Comprovante em folha A4 (
@page { size: A4 }), com layout de documento moderno: título (ORÇAMENTOantes da finalização,VENDA #NNNdepois), cliente, telefone do cliente quando preenchido e tabela de itens com total. Na impressão o fundo é forçado a branco com letras pretas, independente do tema ativo.
- A tela é dividida em cards (produto e itens da venda) mais uma barra de ações, com cabeçalhos com ícone e descrição, no mesmo padrão visual das telas de cadastro. O pagamento fica em um modal.
- Campos de operação usam
input-group-lg/form-control-lgdo Bootstrap, com ícone à esquerda (input groups); ong-selectrecebe CSS mínimo apenas para acompanhar a altura e a fonte desses campos. - O cliente vinculado aparece como botão no cabeçalho da página e no cabeçalho do card de itens.
- Atalhos documentados com
<kbd>(estilizado discreto, sem o preto forte padrão) ao lado dos labels; nos botões, o atalho aparece como prefixo (ex.:[F10] Pagar). - Priorizar os recursos do Bootstrap 5 no desenho da tela e reduzir ao mínimo o CSS customizado.
- As tabelas (sem YAML de CRUD) são
Venda(id,data_hora,totale auditoria),ItemVenda(id,fk_venda,fk_produto,quantidade,valor_unitario,valor_total) eReceber(id,fk_venda,parcela,data_vencimento,data_pagamento,forma_pagamento,valor_a_receber,valor_pago). A modelagem deRecebercomporta parcelamento, mas a regra atual é simplificada: 1 venda = 1 registro deReceber, sempre pago (parcelafixo em 0 = à vista). quantidadeé decimal, para permitir fracionar (ex.: produtos em metro); lançar o mesmo produto de novo soma a quantidade na linha existente.valor_unitarioguarda o preço no momento da venda; ototalé recalculado no backend a partir dos itens.- O formulário de finalização informa
juros,desconto(inteiros, em percentual) e aforma_pagamento. O valor líquido da venda étotal+total×juros% −total×desconto% e vira o único registro deReceber, comvalor_a_receber=valor_pago= líquido. Juros e desconto ficam embutidos no valor e não são colunas deReceber. data_vencimentoedata_pagamentorecebem a data da venda (registro já quitado).forma_pagamentoé o enumFormaPagamento(DINHEIRO,PIX,CARTAO_DEBITO,CARTAO_CREDITO).- Ao finalizar, a venda baixa o
estoque_atualde cada produto na mesma transação. A baixa fica pronta, mas nesta fase não há validação de estoque negativo ou zero. - O fluxo de caixa não será implementado nesta fase.
A tela Vendas (menu Vendas, rota /vendas) consulta as vendas registradas no PDV, baseada na tabela venda. Não é um CRUD gerado por YAML.
- Filtros: número da venda, período (data da venda), CPF do cliente e consumidor (somente vendas sem cliente vinculado). A pesquisa exige ao menos um filtro; limpar os filtros lista todas as vendas.
- Grid: a primeira coluna é a de ação, com os botões consultar, imprimir e estorno; as demais exibem id, data/hora, cliente (ou "Consumidor"), CPF, forma de pagamento, total e valor pago.
- Consultar: abre a página somente leitura
/vendas/consultar/:idcom os dados da venda (data/hora, cliente, forma de pagamento e valor pago) e a tabela de itens vendidos; o único botão de ação é Imprimir, que abre o modal do componentevenda-imprimir. - Imprimir: busca a venda (
GET /vendas/{id}) e abre o modal de impressão direto na grid, sem navegar, reutilizando o componentevenda-imprimirdo PDV. - Estorno: mediante confirmação (opção padrão Não), exclui a
Venda, osItemVendae oRecebere devolve as quantidades vendidas ao estoque, tudo na mesma transação.
Os grids de Produtos, Vendas e Clientes usam o server-side processing do DataTables (suporte na lib ngx-apcore: Datatables.serverSide(...) e Datatables.aoClicarAcao(...)): o grid pede apenas a página atual (start/length, busca global e ordenação) e o backend responde com a página e os contadores — nada de carregar milhares de registros no navegador.
- Endpoints:
POST /produtos/datatables,POST /vendas/datatablesePOST /clientes/datatables, com body{ datatables, filtro }(o request do protocolo DataTables + o filtro da tela). A paginação usaQuerydslPredicateExecutor.findAll(Predicate, Pageable); a ordenação é validada por whitelist de colunas (nunca aplica a string do cliente direto noSort). - Busca global do grid: produto pesquisa em nome, código de barras (exato), categoria e marca; venda pesquisa em nome do cliente e número da venda; cliente pesquisa em nome, telefone e CPF/CNPJ (exato).
- Renderização: em server-side as linhas são HTML gerado pelo DataTables (
columns[].render), não template Angular; os botões de ação usamdata-acao/data-idcom listener delegado (Datatables.aoClicarAcao). - Cards de resumo de Vendas: os agregados (valor total e valor pago) vêm do backend calculados sobre o resultado filtrado inteiro (
VendaDatatablesResponse), não somando a página. - Tamanhos de página: fixos (10/25/50/100) — não há "mostrar todos". Exportações (Excel/PDF/Imprimir) exportam apenas a página visível.
- Os grids pequenos (marcas e categorias) continuam com paginação client-side (
Datatables.config). - Filtros persistentes: todas as telas de pesquisa guardam o filtro aplicado na sessão do navegador (
FiltroSessaoService,sessionStorage): ao navegar para outra tela (ou para o cadastro) e voltar, o filtro é restaurado e a pesquisa refeita; o filtro só é descartado quando o usuário limpa/muda ou fecha a aba.