Documento Técnico · Interno

Sistema de Planes
y Suscripciones

Cómo controlar qué módulos puede usar cada empresa, cómo cobrar por ello y dónde encajan las pasarelas de pago en Growth54.

4 Planes
10+ Módulos
3 Pasarelas
Laravel Backend
01 — Concepto base

¿Qué es un plan de suscripción?

Un plan define exactamente qué puede hacer una empresa dentro de la plataforma. No es solo un precio — es una lista de permisos.

📋

El Plan

Define qué módulos están habilitados, cuántos recursos se pueden usar y cuánto cuesta. Se crea una sola vez y aplica a muchas empresas.

🏢

La Suscripción

Es el vínculo entre una empresa y un plan. Tiene fecha de inicio, fecha de vencimiento y estado: trial, activa, vencida o cancelada.

🔐

El Control de Acceso

Cuando un usuario intenta usar un módulo, el sistema verifica si el plan activo de su empresa incluye ese módulo. Si no, devuelve error 403.

Analogía con Banahosting

En un hosting, el plan Básico te da 1 dominio, 10 GB y sin SSL premium. El plan Business da 10 dominios, 100 GB y SSL incluido. En Growth54 funciona igual: el plan Starter da acceso a keywords y auditorías, el plan Pro desbloquea RRSS, agentes de IA y más recursos.

Relación entre las piezas
👤
Usuario
se autentica
🏢
Empresa
empresa activa
📋
Suscripción
activa o trial
🎯
Plan
features + módulos
Acceso
permitido o denegado
02 — Planes de suscripción

Los 4 planes de Growth54

Diseñados para escalar desde el primer cliente hasta empresas con operación completa asistida por IA.

Free Trial
$0
7 días gratis · sin tarjeta
Para que el cliente pruebe la plataforma. Una sola vez por persona.
  • ~ 1 empresa
  • Perfil de empresa
  • Auditoría inicial
  • Keywords
  • Artículos SEO
  • RRSS
  • Agentes IA
Registro gratuito
Starter
$29
/ mes · facturación mensual
Para el dueño de negocio que gestiona su propia empresa.
  • ~ 1 empresa
  • Perfil + Auditoría
  • ~ Keywords (hasta 50)
  • ~ Artículos (hasta 20/mes)
  • RRSS
  • Agentes IA
  • 1 integración CMS
Comenzar ahora
Agency
$149
/ mes · facturación mensual
Para agencias medianas con múltiples clientes activos.
  • ~ hasta 8 empresas
  • Todo Pro incluido
  • Keywords ilimitadas
  • Artículos ilimitados
  • Soporte prioritario
  • Reportes descargables
  • Multi-CMS
Activar Agency
Enterprise
Custom
/ hablamos y hacemos descuento
Para agencias grandes o empresas con necesidades específicas.
  • Empresas ilimitadas
  • Todo Agency incluido
  • Precio negociado
  • Integraciones a medida
  • White label (opcional)
  • Soporte dedicado
Hablar con ventas
03 — Control de módulos

Qué módulo tiene cada plan

Cada módulo tiene un slug que se almacena en el JSON del plan. Si el slug está en la lista, el módulo está habilitado.

Módulo Slug Free Trial Starter Pro Enterprise
Perfil de empresa company_profile
Auditoría inicial auditoria_inicial
Keywords SEO keywords 50 máx 200 máx ilimitado
Artículos SEO articulos 20/mes 100/mes ilimitado
Páginas del sitio paginas
Productos y servicios productos_servicios
Competidores competitors
Redes Sociales (RRSS) rrss
Integración CMS cms 1 sitio ilimitado ilimitado
Agentes IA agentes_ia

Cómo se almacena en la base de datos

El campo features en la tabla plans es un JSON con esta estructura:

{
  "modules":       ["company_profile", "auditoria_inicial", "keywords", "articulos"],
  "max_keywords":  50,
  "max_articulos": 20,
  "rrss":          false,
  "agentes_ia":    false
}
04 — Arquitectura técnica

Diseño simple del sistema de planes

El plan lo tiene el usuario, no la empresa. El usuario puede gestionar N empresas según su plan. Simple, sin tablas extra.

Principio de diseño: mantenerlo simple

