ZocialyMás de 5.000 servicios en 6 plataformas

Haz que tus redes despeguen

Panel SMM con precio calculado en servidor, saldo atómico y aviso de riesgo imposible de saltar

Plataforma web2026
Sin suscripción Sin pedir tu contraseña Soporte en español

Seguidores · últimas 12 semanas

0

▲ 312 %

Incluida la corrección natural del final: así se comporta una cuenta real.

Entrega iniciada · hace 2 sPrecio recalculado en servidor

En producción en https://zocialy-47c9c.web.app · compila limpio (typecheck + build) · pendiente saldo en Peakerr y pasarela automática

Plataforma web · Marketing en redes sociales (SMM) · Diseño de producto, arquitectura y desarrollo full-stack: landing, panel de cliente, panel de administración, API de reventa y app móvil de administración

01 / El repositorio

Ocho barras que se levantan solas

Un panel de métricas contado como panel de métricas: cada columna es una cifra real del proyecto, en escala logarítmica para que la más grande no aplaste a las demás.

28

Pantallas (page.tsx)

36

Rutas de API en el servidor

16

Colecciones de Firestore

54

Componentes React

22

Ficheros de test con node:test

~40.000

Líneas de TypeScript en la web

11

Pantallas en la app Flutter de admin

6

Métodos de recarga configurados

InstagramSeguidores · ReelsTikTokViews · LikesYouTubeSuscriptoresFacebookPágina · PostXFollowersTelegramMiembros · Vistas
InstagramSeguidores · ReelsTikTokViews · LikesYouTubeSuscriptoresFacebookPágina · PostXFollowersTelegramMiembros · Vistas
InstagramSeguidores · ReelsTikTokViews · LikesYouTubeSuscriptoresFacebookPágina · PostXFollowersTelegramMiembros · Vistas
InstagramSeguidores · ReelsTikTokViews · LikesYouTubeSuscriptoresFacebookPágina · PostXFollowersTelegramMiembros · Vistas
02 / El encargo

Tres vicios del mercado y dos exigencias del contexto

El problema

Los paneles SMM del mercado comparten tres vicios: prometen crecimiento perpetuo escondiendo que las plataformas depuran cuentas y las métricas caen; confían el precio y el estado del pedido al navegador, que es exactamente donde no debe decidirse el dinero; y arrastran catálogos de miles de servicios que obligan a descargar la colección entera solo para rellenar un desplegable, con una factura de Firestore que crece sin que nadie la mire. A eso se sumaban dos exigencias del contexto venezolano: cobrar en bolívares con la tasa oficial del BCV, que no publica API y sirve la cifra dentro del HTML con una cadena de certificados incompleta, y verificar cada pago a mano sin que un doble clic acredite el saldo dos veces.

La solución

Se construyó un panel donde el navegador nunca escribe dinero ni estado. `/api/orders` ignora el importe que envía el cliente y lo recalcula desde `serviceId` + `quantity` con la misma función pura (`calculateCharge`) que usa la tarjeta de producto, el formulario y la API de reventa, así que lo que se muestra y lo que se cobra no pueden divergir. El cobro ocurre dentro de una transacción de Firestore y, si Peakerr rechaza el pedido, el importe vuelve al saldo con su movimiento trazado. La transparencia de riesgos se resolvió con una sola constante de texto (`RISK_NOTICE_TEXT`) que alimenta a la vez el formulario de compra, la página de política de refill y el resumen de la landing, con tres cerrojos encadenados: el hook no habilita el botón, el submit corta y la API devuelve 400. El coste se atacó sustituyendo listeners en vivo por páginas con cursor `startAfter`, agregaciones `count`/`sum` en servidor y un documento agregado `catalog/index` de 8 KB que reduce el formulario de pedido de más de 3.000 lecturas a una más la categoría elegida. Las recargas siguen un flujo manual verificado por un humano, con la tasa congelada en cada solicitud, aprobación idempotente y aviso a Telegram que jamás puede tumbar una solicitud ya guardada.

03 / La barrera

Aquí no se lee una advertencia: se choca contra ella

Un único texto constante alimenta compra, política y landing; el hook no habilita el botón sin aceptación, el submit corta y la API rechaza con 400. Cada pedido guarda `riskAcknowledgedAt` y `riskNoticeVersion` para dejar constancia de qué texto aceptó cada cliente.

