ADR 003: Estrategia hibrida monorepo + polyrepo

Estado: Aceptado Fecha: 2025-03-15 Ultima actualizacion: 2026-02-26

Contexto

Tenemos librerias compartidas (design system, tipos, configuraciones) y 5-10 micro frontends desplegables de forma independiente mantenidos por 3-5 equipos. Necesitamos una estrategia de repositorios que equilibre la comparticion de codigo con la autonomia de los equipos.

Decision

Enfoque hibrido: un monorepo (platform-core) para paquetes compartidos (design system, tipos, utils, configuraciones) usando pnpm 10.30.3 workspaces + Turborepo, y polyrepos separados para cada micro frontend. Los paquetes compartidos apuntan a React ^19.2.4.

Tarjeta de decision Hibrido Mono + Polyrepo Hybrid Mono + Polyrepo Positivo Cambios atomicos compartidos Autonomia de equipo Control de acceso separado Changesets → Renovate Negativo Latencia cross-repo Necesita Verdaccio/yalc Dos repos abiertos

Consecuencias

Positivas

  • Los paquetes compartidos se benefician de cambios atomicos (actualizar design system + tipos en un solo PR)
  • Los equipos de MFE tienen autonomia total: su propio CI/CD, su propia estrategia de ramas, su propia cadencia de releases
  • Control de acceso separado por repositorio de MFE
  • Los cambios del monorepo se propagan via Changesets -> npm publish -> Renovate
  • No es necesario reconstruir todos los MFEs cuando cambia una libreria compartida (solo los afectados via PRs de Renovate)
  • CI mas simple para cada MFE (solo construye un MFE, no toda la plataforma)

Negativas

  • Las actualizaciones de dependencias cross-repo tienen latencia (publish -> Renovate -> merge)
  • Probar la integracion entre repos requiere Verdaccio o yalc
  • Los desarrolladores que trabajan en libreria compartida y MFE necesitan dos repos abiertos
  • Gestion de Renovate/Dependabot en multiples repos
  • El versionado de paquetes compartidos requiere disciplina (Changesets ayuda)

Guia de deprecacion de paquetes compartidos

Al deprecar un paquete compartido del monorepo platform-core, seguir este proceso:

  1. Aviso de deprecacion: Agregar una entrada ## Deprecated al inicio del CHANGELOG del paquete con la fecha de deprecacion, la razon y el reemplazo recomendado (si existe).
  2. Guia de migracion: Publicar una guia de migracion en el README del paquete o en un archivo dedicado MIGRATION.md que explique paso a paso como los MFEs consumidores deben migrar desde el paquete deprecado.
  3. Ventana minima de soporte: Mantener el paquete deprecado durante un minimo de 90 dias (3 ciclos de release) tras el aviso de deprecacion. Durante esta ventana, los parches criticos de seguridad deben seguir aplicandose.
  4. Notificacion de Renovate: Configurar Renovate para agregar una etiqueta de aviso de deprecacion a los PRs que aun dependan del paquete deprecado.
  5. Procedimiento de eliminacion: Tras expirar la ventana de soporte y confirmar que todos los MFEs consumidores han migrado (verificado via estadisticas de descargas de npm y dashboards de Renovate), eliminar el paquete del workspace del monorepo y publicar una version final con un script postinstall que muestre un aviso de deprecacion.

Alternativas consideradas

  • Monorepo completo (todos los MFEs + librerias compartidas): Gestion de dependencias mas simple, cambios atomicos transversales. Pero: tiempos de CI enormes, todos los equipos en un repo genera conflictos de merge, el control de acceso es de grano grueso, no es facil tener pipelines de despliegue independientes. No escala bien mas alla de 3 equipos.
  • Polyrepo completo (todo separado): Maxima autonomia de equipo. Pero: pesadilla de versionado de paquetes compartidos, sin cambios atomicos entre librerias compartidas, deriva de configuracion entre repos, configuracion de herramientas duplicada. Los refactors transversales requieren PRs coordinados en mas de 10 repos.
  • Git submodules: Solucion tecnica para compartir codigo entre repos. Pero: flujo de trabajo complejo, conflictos de merge en referencias de submodules, mala experiencia de desarrollo, la mayoria de equipos no disfruta trabajar con submodules.