LS

LeadSpark CRM — Arquitectura Backend Xano

SaaS B2B para agencias de marketing · Diseño completo de API, base de datos e integraciones
Xano No-Code Backend
5 tablas relacionales
18 endpoints REST
4 integraciones externas
JWT + roles auth
🗄️ Modelo de Datos — Tablas Xano
U
users
Usuarios y roles del sistema
idintegerPK
emailtextunique, indexed
nametextrequired
passwordpasswordhashed auto
roleenumadmin/agente/viewer
planenumstarter/pro
stripe_cidtextstripe customer id
created_attimestampauto
L
leads
Prospectos y oportunidades
idintegerPK
pipeline_idintegerFK
assigned_tointegerFK
nametextnombre contacto
emailtextcontacto
companytextempresa
statusenumnuevo→cerrado
value_eurdecimalvalor estimado
last_activitytimestampúltima acción
P
pipelines
Embudos de ventas
idintegerPK
owner_idintegerFK
nametextnombre pipeline
stageslist[text]etapas custom
colortexthex color
is_activebooleandefault: true
A
activities
Registro de acciones por lead
idintegerPK
lead_idintegerFK
user_idintegerFK
typeenumcall/email/meeting
notestexttexto libre
scheduled_attimestampnullable
created_attimestampauto
$
subscriptions
Suscripciones Stripe
idintegerPK
user_idintegerFK
stripe_sub_idtextsub_xxx
planenumstarter/pro
statusenumactive/cancelled
amount_eurdecimal49/149
next_billingtimestamppróximo cobro

Endpoints REST — 18 rutas en 5 grupos de API
/api:auth
Autenticación JWT — registro, login, perfil, roles
POST /auth/signup Registro de nuevo usuario (nombre, email, pass) → devuelve JWT PUBLIC
POST /auth/login Login con email/password → devuelve JWT + datos de usuario PUBLIC
GET /auth/me Devuelve el usuario autenticado (id, name, email, role, plan) JWT
PATCH /auth/me Actualiza datos del perfil (name, avatar_url) JWT
/api:leads
CRUD de leads con filtros, paginación y asignación
GET /leads Listado paginado con filtros: status, pipeline_id, assigned_to, búsqueda JWT
POST /leads Crear lead nuevo. Asignación auto al agente con menos leads activos JWT
GET /leads/:id Detalle del lead con actividades recientes (join activities, 5 últimas) JWT
PUT /leads/:id Actualizar lead. Si cambia assigned_to → dispara email notificación Resend JWT
DELETE /leads/:id Soft-delete (status = "archivado"). Solo admin/agente propietario ADMIN
/api:pipelines
Gestión de embudos de ventas personalizables
GET /pipelines Listar pipelines del usuario (owner_id = auth.id, o todos si admin) JWT
POST /pipelines Crear pipeline. Plan Starter: máx 2 pipelines. Pro: ilimitado JWT
PUT /pipelines/:id Editar nombre, etapas y color del pipeline JWT
GET /pipelines/:id/stats KPIs del pipeline: leads por etapa, valor total, tasa conversión JWT
/api:activities
Log de acciones por lead
POST /activities Registrar acción. Actualiza last_activity en lead JWT
GET /activities/lead/:id Historial paginado de un lead JWT
/api:webhooks
Webhooks entrantes externos
POST /webhook/calendly Reunión agendada → crea actividad tipo meeting en lead PUBLIC
POST /webhook/stripe Eventos Stripe: pago ok/fallo → actualiza plan en users PUBLIC

🔧 Function Stacks — Lógica Visual en Xano
POST /api:leads/leads Crear lead con asignación
1
Auth
Verificar JWT · obtener user_id y role
2
Input
name, email, company, pipeline_id, value_eur
validación: required(name, email), type(value_eur=decimal)
3
Query
Agente con menos leads activos
SELECT user_id, COUNT(*) FROM leads WHERE status != 'cerrado' GROUP BY user_id ORDER BY count ASC LIMIT 1
4
DB Add
Insertar en tabla leads
status='nuevo', assigned_to=step3.user_id, last_activity=NOW()
5
Ext API
Resend — email al agente asignado
POST https://api.resend.com/emails · "Nuevo lead: {name}"
6
Return
{ id, name, status, assigned_to, created_at }
GET /api:pipelines/pipelines/:id/stats KPIs del pipeline
1
Auth
Verificar JWT · comprobar ownership del pipeline
2
Query
Leads por status en este pipeline
GROUP BY status · COUNT + SUM(value_eur)
3
Variable
Calcular tasa conversión
cerrado / total * 100 → conversion_rate
4
Query
Leads sin actividad >7 días
WHERE last_activity < NOW() - INTERVAL 7 DAY AND status != 'cerrado'
5
Return
{ by_status[], total_value_eur, conversion_rate, stale_leads }

