API Reference: Loja

Base URL: /api/loja. Todos os endpoints requerem autenticacao (AuthGuard).

Restricao de convidados: Membros com is_nucleo_origem = false (convidados de outro nucleo) recebem 403 Forbidden em comprar, doar e checkout. A loja esta disponivel apenas no nucleo de origem do membro.

Resumo de Endpoints

MetodoRotaPermissaoDescricao
POST/api/loja/produtosCOORDENADOR / ADMINISTRADORCriar produto
GET/api/loja/produtosAutenticadoListar produtos (vitrine)
GET/api/loja/produtos/:idAutenticadoDetalhe do produto + galeria + similares
PATCH/api/loja/produtos/:idCOORDENADOR / ADMINISTRADORAtualizar produto
POST/api/loja/comprarAutenticado (nao convidado)Compra unitaria com split payment
POST/api/loja/checkoutAutenticado (nao convidado)Checkout de carrinho multi-item
GET/api/loja/meus-pedidosAutenticadoHistorico de pedidos do usuario
GET/api/loja/pedidosCOORDENADOR / ADMINISTRADORListar todos os pedidos do nucleo
PATCH/api/loja/pedidos/:id/statusCOORDENADOR / ADMINISTRADORAtualizar status do pedido
POST/api/loja/pedidos/:id/cancelarCOORDENADOR / ADMINISTRADORCancelar pedido (estorna CC + devolve estoque)
POST/api/loja/cuponsADMINISTRADORCriar cupom de desconto
GET/api/loja/cuponsADMINISTRADORListar cupons do nucleo
PATCH/api/loja/cupons/:idADMINISTRADORAtualizar cupom
POST/api/loja/cupons/validarAutenticadoValidar cupom por codigo
POST/api/loja/doarAutenticado (nao convidado)Fazer doacao ao nucleo
GET/api/loja/doacoesADMINISTRADORListar doacoes do nucleo

Produtos

POST /api/loja/produtos

Cria um novo produto na loja do nucleo.

Permissao: COORDENADOR / ADMINISTRADOR

Body

CampoTipoObrigatorioDescricao
nomestringSimNome do produto
descricaostringNaoDescricao do produto
categoriastringSimCategoria do produto
precoMoedasnumberSimPreco em moeda do nucleo (CC)
precoRealnumberSimPreco em R$
estoquenumberSimQuantidade em estoque
isIlimitadobooleanNaoEstoque ilimitado (default: false)
fotoUrlstringNaoURL da foto principal
imagensUrlsstring[]NaoURLs da galeria de imagens (tabela produto_imagens)
precoPromocionalMoedasnumberNaoPreco promocional em CC
precoPromocionalRealnumberNaoPreco promocional em R$
dataInicioPromostring (ISO)NaoInicio do periodo promocional
dataFimPromostring (ISO)NaoFim do periodo promocional
isDestaquebooleanNaoProduto em destaque na vitrine (default: false)

Response 200

{
  "id": "uuid",
  "nome": "Camiseta MBL",
  "categoria": "VESTUARIO",
  "preco_moedas": 500,
  "preco_real": 59.90,
  "estoque": 30,
  "ativo": true
}

GET /api/loja/produtos

Lista produtos do nucleo. Ordenados por destaque (desc) e data de criacao (desc).

Query Params

ParamTipoDescricao
todosstringSe true, retorna todos (incluindo inativos). Default: apenas ativos.

Campos extras no response

  • isPromoAtiva: boolean calculado — true se o preco promocional esta definido e a data atual esta dentro do periodo.
  • isNovo: boolean calculado — true se o produto foi criado ha menos de 7 dias.

GET /api/loja/produtos/:id

Detalhe completo do produto incluindo galeria de imagens e ate 4 produtos similares (mesma categoria, mesmo nucleo, ativos).

Response inclui

  • Todos os campos do produto + isPromoAtiva + isNovo
  • imagens: array de { id, url, ordem } ordenado por ordem
  • similares: ate 4 produtos da mesma categoria com isPromoAtiva e isNovo

PATCH /api/loja/produtos/:id

Atualiza campos permitidos de um produto. Se imagensUrls for enviado, substitui toda a galeria.

Permissao: COORDENADOR / ADMINISTRADOR

Campos permitidos

nome, descricao, categoria, precoMoedas, precoReal, estoque, isIlimitado, ativo, fotoUrl, precoPromocionalMoedas, precoPromocionalReal, dataInicioPromo, dataFimPromo, isDestaque


Compra (Split Payment)

POST /api/loja/comprar

Compra unitaria de um produto com split payment (CC + R$).

Restricoes

  • assertNaoEhConvidado: verifica membros_nucleos.is_nucleo_origem. Convidados recebem 403.
  • Quantidade entre 1 e 3.
  • Saldo de CC verificado via membros_nucleos.saldo_capixacoins (filtrado por usuario + nucleo).

Body

{
  "produtoId": "uuid",
  "quantidade": 2,
  "valorCC": 3000,
  "metodo": "PIX"
}

