Skip to content

Como funciona el proyecto

⚠️ Importante - Arquitectura Multivertical

Section titled “⚠️ Importante - Arquitectura Multivertical”

Este proyecto está diseñado para alimentar todas las verticales de Alebat Education. Cada función, servicio y componente debe desarrollarse pensando en la modularidad y reutilización entre múltiples tiendas.

  • Una sola lógica unificada que sirva a todas las tiendas simultáneamente
  • Mantenimiento de productos y funcionamiento independientes por vertical
  • Distribución de pagos y relaciones con CRMs individuales e independientes
  • Escalabilidad y sostenibilidad - un cambio necesario en todas las tiendas se modifica solo una vez

🚀 Instalación y Configuración Inicial

Section titled “🚀 Instalación y Configuración Inicial”
Terminal window
# Instalar dependencias
npm i
# Iniciar el proyecto en desarrollo (NO usar 'develop')
npm run dev

Este proyecto está construido con Strapi 5 y utiliza TypeScript como lenguaje principal.

  • CMS: Strapi v5
  • Lenguaje: TypeScript (obligatorio)
  • Base de datos: Compatible con múltiples BBDD - MySQL(recomendada), PostgreSQL, SQLite, etc.

La estructura sigue la organización estándar de Strapi 5:

src/
├── api/ # 📂 APIs personalizadas
│ ├── [collection]/ # Colecciones individuales
│ │ ├── content-types/ # Schemas de la estructura
│ │ | └── lifecycles # Hooks de ciclo de vida
│ │ ├── controllers/ # Controladores de API
│ │ ├── routes/ # Rutas personalizadas
│ │ ├── services/ # Servicios de negocio
│ └── ...
├── components/ # 🧩 Componentes reutilizables
├── constants/ # 📋 Constantes del sistema
├── plugins/ # 🔌 Plugins personalizados
├── types/ # 📝 Tipos TypeScript
└── utils/ # 🔧 Utilidades generales

🛠️ Configuración del Entorno de Desarrollo

Section titled “🛠️ Configuración del Entorno de Desarrollo”

⚠️ IMPORTANTE: Los siguientes linters DEBEN estar instalados y configurados en Visual Studio Code:

// .vscode/extensions.json (recomendado)
{
"recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
}
.vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"eslint.validate": ["javascript", "typescript"]
}

¿Por qué son obligatorios?

  • ESLint: Detecta errores de código, magic strings, variables no utilizadas
  • Prettier: Mantiene formato consistente de código

Este proyecto utiliza el plugin de user-permissions de Strapi para la gestión de:

  • Roles y permisos de usuarios
  • Seguridad de las APIs del proyecto
  • Autenticación y autorización

📖 Documentación específica: User-Permissions


TODOS los archivos deben estar escritos en TypeScript.

// ✅ Con TypeScript - Detección temprana de errores
interface User {
id: number;
name: string;
email: string;
}
const getUser = (id: number): User => {
// TypeScript verifica los tipos en tiempo de compilación
return strapi.entityService.findOne("api::user.user", id);
};
// ❌ Sin TypeScript - Errores en runtime
const getUser = (id) => {
// ¿Qué tipo es 'id'? ¿Qué devuelve esta función?
return strapi.entityService.findOne("api::user.user", id);
};

NO pueden existir strings hardcodeados en el código.

Problema - Magic Strings y Magic Numbers

Section titled “❌ Problema - Magic Strings y Magic Numbers”
// ❌ Imagina que 'admin' se usa en 15 archivos diferentes, 10 veces en cada uno
if (user.role === "admin") {
// Lógica administrativa
}
// En otro archivo:
if (user.role === "admin") {
// Más lógica
}
// Y en 148 lugares más...

💥 ¿Qué pasa cuando necesitas cambiar ‘admin’ por ‘administrator’?

❌ Debes encontrar y reemplazar 150 ocurrencias manualmente
❌ Riesgo de olvidar algunas y crear bugs
❌ No hay autocompleta ni verificación de tipos
❌ Errores silenciosos si escribes mal el string

