Saltar al contenido
LDC App

Full Stack · SaaS · Gestión Operativa

Sistema de Gestión Integral para Academia de Baile

De hojas físicas y Excel a un sistema que gestiona 240+ alumnos, 12 géneros de baile y liquidación automática de profesores — construido en dos semanas, en producción desde marzo 2026

Construcción: 2 semanas — Producción: Mar 2026

240+
Alumnos activos
12+
Géneros de baile
12+
Profesores con contratos distintos
2 sem
De diseño a producción

#El problema

La academia tenía más de 240 alumnos activos — entre alumnos externos y miembros del equipo de competición con clases todos los días —, 12 géneros de baile y más de una docena de profesores. Cada uno con un contrato distinto: algunos cobran por cantidad de alumnos en clase, otros por porcentaje del ingreso, otros por clase fija. El proceso antes del sistema:

Asistencia en hojas físicas — papel, bolígrafo, y esperar que nadie olvidara anotar a alguien
Transcripción a Excel — cada semana, alguien pasaba las hojas a una planilla manualmente
Cálculo de pago de profesores — cruzar asistencia del mes con el contrato de cada uno, uno por uno
Si algo no cuadraba, había que buscar las hojas físicas del mes y rezar para que no se hubieran perdido

El cálculo de pago de un solo profesor tomaba más de una hora. Con múltiples profesores, el cierre de mes era un proceso de días, lleno de incertidumbre y margen de error. El dueño no podía confiar en los números porque los números dependían de hojas de papel.

#La decisión

El cliente — un amigo — me explicó el desorden y pedí dos cosas: entender cómo funcionaba cada contrato de profesor, y entender el flujo completo de la operación. A partir de ahí, el diseño fue consecuencia natural.

El reto no era solo digitalizar — era estandarizar una operación llena de excepciones: descuentos a alumnos para no perderlos, paquetes especiales negociados caso a caso, contratos de profesores que mezclaban modalidades. Todo eso tenía que caber en un sistema que fuera simple de operar. Entró en producción en dos semanas.

#El flujo completo en una vista

LDC App gestiona el ciclo completo de la academia: desde que el alumno compra un pack, hasta el cierre de mes con liquidación automática por profesor.

🛒

01 / 08

Alumno compra pack de clases (cantidad variable por género)

#Módulos Core: El Ecosistema

La aplicación está estructurada en módulos accesibles desde el dashboard principal. Cada módulo resuelve una fricción operativa específica de la academia:

🔫
Recepción
Control de Acceso QR

Input invisible con foco permanente. Captura UUID de pistola USB, valida pack activo y registra asistencia en < 2 segundos.

🎓
Alumnos
Gestión de Alumnos

Alta, edición, historial de asistencia, saldo de packs activos y carnets PDF descargables.

🛒
Ventas
Packs & Carrito

Packs flexibles con carrito de compra. Un pago puede incluir múltiples packs de géneros distintos en una sola transacción atómica.

🗓️
Programación
Calendario de Clases

FullCalendar integrado. Clases por género, horario y profesor con zona horaria America/Santiago explícita.

💼
Profesores
Contratos & Liquidación

Motor de liquidación configurable por profesor y por clase: fijo, comisión, mixto o convenio. Cierre automático con desglose auditado.

📊
Reportes
Exportación

Reportes XLSX y PDF con desglose de asistencia y pagos por período. Carnets de alumno con QR incluido.

#Las decisiones técnicas que importan

1. Motor de liquidación configurable por modalidad

El problema central era que cada profesor tenía esquemas de pago distintos — y un mismo profesor podía tener esquemas diferentes según el género que enseñara. El sistema permite configurar por separado: Fijo (monto fijo por clase, independiente de asistencia), Comisión (porcentaje del ingreso proporcional), Mixto (monto fijo más porcentaje) y Convenio (monto negociado manualmente). Al cerrar el mes, el sistema calcula automáticamente el pago de cada profesor, desagregado por clase, con el detalle del cálculo guardado en JSON para auditoría completa. Lo que antes tomaba más de una hora por profesor ahora toma segundos, con trazabilidad total.