Fluxo

  • 100% CC (valorRealAPagar <= 0): debita CC instantaneamente, pedido vai para PENDENTE.
  • Mix CC + R$: calcula proporcao CC/total, gera cobranca Asaas pelo restante em R$, pedido fica AGUARDANDO_PAGAMENTO.
  • 100% R$ (valorCC = 0): gera cobranca Asaas pelo total.
  • Se a cobranca Asaas falhar, o pedido criado e deletado (rollback).
  • Precos promocionais sao usados automaticamente quando a promocao esta ativa.

Response 200 (100% CC)

{
  "pedidoId": "uuid",
  "status": "PENDENTE",
  "message": "Compra realizada com Capixacoins"
}

Response 200 (com R$)

{
  "pedidoId": "uuid",
  "status": "AGUARDANDO_PAGAMENTO",
  "pagamento": {
    "pagamentoId": "uuid",
    "pixQrCode": "00020126...",
    "urlPagamento": "https://...",
    "status": "PENDENTE"
  },
  "message": "Pedido criado. Pague R$45.90 via PIX."
}

Checkout (Carrinho Multi-item)

POST /api/loja/checkout

Checkout de carrinho com multiplos itens, suporte a cupom de desconto e parcelamento no cartao.

Restricoes

  • assertNaoEhConvidado: convidados (is_nucleo_origem = false) recebem 403.
  • Saldo de CC verificado via membros_nucleos.saldo_capixacoins.
  • valorCC e truncado para inteiro (campo INTEGER no banco).
  • Parcelamento apenas disponivel para CARTAO_CREDITO, limitado por nucleos.max_parcelas_cartao.

Body

{
  "items": [
    { "produtoId": "uuid-1", "quantidade": 2 },
    { "produtoId": "uuid-2", "quantidade": 1 }
  ],
  "valorCC": 5000,
  "metodo": "PIX",
  "cupomCodigo": "DESCONTO10",
  "parcelas": 3,
  "dadosCartao": {
    "holderName": "JOAO SILVA",
    "number": "4111111111111111",
    "expiryMonth": "12",
    "expiryYear": "2028",
    "ccv": "123"
  }
}

Fluxo detalhado

  • Valida todos os itens (existencia, estoque, ativo).
  • Calcula totais usando precos promocionais quando ativos.
  • Valida e aplica cupom (PERCENTUAL ou FIXO). Desconto distribuido proporcionalmente entre itens.
  • Valida valor CC e verifica saldo.
  • Reduz estoque de cada produto.
  • Cria um pedido_loja por item (com valor_cc_pago e valor_real_pago proporcionais).
  • Incrementa uso_atual do cupom se aplicavel.
  • Se 100% CC: debita CC agora (unica transacao no ledger, referenciando o primeiro pedido).
  • Se tem R$: gera cobranca unica Asaas e vincula pagamento_id a todos os pedidos.
  • Para PIX: tenta obter QR code encoded image via Asaas.
  • Se a cobranca falhar: rollback (deleta pedidos e restaura estoque).

Response 200 (com pagamento)

{
  "pedidos": [
    { "id": "uuid-1", "status": "AGUARDANDO_PAGAMENTO", "produtoNome": "Camiseta MBL" },
    { "id": "uuid-2", "status": "AGUARDANDO_PAGAMENTO", "produtoNome": "Bone MBL" }
  ],
  "pagamento": {
    "pixQrCode": "00020126...",
    "pixEncodedImage": "base64...",
    "urlPagamento": "https://...",
    "status": "PENDENTE"
  },
  "message": "Pedido criado. Pague R$89.90 via PIX."
}

Pedidos

GET /api/loja/meus-pedidos

Historico de pedidos do usuario logado com paginacao.

Query Params

ParamTipoDescricao
pagenumberPagina (default: 1)
limitnumberItens por pagina (default: 20)

Response 200

{
  "data": [
    {
      "id": "uuid",
      "quantidade": 2,
      "valor_total_moedas": 1000,
      "valor_cc_pago": 600,
      "valor_real_pago": 35.94,
      "status": "PENDENTE",
      "data_pedido": "2026-04-01T12:00:00Z",
      "produtos_loja": { "nome": "Camiseta MBL", "foto_url": "https://..." }
    }
  ],
  "pagination": { "page": 1, "limit": 20, "total": 5, "totalPages": 1 }
}

GET /api/loja/pedidos

Lista todos os pedidos do nucleo (gestao administrativa).

Permissao: COORDENADOR / ADMINISTRADOR

Query Params

ParamTipoDescricao
statusstringFiltrar por status do pedido
pagenumberPagina (default: 1)
limitnumberItens por pagina (default: 20)

PATCH /api/loja/pedidos/:id/status

Atualiza o status de um pedido. Envia notificacao ao usuario.

Permissao: COORDENADOR / ADMINISTRADOR

Body

{ "status": "SEPARADO" }

