Produtos — arquitetura, API e análise técnica
Análise estática do pepper-front e pepper-api em 08/10/2026, complementada pela renderização local dos componentes com dados fictícios. Os caminhos abaixo são relativos às raízes desses repositórios. Esta revisão documenta o comportamento encontrado; não altera código da aplicação nem comprova integrações em produção.
Entidades e responsabilidades
| Entidade | Campos / comportamento relevante |
|---|---|
Product | business referencia ProfileBusiness, não Business. Nome, tipo, unidade, preço, quantidade padrão, links, imagem, endereços digitais e publicFlag. |
Affiliation | Produto, empresa proprietária, CPF/CNPJ do parceiro, comissão, status, limite, link e anexos. Índice único produto + documento. |
Lote | Produto, empresa, quantidade máxima e intervalo de datas. |
FairProduct | Associação área + produto, status, mistura de fornecedores e modelo de avaliação. |
OrderProduct | Produto do pedido, valor, quantidade, desconto e referências complementares. |
ProductAcquisition | Área, produto, usuário, lote opcional, posição, status e prazo da reserva. |
Fornecedor (Product.provider) é texto. A propriedade é dada por Product.business. Afiliação não duplica nem transfere o produto.
Frontend: telas e serviços
| Fluxo | Evidência no pepper-front |
|---|---|
| Rotas all/new/edit/view e resolução | src/app/product/product-routing.module.ts e módulos de cada página. |
| Catálogo, busca e contagens | src/app/product/product.page.ts, product.page.html, product.service.ts. |
| Cartões próprios/afiliados | src/app/product/product-shared/product-item/. |
| Cadastro e etapas | src/app/product/new/, product-local.ts; etapas locais via src/utils/Local/Local.ts. |
| Edição, upload, erros e endereços | src/app/product/edit/; src/utils/Swipper.ts seleciona controles alterados. |
| Detalhes, clonagem, exclusão e abas | src/app/product/view/view.page.ts, view.service.ts. |
| Afiliação | src/app/affiliation/affiliation.service.ts e product/view/affiliation-modal/. |
| Lotes | product/view/lote-modal/. |
| Associação às áreas | src/app/fair/view/fair-products-modal/ e página de gerenciamento da área. |
| Marketplace, carrinho e checkout | src/app/public/view-public/, incluindo marketplace-cart.service.ts e checkout/. |
A edição normaliza o objeto indexado de endereços digitais gerado pelo mecanismo de controles alterados para uma lista antes de enviar à API. O upload é um fluxo separado da atualização do documento.
API do catálogo
Todas as rotas abaixo usam o prefixo /api/v1. As consultas retornam o envelope data e, quando paginadas, metadata.
| Método e rota | Uso / proteção observada |
|---|---|
POST /product | Cadastro, validação, token e permissão product.write. |
GET /product?business=…&pagination=… | Próprios + afiliados; sem auth.checkToken nessa rota. Sem empresa válida devolve lista vazia. |
GET /product/:productId | Ficha; token e product.read. |
PUT /product/:productId | Atualização; validação, token e product.write. business é obrigatório no corpo. |
DELETE /product/:productId | Exclusão; token e product.delete. |
POST /product/:productId/clone | Cópia; token e productClone.write. Ignora nome enviado e usa “Cópia de…”. |
GET /product/:productId/videos | Vídeos a partir de endereços YouTube; sem auth.checkToken nessa rota. |
GET /public/business/:businessId/products | Catálogo público, exige publicFlag = true; inclui afiliações elegíveis. |
GET /order/by-product/:productId?business=… | Pedidos relacionados, filtrados por empresa e sem soft delete. |
Evidências: src/domains/Product/{routes,controller,validations,product.model,policies,permission}.js, src/domains/Public/routes.js e src/domains/Order/controller.js#getByProduct.
O backend exige empresa, nome, tipo e unidade no cadastro. Preço e quantidade não têm restrições positivas equivalentes a uma validação de negócio completa. Publicação começa falsa no modelo. Na edição, URL/descrição têm permissões para vazio/null que não são uniformes com os demais campos.
API de parcerias, lotes e áreas
| Recurso | Rotas |
|---|---|
| Afiliação | POST/GET /affiliation, GET/PUT/DELETE /affiliation/:affiliationId. Token e permissões de afiliação. |
| Lote | POST/GET /lote, PUT/DELETE /lote/:loteId. Token e permissões baseadas em Produtos. |
| Associação | GET/POST /fair/:fairId/products, PUT /fair/:fairId/products/bulk, PUT/DELETE /fair/:fairId/products/:fairProductId. |
| Disponibilidade | GET /public/fair/:fairId/product/:productId/acquisition/availability. |
| Entrar na fila | POST /public/fair/:fairId/product/:productId/acquisition/queue. |
| Consultar/sair da fila | GET/DELETE /public/fair/:fairId/product/:productId/acquisition/queue/:queueId. |
| Confirmar aquisição | POST /public/fair/:fairId/product/:productId/acquisition/confirm, corpo com queueId. |
Na fila, as operações do usuário exigem token; a disponibilidade é pública. FairProduct.bulkSet remove associações fora da seleção enviada e faz upsert das selecionadas. Uma seleção parcial, portanto, pode retirar itens existentes da área.
Evidências: src/domains/Affiliation/, src/domains/Lote/, src/domains/Fair/{routes,fairProduct.controller}.js, src/domains/ProductAcquisition/ e src/domains/Public/routes.js.
Descoberta de produtos afiliados
Product.controller#get/getPublic resolve ProfileBusiness → Business, lê CPF/CNPJ, normaliza para dígitos e procura afiliações com status accepted ou progress. A consulta reúne IDs próprios e afiliados. O retorno inclui viaAffiliation, isOwnProduct, proprietário e afiliação correspondente; a listagem administrativa também informa contagem de afiliações ativas.
O catálogo público exige publicFlag inclusive para os itens afiliados. A consulta administrativa de produtos, sem token na rota, não filtra por esse campo. A indicação Privado descreve a publicação no marketplace, não uma garantia de confidencialidade do endpoint administrativo.
Disponibilidade e reserva
A resolução de limite prioriza lote vigente com quantidade positiva e, na ausência dele, uma afiliação ativa com maxSales positivo. O saldo subtrai registros holding/confirmed por área e produto. A reserva expira em dez minutos e depende do scheduler para liberar/promover a fila.
Há diferenças entre a seleção de lotes do controlador, da listagem pública e do scheduler: nem todos os caminhos ordenam igualmente os lotes. A confirmação atualiza a aquisição, sem chamada de cobrança ou criação de pedido nesse método.
Permissões: limites da análise
As rotas de mutação usam BasePermission. As policies de Produto e Afiliação resolvem a empresa por productId/affiliationId para operações por ID. Quando esses IDs não existem no recurso, alguns callbacks retornam permissão positiva sem resolver a empresa enviada no corpo/query.
Lotes reutilizam a policy de Produto, mas as rotas por ID usam loteId. Isso exige revisão da resolução do proprietário do lote. Há também callbacks permissivos para perfis de fornecedor/cliente no recurso Produto, enquanto clonagem e afiliação têm regras distintas.
Esses achados são pontos de revisão de escopo; a autorização final depende também do middleware e das permissões do perfil. Não foram feitos testes de exploração ou acessos a dados reais.
Achados e prioridades
| Prioridade proposta | Achado verificável | Consequência / ajuste recomendado |
|---|---|---|
| Alta | GET /product e vídeos sem autenticação explícita na rota; consulta administrativa inclui privados. | Rever exposição, campos retornados e intenção de acesso público. |
| Alta | Ownership das policies depende dos IDs presentes; criação/listagem e lotes exigem revisão de escopo. | Validar empresa pelo recurso efetivo, corpo e query; cobrir cenários entre empresas. |
| Alta | Exclusão chama findByIdAndDelete antes de procurar pedidos; não limpa dependências. | Verificar referências antes de remover, tratar produto inexistente e definir política de retenção/cascata. As rotas estão envolvidas pelo middleware global de transação (src/routes.js e src/middlewares/transactions.js), que prevê abortar em caso de erro; o rollback não foi exercitado nesta revisão. |
| Alta | CheckoutPage.finish somente altera estado local, sem API. | Integrar pedido, validação de preços, pagamentos e liberação antes de operar cobrança pública. |
| Alta | Limites usam afiliação por produto, sem parceiro; saldo por área/produto, sem lote. | Definir escopo de capacidade e consistência entre consumo e venda. |
| Alta | Fila usa contagens e posição calculadas em operações separadas. | Validar concorrência, idempotência, ocupação e promoção com testes de integração. Não há prova de exclusividade atômica nesta revisão. |
| Média | ProductPage.getParams devolve query vazia; getItems substitui a lista. | Manter empresa, avançar página e acumular resultados sem duplicar. |
| Média | Cadastro/edição usam regras divergentes para nulos, positivos e campos opcionais. | Uniformizar normalização e validação do formulário/API. |
| Média | Clonagem ignora nome; modal não recebe configuração de inputs; copia publicação e timestamps. | Corrigir contrato, escolher visibilidade inicial e regenerar metadados. |
| Média | Abas mascaram erros como listas vazias; afiliações limitadas a 100 registros. | Exibir erro/retry e paginar. |
| Média | ViewPage.formatDate converte data ISO para o fuso local; datas à meia-noite UTC podem aparecer no dia anterior. | Normalizar apresentação de datas de calendário; conferir também o corte em UTC da vigência. |
| Média | Seleção de lote no scheduler não segue necessariamente a mesma ordem das consultas. | Centralizar resolução do limite e tratar múltiplos lotes. |
| Média | Encerrar afiliação não remove associações existentes às áreas. | Definir/revalidar elegibilidade por canal na operação. |
| Baixa | Qualquer status de pedido diferente de paid aparece como Pendente. | Mapear estados financeiros completos na aba Vendas. |
| Baixa | Controllers de report/audit de Produtos retornam data: null. | Não anunciar relatórios ou auditoria de produto concluídos; implementar ou retirar rotas vazias. |
Os logs de descoberta de afiliações também incluem documentos empresariais e candidatos consultados em Product.controller#get. Rever necessidade e exposição desses logs na operação.
Validação e manutenção da documentação
Os prints vêm de componentes e estilos reais, montados em workspace Angular temporário pelo scripts/capture-products.cjs do pepper-docs. Serviços locais fornecem fixtures e bloqueiam gravações; não há backend, provedor de pagamento ou dados reais nessa captura.
A compilação desse preview verifica que os componentes selecionados e seus templates podem ser renderizados no cenário documentado. O build/typecheck do pepper-docs valida a publicação estática e referências internas. Essas verificações não substituem testes de API, autorização, concorrência, armazenamento ou pagamentos.
Ao mudar o produto, atualize o guia operacional afetado, os prints, os achados desta análise e a data da revisão. O README do pepper-docs contém o comando para reproduzir as imagens.