2. Control de acceso QR en tiempo real

El módulo de acceso mantiene un input invisible con foco permanente que captura el UUID enviado por una pistola lectora USB. El flujo completo dura menos de 2 segundos: escaneo QR → búsqueda alumno → validación pack activo → descuento de saldo → confirmación visual → siguiente alumno. Si el pack está vencido o sin clases, el sistema alerta inmediatamente con opción de renovar en el momento. El registro de asistencia es automático — sin intervención manual.

3. Estandarización de excepciones operativas

El mayor reto no fue técnico en el sentido clásico — fue modelar la realidad de un negocio lleno de casos especiales. Descuentos para retener alumnos, packs con cantidad de clases no estándar, modalidades mezcladas en una sola transacción. La solución fue un sistema de packs flexible con carrito de compra: un pago puede incluir múltiples packs de géneros distintos, cada uno con su precio y modalidad, procesados en una sola transacción atómica vía RPC de PostgreSQL.

Packs Flexibles

Carrito multi-género

Un alumno puede comprar packs de géneros distintos en una sola operación. Cada pack tiene precio, cantidad de clases y vigencia independiente.

Atómico

Row Level Security

Policy: auth.uid() = user_id

RLS en todas las tablas. Los datos de la academia no son accesibles sin autenticación. Admin y recepción con roles diferenciados.

Seguro

Zona Horaria

America/Santiago explícito

Con clases programadas en hora local chilena y BD en UTC, todo el sistema usa America/Santiago para manejar UTC-4 (verano) y UTC-3 (invierno) sin errores.

Preciso

El resultado: el dueño puede hacer excepciones — descuentos, packs especiales, contratos a medida — sin romper la consistencia del sistema. Todo queda registrado y es auditable.

Motor de liquidación: cálculo por modalidad

El cálculo se desagrega por clase y modalidad de contrato. El detalle en JSON permite auditar exactamente cómo se llegó a cada número — sin hojas de papel ni fórmulas manuales en Excel.

lib/liquidacion/calcularPagoProfesor.ts
"text-slate-500">// lib/liquidacion/calcularPagoProfesor.ts
"text-purple-400">export "text-purple-400">async "text-purple-400">function calcularPagoProfesor(
  profesorId: string,
  mes: number,
  anio: number
): Promise {
  "text-purple-400">const { data: clases } = "text-purple-400">await supabase
    ."text-purple-400">from('clases_mes')
    .select(`
      id, nombre, asistencia_count,
      ingreso_proporcional,
      contrato_profesor!inner(modalidad, monto_fijo, porcentaje)
    `)
    .eq('profesor_id', profesorId)
    .eq('mes', mes)
    .eq('anio', anio);

  "text-purple-400">const desglose = clases."text-purple-400">map((clase) => {
    "text-purple-400">const { modalidad, monto_fijo, porcentaje } = clase.contrato_profesor;

    "text-purple-400">const pago =
      modalidad === 'FIJO'      ? monto_fijo :
      modalidad === 'COMISION'  ? clase.ingreso_proporcional * porcentaje :
      modalidad === 'MIXTO'     ? monto_fijo + clase.ingreso_proporcional * porcentaje :
      /* CONVENIO */              monto_fijo;

    "text-purple-400">return { claseId: clase.id, nombre: clase.nombre, pago, detalleJSON: { modalidad, monto_fijo, porcentaje } };
  });

  "text-purple-400">const total = desglose."text-purple-400">reduce((sum, d) => sum + d.pago, 0);
  "text-purple-400">return { profesorId, mes, anio, total, desglose };
}

Control de acceso QR: flujo completo

El input invisible mantiene foco permanente para capturar la pistola lectora USB. El Server Action valida el pack, descuenta el saldo y registra la asistencia — todo en una sola operación atómica.

