Marketplace · classificados

Admister — sete marketplaces que compartilham um motor

Classificados, carros, imóveis, um mercado de bens com lojas, chaves digitais, cupons e um agregador de preços. Sete serviços vivem em seus próprios subdomínios, e cada um deles é a mesma aplicação: o serviço é escolhido a partir do nome do host, e o catálogo, contas, dinheiro, moderação e busca são compartilhados. Nós projetamos o modelo, escrevemos o motor e lançamos todos os sete.

Quero similarVisitar site
Categoria
Marketplace · classificados
Custo estimado
a partir de €32.000
Serviços
sete, um código-fonte
Idiomas
EN, UK · quatro moedas de exibição
Pilha
PHP 8.3, MariaDB, sem framework
admister.org
Admister
Página inicial do projeto — admister.org

01Visão geral do projeto

Admister é um marketplace multi-vertical. Sob um mesmo teto, ele opera classificados, um quadro de carros e peças, imóveis para venda e aluguel, um mercado de produtos com lojas de vendedores, bens digitais, um serviço de cupons e um agregador de preços. Cada um deles tem seu próprio subdomínio, sua própria página inicial e sua própria ideia do que é um item.

Por fora, eles parecem sete produtos separados. Por dentro, são uma única aplicação: o serviço é decidido pelo nome do host da solicitação, e tudo o que está por trás — contas, dinheiro, moderação, busca, mídia, notificações — é compartilhado. O projeto foi nosso do início ao fim: o modelo, o motor, a interface e o lançamento de cada vertical.

02Contexto e o problema

A maneira usual de lançar vários marketplaces é lançar vários sites. Funciona até o segundo: agora há duas tabelas de usuários, duas filas de moderação, duas integrações de pagamento e dois lugares onde o mesmo bug precisa ser corrigido duas vezes — e corrigido de maneira diferente, porque até lá o código se desviou.

O extremo oposto é igualmente ruim. Um site com uma categoria chamada «Carros» não pode pedir quilometragem, motor e placa da maneira que um quadro de carros deve, e uma busca de imóveis que não pode filtrar por andar e quartos não é uma busca de imóveis. A tarefa era manter um único motor sem fingir que sete catálogos muito diferentes são o mesmo catálogo.

03Objetivos do projeto

  • um código base e uma conta para todos os verticais, com o serviço escolhido pelo nome do host;
  • atributos e filtros por vertical: dezenas de campos para carros e imóveis, nenhum deles arrastado para os outros serviços;
  • dinheiro em que o proprietário pode confiar — um saldo, faturas em criptomoeda, creditação idempotente e reconciliação de pagamentos pendentes;
  • razões para os compradores voltarem: pesquisas salvas com notificações, emblemas de vendedores, leilões e compras em grupo;
  • duas línguas e quatro moedas de exibição sem duplicar conteúdo;
  • um aplicativo móvel que se comunica com um backend-for-frontend em vez de raspar o site.

04O que fizemos

Construímos o registro de serviços na sequência de inicialização. Um pedido chega, o nome do host é comparado com o registro, e a partir desse momento a aplicação sabe qual vertical é: quais módulos carregar, qual conjunto de atributos usar, qual página inicial e qual menu renderizar. O domínio básico é o quadro de classificados, então o endereço mais curto também é o mais geral.

Tudo que não é específico de vertical foi escrito uma vez: contas e sessões, saldo e pagamentos, recebimento de mídia, moderação, pesquisas salvas, notificações, o sitemap e a API. Adicionar o sétimo serviço foi principalmente escrever seus atributos e sua página inicial — não outro mercado.

05Sete serviços, sete catálogos

  • Classificados — o quadro geral: qualquer coisa, de uma bicicleta a um sofá, grátis para postar.
  • Carros — veículos, placas e peças, com um conjunto de atributos dedicado de várias dezenas de campos e filtros construídos sobre isso.
  • Imóveis — venda e aluguel, seu próprio conjunto de atributos, mapas e busca por distrito.
  • Mercado — produtos com lojas de vendedores: uma vitrine por vendedor, estoque, pedidos.
  • Digital — chaves, cartões-presente e eSIM: produtos que são entregues, não enviados.
  • Negócios — cupons e códigos promocionais de lojas parceiras.
  • Preço — um agregador de preços: o mesmo produto em lojas, comparado, com cliques de saída contados.

Eles compartilham a conta, o saldo, a fila de moderação e o índice de busca — e não compartilham nada em seus atributos, que é o ponto.

06Dinheiro: um saldo, faturas em cripto, reconciliação

Recursos pagos — promoção, planos de loja, bens digitais — são pagos a partir de um saldo interno, e o saldo é recarregado com cripto através de Payora, nosso próprio gateway. O corpo da fatura é construído em exatamente uma função, porque o mesmo corpo é reproduzido pelo cron de reconciliação sob a mesma chave de idempotência: um único campo que difere entre os dois retornaria como um conflito e deixaria o pagamento pendente.

Dois detalhes que repetiríamos em qualquer gateway. A fatura carrega o próprio local do comprador retirado da linha de sua conta, não da solicitação da web — o cron não tem solicitação e, caso contrário, enviaria todos em inglês. E carrega um endereço de retorno que leva de volta à conta no domínio básico, para que um comprador que começou na vertical de carros retorne logado, e não para uma página que pede para que ele faça login novamente.

