Saltar a contenido

0007. Frontend React: stack y conexión con el backend

Estado: Propuesto Fecha: 2026-08-28 Autor: Duval Alcivar

Contexto

El backend es un conjunto de microservicios FastAPI con contratos OpenAPI (ADR 0003) y autenticación JWT emitida por svc-identidad (ADR 0006). El frontend (ERP y CRM) necesita un stack único y reglas de conexión con la API: cómo lleva el token, cómo valida permisos en pantalla y cómo genera los tipos de las respuestas sin duplicarlos a mano.

Decisión

Stack

Área Herramienta
Framework React 18
Bundler / dev server Vite
Lenguaje TypeScript en modo estricto (strict: true)
UI MUI, con tema corporativo centralizado
Estado de servidor TanStack Query (fetch, caché, invalidación)
Estado de interfaz Zustand (filtros, sidebar, preferencias UI)
Formularios react-hook-form + zod (validación declarativa y tipada)
HTTP Axios centralizado, con interceptores para token y 401/403
Tipos de API Generados automáticamente desde el OpenAPI del backend
Testing Vitest + React Testing Library (unidad/componentes) + Playwright (E2E)
Calidad ESLint + Prettier + pre-commit (Husky + lint-staged)

Cómo se conecta con el backend (auth + API)

sequenceDiagram
    participant B as Navegador (app React)
    participant I as svc-identidad
    participant A as API (cualquier servicio)

    B->>I: login (usuario + clave + empresa elegida)
    I-->>B: access + refresh (empresa_id va DENTRO del token, no en la petición)
    B->>A: GET /datos — Axios inyecta Authorization: Bearer (interceptor)
    A-->>B: 200 respuestas / 401 / 403
    B->>B: guard de ruta valida rol (espejo del backend, ADR 0006)
    B->>B: 401 → refresh automático (o logout si el refresh expiró)

Reglas de conexión:

  1. El token nunca lo manda el código de negocio: el interceptor de Axios lo inyecta solo. Nunca en query, cuerpo o logs (ADR 0006).
  2. La empresa se elige al loguear desde el selector de empresas del usuario; empresa_id viaja dentro del token que emite identidad. El frontend nunca manda empresa_id como parámetro libre (ADR 0002).
  3. Tipos de API generados desde el OpenAPI (ADR 0003) en src/types/; si un tipo no sale de ahí, se rechaza el PR.
  4. Guards de ruta por rol, espejo de los permisos del backend: la UI oculta lo que no corresponde, pero el permiso real lo valida la API (defensa en dos capas).

Estructura de carpetas (por app)

app/
└── src/
    ├── app/            # router, guards, layout (sidebar, header)
    ├── core/           # axios, auth, tema MUI, utilidades
    ├── features/       # un módulo por dominio (ej. inventario, casos)
    │   └── inventario/
    │       ├── api/        # hooks de TanStack Query
    │       ├── components/ # componentes de UI del módulo
    │       ├── forms/      # react-hook-form + zod
    │       └── store/      # Zustand (estado de UI del módulo)
    └── types/          # tipos generados desde OpenAPI

Buenas prácticas (obligatorias en el PR)

  • strict: true — errores de tipo se detectan al compilar, no en producción.
  • TanStack Query para todo estado de servidor; nada de useEffect + fetch ad-hoc para datos.
  • react-hook-form + zod para formularios grandes: validación declarativa y tipada.
  • Code-splitting por módulo/ruta: carga inicial liviana.
  • Cobertura ≥75% en hooks y lógica de negocio (Vitest + RTL), con E2E de Playwright para los flujos críticos: login, crear/aprobar un caso, generar pedido.
  • ESLint + Prettier vía Husky/lint-staged antes de commit.

Alternativas descartadas

  • Next.js (SSR/SSG) — descartado: la app es una SPA que consume una API ya separada en servicios; Vite basta y hay menos superficie de despliegue.
  • Redux Toolkit — descartado para estado de interfaz: más boilerplate que Zustand para lo que se maneja aquí (filtros, sidebar, preferencias).
  • fetch nativo — descartado: los interceptores de Axios centralizan token, 401/403 y reintentos en un solo lugar.
  • Tipos de API escritos a mano — descartado: se desincronizan del contrato; se generan del OpenAPI (ADR 0003).

Consecuencias

  • Un solo lugar se encarga de auth y errores (core/axios); los módulos solo usan hooks de TanStack Query.
  • El permiso se valida en dos capas (guard de UI + API), así la UI puede mentir pero la API no.
  • Queda para el ADR de identidad (0006 + siguiente) el flujo exacto de refresh en el navegador y el manejo de la sesión en pestañas/recargas.