app/acceso/page.tsx
"text-slate-500">// app/acceso/page.tsx — Input invisible con foco permanente
'use client';
"text-purple-400">export "text-purple-400">default "text-purple-400">function AccesoPage() {
  "text-purple-400">const inputRef = "text-purple-400">useRef(null);
  "text-purple-400">const [resultado, setResultado] = "text-purple-400">useState(null);

  "text-slate-500">// Mantener foco permanente para capturar pistola USB
  "text-purple-400">useEffect(() => {
    "text-purple-400">const mantenerFoco = () => inputRef.current?.focus();
    document.addEventListener('click', mantenerFoco);
    mantenerFoco();
    "text-purple-400">return () => document.removeEventListener('click', mantenerFoco);
  }, []);

  "text-purple-400">async "text-purple-400">function handleScan(uuid: string) {
    "text-purple-400">const res = "text-purple-400">await validarAcceso(uuid); "text-slate-500">// Server Action
    setResultado(res);
    "text-slate-500">// Auto-reset para siguiente alumno
    setTimeout(() => { setResultado(null); inputRef.current?.focus(); }, 2000);
  }

  "text-purple-400">return (
    
"sr-only" onKeyDown={/* captura UUID */} /> {resultado && }
); }

#El impacto en números

Antes vs. después: el mismo equipo, el mismo volumen de operación, resultados completamente distintos.

Antes
Después
Asistencia en hojas físicas
Registro QR automático en < 2 segundos
Transcripción manual a Excel cada semana
Dato capturado en tiempo real
+1 hora por profesor para calcular pago
Liquidación automática en segundos
Hojas que se perdían
Trazabilidad completa, todo auditado en JSON
Cierre de mes con incertidumbre y días de trabajo
Reporte exportable con desglose total
Dueño gestionando la operación
Dueño enfocado en crecer la academia
240+
Alumnos activos
12+
Profesores con contratos distintos
~98%
Reducción en tiempo de liquidación
2 sem
De idea a producción

#Stack Tecnológico

Capa
Tecnología
Por qué
Framework
Next.js 16 (App Router)
SSR para carga inicial rápida. Server Actions para mutaciones sin API layer adicional.
Lenguaje
TypeScript 5 (strict mode)
Tipado estricto en toda la aplicación. Errores detectados en build, no en producción.
UI
React 19 + Tailwind CSS v4
Iteración rápida. Componentes de UI propios sin dependencias opinadas.
Base de datos
Supabase (PostgreSQL + Auth + Storage)
Auth + DB + Storage + RLS en una sola plataforma. RPC para transacciones atómicas.
Mutaciones
Server Actions + revalidación selectiva
Sin API layer adicional. Revalidación quirúrgica por path para UX inmediata.
Calendario
FullCalendar 6
Vista semanal y mensual de clases por género y profesor. Drag & drop para reprogramar.
QR
qrcode.react + pistola USB HID
Generación de QR en cliente. Lectura por pistola USB vía input HID — sin drivers adicionales.
Exportación
XLSX + PDF (carnets de alumno)
Reportes de liquidación en XLSX. Carnets con QR integrado en PDF.

#Lo que sigue

🔔

Notificaciones automáticas

Email o SMS cuando un pack está por vencer, para reducir la pérdida de alumnos antes de que dejen de asistir.

📱

Portal del alumno

Consulta de saldo, historial de asistencia y reserva de clase desde el teléfono.

💳

Pago online

Integración con Webpay o MercadoPago para que los alumnos paguen sus packs sin ir a recepción.

📈

Análisis de retención predictivo

Identificar alumnos en riesgo de abandono antes de que dejen de asistir, usando patrones de asistencia.

#Reflexión

Este proyecto se construyó en dos semanas porque el problema estaba claro desde el primer día. Cuando entiendes la operación antes de abrir el editor, el diseño se vuelve obvio. Lo más valioso no fue el código — fue la conversación inicial donde entendí que el dueño no necesitaba un sistema genérico.

Necesitaba uno que siguiera exactamente cómo funcionaba su academia, con todas sus excepciones incluidas. Hoy el dueño confía en los números. Tiene información en tiempo real, y puede concentrarse en lo que realmente importa: mejorar la academia para que vengan más alumnos.

— Jaime Arias · Diseño, arquitectura e implementación completa · Construcción: 2 semanas · Producción desde marzo 2026 · Evolución continua

¿Interesado en la arquitectura técnica o en una solución similar?

Contáctame