Status validos

PENDENTESEPARADOENTREGUE

POST /api/loja/pedidos/:id/cancelar

Cancela um pedido. Nao permite cancelar pedidos ja entregues ou ja cancelados.

Permissao: COORDENADOR / ADMINISTRADOR

Efeitos do cancelamento

  • Estorna CC pagas: insere transacao CREDITO com origem: ESTORNO no ledger.
  • Devolve estoque ao produto (exceto se is_ilimitado).
  • Atualiza status do pedido para CANCELADO.
  • Envia notificacao ao usuario.

Response 200

{ "message": "Pedido cancelado. CC estornadas e estoque devolvido." }

Cupons de Desconto

POST /api/loja/cupons

Cria um novo cupom de desconto.

Permissao: ADMINISTRADOR

Body

CampoTipoObrigatorioDescricao
codigostringSimCodigo do cupom (convertido para maiusculas)
tipostringSimPERCENTUAL ou FIXO
valornumberSimValor do desconto (% ou R$ fixo)
usoMaximonumberNaoLimite de usos (null = ilimitado)
validadestring (ISO)NaoData de validade (null = sem expiracao)

Response 200

{
  "id": "uuid",
  "codigo": "DESCONTO10",
  "tipo": "PERCENTUAL",
  "valor": 10,
  "uso_maximo": 100,
  "ativo": true
}

GET /api/loja/cupons

Lista todos os cupons do nucleo (ativos e inativos). Ordenados por data de criacao desc.

Permissao: ADMINISTRADOR

PATCH /api/loja/cupons/:id

Atualiza campos de um cupom existente.

Permissao: ADMINISTRADOR

Campos permitidos

codigo, tipo, valor, usoMaximo, ativo, validade

POST /api/loja/cupons/validar

Valida um cupom por codigo antes de aplicar no checkout.

Body

{ "codigo": "DESCONTO10" }

Validacoes

  • Cupom existe no nucleo (codigo convertido para maiusculas).
  • Cupom esta ativo.
  • Cupom nao expirou (validade).
  • Cupom nao atingiu limite de uso (uso_atual < uso_maximo).

Response 200

{ "cupomId": "uuid", "tipo": "PERCENTUAL", "valor": 10 }

Erros

  • 404 — Cupom nao encontrado
  • 400 — Cupom inativo / expirado / limite atingido

Doacoes

POST /api/loja/doar

Registra uma doacao ao nucleo. Aceita CC, R$ ou mix.

Restricoes

  • assertNaoEhConvidado: convidados (is_nucleo_origem = false) recebem 403. Doacao e receita do nucleo de origem.
  • Ao menos um dos valores (valorReal ou valorCC) deve ser positivo.
  • Saldo de CC verificado via membros_nucleos.saldo_capixacoins.

Body

{
  "valorReal": 50.00,
  "valorCC": 200,
  "metodo": "PIX"
}

Fluxo

  • Cria registro na tabela doacoes.
  • Se valorCC > 0: debita CC imediatamente (transacao DEBITO/LOJA).
  • Se valorReal > 0: gera cobranca Asaas e vincula pagamento_id a doacao.
  • Se 100% CC: marca doacao como CONFIRMADO imediatamente.

Response 200 (100% CC)

{ "doacaoId": "uuid", "message": "Doacao realizada com sucesso!" }

GET /api/loja/doacoes

Lista todas as doacoes do nucleo com dados do doador.

Permissao: ADMINISTRADOR

Response 200

[
  {
    "id": "uuid",
    "valor_real": 50.00,
    "valor_cc": 200,
    "status": "CONFIRMADO",
    "criado_em": "2026-04-01T12:00:00Z",
    "usuarios": { "nome": "Joao Silva", "email": "joao@email.com" }
  }
]

Status de Pedido (ciclo de vida)

StatusDescricao
AGUARDANDO_PAGAMENTOPedido criado com parte em R$, aguardando confirmacao Asaas
PENDENTEPagamento confirmado (ou 100% CC), aguardando separacao
SEPARADOProduto separado, pronto para entrega
ENTREGUEProduto entregue ao membro
CANCELADOPedido cancelado (CC estornadas, estoque devolvido)

Notas de Arquitetura

  • Todas as queries filtram por nucleo_id — multi-tenant com RLS ativo.
  • O guard assertNaoEhConvidado verifica em membros_nucleos se o membro tem is_nucleo_origem = true e status = ATIVO. Membros de outros nucleos (convidados) nao podem transacionar na loja.
  • Saldo de CC e sempre verificado via membros_nucleos.saldo_capixacoins (nunca mais via tabela usuarios diretamente).
  • Precos promocionais sao verificados em tempo real via isPromoAtiva() (checa data atual vs periodo configurado).
  • Galeria de imagens usa tabela separada produto_imagens com campo ordem para controle de exibicao.
  • Integracoes de pagamento via Asaas: PIX (QR code), boleto e cartao de credito (com parcelamento configuravel por nucleo).