Ir al contenido

Funcionalidades

Ruta: /owner/settings/features Visualiza y gestiona las funcionalidades incluidas en tu plan de suscripción actual.


La pantalla de Funcionalidades muestra un dashboard con todas las características disponibles en Factux, indicando cuáles están activas según tu plan de suscripción.

TarjetaColorDescripción
Funcionalidades ActivasVerdeCantidad de features habilitadas vs total
Estado de SuscripciónVariableIndica si tienes plan activo, trial o sin suscripción
Plan ActualInfoMuestra el nombre y slug de tu plan

Columnas de la tabla: Expansión, Funcionalidad, Categoría, Estado, Acciones

Categorías disponibles:

  • Cumplimiento (compliance)
  • Integración (integration)
  • Reportes (reporting)
  • Colaboración (collaboration)
  • Seguridad (security)
  • Automatización (automation)
  • Ventas (sales)
  • Inventario (inventory)
  • Operaciones (operations)
  • Financiero (financial)

Estados posibles:

EstadoBadgeDescripción
IncluidaVerdeFuncionalidad activa en tu plan
No disponibleRojoRequiere actualizar plan
En BetaAzulFuncionalidad en versión beta
Temporalmente no disponibleAmarilloEn desarrollo o pausada

Factux utiliza un sistema granular de control de funcionalidades basado en planes:

  1. Catálogo de funcionalidades (plan_features)

    • Cada funcionalidad tiene una clave única (feature_key)
    • Se categoriza para mejor organización
    • Puede requerir configuración adicional
  2. Asignación a planes (plan_features_mapping)

    • Define qué funcionalidades incluye cada plan
    • Permite habilitar/deshabilitar features por plan
    • Establece prioridades de acceso
  3. Validación en tiempo real

    • Edge function valida acceso antes de usar una feature
    • Registra intentos de acceso (permitidos y bloqueados)
    • Sugiere plan siguiente si no tienes acceso

Las funcionalidades pueden tener diferentes estados de visibilidad:

VisibilidadAccesoDescripción
publicTodos los planes que la incluyanFuncionalidad disponible públicamente
betaPlanes seleccionados + aviso betaEn pruebas con usuarios reales
internalSolo desarrollo internoNo visible para clientes
developmentBloqueadaEn construcción activa

Funcionalidades relacionadas con normativas fiscales y legales.

Ejemplos:

  • VeriFactu (envío de registros AEAT)
  • Facturación electrónica
  • Certificados digitales
  • SII (Suministro Inmediato de Información)

Conexiones con servicios externos y APIs.

Ejemplos:

  • Conexión bancaria
  • Pasarelas de pago
  • ERP externos
  • API REST de Factux

Tareas programadas y flujos automáticos.

Ejemplos:

  • Facturas recurrentes
  • Recordatorios de pago
  • Workflows personalizados
  • Notificaciones automáticas

Generación de informes y análisis.

Ejemplos:

  • Informes de ventas
  • Análisis de cobros
  • Métricas de negocio
  • Exportaciones avanzadas

FunciónDescripciónDocumentación
Ver funcionalidadesConsulta todas las features y su estadoVer
Filtrar por categoríaMuestra solo features de una categoríaVer
Expandir detallesVisualiza descripción completa de una featureVer
Actualizar planAcceso directo a página de planesVer

Esta configuración está restringida a propietarios del negocio. Los colaboradores y empleados no pueden acceder.

Mensaje mostrado:

Acceso restringido Solo los propietarios pueden acceder a esta configuración.

Cuando una funcionalidad no está disponible, se muestra uno de estos mensajes:

CódigoMensaje cortoDescripción completa
no_subscriptionNo tienes una suscripción activaNecesitas suscribirte a un plan para acceder
feature_not_in_planNo incluida en tu plan actualActualiza tu plan para acceder
feature_disabledFuncionalidad deshabilitada temporalmenteInténtalo más tarde
limit_exceededLímite de uso alcanzadoHas alcanzado el límite de tu plan
trial_expiredPeríodo de prueba finalizadoSuscríbete a un plan para continuar
feature_in_developmentEn desarrolloFuncionalidad no disponible públicamente
feature_temporarily_unavailableTemporalmente no disponibleEn mantenimiento o pausada

