O que é e o que não é
FakeStore BaaS não tem frontend. É uma API headless — o lojista integra via API key e constrói qualquer interface em cima. O “Fake” do nome não é depreciativo: é uma referência à FakeStore API pública usada em tutoriais, que o projeto substitui com uma versão real, multi-tenant e pronta para produção.
Por que RLS e não WHERE clauses
A decisão mais importante do projeto foi onde implementar o isolamento de dados. A abordagem convencional é colocar WHERE tenant_id = $1 em todas as queries da aplicação. Funciona — até que alguém esqueça, ou até que um JOIN pule o filtro, ou até que uma query de debug rode em produção sem o contexto.
Com RLS, o PostgreSQL recusa qualquer acesso a linhas fora do tenant ativo na transação — independente do que o código Node.js faça. O mecanismo é:
SET LOCAL app.current_tenant_id = '42';
-- A partir daqui, qualquer SELECT/INSERT/UPDATE/DELETE
-- filtra automaticamente tenant_id = 42
-- Rollback ou fim da transação limpa o contexto
O teste de RLS na suite de integração verifica isso explicitamente: cria dois tenants com dados separados e confirma que as queries de um não retornam nada do outro, nem com SQL direto.
Worker de webhooks em processo separado
O webhook engine roda em um container Docker completamente separado da API. Quando o pedido é confirmado, a API empurra um job para a fila BullMQ. O worker consome assincronamente, assina o payload com HMAC-SHA256 e faz entrega com retry exponencial (até 5 tentativas, base 60s). Toda entrega — sucesso ou falha — fica registrada em webhook_events.
Isso significa que um endpoint de cliente que demora 10 segundos para responder não bloqueia nenhuma request da API. E o cliente consegue auditar exatamente quando cada webhook foi entregue, com qual resposta HTTP.
Dinheiro como Integer
Todos os valores monetários no banco são centavos (Integer). R$ 49,90 vira 4990. Descontos percentuais são basis points: 15% = 1500. A divisão para reais acontece só na resposta JSON. Isso elimina 0.1 + 0.2 = 0.30000000000000004 estruturalmente — nenhum desenvolvedor precisa lembrar de usar toFixed(2).