Mientras más simple sea la arquitectura, más fácil de programar, de mantener y de explicar al cliente. La regla es: el usuario tiene un plan, el plan dice cuántas empresas puede tener y qué puede hacer en cada una. Eso es todo.

El modelo en una imagen

👤
Usuario
Tiene un plan activo
y una fecha de vencimiento
plan_id = Pro
plan_expires_at = 2026-06-06
📋
Plan Pro
Define qué puede hacer
y cuántas empresas tiene
max_companies: 5
modules: [keywords, articulos, rrss...]
max_keywords: 200
agentes_ia: true
🏢 Empresa 1 — cliente A activa
🏢 Empresa 2 — cliente B activa
🏢 Empresa 3 — cliente C activa
Puede crear 2 más (hasta 5)

Tablas en base de datos

Tabla: users (se agregan 3 campos)
id name email plan_id plan_expires_at trial_used_at current_company_id
Tabla: plans (sin cambios)
id slug name price features (JSON) duration_days
Tabla: companies (sin cambios)
id name owner_user_id is_active

¿Y la tabla company_subscriptions?

Se puede conservar para historial de pagos y facturación, pero el control de acceso ya no depende de ella. El acceso se verifica directamente desde el plan_id del usuario.

El JSON features del plan con max_companies

{
  "max_companies":  5,      ← cuántas empresas puede tener
  "modules": [
    "company_profile",
    "auditoria_inicial",
    "keywords",
    "articulos",
    "rrss",
    "agentes_ia"
  ],
  "max_keywords":  200,   ← por empresa
  "max_articulos": 100,   ← por empresa por mes
  "rrss":          true,
  "agentes_ia":    true
}

Método nuevo en el modelo User

// User.php

public function plan(): BelongsTo
{
    return $this->belongsTo(Plan::class);
}

public function canAccessModule(string $module): bool
{
    if (!$this->plan || !$this->planIsActive()) {
        return false;
    }
    return $this->plan->hasModule($module);
}

public function planIsActive(): bool
{
    if (!$this->plan_expires_at) return true; // sin vencimiento
    return $this->plan_expires_at->isFuture();
}

public function canCreateCompany(): bool
{
    $max = $this->plan->features['max_companies'] ?? 1;
    $owned = $this->companies()->wherePivot('role', 'owner')->count();
    return $owned < $max;
}

Flujo de verificación de acceso a un módulo

📨
Request
GET /api/keywords
🔑
auth:sanctum
¿token válido?
👤
EnsureHasModule
¿plan del usuario incluye keywords?
🎯
Controller
ejecuta lógica
📤
Response
200 OK

Código del middleware

// app/Http/Middleware/EnsureUserHasModule.php

public function handle(Request $request, Closure $next, string $module): Response
{
    $user = $request->user();

    if (!$user->canAccessModule($module)) {
        return response()->json([
            'message' => 'Tu plan no incluye este módulo.',
            'upgrade' => true,
        ], 403);
    }

    return $next($request);
}

Control al crear empresa

// OnboardingController::createCompany() — validación que se agrega al inicio

if (!$user->canCreateCompany()) {
    return response()->json([
        'message' => 'Has alcanzado el límite de empresas de tu plan.',
        'upgrade' => true,
        'max_companies' => $user->plan->features['max_companies'],
    ], 403);
}
05 — Flujo de pago

Cómo se procesa una suscripción de pago

El flujo completo desde que el usuario elige un plan hasta que su empresa tiene acceso activo.

1
Usuario elige plan en el frontend
El panel muestra los planes disponibles. El usuario hace clic en "Activar Plan Pro".
2
Frontend llama al backend para crear sesión de pago
POST /api/subscriptions/checkout con { plan_slug: "pro" }
El backend crea una sesión en Stripe/MercadoPago y devuelve la URL de pago.
3
Usuario completa el pago en la pasarela (Stripe, MercadoPago...)
El usuario sale brevemente del panel, ingresa tarjeta y confirma. La pasarela maneja la seguridad PCI.
4
La pasarela notifica al backend (Webhook)
POST /api/webhooks/stripe o POST /api/webhooks/mercadopago
El backend recibe la confirmación de pago exitoso.
5
Backend activa la suscripción en la base de datos
Se crea o actualiza el registro en company_subscriptions con status = "active", starts_at = ahora, ends_at = ahora + 30 días.
6
Usuario regresa al panel con acceso completo
El frontend detecta el cambio de plan, desbloquea los módulos del Plan Pro en el menú lateral y en las rutas.