Tablas de base de datos

Catálogo maestro de todas las funcionalidades disponibles.

ColumnaTipoDescripción
iduuidIdentificador único
keytextClave única de la funcionalidad (ej: verifactu)
nametextNombre visible (ej: “VeriFactu”)
descriptiontextDescripción completa
categorytextCategoría (compliance, integration, etc.)
icon_nametextNombre del icono Lucide (ej: shield)
requires_setupbooleanSi requiere configuración adicional
documentation_urltextURL a documentación específica
created_attimestamptzFecha de creación
updated_attimestamptzÚltima actualización

Constraints:

  • category debe ser uno de: compliance, integration, collaboration, reporting, automation, security, sales, inventory, operations, financial
  • key es único (índice idx_plan_features_key_unique)

Asignación de funcionalidades a planes de suscripción.

ColumnaTipoDescripción
iduuidIdentificador único
plan_iduuidFK a subscription_plans
feature_keytextFK a plan_features.key
enabledbooleanSi la feature está activa en este plan
priorityintegerPrioridad de acceso (mayor = más prioritario)
created_attimestamptzFecha de creación
updated_attimestamptzÚltima actualización

Constraints:

  • Único por combinación (plan_id, feature_key)
  • Cascada en DELETE de plan o feature

Estado de desarrollo y visibilidad de funcionalidades.

ColumnaTipoDescripción
feature_keytextFK a plan_features.key
is_activebooleanSi la feature está activa globalmente
is_pausedbooleanSi está temporalmente pausada
pause_reasontextRazón de la pausa
is_betabooleanSi está en fase beta
visibilitytextNivel de visibilidad (public, beta, internal, development)
release_datetimestamptzFecha de lanzamiento planificada
metadatajsonbMetadatos adicionales

Registro de intentos de acceso a funcionalidades.

ColumnaTipoDescripción
business_iduuidNegocio que intenta acceder
feature_keytextFuncionalidad solicitada
actiontextAcción: access o blocked
reasontextRazón del resultado
metadatajsonbInformación adicional del intento
created_attimestamptzTimestamp del intento
Políticas RLS
PolíticaOperaciónRegla
Anyone can read plan_featuresSELECTPúblico (cualquiera puede leer)
Active admins can insert plan_featuresINSERTSolo administradores activos
Active admins can update plan_featuresUPDATESolo administradores activos
Active admins can delete plan_featuresDELETESolo administradores activos
PolíticaOperaciónRegla
Anyone can read plan_features_mappingSELECTPúblico (cualquiera puede leer)
Admins can manage plan_features_mappingALLSolo administradores activos

Nota: Los logs de acceso (feature_access_logs) son solo escritura desde Edge Functions.

Edge Functions

Ruta: supabase/functions/validate-feature-access

Propósito: Valida si un negocio tiene acceso a una funcionalidad específica.

Request:

interface ValidateFeatureAccessRequest {
business_id: string;
feature_key: string;
}

Response:

interface FeatureAccessResponse {
enabled: boolean;
reason?: string;
nextPlan?: {
id: string;
name: string;
price: number;
billing_cycle: string;
};
currentUsage?: number;
limit?: number;
limitKey?: string;
isBeta?: boolean;
betaMessage?: string;
metadata?: Record<string, any>;
}

Flujo de validación:

  1. Verifica suscripción activa o en trial
  2. Busca feature en plan_features_mapping
  3. Valida feature_development_status
  4. Registra el intento en feature_access_logs
  5. Retorna resultado + siguiente plan si bloqueado

Razones de bloqueo:

  • no_subscription — Sin suscripción activa
  • feature_not_in_plan — Feature no incluida
  • feature_disabled — Deshabilitada explícitamente
  • feature_temporarily_unavailable — En pausa o inactiva
  • feature_in_development — Visibilidad internal/development