1. El hook no habilita 2. El submit corta 3. La API responde 400

Puerta de pago

Total del pedido$ 1,14

Aviso importante: las métricas pueden fluctuar o descender tras la entrega. Las plataformas depuran cuentas y parte de lo entregado puede caer.

Confirmar pedido

Marca la casilla para desbloquear el botón. Es la única llave.

04 / Decisiones

Seis piezas donde se juega la confianza

01

El aviso de riesgo es una barrera, no un párrafo

Un único texto constante alimenta compra, política y landing; el hook no habilita el botón sin aceptación, el submit corta y la API rechaza con 400. Cada pedido guarda `riskAcknowledgedAt` y `riskNoticeVersion` para dejar constancia de qué texto aceptó cada cliente.

02

El dinero se decide en el servidor

El importe que envía el navegador se ignora y se recalcula desde servicio y cantidad; el saldo se descuenta en una transacción de Firestore, así que dos pestañas no gastan el mismo saldo dos veces, y un rechazo del proveedor dispara el reembolso automático con su movimiento trazado.

03

Firestore paginado con cursores y agregaciones

Nada de `onSnapshot` sobre listas ni de `offset`: páginas con `startAfter`, `limit(pageSize + 1)` para saber si hay siguiente sin una segunda consulta, y `getCountFromServer` / `getAggregateFromServer` para los resúmenes. El formulario de pedido bajó de más de 3.000 lecturas a una más la categoría elegida.

04

Claves de reventa con hash y consentimiento firmado

La API pública `/api/v2` imita el estándar de facto de los paneles SMM (POST form-urlencoded, siempre HTTP 200 con `error`). La clave solo vive como SHA-256 y se enseña una vez; como una API no tiene pantalla donde mostrar el aviso, el consentimiento se firma al generarla y cada pedido lo hereda.

05

El grupo de Telegram se conecta escribiendo `/id`

El enlace de invitación de un grupo privado no da `chat_id` y el modo privacidad oculta los mensajes normales al bot, pero los comandos siempre llegan. El webhook guarda el chat en `settings/site` con doble cerrojo: el secreto de cabecera de Telegram y el ID del administrador.

06

Tasa del BCV raspada con salvaguarda de rango

El BCV no tiene API y su cadena de certificados está incompleta, así que se usa el módulo `https` con la verificación relajada solo en esa petición. El parser lee `<div id="dolar">` en formato venezolano y rechaza cualquier cifra fuera de rango antes que cobrar mal; el refresco es perezoso y la tasa se congela en cada solicitud.

05 / La interfaz

Un producto, tres puertas

Cliente, administración y teléfono comparten paleta, tipografía y reglas. Todo en tema claro forzado, todo en español, incluidas las rutas.

zocialy-47c9c.web.app/panel

Dashboard

Resumen de tu cuenta · cifras calculadas en servidor

Saldo disponible

$ 128,40

Recargar

7

Pedidos activos

241

Completados

98,4 %

Tasa de entrega

12

Refills aprobados

Productos destacados

Instagram

Seguidores reales · 30d refill

5001K5K

$ 1,20 / 1.000

TikTok

Views rápidas HQ

5001K5K

$ 0,08 / 1.000

YouTube

Suscriptores estables

5001K5K

$ 4,60 / 1.000

PedidoServicioCantidadImporteEstado
a91f4c7dIG · Seguidores 30d1.000$ 1,20Completado
7b0e22aaTT · Views HQ10.000$ 0,80En progreso
c4d81903YT · Suscriptores250$ 1,15Pendiente
2f6ab5e1FB · Likes de página500$ 0,45Cancelado

Panel del cliente — dashboard

zocialy-47c9c.web.app/panel/nueva-orden

Nueva orden

Red → categoría → servicio

Red social

InstagramTikTokYouTubeFacebookXTelegram

Categoría

Instagram · Seguidores

Servicio

seguidores 30d…
1842 · IG Followers Real | 30d Refill$ 1,20 / 1.000
1907 · IG Followers Mix | No refill$ 0,74 / 1.000

Enlace

