CULTIVA IA · Consultoría & Estrategia

Arquitecto Senior de Sistemas

Análisis arquitectónico completo — cultiva-plataforma v1.0.0

Proyecto: cultiva-plataforma
Stack: TypeScript / Node.js + React
Analizado: 12 jun 2026
Issues detectados: 7 críticos
🏗

Veredicto: Monolito Modular + extracción progresiva

El sistema tiene arquitectura en capas bien intencionada pero con 3 dependencias circulares críticas y un dios objeto (SkillExecutorService, 1 873 líneas). La recomendación es refactorizar el monolito en módulos cohesivos y extraer únicamente el módulo reports como primer microservicio autónomo, dado que ya tiene su propio repositorio y no comparte base de datos con el núcleo.

Coupling Score
68/100
Acoplamiento moderado-alto
Dependencias circulares
3
auth → user → permissions → auth
Archivos problemáticos
1
SkillExecutorService.ts (1 873 líneas)
Patrón detectado
Layered
Architecture
Confianza: 85%
Cobertura de tests
12%
Módulo agents sin tests de integración
Health score global
42/100
Requiere refactorización urgente
Diagrama de Arquitectura — Componentes (Mermaid)
Vista visual
API
Express API Gateway
:3000 · 5 route groups
↓↓↓↓↓
Controllers
AuthCtrl
ClientCtrl
SkillCtrl
AgentCtrl
ReportCtrl
↓↓↓↓↓
Services
AuthSvc
ClientSvc
SkillExecutor
GOD
AgentOrch
ReportSvc
PaymentSvc
CIRC
↓↓↓↓
Repos
UserRepo
ClientRepo
SkillRepo
ReportRepo
↓↓
Data
PostgreSQL
pg 8.11.3
Redis
redis 4.6.12
Stripe API
stripe 14.13
Anthropic API
skills engine
Código Mermaid generado
graph TD GW[Express API Gateway] --> AC[AuthController] GW --> CC[ClientController] GW --> SC[SkillController] GW --> AGC[AgentController] GW --> RC[ReportController] AC --> AS[AuthService] CC --> CS[ClientService] SC --> SE[SkillExecutorService] AGC --> AO[AgentOrchestrator] RC --> RS[ReportService] SE --> AO SE --> CS SE --> RS PS[PaymentService] --> AS PS --> CS PS --> SE subgraph Repositories UR[UserRepo] CR[ClientRepo] SKR[SkillRepo] RR[ReportRepo] end subgraph ExternalAPIs DB[(PostgreSQL)] RD[(Redis)] STR[Stripe API] ANT[Anthropic API] end
🔗
Análisis de Dependencias
Dependencias circulares detectadas
PaymentService
AuthService
UserRepository
PaymentService
SkillExecutor
AgentOrchestrator
SkillExecutor
ClientService
AuthService
ClientRepository
ClientService
Solución recomendada: extraer interfaces compartidas a src/shared/interfaces/ e inyectar dependencias por contrato.
Top 10 dependencias externas
PaqueteVersiónEstado
express4.18.2OK
typescript5.3.3OK
stripe14.13.0OK
jsonwebtoken9.0.2OK
axios1.6.5Update
bcryptjs2.4.3Deprecated
bull4.12.2→ BullMQ
pg8.11.3OK
redis4.6.12OK
zod3.22.4OK
Issues Detectados (7 críticos)
Code Smells
🔴
God Object — SkillExecutorService
Clase con 30+ métodos y 1 873 líneas que mezcla ejecución, validación, reporting, caché y gestión de errores. Viola SRP gravemente.
src/services/SkillExecutorService.ts (1873 líneas)
🔴
Mixed Concerns — PaymentController
La capa de control invoca directamente lógica de negocio de auth, clients y skill execution sin pasar por un facade de pagos.
src/controllers/ClientController.ts
🟡
Layer Violation — Repos importados en Services
Varios services importan repositories directamente sin abstracción de unidad de trabajo (Unit of Work pattern).
src/services/*.ts
🟡
Missing DTOs — Models mezclados con domain
Los interfaces en src/models/ mezclan entidades de dominio y DTOs de transferencia de datos, generando acoplamiento innecesario con la API.
src/models/*.ts
Gaps de calidad
🔴
Sin tests de integración en módulo agents
El directorio tests/integration/ está vacío. AgentOrchestrator es el componente más crítico (orquesta llamadas a LLMs externos) y carece de tests de contrato.
tests/integration/ ← vacío
🔴
Error handling no estandarizado
Hay una clase AppError definida pero no todos los servicios la usan. Algunos lanzan Error genérico. Los errores de Stripe y Anthropic no se mapean a errores de dominio.
src/shared/errors.ts
🟡
Dependencia de bull (deprecated)
La librería bull 4.x está en modo mantenimiento. Migrar a BullMQ con soporte de TypeScript nativo y Redis Streams.
package.json
🔵
bcryptjs → argon2id
bcryptjs no recibe actualizaciones de seguridad activas. Migrar a argon2 (argon2id) para hashing de contraseñas con mejor resistencia a GPU attacks.
src/services/AuthService.ts
🏛
Evaluación Arquitectónica
Patrón actual: Layered Architecture
Presentación (controllers + routes) ✓ Detectado
Negocio (services) ⚠ Problemas
Acceso a datos (repositories) ✓ Detectado
Domain models / DTOs separados ✗ Mezclados
Tests en todas las capas ✗ Incompleto
Decisión: Monolito vs Microservicios
¿Equipo < 10 desarrolladores?
Sí (4 devs)
¿Fronteras de dominio bien definidas?
Parcial
¿Iteración rápida es prioridad?
¿Scaling independiente de reports?
Sí (requerido)
¿Base de datos compartida aceptable?
Parcial
Decisión: Mantener monolito modular + extraer reports como primer microservicio independiente (fase 2).
🎯
Plan de Refactorización (5 pasos)
  1. 1
    Dividir SkillExecutorService en 5 servicios focalizados Crear: SkillValidatorService, SkillRunnerService, SkillCacheService, SkillReporterService, SkillPermissionsService. Cada uno con <300 líneas y una única responsabilidad. Estimar: 2 sprints.
  2. 2
    Romper dependencias circulares con interfaz compartida Crear src/shared/interfaces/IAuthProvider.ts, IClientProvider.ts. PaymentService depende de las interfaces, no de las implementaciones. Aplicar inyección de dependencias con un IoC container (tsyringe o InversifyJS).
  3. 3
    Añadir tests de integración al módulo agents Implementar contract tests para AgentOrchestrator usando MSW (Mock Service Worker) para interceptar llamadas a Anthropic API. Objetivo: 80% coverage en agents antes de la siguiente release.
  4. 4
    Separar Domain Models de DTOs Crear src/domain/ para entidades puras y src/api/dtos/ para contratos de API. Usar Zod para validar en la capa de entrada. Esto también facilitará la extracción de ReportService como microservicio.
  5. 5
    Extraer módulo reports como microservicio autónomo ReportService + ReportRepository tienen la menor dependencia con el núcleo. Exponer via gRPC o REST interno. Base de datos propia (PostgreSQL schema reports). Permite escalar reports 10x sin afectar el monolito principal.
📋
Architecture Decision Records (ADRs)
ADR-001: Mantener monolito modular como base arquitectónica
Aceptado
Contexto: Equipo de 4 personas, 6 meses de historia, deuda técnica acumulada. Decisión: Refactorizar el monolito a módulos cohesivos en lugar de migrar a microservicios completos. Trade-offs: Simplicidad operacional a cambio de escalado selectivo limitado.
ADR-002: Extraer módulo reports como primer servicio independiente
Aceptado
Contexto: El equipo necesita escalar reports independientemente del core. ReportService tiene las menores dependencias externas (solo ReportRepository y su DB schema). Decisión: Extraer en Fase 2 como servicio REST interno en el mismo cluster Kubernetes. Trade-offs: Latencia de red < 2ms vs gestión de servicio adicional.
ADR-003: Migrar de bull a BullMQ para colas de skill execution
Propuesto
Contexto: bull 4.x en modo mantenimiento. La ejecución de skills de IA requiere colas confiables con retry y dead-letter queues. Decisión propuesta: Migrar a BullMQ 5.x antes del Q3 2026. Esfuerzo estimado: 1 sprint.