Propósito: Valida múltiples features de una sola vez (optimización).

Request:

interface ValidateFeatureAccessBatchRequest {
business_id: string;
feature_keys: string[];
}

Response:

interface BatchResponse {
results: Record<string, FeatureAccessResponse>;
}
Tipos TypeScript
// Desde src/integrations/supabase/types.ts
interface PlanFeatures {
Row: {
id: string;
key: string;
name: string;
description: string | null;
category: string;
icon_name: string | null;
requires_setup: boolean | null;
documentation_url: string | null;
created_at: string | null;
updated_at: string | null;
};
Insert: {
id?: string;
key: string;
name: string;
description?: string | null;
category: string;
icon_name?: string | null;
requires_setup?: boolean | null;
documentation_url?: string | null;
created_at?: string | null;
updated_at?: string | null;
};
Update: {
key?: string;
name?: string;
description?: string | null;
category?: string;
icon_name?: string | null;
requires_setup?: boolean | null;
documentation_url?: string | null;
updated_at?: string | null;
};
}
interface PlanFeaturesMapping {
Row: {
id: string;
plan_id: string;
feature_key: string;
enabled: boolean | null;
priority: number | null;
created_at: string | null;
updated_at: string | null;
};
Insert: {
id?: string;
plan_id: string;
feature_key: string;
enabled?: boolean | null;
priority?: number | null;
created_at?: string | null;
updated_at?: string | null;
};
Update: {
plan_id?: string;
feature_key?: string;
enabled?: boolean | null;
priority?: number | null;
updated_at?: string | null;
};
}
// Desde src/config/features.ts
export const FEATURE_FLAGS = {
// Dynamic Sidebar con feature access control
DYNAMIC_SIDEBAR: import.meta.env.VITE_ENABLE_DYNAMIC_SIDEBAR !== 'false',
// Debug mode para sidebar
DEBUG_SIDEBAR: import.meta.env.VITE_DEBUG_SIDEBAR === 'true',
// Feature access validation
STRICT_FEATURE_VALIDATION: import.meta.env.VITE_STRICT_FEATURE_VALIDATION === 'true',
} as const;
export type FeatureFlag = keyof typeof FEATURE_FLAGS;
export function isFeatureEnabled(flag: FeatureFlag): boolean {
return FEATURE_FLAGS[flag] ?? false;
}
Hooks React

Archivo: src/hooks/useFeatureAccess.ts

Verifica acceso a una funcionalidad específica.

interface UseFeatureAccessOptions {
businessId: string;
featureKey: string;
autoCheck?: boolean;
}
interface UseFeatureAccessReturn {
enabled: boolean;
loading: boolean;
error: string | null;
data: FeatureAccessResponse | null;
check: () => Promise<void>;
nextPlan?: {
id: string;
name: string;
price: number;
billing_cycle: string;
};
reason?: string;
limit?: number;
limitKey?: string;
}
// Uso
const { enabled, loading, nextPlan } = useFeatureAccess({
businessId: currentBusinessId,
featureKey: 'verifactu',
autoCheck: true
});
if (loading) return <Spinner />;
if (!enabled) return <FeatureBlocker nextPlan={nextPlan} />;
return <FeatureComponent />;

Verifica múltiples funcionalidades a la vez.

const features = useMultipleFeatureAccess({
businessId: currentBusinessId,
featureKeys: ['verifactu', 'bank_connection', 'api_access'],
autoCheck: true
});
return (
<div>
{features.features.map(f => (
<div key={f.featureKey}>
{f.featureKey}: {f.enabled ? 'Habilitado' : 'Bloqueado'}
</div>
))}
</div>
);

Archivo: src/hooks/useSubscriptionStatus.ts

Obtiene el estado completo de la suscripción.