El punto clave: el Webhook

El backend NUNCA debe activar la suscripción solo porque el usuario dice "pagué". La activación solo ocurre cuando la pasarela confirma el pago mediante un webhook firmado. Esto evita fraudes.

06 — Pasarelas de pago

Opciones de pasarelas de pago

Cada pasarela tiene sus ventajas según el mercado objetivo, la moneda y la complejidad técnica.

Stripe
La opción más completa del mercado. Excelente para pagos internacionales, recurrentes y con múltiples monedas. Documentación impecable y SDK para Laravel disponible.
Recomendado Suscripciones Internacional
  • 2.9% + $0.30 por transacción
  • Webhook nativo y firmado
  • Portal de cliente incluido
  • Soporte multi-moneda
Dónde va: POST /api/webhooks/stripe
MercadoPago
La pasarela dominante en Latinoamérica. Ideal si el mercado principal es México, Colombia, Argentina, Chile o Perú. Acepta cuotas, PSE y métodos locales.
LATAM Cuotas Métodos locales
  • 3.5%–5% según país
  • Transferencia bancaria local
  • Checkout Pro / Transparent
  • SDK oficial PHP
Dónde va: POST /api/webhooks/mercadopago
PayPal
Muy conocido por los clientes finales, especialmente en México. Permite pagos con tarjeta sin que el cliente tenga cuenta PayPal. Buena opción como alternativa a Stripe.
Alternativa Reconocimiento
  • 3.49% + tarifa fija
  • Muy conocido por usuarios
  • Suscripciones disponibles
  • IPN / Webhook
Dónde va: POST /api/webhooks/paypal

¿Dónde va cada pieza en el proyecto?

Backend — archivos a crear

ArchivoResponsabilidad
app/Services/StripeService.php Crear sesiones de checkout y manejar cliente Stripe
app/Http/Controllers/Api/SubscriptionController.php Endpoint para elegir plan e iniciar checkout
app/Http/Controllers/Api/Webhooks/StripeWebhookController.php Recibir notificación de pago y activar suscripción
app/Http/Middleware/EnsureCompanyHasModule.php Verificar plan activo antes de cada endpoint
routes/api.php (modificar) Agregar middleware module:X a las rutas protegidas

Frontend — archivos a crear

ArchivoResponsabilidad
src/hooks/useCanAccess.ts Hook: ¿el plan activo incluye este módulo?
src/components/ModuleGate.tsx Wrapper que bloquea visualmente si no hay acceso
src/pages/Planes.tsx Pantalla de selección y upgrade de plan
src/services/subscriptions.ts Llamadas API para checkout y estado de suscripción

Recomendación: empezar con Stripe

Stripe tiene el mejor soporte para suscripciones recurrentes con Laravel. El paquete laravel/cashier (oficial de Laravel) hace que integrar Stripe tome horas en lugar de días. Maneja renovaciones, cancelaciones, facturas y webhooks de forma automática.

07 — Cómo configurar los planes hoy mismo

Modificar planes sin tocar código

Los planes se pueden crear y editar directamente desde la API con un token de administrador. No se necesita desplegar código.

Crear un nuevo plan (Plan Starter)

# POST /api/admin/plans
{
  "slug":          "starter",
  "name":          "Starter",
  "price":         29.00,
  "duration_days": 30,
  "is_active":     true,
  "features": {
    "modules": [
      "company_profile",
      "auditoria_inicial",
      "keywords",
      "articulos",
      "paginas"
    ],
    "max_keywords":  50,
    "max_articulos": 20,
    "rrss":          false,
    "agentes_ia":    false
  }
}

Modificar un plan existente (agregar módulo)

# PATCH /api/admin/plans/2
{
  "features": {
    "modules": [
      "company_profile",
      "auditoria_inicial",
      "keywords",
      "articulos",
      "paginas",
      "rrss"  ← se agregó este módulo
    ],
    "max_keywords":  50,
    "max_articulos": 20,
    "rrss":          true,  ← se habilitó
    "agentes_ia":    false
  }
}

Asignar un plan a una empresa manualmente

Esto se hace cuando se activa una cuenta nueva o se cambia el plan de forma manual (sin pasarela de pago).

