AgriSense SaaS — Monorepo Nx

Plan de arquitectura y patrones de workspace para produccion · Generado por CULTIVA IA

Nx 19 + Cloud Cache
🗂️
Estructura del Workspace
agrisense-workspace/
agrisense-workspace/ apps/ # Aplicaciones deployables portal-cooperativas/ # Next.js 14 — portal B2B │ │ project.json # tags: type:app, scope:web │ │ src/ │ └admin-panel/ # React SPA — panel interno project.json # tags: type:app, scope:admin src/ libs/ # Librerias compartidas shared/ # scope:shared — disponible a todos │ │ ui-components/ # type:ui — Design System AgriSense │ │ │ src/lib/Button.tsx │ │ │ src/lib/Chart.tsx │ │ │ src/lib/SensorCard.tsx │ │ util-formatting/ # type:util — fechas, unidades, i18n │ │ util-validators/ # type:util — validators puros │ │ data-access-auth/ # type:data-access — tokens, session web/ # scope:web — solo portal cooperativas │ │ feature-dashboard/ # type:feature — dashboard sensores │ │ feature-alertas/ # type:feature — alertas y notifs │ │ feature-informes/ # type:feature — export PDF/Excel │ │ data-access-sensors/ # type:data-access — API sensores IoT │ └admin/ # scope:admin — solo panel interno feature-usuarios/ # type:feature — CRUD cooperativas feature-facturacion/ # type:feature — billing y planes tools/ # Generators y executors custom generators/ feature-lib/ # nx g agrisense:feature-lib nx.json # Configuracion global + NxCloud tsconfig.base.json # Path aliases compartidos .eslintrc.json # Module boundary rules .github/workflows/ci.yml # CI con affected commands
📦
Tipos de Libreria — AgriSense
feature
Componentes inteligentes y logica de negocio especifica
feature-dashboard
🎨
ui
Componentes presentacionales puros sin estado global
ui-components
🔌
data-access
Llamadas API, gestion de estado y caches de datos
data-access-sensors
🔧
util
Funciones puras, helpers, formatters sin dependencias UI
util-formatting
🐚
shell
Bootstrapping, routing raiz y providers globales de la app
shell-portal
⚙️
Configuracion nx.json con NxCloud
📄 nx.json
JSON
{ "$schema": "./node_modules/nx/schemas/nx-schema.json", "npmScope": "agrisense", // Solo testear/construir lo que cambia respecto a main "affected": { "defaultBase": "main" }, "tasksRunnerOptions": { "default": { "runner": "nx-cloud", // Cache remoto compartido entre devs "options": { "cacheableOperations": ["build", "lint", "test", "e2e"], "accessToken": "${NX_CLOUD_ACCESS_TOKEN}", "parallel": 3 } } }, "targetDefaults": { "build": { "dependsOn": ["^build"], // Construye deps primero "inputs": ["production", "^production"], "cache": true }, "test": { "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"], "cache": true }, "lint": { "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], "cache": true } }, "namedInputs": { "production": [ "default", "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", "!{projectRoot}/tsconfig.spec.json" ], "sharedGlobals": [ "{workspaceRoot}/tsconfig.base.json" ] } }
🛡️ .eslintrc.json — Module Boundary Rules
JSON
{ "plugins": ["@nx"], "overrides": [{ "rules": { "@nx/enforce-module-boundaries": ["error", { "depConstraints": [ // Apps pueden importar cualquier tipo de lib { "sourceTag": "type:app", "onlyDependOnLibsWithTags": ["type:feature","type:ui","type:data-access","type:util"] }, // Feature solo puede usar ui, data-access y util { "sourceTag": "type:feature", "onlyDependOnLibsWithTags": ["type:ui","type:data-access","type:util"] }, // UI solo puede importar util (sin logica de negocio) { "sourceTag": "type:ui", "onlyDependOnLibsWithTags": ["type:ui", "type:util"] }, // Scope: web no puede importar libs de admin (y viceversa) { "sourceTag": "scope:web", "onlyDependOnLibsWithTags": ["scope:web", "scope:shared"] }, { "sourceTag": "scope:admin", "onlyDependOnLibsWithTags": ["scope:admin", "scope:shared"] } ] }] } }] }
🔒
Matriz de Limites de Modulo
Tipo fuente Puede importar Ejemplo en AgriSense
type:app
type:feature type:ui type:data-access type:util
portal-cooperativas importa feature-dashboard
type:feature
type:ui type:data-access type:util
feature-alertas usa ui-components + data-access-sensors
type:ui
type:ui type:util
SensorCard solo usa util-formatting para labels
type:data-access
type:data-access type:util
data-access-sensors usa util-validators para schemas
type:util
type:util
util-formatting no importa nada externo
scope:web
scope:web scope:shared
portal-cooperativas no puede tocar libs de admin
🚀
CI Pipeline con Affected Commands
Step 1
Checkout
~15s
Step 2
npm ci
~45s
Step 3
affected lint
~30s
Step 4
affected test
~60s
Step 5
affected build
~90s
❌ Antes — Build Total
🔨Build portal-cooperativas completo
🔨Build admin-panel completo
🧪Tests de las 11 libs (todas)
🔍Lint de todo el workspace
⚠️Sin cache — siempre reconstruye
25 min
por cada PR
✅ Ahora — Affected + Cache
Solo proyectos afectados por el diff
💚Cache hit para libs no modificadas
Paralelo x3 (lint, test, build)
☁️NxCloud comparte cache entre devs
🔄SHA derivation automatica (nrwl/nx-set-shas)
~4 min
promedio por PR tipico
.github/workflows/ci.yml
YAML
name: CI AgriSense on: push: branches: [main] pull_request: branches: [main] env: NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} jobs: main: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Necesario para calcular affected - uses: actions/setup-node@v4 with: node-version: 20 cache: "npm" - name: Install dependencies run: npm ci - name: Derive SHAs for affected uses: nrwl/nx-set-shas@v4 # Calcula base SHA automaticamente - name: Lint affected run: npx nx affected -t lint --parallel=3 - name: Test affected run: npx nx affected -t test --parallel=3 --configuration=ci - name: Build affected run: npx nx affected -t build --parallel=3
🔮
Custom Generator — Feature Lib AgriSense
1

Invocar el generator

nx g agrisense:feature-lib --name=exportar-csv --scope=web

2

Crea la libreria con tags correctos

Genera libs/web/feature-exportar-csv/ con tags: type:feature, scope:web automaticamente. Sin riesgo de olvidar los tags.

3

Estructura estandar garantizada

Incluye src/index.ts, jest.config.ts, tsconfig.json y project.json preconfigurados. Listo para desarrollar.

4

Path alias registrado en tsconfig.base.json

Anade "@agrisense/feature-exportar-csv": ["libs/web/feature-exportar-csv/src/index.ts"] automaticamente.

🔧 tools/generators/feature-lib/index.ts
TypeScript
import { Tree, formatFiles, generateFiles, names, joinPathFragments } from "@nx/devkit"; import { libraryGenerator } from "@nx/react"; interface FeatureLibSchema { name: string; scope: "web" | "admin" | "shared"; } export default async function featureLibGenerator( tree: Tree, options: FeatureLibSchema ) { const { name, scope } = options; await libraryGenerator(tree, { name: `feature-${name}`, directory: `libs/${scope}/feature-${name}`, // Tags: garantizan que module boundaries funcionen tags: `type:feature,scope:${scope}`, style: "css", unitTestRunner: "jest", linter: "eslint", skipFormat: true }); await formatFiles(tree); return () => console.log(`✅ Lib feature-${name} creada en scope:${scope}`); }
Comandos Esenciales del Dia a Dia
Comando Descripcion Uso
nx affected -t test --base=main
Ejecuta tests solo en proyectos afectados por cambios vs main
CI
nx graph
Visualiza el grafo de dependencias interactivo del workspace
DEV
nx g agrisense:feature-lib --name=X --scope=web
Genera nueva feature lib con tags y estructura estandar
DEV
nx build portal-cooperativas --configuration=production
Build de produccion del portal (usa cache si no hay cambios)
CACHE
nx reset
Limpia cache local cuando hay problemas de estado inconsistente
CACHE
nx migrate latest && nx migrate --run-migrations
Actualiza Nx y todos los plugins a la ultima version estable
MAINT
📊
ROI Estimado para AgriSense
-84%
Tiempo CI por PR
De 25 min a ~4 min
con affected + NxCloud cache
3.360h
Horas dev ahorradas/ano
10 devs × 8 PRs/sem
× 21 min ahorrados × 52 sem
~42k€
Valor monetario/ano
3.360h × 12,5 €/h (coste medio)
sin contar frustración dev
Plan de migracion — 4 semanas
SEMANA 1
Init workspace Nx. Mover apps existentes a apps/. Configurar nx.json base.
SEMANA 2
Extraer ui-components y utils compartidos. Definir tags y module boundaries.
SEMANA 3
Crear feature libs por dominio. Activar NxCloud. Primer CI con affected.
SEMANA 4
Custom generators. Documentar limites. Training equipo. Go-live completo.