constants/userRoles.ts
export const USER_ROLES = {
ADMIN: "admin",
USER: "user",
MODERATOR: "moderator",
} as const;
// Uso en cualquier archivo:
if (user.role === USER_ROLES.ADMIN) {
// Lógica administrativa - ¡Autocompleta y verificación de tipos!
}

🎯 Beneficios:

  • Un solo lugar para cambiar el valor (1 línea vs 150)
  • Autocompleta de TypeScript
  • Errores en tiempo de compilación si escribes mal
  • Refactoring seguro con herramientas IDE

src/constants/
├── errors/ # 🚨 Mensajes de error organizados
├── structures/ # 🏗️ Estructuras de datos complejas
├── countryCodes.ts # 🌍 Códigos de países internacionales
├── crmStripe.ts # 💳 Configuraciones de Stripe CRM
├── defaultLocale.ts # 🌐 Configuración de idiomas por defecto
├── emails.ts # 📧 Templates y configuraciones de email
├── laabProServices.ts # 🔬 Servicios de LaabPro
├── record.ts # 📊 Constantes para records/grabaciones
├── regex.ts # 📝 Patrones de expresiones regulares
└── verticals.ts # 🏢 Configuraciones de verticales

Esta estructura está diseñada para soportar múltiples verticales de manera eficiente:

  • 📁 errors/ - Mensajes de error centralizados y tipados
  • 📁 structures/ - Estructuras de datos complejas reutilizables
  • 📄 Archivos específicos - Cada uno enfocado en un dominio particular

🎯 Ejemplo Real del Proyecto - Constantes de Productos

Section titled “🎯 Ejemplo Real del Proyecto - Constantes de Productos”

Este es un ejemplo real de cómo están organizadas las constantes en el proyecto:

// constants/products.ts - Ejemplo real del proyecto
// 📝 Campos básicos de productos
export const FIELDS_PRODUCT = [
"id",
"SKU",
"acronym",
"contract",
"locale",
"order",
"type",
"publishedAt",
"slug",
"stripeID",
"title",
"vertical",
"stripeCrm",
];
// 🧩 Componentes reutilizables
export const COMPONENTS_PRODUCT = [
"fullPrice",
"tuitionPrice",
"instalmentsPrices",
"laabConnection",
];
// 🔗 Referencias de servicios API
export const PRODUCT = "api::product.product";
export const PRODUCT_STRIPE_SERVICE = "api::product.stripe";
export const PRODUCT_HANDLER_SERVICE = "api::product.handler";

🏗️ Principios de Organización Aplicados

Section titled “🏗️ Principios de Organización Aplicados”

Este ejemplo muestra las mejores prácticas implementadas:

  • Campos base vs campos específicos por tipo de producto
  • Componentes generales vs componentes especializados
  • Configuraciones (IVA, tipos) separadas de datos operacionales
  • FIELDS_* para campos de base de datos
  • COMPONENTS_* para componentes Strapi
  • *_TYPES para enumeraciones de tipos
  • *_SERVICE para referencias de servicios
  • Las constantes soportan múltiples tipos de productos
  • Reutilización entre diferentes verticales
  • Extensibilidad fácil para nuevos tipos de productos

Los componentes son bloques de contenido reutilizables que se pueden usar múltiples veces dentro de diferentes tipos de contenido.

Úsalos cuando:

  • Un conjunto de campos se repite en múltiples collection types
  • Necesitas estructuras de datos complejas y reutilizables
  • Quieres mantener consistencia en la estructura de datos
// 📞 Componente: Phone
{
"displayName": "Phone",
"attributes": {
"countryCode": { "type": "string" },
"number": { "type": "string" },
"extension": { "type": "string" }
}
}
// 🏠 Componente: Address
{
"displayName": "Address",
"attributes": {
"street": { "type": "string" },
"city": { "type": "string" },
"postalCode": { "type": "string" },
"country": { "type": "string" }
}
}
// En User collection
{
"attributes": {
"name": { "type": "string" },
"phone": {
"type": "component",
"component": "contact.phone",
"repeatable": true // Múltiples teléfonos
},
"address": {
"type": "component",
"component": "contact.address"
}
}
}