🔌 Integraciones Externas
💳
Stripe
Pagos y suscripciones recurrentes
1
POST a stripe.com/v1/subscriptions al registrarse
2
Webhook /webhook/stripe recibe invoice.paid / customer.subscription.deleted
3
Condicional: actualiza users.plan y subscriptions.status
4
Si pago fallido: notificación email + downgrade a plan free tras 3 días
📧
Resend
Emails transaccionales automáticos
1
Al asignar lead: "Tienes un nuevo lead — {nombre}" al agente
2
Al crear cuenta: bienvenida con onboarding steps
3
Tarea cron diaria: resumen de leads inactivos al admin
4
Headers: Authorization: Bearer re_xxx · from: hola@leadspark.io
📅
Calendly
Webhook de reuniones agendadas
1
Xano expone POST /webhook/calendly como endpoint público
2
Payload contiene invitee.email → buscar lead por email
3
Si existe: crear activity tipo meeting + actualizar last_activity
4
Si no existe: crear lead nuevo con status contactado
Tarea Cron Diaria
Resumen leads inactivos · 09:00 CET
1
Cron schedule: 0 9 * * * (Europa/Madrid)
2
Query: leads WHERE last_activity < NOW()-7days AND status != cerrado
3
Agrupar por agente asignado · construir tabla resumen
4
Resend: email a cada admin con la tabla de leads dormidos

💻 Cliente TypeScript — Next.js Integration
lib/leadspark-api.ts TypeScript
// LeadSpark CRM — Cliente para Xano Backend
// Instancia: https://leadspark.xano.io

const BASE = "https://leadspark.xano.io";

// ── AUTH ──────────────────────────────────────────
export const authLogin = async (email: string, password: string) => {
  const res = await fetch(`${BASE}/api:auth/auth/login`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email, password }),
  });
  const { authToken, user } = await res.json();
  localStorage.setItem("ls_token", authToken);
  return { authToken, user };
};

// ── LEADS ──────────────────────────────────────────
interface LeadsQuery {
  page?: number; per_page?: number;
  status?: "nuevo" | "contactado" | "calificado" | "propuesta" | "cerrado";
  pipeline_id?: number;
}

export const getLeads = async (token: string, query: LeadsQuery = {}) => {
  const params = new URLSearchParams({
    page: String(query.page ?? 1),
    per_page: String(query.per_page ?? 20),
    ...(query.status && { status: query.status }),
    ...(query.pipeline_id && { pipeline_id: String(query.pipeline_id) }),
  });
  const res = await fetch(`${BASE}/api:leads/leads?${params}`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  return res.json(); // { items: Lead[], total, page, pages }
};

export const createLead = async (token: string, data: {
  name: string; email: string; company: string;
  pipeline_id: number; value_eur: number;
}) => {
  const res = await fetch(`${BASE}/api:leads/leads`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify(data),
  });
  return res.json(); // { id, name, status, assigned_to, created_at }
};

📋 Directrices de Producción
1
Datos primero
Diseña las tablas y relaciones antes de construir endpoints. Xano genera CRUD automáticamente desde el schema.
2
Lógica en Function Stacks
Toda la lógica de negocio va en Xano. El frontend Next.js solo consume. Nunca pongas reglas de negocio en el cliente.
3
Auth JWT integrado
Usa el sistema de auth nativo de Xano. No construyas el tuyo. Configura expiración del token a 7 días (renovar con refresh token).
4
Paginación obligatoria
Todos los endpoints de listado llevan page y per_page. Máximo 50 registros por página. Las queries sin límite degradan el rendimiento.
5
Rate limiting en endpoints públicos
Activa rate limiting en /auth/signup, /auth/login y webhooks entrantes: máx 20 req/min por IP.
6
Grupos de API por dominio
Separa auth, leads, pipelines, activities y webhooks en grupos distintos. Facilita versioning y control de acceso.
7
Validación de inputs
Cada endpoint valida required, type, min/max en Xano antes de ejecutar lógica. Nunca confíes en el frontend para validar.
8
SQL avanzado con Addons
Para agregaciones complejas (stats del pipeline, ranking de agentes) usa Xano Addons con SQL raw en lugar de forzar la lógica visual.
Xano No-Code Backend REST API JWT Auth Next.js Stripe Resend Calendly Webhook Function Stacks CRM SaaS TypeScript