El enlace debe apuntar al perfil, no a una publicación.

instagram.com/p/C8xk…

Eso es una publicación. Pega la URL del perfil.

Cantidad

1.000
mín. 100 · máx. 100.000
Tarifa por 1.000$ 1,20
Cantidad1.000
Descuento aplicado− $ 0,06
Total$ 1,14

Aviso importante: las métricas pueden fluctuar o descender tras la entrega. Ver política de refill

  • · Entrega estimada entre 1 y 24 horas.
  • · Fluctuación normal durante las primeras 72 h.
  • · Ventana de garantía según el servicio elegido.
Entiendo y acepto el aviso sobre la fluctuación de métricas.
Confirmar pedido

Saldo $ 128,40 · quedarán $ 127,26

Nueva orden — cascada y puerta de pago

zocialy-47c9c.web.app/admin

Resumen

Cifras calculadas en servidor sobre todo el histórico

Sincronizar catálogo

Facturación total

$ 9.482,10

Pedidos activos

34

Tasa de entrega

97,6 %

Refills en revisión

3

Pedidos totales

4.117

Usuarios registrados

612

Cuentas suspendidas

Saldo en circulación

$ 1.204,55

Deuda pendiente con clientes

Últimos pedidos

Ver todos
a91f4c7dana.***@gmail.comIG · Seguidores 30d$ 1,20Completado14:02
7b0e22aajos***@hotmail.comTT · Views HQ 10K$ 0,80En progreso14:02
c4d81903mar***@gmail.comYT · Suscriptores 250$ 1,15Pendiente14:02

Administración — resumen

zocialy-47c9c.web.app/admin/metricas

Métricas

Tráfico, embudo de conversión e ingresos. Los días se cortan en UTC

7 días14 días30 días
Actualizar

Hoy, comparado

Vistas de página

1.284+16,0 %

Ayer 1.107 · media 7 d 1.036

Sesiones

612+4,1 %

Ayer 588 · media 7 d 551

Visitantes nuevos

204−12,4 %

Ayer 233 · media 7 d 241

El día va por las 14 h de 24 (UTC)

Vistas de página

máx. 72 · media 37 · total 521

Sesiones

máx. 41 · media 22 · total 308

Páginas más vistas

/412
/precios268
/panel141

Países

Venezuela381
Colombia144
México96

Fuentes

Directo302
Instagram188
Google97

Administración — métricas del sitio — sparklines dibujados a mano, sin librería de gráficas.

Zocialy admin

Recargas

3
PendientesAprobadasRechazadas
Pago Móvil$ 20,00

Bs 3.284,00 · tasa congelada · ref. 004417832

AprobarRechazar
Binance Pay$ 50,00

USDT 50,00 · tasa congelada · ref. 8812-KQ

Toca para revisar el comprobante

Zinli$ 10,00

$ 10,00 · tasa congelada · ref. ZN-4471

Toca para revisar el comprobante

ResumenRecargasPedidosMás

App Flutter de administración — la misma paleta, para aprobar recargas desde el teléfono.

Las maquetas reproducen la interfaz real; los datos que muestran son de ejemplo.

06 / La marca

Una Z que despega hasta un punto cian

