Skip to content

Visión General de la Arquitectura ​

Kaleo es una plataforma SaaS multi-tenant construida en capas claramente separadas. Cada capa tiene una responsabilidad única y solo se comunica con las capas adyacentes.

Diagrama de capas ​

┌─────────────────────────────────────────────────────────────────┐
│                         NAVEGADOR                               │
├─────────────────────────────────────────────────────────────────┤
│  View (.vue)                                                    │
│    ├── Feature Component (components/features/**/*)            │
│    │     └── Ui Component (components/ui/Ui*.vue)              │
│    └── Composable (composables/use*.ts)                         │
│          ├── Store (stores/*.store.ts)                          │
│          │     └── Service (services/*.service.ts)              │
│          │           └── apiClient (api/axios.ts)              │
└──────────────────────────────┬──────────────────────────────────┘
                               │ HTTP + JWT + x-company-id
┌──────────────────────────────▼──────────────────────────────────┐
│                     BACKEND (NestJS)                            │
│  Guards → Controller → Service                                  │
│                 └── Repository (raw SQL)                        │
│                       └── TypeORM DataSource                   │
│                             └── PostgreSQL (Supabase)          │
└─────────────────────────────────────────────────────────────────┘

Reglas de arquitectura ​

#ReglaRazón
1Las views no llaman a apiClient directamenteTodo pasa por el store o un composable
2Los stores paginados usan usePaginatedSetupEvita ~80 líneas de boilerplate idéntico por módulo
3Los feature components emiten eventos, no modifican el storeSeparación de presentación y estado
4Los componentes Ui* no tienen lógica de dominioSon reutilizables entre módulos
5Los repositorios usan rows<T>() y row<T>()Centraliza el cast desde any[]
6packages/shared es la fuente de verdad de permisos y rolesBackend y frontend nunca se desincronían
7Las migraciones SQL son numeradas e inmutables después de aplicarseGarantiza estado reproducible de la BD

Estructura del frontend (frontend/src/) ​

DirectorioResponsabilidad
api/Instancia axios con interceptores de auth, refresh automático y enriquecimiento de errores
assets/main.css — sistema de diseño completo en CSS custom properties
components/ui/32 componentes del design system (Ui*) — sin lógica de dominio
components/features/Componentes de dominio por módulo (tablas, cards, badges específicos)
composables/Lógica reutilizable: paginación, tablas, modales, formularios, async
constants/Permisos, roles, brand — re-exportan packages/shared
directives/v-permission para ocultar elementos sin permiso
layouts/AuthenticatedLayout.vue (app post-login), AuthLayout.vue (páginas públicas)
router/index.ts — rutas + navigation guards de autenticación, permisos y tenant
services/Una clase por recurso API (llaman a apiClient)
stores/5 stores Pinia: auth, company, branch, member, audit
types/Interfaces TypeScript por entidad
utils/Helpers de error, texto, fechas, tokens, contraseñas
views/Una view por ruta/página — orquestan composables, stores y componentes

Estructura del backend (backend/src/) ​

Directorio / ArchivoResponsabilidad
auth/JWT, refresh tokens, registro, sesión, cambio de contraseña
members/CRUD de usuarios por empresa
company/Empresas multi-tenant, creación, actualización
branches/Sedes (ubicaciones) por empresa
rbac/Roles y permisos configurables por empresa
audit/Interceptor global + logs con paginación por cursor
email/Brevo API → SMTP → stub
two-factor/Tipos para 2FA (TOTP)
common/config/Validación de variables de entorno con Joi
common/constants/Permisos y roles (espejo de packages/shared)
common/decorators/@Public, @RequirePermissions, @Roles, @CurrentUser, @Audit
common/dto/DTOs compartidos: PaginationQueryDto, buildOrderBy
common/filters/SentryExceptionFilter (global, captura 5xx)
common/guards/JWT, CompanyAccess, Permissions, Roles, SuperAdmin
common/middleware/RequestLoggerMiddleware (pino JSON)
common/types/db-rows.ts — interfaces de filas SQL
common/utils/db.ts, sql.helper.ts, transaction.helper.ts
migrations/SQL versionado 000–017
main.tsBootstrap NestJS: Sentry, CORS, ValidationPipe, Swagger

Flujo de una request típica ​

1. Browser envía: POST /api/companies/branches
   Headers: Authorization: Bearer <token>, x-company-id: <uuid>

2. Guards (en orden):
   ThrottlerGuard     → ¿demasiados requests?
   JwtAuthGuard       → ¿token válido y no en blacklist?
   PasswordChangedGuard → ¿debe cambiar contraseña?
   CompanyAccessGuard → ¿usuario pertenece a la empresa del header?

3. Controller: @RequirePermissions('branches:create')
   PermissionsGuard verifica el permiso

4. Service: lógica de negocio

5. Repository: SQL crudo tipado con rows<T>()

6. AuditLogInterceptor: registra la acción automáticamente

7. Respuesta: { success: true, data: Branch, message: 'Sede creada' }

Documentación de Kaleo — plataforma SaaS multi-tenant