Ir al contenido

Monitorear uso

Visualiza tu consumo actual frente a los límites de tu plan.

  1. Ve a la pestaña “Uso”
  2. Se muestran 4 métricas principales con barras de progreso:
    • Usuarios: Usuarios activos vs. límite del plan
    • Facturas: Facturas emitidas este mes vs. límite mensual
    • Clientes: Clientes totales vs. límite del plan
    • Almacenamiento: Espacio usado vs. límite del plan
  3. Cada barra indica el porcentaje de uso:
    • 🟢 Verde: menos de 75% del límite
    • 🟡 Amarillo: 75-90% del límite
    • 🔴 Rojo: más de 90% del límite
  4. Al alcanzar el 100%, aparece alerta sugiriendo upgrade

“No se pudo cargar el uso”

Causa: Error temporal al calcular estadísticas.

Solución:

  1. Recarga la página
  2. Si persiste, verifica que tengas suscripción activa
  3. Contacta a soporte si continúa el error
Cálculo de límites y uso

Componente: UsageLimitsCard

Ubicación: src/panels/owner/subscriptions/components/management/UsageLimitsCard.tsx

Obtención de límites efectivos:

// RPC function: get_business_effective_limits
const { data: limits } = await supabase
.rpc('get_business_effective_limits', {
p_business_id: currentBusinessId
});
// Retorna límites combinados (plan + custom overrides)
{
users: 3, // -1 = ilimitado
monthly_invoices: 100,
customers: 500,
storage_gb: 10,
// ... otros límites
}

Lógica de la función RPC:

CREATE OR REPLACE FUNCTION get_business_effective_limits(p_business_id UUID)
RETURNS JSONB AS $$
DECLARE
v_limits JSONB;
v_custom_limits JSONB;
BEGIN
-- 1. Obtener límites del plan
SELECT sp.limits INTO v_limits
FROM business_subscriptions bs
JOIN subscription_plans sp ON sp.id = bs.plan_id
WHERE bs.business_id = p_business_id
AND bs.status IN ('active', 'trialing')
ORDER BY bs.created_at DESC
LIMIT 1;
-- 2. Obtener límites custom (si existen)
SELECT custom_limits INTO v_custom_limits
FROM business_subscriptions
WHERE business_id = p_business_id
AND custom_limits IS NOT NULL;
-- 3. Combinar (custom overrides plan)
IF v_custom_limits IS NOT NULL THEN
v_limits := v_limits || v_custom_limits;
END IF;
RETURN v_limits;
END;
$$ LANGUAGE plpgsql;

Cálculo de uso actual:

// Query en paralelo para optimizar rendimiento
const [invoices, customers, users, documents] = await Promise.all([
// Facturas del mes actual
supabase
.from('invoices')
.select('id', { count: 'exact', head: true })
.eq('business_id', currentBusinessId)
.gte('created_at', startOfMonth(new Date()).toISOString()),
// Clientes totales
supabase
.from('customers')
.select('id', { count: 'exact', head: true })
.eq('business_id', currentBusinessId),
// Usuarios activos
supabase
.from('user_businesses')
.select('id', { count: 'exact', head: true })
.eq('business_id', currentBusinessId),
// Documentos almacenados
supabase
.from('documents')
.select('id', { count: 'exact', head: true })
.eq('business_id', currentBusinessId)
]);
const usage = {
invoices: invoices.count || 0,
customers: customers.count || 0,
users: users.count || 0,
documents: documents.count || 0
};

Cálculo de porcentajes:

const percentage = limit === -1
? 0 // Ilimitado → no mostrar barra
: Math.min((current / limit) * 100, 100);
const variant =
percentage >= 90 ? 'destructive' :
percentage >= 75 ? 'warning' :
'default';

Alertas automáticas:

// Si uso >= 90%, mostrar alerta
{isAtLimit && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>
Has alcanzado el límite. Considera actualizar tu plan.
</AlertDescription>
</Alert>
)}
// Si uso >= 75%, mostrar advertencia
{isNearLimit && !isAtLimit && (
<Alert className="border-yellow-500/50 bg-yellow-500/10">
<AlertCircle className="h-4 w-4 text-yellow-600" />
<AlertDescription className="text-yellow-600">
Estás cerca del límite ({percentage.toFixed(0)}%)
</AlertDescription>
</Alert>
)}

Reseteo de límites mensuales:

Los límites mensuales se resetean automáticamente al inicio de cada período de facturación:

// Webhook: invoice.payment_succeeded
stripe.webhook.on('invoice.payment_succeeded', async (invoice) => {
// Se considera inicio de nuevo período
const newPeriodStart = new Date(invoice.period_start * 1000);
// NO se borran facturas, solo se ignoran las anteriores al nuevo período
// El conteo se hace con filtro de fecha en el query
});