Optimista y de producto: violeta profundo que abre a magenta y coral, como una flecha que despega. Neutros entintados de violeta para que ningún gris se vea sucio al lado de la marca, superficies blancas con sombras muy difusas de tinte morado, esquinas muy redondeadas (hasta 2rem) y un punto cian (#6bc5dc) usado con cuentagotas. Los semánticos (ámbar aviso, esmeralda correcto, rosa error) se dejan fuera de la marca a propósito: un aviso de riesgo no debe teñirse de violeta. Tema claro forzado con `color-scheme: light`.

#7a3fc4#421f6e#f0547e#faf9fd#ffffff#211a2e
Lockup completo de Zocialy: isotipo en degradado violeta a coral junto al wordmark.
Lockup completo de Zocialy: isotipo en degradado violeta a coral junto al wordmark.
Lockup completo de Zocialy: isotipo en degradado violeta a coral junto al wordmark.
Isotipo original a alta resolución; de esta imagen se muestreó píxel a píxel toda la paleta del producto.
Isotipo original a alta resolución; de esta imagen se muestreó píxel a píxel toda la paleta del producto.
Isotipo suelto, separado del wordmark para poder componer el lockup horizontal de la navegación sin deformar nada.
Isotipo suelto, separado del wordmark para poder componer el lockup horizontal de la navegación sin deformar nada.
Wordmark suelto en imagen, no en texto, para conservar la tipografía original de la marca.
Wordmark suelto en imagen, no en texto, para conservar la tipografía original de la marca.
Icono de aplicación 512×512 declarado en el manifest de la PWA.
Icono de aplicación 512×512 declarado en el manifest de la PWA.
Icono de aplicación 192×192 del manifest.
Icono de aplicación 192×192 del manifest.
Favicon de 32 píxeles.
Favicon de 32 píxeles.
El mismo lockup empaquetado como asset de la app Flutter de administración.
El mismo lockup empaquetado como asset de la app Flutter de administración.

Arrastra la tira · 8 piezas de marca, todas derivadas del mismo isotipo.

07 / Arquitectura

El navegador no escribe dinero

El importe que llega del cliente se descarta. La misma función pura que pintó el precio en pantalla lo recalcula en el servidor, y el saldo se mueve dentro de una transacción.

Navegador

POST /api/orders

  • serviceId: 1842
  • quantity: 1000
  • amount: 0.01

El importe se ignora.

Cloud Run · Next.js

calculateCharge(serviceId, quantity)

La misma función pura que usa la tarjeta de producto, el formulario y la API de reventa. Lo que se muestra y lo que se cobra no pueden divergir.

runTransaction · cobro atómico
Firestore
  • users/{uid}.balance− 1,14
  • orders/{id}creado
  • transactions/{id}movimiento

Si Peakerr rechaza, el importe vuelve con su movimiento trazado.

Monorepo web en `/Users/macbook/zocialy` con el App Router de Next.js como única aplicación: `src/app/page.tsx` es la landing, `src/app/panel/*` el área de cliente (guarda de sesión), `src/app/admin/*` la de gestión (guarda `role=admin`) y `src/app/api/*` las 36 rutas de servidor. La lógica de negocio vive en `src/lib` en módulos puros que no importan el SDK a propósito —`pricing.ts`, `commissions.ts`, `referrals.ts`, `classify.ts`— para poder ejecutarse tal cual con `node --test`; los adaptadores con estado (`lib/firebase/admin.ts`, `lib/peakerr/client.ts`, `lib/bcv.ts`, `lib/trm.ts`) llevan `server-only`, de modo que el build falla si alguien intenta importar la clave del proveedor desde el navegador. Los datos se modelan en `lib/firebase/schema.ts` sobre 16 colecciones de Firestore, y las reglas declaran la frontera real: el cliente lee lo suyo y no escribe ni saldo ni estado de pedido. La lectura se hace siempre con `usePagedCollection` (cursores `startAfter` y `limit(pageSize + 1)`), y los resúmenes con agregaciones de servidor. Todo el despliegue va a Firebase Hosting con `frameworksBackend`, es decir, la app entera corre en Cloud Run sin una carpeta `functions/`. Aparte, `/Users/macbook/zocialy_admin` es una app Flutter independiente (Riverpod + go_router, ~7.300 líneas de Dart) que ataca las mismas colecciones y las mismas rutas de API con el token del administrador, reproduciendo píxel a píxel la paleta de la web para que se sientan un mismo producto.

08 / Entregado

Lista de entrega: 19 de 19

No es una lista de deseos: es lo que ya está en producción, contado como el panel cuenta un pedido completado.

01Landing pública con hero animado, marquesina de plataformas, tabla de precios y resumen del aviso de riesgo
02Dos puertas de acceso separadas: clientes solo con Google, administración solo con email + contraseña y custom claim `role: admin`
03Formulario de pedido en cascada red → categoría → servicio, con validación de forma del enlace y guía por métrica
04Puerta de pago (`PaymentGate`) como único componente autorizado a renderizar un botón de compra
05Catálogo sincronizado desde Peakerr con normalización de texto (emojis, Unicode matemático, İ turca) y clasificación automática
06Doble verdad del refill: lo que el proveedor anuncia (`refill`) y lo que la API puede ejecutar (`refillViaApi`), con cola manual cuando no hay automatismo
07Recargas de saldo con seis métodos (Pago Móvil, Nequi, Binance Pay, Zinli, PayPal, Wally), importe convertido a moneda local y tasa congelada
08Aprobación idempotente de recargas en `/admin/recargas` con acreditación, movimiento y auditoría en una sola transacción
09Programa de afiliados con niveles de trinquete, comisiones en enteros de diezmilésima de dólar y correos de referidos enmascarados por el servidor
10Retiros de ganancias con identidad de cobro e histórico propio
11Productos destacados curados, con escalones de cantidad y compra rápida en hoja modal
12Analítica propia: recolección de eventos, agregación diaria y pantalla de métricas con comparativas contra ayer y contra la media de 7 días
13Auditoría inmutable: toda acción de administración queda en `auditLog`, que ni un admin puede escribir desde el cliente
14API pública `/api/v2` para revendedores con clave hasheada y limitación de peticiones
15Sistema de tickets de soporte con hilo de mensajes
16Avisos a Telegram para recargas y retiros, con registro del chat por comando
17Rutas de cron para sincronizar catálogo y estados de pedido
18App Flutter de administración con notificaciones push para aprobar recargas desde el teléfono
19Política de limpieza de Artifact Registry documentada para no pagar imágenes de despliegues viejos
09 / Stack

Con qué está construido

Web

Next.js 15 (App Router)React 19TypeScript 5.6Tailwind CSS 3.4PostCSSAutoprefixer

Backend y datos

Firebase 12 (Auth + Firestore)firebase-admin 13server-onlyFirebase Hosting con frameworksBackend (Cloud Run, us-central1)Reglas e índices de Firestore versionados

App de administración

Flutter (Dart SDK ^3.10)firebase_corefirebase_authcloud_firestorefirebase_messagingflutter_riverpodgo_routergoogle_fontsflutter_animateshimmerfl_chartintlhttpurl_launcherflutter_local_notificationsflutter_launcher_icons

Integraciones

API de Peakerr (catálogo y despacho de pedidos)Telegram Bot API (webhook)Banco Central de Venezuela (raspado de la tasa oficial)

Calidad y operación

node:test con --experimental-strip-typestsc --noEmitFirebase CLIgcloud Artifact Registry (política de limpieza)
10 / Lo que costó

Nueve piedras y cómo se apartaron

reto 01

El formulario de pedido necesitaba los más de 3.000 servicios del catálogo solo para rellenar tres desplegables, y cada visita se facturaba entera.

solución

La sincronización escribe un documento agregado `catalog/index` de 8 KB con las redes y categorías, y los servicios se piden solo de la categoría que el usuario elige. La pantalla pasó de más de 3.000 lecturas a una más un lote de unos cientos, y solo cuando hace falta.

reto 02

El flag `refill` de Peakerr no es fiable: cientos de servicios lo traen en `false` mientras anuncian «Refill 30d» en el nombre, y otros lo traen en `true` sin mencionarlo.

solución

Se guardan las dos verdades en lugar de elegir una: `refill` es lo que el proveedor anuncia y es lo que ve el cliente; `refillViaApi` es si la acción automática funcionará. Cuando no hay automatismo la solicitud se registra igual y queda en cola manual, porque ocultar una garantía anunciada perjudica al cliente y prometer un botón que va a fallar, también.

reto 03

El texto que devuelve el proveedor está escrito por humanos: emojis decorativos, caracteres matemáticos Unicode, banderas, la İ turca que NFKC no descompone y tres grafías distintas de «TikTok».

solución

`lib/peakerr/classify.ts` normaliza con `cleanText` antes de reconocer nada, con casos explícitos para los caracteres que la normalización estándar no resuelve, y el resultado se verifica contra el catálogo real con scripts de comprobación en `scripts/`.

reto 04

El BCV no publica API, sirve la tasa dentro del HTML en formato venezolano y su cadena de certificados está incompleta, con lo que Node falla con `UNABLE_TO_VERIFY_LEAF_SIGNATURE`.

solución

Se usa el módulo `https` con la verificación desactivada únicamente en esa petición, en lugar de tocar `NODE_TLS_REJECT_UNAUTHORIZED`, que la relajaría también para Firebase y Peakerr. El parser lee la cifra de `<div id="dolar">`, la convierte desde el formato local y aplica una salvaguarda de rango: si un cambio de maquetación hiciera leer un año o un teléfono, se rechaza antes que cobrar mal.

reto 05

Aprobar una recarga dos veces —un doble clic, dos pestañas— acreditaría el saldo dos veces, que es el error clásico de este tipo de cola.

solución

La aprobación es una transacción idempotente: vuelve a leer el estado antes de acreditar, y acredita saldo, registra el movimiento y escribe la auditoría en el mismo bloque atómico. Se suman dos límites antifraude: máximo tres solicitudes pendientes por usuario y referencias de pago no reutilizables.

reto 06

El aviso al canal de Telegram estaba en el camino del dinero: si Telegram fallaba, la solicitud de recarga se caía con él.

solución

El módulo de avisos no lanza nunca. La solicitud se guarda primero y el aviso se intenta después; si Telegram no responde, el administrador la ve igual en el panel. El dinero del cliente no puede depender de la disponibilidad de un bot.

reto 07

El menú del panel de cliente tiene nueve destinos y la barra inferior de móvil solo admite cuatro sin aplastar los textos, así que Historial, Afiliados, API, Garantía y Soporte quedaban inalcanzables desde el teléfono, que es por donde entra la mayoría.

solución

Los cuatro destinos fijos se seleccionan por `href` y no por posición (antes un `slice(0, 4)` expulsaba «Saldo» al insertar una entrada nueva), y un quinto botón abre el resto en una hoja, el patrón que usan las apps nativas. El botón «Más» se marca activo cuando la ruta actual está dentro de la hoja.

reto 08

`firebase-admin` es CommonJS y al empaquetarlo Next rompía la interoperabilidad: `AggregateField` llegaba como `undefined` y cualquier consulta con `sum()` reventaba solo en producción.

solución

Se declaró en `serverExternalPackages` para que se cargue en tiempo de ejecución tal cual lo publica el paquete. El fallo era invisible en local, que es la peor forma de encontrarlo.

reto 09

Cada despliegue dejaba una imagen de contenedor nueva en Artifact Registry; en dos días de trabajo se acumularon 5,5 GB en 22 imágenes, el único coste real del proyecto.

solución

Una política de limpieza documentada en `infra/artifact-cleanup.json`: nunca borrar una imagen etiquetada (Cloud Run sirve por etiqueta), conservar las tres más recientes y borrar las huérfanas. La imagen viva queda protegida dos veces.

Zocialy

Zocialy es un panel de servicios de marketing en redes sociales (seguidores, me gusta, visualizaciones) construido sobre Next.js 15 y Firebase, con el catálogo del proveedor mayorista Peakerr como fuente de servicios.

Son tres productos en un mismo repositorio: una landing pública animada sin librerías de motion, un panel de cliente con 9 secciones y un área de administración con 12, más una app Flutter aparte para aprobar recargas desde el teléfono.

La frontera de seguridad no está en el navegador: el precio se recalcula siempre en el servidor a partir de servicio y cantidad, el saldo se descuenta dentro de una transacción de Firestore y los roles viven en custom claims, no en un campo del documento que el usuario pueda escribir.

El requisito más delicado del cliente —advertir de la caída natural de métricas tras la entrega— está implementado como una barrera real: un único texto constante, un componente que siempre se renderiza antes del botón de pago y un rechazo 400 en la API si el pedido llega sin la aceptación firmada.

El proyecto está escrito íntegramente en español, incluidos rutas, nombres de estado en Firestore y comentarios de código, y toda la interfaz se sirve en tema claro forzado.

PeakerrFirestoreCloud RunTelegram Bot APITasa del BCVAPI de reventaRiverpodnode:testPeakerrFirestoreCloud RunTelegram Bot APITasa del BCVAPI de reventaRiverpodnode:test

Zocialy

¿Quieres algo así para tu producto?

Un panel donde el precio se decide en el servidor, el saldo se mueve en una transacción y la advertencia al cliente es una regla del sistema, no un párrafo decorativo. Si necesitas producto, pasarela y panel de gestión en el mismo repositorio, es exactamente este terreno.