01Resumen del proyecto
Admister es un mercado multi-vertical. Bajo un mismo techo, opera clasificados, un tablón de coches y piezas, bienes raíces con venta y alquiler, un mercado de productos con tiendas de vendedores, bienes digitales, un servicio de cupones y un agregador de precios. Cada uno de ellos tiene su propio subdominio, su propia página de inicio y su propia idea de lo que es un artículo.
Desde fuera parecen siete productos separados. Desde dentro son una sola aplicación: el servicio se decide por el nombre de host de la solicitud, y todo lo que está debajo —cuentas, dinero, moderación, búsqueda, medios, notificaciones— es compartido. El proyecto fue nuestro de principio a fin: el modelo, el motor, la interfaz y el lanzamiento de cada vertical.
02Contexto y el problema
La forma habitual de lanzar varios mercados es lanzar varios sitios web. Funciona hasta el segundo: ahora hay dos tablas de usuarios, dos colas de moderación, dos integraciones de pago y dos lugares donde el mismo error tiene que ser corregido dos veces —y corregido de manera diferente, porque para entonces el código se ha desviado.
El extremo opuesto es igual de malo. Un sitio con una categoría llamada «Coches» no puede pedir kilometraje, motor y matrícula de la manera en que debe hacerlo un tablón de coches, y una búsqueda de bienes raíces que no puede filtrar por piso y habitaciones no es una búsqueda de bienes raíces. La tarea era mantener un solo motor sin pretender que siete catálogos muy diferentes son el mismo catálogo.
03Objetivos del proyecto
- un solo código base y una cuenta para todos los verticales, con el servicio elegido por el nombre de host;
- atributos y filtros por vertical: docenas de campos para coches y bienes raíces, ninguno de ellos arrastrado a los otros servicios;
- dinero en el que el propietario puede confiar: un saldo, facturas de criptomonedas, acreditación idempotente y reconciliación de pagos atascados;
- razones para que los compradores regresen: búsquedas guardadas con notificaciones, insignias de vendedor, subastas y compras grupales;
- dos idiomas y cuatro monedas de visualización sin duplicar contenido;
- una aplicación móvil que se comunica con un backend-for-frontend en lugar de raspar el sitio.
04Lo que hicimos
Construimos el registro de servicios en la secuencia de arranque. Llega una solicitud, el nombre de host se compara con el registro, y a partir de ese momento la aplicación sabe qué vertical es: qué módulos cargar, qué conjunto de atributos usar, qué página de inicio y qué menú renderizar. El dominio básico es el tablón de anuncios, por lo que la dirección más corta también es la más general.
Todo lo que no es específico de vertical se escribió una vez: cuentas y sesiones, el saldo y los pagos, la recepción de medios, moderación, búsquedas guardadas, notificaciones, el mapa del sitio y la API. Agregar el séptimo servicio fue principalmente escribir sus atributos y su página de inicio, no otro mercado.
05Siete servicios, siete catálogos
- Clasificados — el tablón general: cualquier cosa, desde una bicicleta hasta un sofá, gratis para publicar.
- Coches — vehículos, matrículas y piezas, con un conjunto de atributos dedicado de varias docenas de campos y filtros construidos sobre él.
- Bienes raíces — venta y alquiler, su propio conjunto de atributos, mapas y búsqueda por distrito.
- Mercado — productos con tiendas de vendedores: una vitrina por vendedor, stock, pedidos.
- Digital — claves, tarjetas de regalo y eSIM: productos que se entregan, no se envían.
- Ofertas — cupones y códigos promocionales de tiendas asociadas.
- Precio — un agregador de precios: el mismo producto en diferentes tiendas, comparado, con clics salientes contados.
Comparten la cuenta, el saldo, la cola de moderación y el índice de búsqueda — y no comparten nada en sus atributos, que es el punto.
06Dinero: un saldo, facturas de criptomonedas, conciliación
Las funciones pagadas — promoción, planes de tienda, bienes digitales — se pagan desde un saldo interno, y el saldo se recarga con cripto a través de Payora, nuestra propia pasarela. El cuerpo de la factura se construye en exactamente una función, porque el mismo cuerpo es reproducido por el cron de reconciliación bajo la misma clave de idempotencia: un solo campo que difiera entre los dos volvería como un conflicto y dejaría el pago pendiente.
Dos detalles que repetiríamos en cualquier pasarela. La factura lleva la localidad propia del comprador tomada de su fila de cuenta, no de la solicitud web — el cron no tiene solicitud y de otro modo enviaría a todos en inglés. Y lleva una dirección de retorno que regresa a la cuenta en el dominio base, por lo que un comprador que comenzó en la vertical de coches regresa conectado, no a una página que les pide que inicien sesión nuevamente.
07Confianza: moderación, insignias, disputas
Un mercado se juzga por su peor anuncio, así que la moderación no es un aspecto secundario aquí. Cada decisión — aprobar, rechazar, eliminar — pasa por un único manejador, y «rechazar» no es deliberadamente lo mismo que «eliminar»: el primero es una respuesta al autor con una razón, el segundo elimina algo que ya estaba activo. Dos verbos, dos letras diferentes, dos estados diferentes en el registro.
Los vendedores y las tiendas llevan insignias que se ganan, no se compran: cuánto tiempo ha existido la cuenta, cuántos tratos se han cerrado, si el teléfono y el correo electrónico están confirmados. El comprador ve la misma insignia en todos los lugares donde aparece el vendedor, porque se calcula en un solo lugar.
08Buscar, búsquedas guardadas y notificaciones
La búsqueda sabe en qué vertical se encuentra. En el tablón de coches ofrece los campos que tiene un coche; en bienes raíces ofrece habitaciones, piso y distrito; en el tablón general se mantiene deliberadamente simple. Las sugerencias provienen de un endpoint propio, así que el campo responde mientras la página aún se está leyendo.
Una búsqueda se puede guardar — y eso es lo que convierte a un visitante en uno recurrente. Nuevos coincidencias llegan como una notificación web, la suscripción pertenece a la cuenta en lugar de a la pestaña del navegador, y el mismo mecanismo lleva los eventos que la gente realmente espera: una subasta a punto de cerrarse, una compra grupal que alcanzó su umbral.
09Una aplicación móvil con su propio backend
La aplicación no raspa el sitio web. Habla con un backend-for-frontend propio: un pequeño conjunto de endpoints que responden en las formas que necesitan las pantallas, con tokens emitidos por separado de las sesiones web. Dos caminos están abiertos sin un token — los datos de referencia que la aplicación necesita antes de que alguien inicie sesión, y un endpoint de salud.
Ese endpoint de salud es una dirección separada a propósito. El registro que observa la flota solía preguntar al endpoint de referencia, y ese ensambla cada diccionario y cada tarifa — una verificación de vitalidad no debería costar más que el trabajo. También responde con la versión del contrato, por lo que un cliente construido para un contrato más antiguo es notado antes de que sus usuarios lo noten.
10Siete frentes de SEO
Siete servicios en un dominio significa siete sitemaps, siete conjuntos de datos estructurados y una forma muy fácil de producir duplicados. Cada vertical publica su propio sitemap desde la caché, las páginas de listado declaran su propio tipo de datos estructurados, y las páginas de resultados de búsqueda nunca afirman ser canónicas para un listado.
El lado del contenido también está automatizado: un flujo editorial llega de Astrina, la plataforma que construimos para exactamente esto, y en el momento en que un artículo llega, la caché del sitemap para su vertical se elimina — de lo contrario, la nueva página esperaría la próxima reconstrucción y nadie sabría por qué faltaba.
11Un canal saliente
Todo lo que la aplicación envía hacia afuera — llamadas a la API, webhooks, feeds de socios, imágenes que recupera, correo — pasa a través de un único módulo vinculado a un proxy de salida SOCKS5, con DNS resuelto a través del proxy también. El módulo es de cierre en fallo: si el proxy no está disponible, la solicitud se bloquea en lugar de enviarse silenciosamente desde la propia dirección del servidor.
Esto no es decoración. Un mercado extrae feeds de socios e imágenes remotas todo el día; cada uno de esos es una solicitud que de otro modo llevaría la dirección de origen del sitio a un tercero. El correo va de la misma manera, a través de TuTendencia, por lo que las cartas están firmadas y el nombre del host del servidor nunca aparece en un encabezado.
12Pila tecnológica
- PHP 8.3 sin un marco, un delgado envoltorio PDO y declaraciones preparadas en todas partes;
- MariaDB, esquema mantenido como archivos de migración numerados en lugar de como la memoria de alguien;
- medios almacenados fuera de la raíz web y servidos por un controlador, por lo que una carga nunca es una ruta ejecutable;
- un paso de construcción que hash assets y no incluye nada que deba ser almacenado en caché, con un interruptor de apagado para cuando se comporta mal;
- salida SOCKS5 para cada llamada saliente, correo a través de YourTrend SMTP;
- Payora para facturas de criptomonedas, Astrina para inicio de sesión y contenido editorial, Adgora para publicidad interna.
13El resultado
Siete servicios en vivo en una única base de código, una cuenta y un saldo en todos ellos, con atributos y filtros que difieren tanto como los catálogos. Un nuevo vertical es un conjunto de atributos y una página de inicio — no un nuevo proyecto, no una segunda tabla de usuarios, no una segunda integración de pago.
Lo que el propietario obtiene día a día es un lugar para mirar. La moderación, el dinero, los vendedores y el contenido se gestionan desde el panel de control compartido de todo el grupo, y el mercado los expone a través de una API de administración firmada en lugar de a través de un segundo sitio de administración propio.
14Conclusiones
La lección que llevaríamos al siguiente mercado: comparte la maquinaria, no el significado. Las cuentas, el dinero, la moderación y la búsqueda son el mismo problema en cada vertical y deben escribirse una vez. Los atributos, filtros y la forma de un anuncio son el producto en sí, y forzarlos en una tabla universal es cómo los mercados se vuelven inutilizables para todos al mismo tiempo.
La segunda lección es sobre el dinero. El lugar donde se describe un pago debe ser una única función, porque algo más lo reproducirá — un cron, un reintento, una conciliación — y dos descripciones de un pago es la forma más barata de perder dinero silenciosamente.
Si estás construyendo un mercado, un tablón de anuncios o una plataforma multi-vertical en un solo motor, este es el tipo de trabajo que hacemos de principio a fin.