07Confiança: moderação, distintivos, disputas

Um marketplace é julgado pela sua pior listagem, então a moderação não é uma tela lateral aqui. Cada decisão — aprovar, rejeitar, remover — passa por um único responsável, e «rejeitar» não é deliberadamente a mesma coisa que «remover»: o primeiro é uma resposta ao autor com uma razão, o segundo remove algo que já estava ativo. Dois verbos, duas letras diferentes, dois estados diferentes no registro.

Vendedores e lojas possuem emblemas que são conquistados, não comprados: há quanto tempo a conta existe, quantos negócios foram fechados, se o telefone e o e-mail estão confirmados. O comprador vê o mesmo emblema em todos os lugares onde o vendedor aparece, porque é calculado em um só lugar.

09Um aplicativo móvel com seu próprio backend

O aplicativo não faz scraping do site. Ele se comunica com um backend-for-frontend próprio: um pequeno conjunto de endpoints que respondem nas formas que as telas precisam, com tokens emitidos separadamente das sessões da web. Dois caminhos estão abertos sem um token — os dados de referência que o aplicativo precisa antes que alguém faça login, e um endpoint de saúde.

Esse endpoint de saúde é um endereço separado de propósito. O registro que monitora a frota costumava perguntar ao endpoint de referência, e esse compila todos os dicionários e todas as taxas — uma verificação de vivacidade não deve custar mais do que o trabalho. Ele responde com a versão do contrato também, então um cliente construído para um contrato mais antigo é notado antes que seus usuários percebam.

10Sete frentes de SEO

Sete serviços em um domínio significam sete sitemaps, sete conjuntos de dados estruturados e uma maneira muito fácil de produzir duplicatas. Cada vertical publica seu próprio sitemap a partir do cache, as páginas de listagem declaram seu próprio tipo de dados estruturados, e as páginas de resultados de busca nunca afirmam ser canônicas para uma listagem.

O lado do conteúdo também é automatizado: um fluxo editorial chega de Astrina, a plataforma que construímos exatamente para isso, e no momento em que um artigo chega, o cache do sitemap para sua vertical é descartado — caso contrário, a nova página aguardaria a próxima reconstrução e ninguém saberia por que estava faltando.

11Um canal de saída

Tudo que a aplicação envia para fora — chamadas de API, webhooks, feeds de parceiros, imagens que busca, e-mail — passa por um único módulo vinculado a um proxy de saída SOCKS5, com DNS resolvido através do proxy também. O módulo é fail-closed: se o proxy estiver indisponível, a solicitação é bloqueada em vez de ser enviada silenciosamente do próprio endereço do servidor.

Isso não é decoração. Um marketplace puxa feeds de parceiros e imagens remotas o dia todo; cada um deles é uma solicitação que, de outra forma, carregaria o endereço de origem do site para um terceiro. O e-mail vai pelo mesmo caminho, através de YourTrend, então as cartas são assinadas e o nome do host do servidor nunca aparece em um cabeçalho.

12Pilha de tecnologia

  • PHP 8.3 sem um framework, um wrapper PDO fino e declarações preparadas em todos os lugares;
  • MariaDB, esquema mantido como arquivos de migração numerados em vez de como a memória de alguém;
  • mídia armazenada fora da raiz da web e servida por um controlador, de modo que um upload nunca seja um caminho executável;
  • uma etapa de construção que hash assets e não insere nada que deva ser armazenado em cache, com um interruptor de desligamento para quando ele se comporta mal;
  • SAÍDA SOCKS5 para cada chamada de saída, e-mail através do SMTP do YourTrend;
  • Payora para faturas de criptomoedas, Astrina para login e conteúdo editorial, Adgora para publicidade interna.

13O resultado

Sete serviços ao vivo em uma única base de código, uma conta e um saldo em todos eles, com atributos e filtros que diferem tanto quanto os catálogos. Um novo vertical é um conjunto de atributos e uma página inicial — não um novo projeto, não uma segunda tabela de usuários, não uma segunda integração de pagamento.

O que o proprietário recebe dia a dia é um lugar para olhar. Moderação, dinheiro, vendedores e conteúdo são gerenciados a partir do painel de controle compartilhado de todo o grupo, e o marketplace os expõe através de uma API de admin assinada em vez de através de um segundo site de admin próprio.

14Principais aprendizados

A lição que levaríamos para o próximo marketplace: compartilhe a maquinaria, não o significado. Contas, dinheiro, moderação e busca são o mesmo problema em todos os verticais e devem ser escritos uma vez. Atributos, filtros e a forma de um anúncio são o próprio produto, e forçá-los em uma tabela universal é como os marketplaces se tornam inutilizáveis para todos ao mesmo tempo.

A segunda lição é sobre dinheiro. O lugar onde um pagamento é descrito deve ser uma única função, porque algo mais irá reproduzi-lo — um cron, uma nova tentativa, uma reconciliação — e duas descrições de um pagamento é a maneira mais barata de perder dinheiro silenciosamente.

Se você está construindo um marketplace, um quadro de classificados ou uma plataforma multi-vertical em um único motor, este é o tipo de trabalho que fazemos de ponta a ponta.