interface SubscriptionStatus {
hasSubscription: boolean;
status: 'active' | 'trialing' | 'past_due' | 'canceled' | 'none';
planName?: string;
planSlug?: string;
planId?: string;
plan?: {
name: string;
slug: string;
limits?: Record<string, any>;
};
currentPeriodStart?: Date;
currentPeriodEnd?: Date;
trialEnd?: Date;
trialDaysRemaining?: number;
isTrialing: boolean;
isActive: boolean;
cancelAtPeriodEnd: boolean;
stripeCustomerId?: string;
canAccessStripePortal: boolean;
}
// Uso
const { subscriptionStatus, isLoading, refetch } = useSubscriptionStatus();
if (subscriptionStatus?.isTrialing) {
return <TrialBanner daysRemaining={subscriptionStatus.trialDaysRemaining} />;
}
Componentes React

Archivo: src/features/settings/components/FeaturesDashboard.tsx

Componente principal que muestra el dashboard de funcionalidades.

Props: Ninguna (usa contexto de autenticación)

Características:

  • Tarjetas de resumen con estadísticas
  • Tabla expandible con todas las features
  • Filtros por categoría y búsqueda
  • Iconos dinámicos desde Lucide
  • Enlaces a actualización de plan

Estados:

interface FeatureFromDB {
id: string;
key: string;
name: string;
description: string;
category: string;
icon_name: string | null;
requires_setup: boolean;
is_enabled: boolean;
}

Categorías traducidas:

const CATEGORY_LABELS: Record<string, string> = {
compliance: 'Cumplimiento',
integration: 'Integración',
reporting: 'Reportes',
collaboration: 'Colaboración',
security: 'Seguridad',
automation: 'Automatización',
};
Queries de diagnóstico
SELECT
pf.key,
pf.name,
pf.category,
pfm.enabled,
pfm.priority,
sp.name as plan_name
FROM plan_features pf
INNER JOIN plan_features_mapping pfm ON pf.key = pfm.feature_key
INNER JOIN subscription_plans sp ON pfm.plan_id = sp.id
WHERE sp.slug = 'profesional'
ORDER BY pf.category, pf.name;
SELECT
pf.key,
pf.name,
pf.category,
bs.status as subscription_status,
sp.name as current_plan
FROM businesses b
INNER JOIN business_subscriptions bs ON b.id = bs.business_id
INNER JOIN subscription_plans sp ON bs.plan_id = sp.id
INNER JOIN plan_features_mapping pfm ON sp.id = pfm.plan_id
INNER JOIN plan_features pf ON pfm.feature_key = pf.key
WHERE b.id = '<business_id>'
AND bs.status IN ('active', 'trialing')
AND pfm.enabled = true
ORDER BY pf.category, pf.name;
SELECT
pf.key,
pf.name,
pf.category,
sp_next.name as next_plan_with_feature,
sp_next.price
FROM plan_features pf
LEFT JOIN plan_features_mapping pfm ON pf.key = pfm.feature_key
AND pfm.plan_id = '<current_plan_id>'
LEFT JOIN LATERAL (
SELECT sp.*, pfm2.enabled
FROM subscription_plans sp
INNER JOIN plan_features_mapping pfm2 ON sp.id = pfm2.plan_id
WHERE pfm2.feature_key = pf.key
AND pfm2.enabled = true
AND sp.display_order > (SELECT display_order FROM subscription_plans WHERE id = '<current_plan_id>')
ORDER BY sp.display_order
LIMIT 1
) sp_next ON true
WHERE pfm.id IS NULL OR pfm.enabled = false;
SELECT
fal.created_at,
b.name as business_name,
pf.name as feature_name,
fal.reason,
fal.metadata->>'current_plan_id' as current_plan
FROM feature_access_logs fal
INNER JOIN businesses b ON fal.business_id = b.id
LEFT JOIN plan_features pf ON fal.feature_key = pf.key
WHERE fal.action = 'blocked'
AND fal.created_at > NOW() - INTERVAL '7 days'
ORDER BY fal.created_at DESC
LIMIT 50;

Los elementos visuales utilizan el color verde característico:

Color principal: hsl(68 100% 50%)

  • Badges de funcionalidades activas
  • Iconos de éxito
  • Indicadores de estado positivo