CreaRack-SL

Plan · Modelo core

Entidadactiveverificado 2026-04-21#core#model#saas#subscription

Plan · Modelo core

Propósito

Plan define el nivel de suscripción de una organización SaaS. Actúa como configuración base de módulos: determina qué funcionalidades (SaaSModule) están disponibles de serie para las organizaciones del tier. Introducido en la migración 0013_module_gating, centraliza la lógica de acceso a funcionalidades evitando hardcoding por organización.

Contrato

Campos (core/models.py:27-47):

CampoTipoNotas
slugSlugField(50, unique)Identificador canónico: starter, pro, custom
nameCharField(100)Nombre legible
descriptionTextField(blank)Descripción opcional
modulesM2M(SaaSModule, related_name="plans", blank)Módulos incluidos por defecto en el plan
sort_orderIntegerField(default=0)Orden en listados

Tiers definidos (constante PLAN_CHOICES, no campo):

  • "starter" — Rack design essentials; solo módulo racks.
  • "pro" — Gestión completa; incluye racks, network-maps, network-management, network-observatory.
  • "custom" — Base Pro + módulos premium à la carte (wireless-monitor, ups-monitor, digital-signage) vía Organization.extra_modules. Tras 0014, hereda los 4 módulos base de Pro.

Meta: ordering = ["sort_order"]. Sin verbose_name explícito.

Dependencias entrantes

ArchivoUso
core/models.py:63 (Organization)FK plan con SET_NULL, null=True
core/api/signup.pyResuelve Plan.objects.filter(slug="starter").first(); asigna max_racks=10
core/admin.py (OrganizationAdmin.plan_modules_display)Itera Plan.objects.prefetch_related("modules") para mapa JS
core/admin.py (PlanAdmin)filter_horizontal = ("modules",), columnas module_count y org_count

Dependencias salientes

  • SaaSModule — M2M vía modules. Inverse: SaaSModule.plans.
  • core/migrations/0013_module_gating — crea los 3 planes semilla y asigna organizaciones existentes al plan custom con todos los módulos no-core en extra_modules.
  • core/migrations/0014_fix_custom_plan_modules — corrige custom para incluir los 4 módulos base de Pro.

Ejemplos

# Signup self-service (core/api/signup.py)
PLAN_MAX_RACKS = {"starter": 10, "pro": 200, "custom": 200}
plan = Plan.objects.filter(slug="starter").first()
org = Organization.objects.create(
    name=org_name,
    plan=plan,
    max_racks=PLAN_MAX_RACKS.get(plan.slug, 10) if plan else 10,
)
# Sync extra_modules = core_modules ∪ plan_modules
core_pks = set(SaaSModule.objects.filter(is_core=True).values_list("pk", flat=True))
plan_pks = set(plan.modules.values_list("pk", flat=True))
org.extra_modules.set(core_pks | plan_pks)

# Admin — mapa de módulos por plan (core/admin.py)
for plan in Plan.objects.prefetch_related("modules").all():
    mod_names = sorted(set(core_names) | set(plan.modules.values_list("name", flat=True)))
    plan_data[str(plan.pk)] = {"label": ", ".join(mod_names), ...}
  • entity--core--model--saasmodule — módulos individuales que componen un plan.
  • entity--core--model--organization — tenant SaaS que consume el plan vía FK.
  • concept--saas--module-gating — lógica get_active_modules() que combina core + plan + extras.

Véase también

  • [[entity—core—model—saasmodule]]
  • [[entity—core—model—organization]]
  • [[concept—saas—module-gating]]