# POST /api/admin/companies/5/subscriptions   (endpoint por implementar)
{
  "plan_id":   2,
  "status":    "active",
  "starts_at": "2026-05-06",
  "ends_at":   "2026-06-06"
}

Nota sobre el frontend

El endpoint /api/auth/me debe devolver los módulos del plan activo de la empresa. El frontend usa esa información para mostrar u ocultar secciones del menú lateral. Hoy ese endpoint existe pero no incluye los módulos del plan — es un campo que falta agregar.

08 — Estado actual del proyecto

Qué existe y qué falta implementar

Un checklist honesto del estado del sistema de planes en Growth54 hoy.

Ya implementado ✓

  • Tabla plans
    Con slug, precio, duración y features JSON
  • Tabla company_subscriptions
    Vínculo empresa–plan con estado y fechas
  • Modelo Plan con hasModule()
    Verifica si un módulo está en el plan
  • Modelo CompanySubscription con isActive()
    Verifica estado y vencimiento
  • API CRUD de planes
    GET/POST/PATCH/DELETE /api/admin/plans
  • Seeder del plan Free Trial
    Con módulos básicos y límites en cero

Pendiente de implementar ⚡

  • !
    Middleware EnsureCompanyHasModule
    Bloquear rutas API por módulo del plan
  • !
    Seeders de planes Starter, Pro, Enterprise
    Solo existe el Free Trial hoy
  • !
    Endpoint asignar plan a empresa
    POST /api/admin/companies/{id}/subscriptions
  • !
    Módulos en respuesta de /api/auth/me
    El frontend necesita saber qué puede mostrar
  • Integración Stripe + Webhooks
    Para cobros recurrentes automáticos
  • Frontend: pantalla de planes y upgrade
    Hook useCanAccess() y componente ModuleGate
  • Job de vencimiento automático
    Scheduler que marca suscripciones como expired

Orden de implementación recomendado

1
Agregar planes Starter, Pro, Enterprise al seeder
Rápido y no rompe nada. Solo editar PlanSeeder.php y correr el seeder.
1 hora
2
Crear middleware EnsureCompanyHasModule
El middleware y registrarlo en las rutas protegidas de api.php.
2 horas
3
Incluir módulos del plan en /api/auth/me
Modificar AuthController para devolver módulos del plan activo de la empresa.
1 hora
4
Hook useCanAccess() y bloqueo visual en frontend
Usar los módulos del plan para mostrar/ocultar secciones del panel.
3 horas
5
Integración pasarela de pago (Stripe recomendado)
Checkout, webhooks y activación automática de suscripciones. Usar laravel/cashier.
1–2 días
09 — Decisión de negocio

La pregunta que define todo

Antes de programar el sistema de planes hay que responder esto con el equipo. No es técnico — es estratégico.

🏢

¿Nuestro cliente es el dueño de la empresa?

Carlos tiene un restaurante. Compra Growth54 para gestionar el SEO de su propio negocio. Solo necesita 1 empresa. No va a gestionar clientes de terceros.

Resultado: Starter con 1 empresa es suficiente para él.
🎯

¿Nuestro cliente es el agente SEO o la agencia?

Laura es freelancer SEO. Tiene 6 clientes. Quiere un solo panel para gestionar todos. No quiere pagar 6 planes por separado — quiere 1 plan que le dé 6 empresas.

Resultado: Necesita el plan Agency con hasta 8 empresas.

Lo más probable: son los dos

Growth54 puede atender ambos perfiles con el mismo modelo. El Starter (1 empresa) cubre al dueño de negocio. El Pro y Agency (5–8 empresas) cubren al freelancer y a la agencia. El precio diferencia quién es quién.

Resumen ejecutivo para presentar al equipo

El modelo de negocio en 3 líneas
1
El plan lo compra la persona, no la empresa
La persona paga una vez y puede gestionar N empresas según su plan. Igual que Semrush, Ahrefs o SE Ranking.
2
Lo que cambia entre planes es cuántas empresas puedes tener
Starter = 1 empresa. Pro = 5. Agency = 8. Enterprise = ilimitadas (precio a negociar).
3
Los colaboradores no pagan — se unen a la empresa del que sí pagó
Laura (agencia) tiene Plan Pro. Contrata a un asistente y lo invita como colaborador. El asistente no necesita plan propio — trabaja bajo el plan de Laura.