Files
task-stream/docs/06-desarrollo.md
Josep Piguillem 6c3550ae9d docs(auth): two Pireon clients, production URLs and sign-in troubleshooting
- Registering clients: the authorization_code client is confidential and needs
  its secret; Pireon shows it once (rotate-secret if lost); containers must be
  recreated to read new environment variables.
- Production URLs (taskstream.pireon.dev, api.taskstream.pireon.dev) and their
  redirect URIs.
- "Si el login falla": each error seen while deploying (not configured,
  unauthorized_client, missing client_secret, invalid_client, redirect URI,
  expired code, wrong credentials, intermittent 404s) with cause and fix.
- READMEs mention both clients; Word/PDF regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 16:01:33 +02:00

7.1 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 (o NEXUS_TOKEN al construir con Docker)
failed to stat /root/.npmrc al desplegar Versión antigua del docker-compose.yml: ahora el token llega por NEXUS_TOKEN (ver Despliegue)
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
El login con Pireon falla (unauthorized_client, client_secret…) Configuración de los clientes OAuth: ver Si el login falla