Files
task-stream/docs/06-desarrollo.md
2026-10-03 13:40:26 +02:00

6.7 KiB

6. Desarrollo

6.1 Requisitos

  • Node 22 y npm 10.

  • Docker (PostgreSQL, MongoDB y Redis).

  • Acceso al Nexus de Pireon para @pi/ui. El scope está en .npmrc (sin token); el token va en tu ~/.npmrc:

    npm config set //nexus.pireon.dev/repository/npm-releases/:_authToken "<token>"
    

6.2 Puesta en marcha

npm install
docker compose up -d postgres mongo redis
cp .env.example .env            # ajusta PIREON_*
npx nx serve api                # http://localhost:3000 (GraphiQL en /graphql)
npx nx serve web                # http://localhost:4200

nx serve web usa apps/web/proxy.conf.json para enviar /api y /graphql (también el WebSocket) a la API, así que la web y la API comparten origen igual que en Docker.

6.3 Comandos

Comando Qué hace
npx nx run-many -t lint Lint de todo, incluidas las reglas de capas y contextos
npx nx run-many -t test Tests unitarios (dominio y aplicación, API y web)
npx nx e2e api Flujo completo de la API contra Docker, con Pireon simulado
npx nx run-many -t build Builds de la API y la web
npx nx run web:codegen Regenera los tipos GraphQL del cliente desde apps/api/schema.gql
npx nx run api:prune Build de la API con package.json y lockfile podados (lo usa Docker)
npx nx graph Grafo de dependencias entre proyectos
npx nx test api-tracker-domain Tests de una librería concreta (api-<contexto>-<capa>, web-<contexto>-<capa>)

Tests

Dónde Qué se prueba Herramienta
api/*/domain Reglas de los agregados y reconstrucción desde el historial de eventos Jest
api/*/application Commands contra un event store en memoria (incluida la concurrencia) Jest + @nestjs/testing
apps/api/e2e Todo el flujo: GraphQL → Postgres → Redis → Mongo → subscriptions Jest contra Docker
web/*/domain, web/*/application Sesión y reducers del tablero Jest / Vitest
apps/web Rutas y guards Vitest

El e2e sustituye a Pireon por usuarios fijos (token-ana, token-bob…) con overrideProvider(IdentityProvider); el resto de la pila es real.

6.4 Cómo añadir una funcionalidad

Ejemplo: marcar un ticket como bloqueado con un motivo. El recorrido es siempre el mismo, de dentro hacia fuera.

API

  1. Dominio (libs/api/tracker/domain)
    • Evento issue-blocked.event.ts con @AutowiredEvent, que extiende TrackerEvent.
    • En Issue, el método block(actorId, reason) valida y hace this.apply(new IssueBlockedEvent(…)); el handler onIssueBlockedEvent(event) cambia el estado.
    • Test en issue.spec.ts, incluida la reconstrucción desde el historial (replay).
  2. Aplicación (libs/api/tracker/application)
    • commands/block-issue.command.ts y block-issue.command-handler.ts: rehidratar (WriteAccess), llamar al dominio y commitAndWait(). Registrar el handler en command-handlers.ts.
    • Método en IssuesService.
    • Proyección event-handlers/issue-blocked.event-handler.ts (@EventsHandler) que actualiza el read model y avisa por ReadModelNotifier. Añadir el evento al ActivityEventHandler y una frase en activity-summary.ts.
    • Si el read model cambia, añadir el campo a IssueReadModel (dominio) y al esquema Mongo (infraestructura).
  3. Presenters (libs/api/tracker/presenters): input y mutation blockIssue en IssueResolver, que llama al service.
  4. Arrancar la API para regenerar apps/api/schema.gql.

Web

  1. npx nx run web:codegen tras añadir la mutation a issues.graphql.
  2. Dominio: método en el puerto IssuesGateway. Infraestructura: implementarlo en GraphqlIssuesGateway.
  3. Aplicación: evento blockRequested en issuePageEvents, su efecto en IssueStore (runCommand) y el método block(reason) en IssueFacade.
  4. Presenters: botón y formulario en la página del ticket que llaman a facade.block(reason).

El lint impide atajos: si un resolver intenta usar un repositorio o una página intenta usar Apollo, falla. Y como application solo exporta facades, una página tampoco puede tocar un store ni despachar eventos por su cuenta.

6.5 Problemas conocidos

Síntoma Causa y solución
npm install falla con Cannot read properties of null (reading 'edgesOut') Bug de npm con un peer opcional de Vite que arrastra vitest 5. El overrides de package.json fija vitest; no lo quites
401 al instalar @pi/ui Falta el token del Nexus en ~/.npmrc
nx serve web arranca en el puerto 3000 Nx carga el .env raíz (PORT=3000) en todas las tareas; apps/web/.env lo fija en 4200
La API no ve un evento nuevo al deserializar La clase del evento no tiene @AutowiredEvent o no se importa
Un componente de @pi/ui lanza Unable to find icon Falta registrar ese icono en libs/web/shared/ui/src/lib/icons.ts
Tablas antiguas (projects, issues, outbox) en tu Postgres local Restos de una versión anterior sin event sourcing; docker compose down -v empieza de cero