Cherry Bomb Vending Machine
em construçãoFull-stack / IoT
Uma máquina de vendas por QR Code para produtos artesanais: um Pix cobre a sacola inteira, e só o webhook de pagamento pode mexer no estoque.
- FastAPI
- Python 3.11
- PostgreSQL
- psycopg2
- Mercado Pago (Pix)
- Cloudinary
- Tailwind CSS
- Vanilla JS
- Railway
- ESP32 / MQTT
● O repositório é público, mas este estudo de caso sai sem link enquanto uma credencial encontrada na documentação dele é rotacionada.
// o caso
- problema
- Vender peças artesanais em condomínios significa ficar horas ao lado de uma mesa ou confiar numa caixinha de honestidade. Uma máquina de vendas convencional não resolve: a maquininha cobra mensalidade e uma fatia por transação que uma presilha de R$ 8,50 não absorve, e dinheiro em espécie precisa ser recolhido e guardado. A máquina precisava vender vinte itens distintos, sem ninguém por perto, entre R$ 5,50 e R$ 24,50, sem hardware nenhum no caminho do cliente.
- solução
- O terminal de pagamento saiu da máquina e virou um adesivo. Um QR Code no vidro abre uma vitrine mobile que espelha o layout físico — uma grade 4×5 em que cada card é uma mola real, endereçada de A1 a E4. O cliente enche a sacola com vários slots e paga um único Pix pelo carrinho inteiro: o backend soma no servidor, pede uma cobrança só ao Mercado Pago, e espera. Nada do pedido é considerado verdade até o webhook dizer que foi aprovado.
- impacto
- Não medido, e propositalmente não afirmado. O caminho de software roda em produção de ponta a ponta — vitrine, cobrança Pix, webhook de confirmação, baixa de estoque — mas a liberação física não está implementada: o arquivo de firmware do ESP32 está vazio e não existe publisher MQTT. O resumo honesto é um sistema de pagamento e estoque funcionando em produção, preso a uma máquina que ainda não gira as molas. Qualquer número de vendas seria ficção.
// meu papel
Autor único, ao longo de quatro dias em abril de 2026 — definição do produto, backend FastAPI, schema PostgreSQL, integração e webhook do Mercado Pago, pipeline de imagens no Cloudinary, a vitrine do cliente, o painel admin, a identidade visual e o deploy. O protocolo de hardware também é meu; o firmware que vai consumi-lo ainda não foi escrito.
// visão geral
O projeto parte de uma restrição, não de uma ideia de produto. No Brasil o Pix é instantâneo, gratuito para pessoa física e já está instalado no celular de todo cliente, no app do banco dele — o que faz do celular um terminal de pagamento melhor do que qualquer coisa que pudesse ser parafusada na máquina. Então a máquina foi desenhada sem nenhum hardware de pagamento. A consequência é que quase todo o produto é uma aplicação web, e a máquina física se reduz a uma grade de molas, um controlador e um adesivo de QR Code. A grade 4×5 não é enfeite: o slot C2 na interface é a mola C2 na máquina, e é isso que permite um único Pix acionar vários motores num pedido só.
A interface se compromete inteira com um contexto — um desconhecido, de pé diante de uma máquina, de celular na mão, provavelmente com pressa. É mobile-only por construção, já que a única porta de entrada é o QR Code no vidro. Não existe nenhuma regra de hover no stylesheet, só o estado ativo com uma escala de pressão, porque nada em tela de toque tem hover. A linguagem visual é neobrutalismo pop-punk anos 2000: quatro cores e nada além, bordas pretas de 2px em tudo, sombras sólidas sem desfoque, nenhum canto arredondado. Lê-se como um adesivo numa máquina, não como um checkout de e-commerce — que é justamente o ponto: o cliente deve sentir que está operando uma máquina, não entrando numa loja.
// notas de engenharia
Um Pix pela sacola, não um por item
A implementação natural — uma cobrança por produto — multiplicaria as idas ao Mercado Pago e obrigaria o cliente a várias confirmações no banco por uma compra só. Em vez disso o backend soma o carrinho no servidor, com aritmética decimal e arredondamento meio-para-cima, antes de criar uma cobrança única, e grava a lista de itens em JSON junto do registro do pagamento. É essa lista que a etapa de aprovação lê depois para saber quais molas girar — e é por isso que um Pix só consegue acionar vários motores.
Só o webhook pode mexer no estoque
O estoque nunca é baixado no cliente, no checkout, nem em nenhum caminho otimista. O botão de mais trava no estoque atual por cortesia de interface; a escrita que vale acontece só quando o webhook do Mercado Pago informa aprovado, num único update SQL protegido por item. A proteção trava o resultado em zero, então um webhook duplicado — coisa que provedores de pagamento realmente enviam — não consegue deixar o estoque negativo. Quem abandona a página no meio do pagamento nunca tira do estoque o que não pagou.
Desenhado para um desconhecido de celular diante da máquina
A interface assume um contexto e se recusa a servir qualquer outro. Mobile-only, porque a única porta de entrada é um QR Code no vidro. Não existe nenhuma regra de hover no stylesheet — só o estado ativo, que afunda o elemento na própria sombra, de modo que todo toque responde. Slots esgotados não somem: ficam apagados e dessaturados, sem eventos de toque, para que a grade na tela continue batendo com a máquina que o cliente está olhando. O controle de quantidade se resolve numa tira dentro do próprio card, o que mantém uma grade de vinte slots usável no celular sem abrir um modal por produto.
Reposição sem desenvolvedor
Um painel admin protegido por senha permite à operadora renomear produtos, mudar preços, ajustar estoque e fotografar itens direto do celular; o upload passa pelo backend até o Cloudinary, é recortado no servidor num quadrado com enquadramento automático, e a URL resultante volta gravada na linha do produto. Sem isso o projeto exigiria um desenvolvedor presente em cada reposição, o que tornaria a máquina inviável na prática.
A fronteira do hardware foi especificada antes do hardware existir
O contrato MQTT — tópico, formato do JSON, quantidade por motor e duração do giro — foi escrito e fechado enquanto o ESP32 ainda estava a caminho pelo correio. Isso permitiu construir, publicar e testar todo o caminho de pagamento e estoque contra uma junta definida, em vez de um chute. É também a fronteira honesta do que está pronto: o contrato existe, o firmware não.