FactuGES_ERP/docs/architecture/http-request-flow.md
David dac22372b9 feat(docs): archive legacy DTO design and naming guidelines, introduce HTTP request flow, module boundaries, and testing guidelines
- Archived historical documents for DTO design and naming conventions.
- Added normative documentation for HTTP request flow and module boundaries.
- Introduced testing guidelines for backend layers.
- Updated onboarding module documentation and clarified onboarding requirements.
- Deprecated backend prompt base and prompt auth documents.
- Adjusted paths in testing documentation for consistency.
2026-09-08 23:40:49 +02:00

3.0 KiB

Flujo HTTP y entrada a Application

Estado: NORMATIVO. Define la frontera Express/Application para código nuevo y refactors futuros.

Flujo normal

RequestSchema
  ↓ validateRequest
RequestDTO
  ↓
Controller
  ↓
UseCase({ dto, context })
  ↓
I<Input>Mapper
  ↓
Value Objects / Application Props
  ↓
Application services / Domain

Este es el patrón de CreateCustomer, CreateProforma y CompleteInitialOnboarding.

Routes y guards

Las routes registran endpoints, guards, validateRequest, obtienen el internal del propio módulo y pueden construir controllers ligeros. No crean repositories, transaction managers, servicios de Application, Value Objects ni lógica de negocio.

Los guards viven en routes: requireAuthenticatedGuard(), requireCompanyContextGuard(), forbidQueryFieldGuard(...) y validateRequest(...). Algunos controllers históricos de customers y proformas aún registran guards; es deuda de alineación, no una segunda norma para código nuevo.

El schema vive junto al DTO. La route ejecuta validateRequest(SomeRequestSchema, "body" | "params" | "query"); el controller no vuelve a ejecutar Zod sobre esa entrada validada.

Controllers

Un controller lee request validada, obtiene contexto HTTP autenticado, invoca el caso de uso y traduce Result a HTTP. No crea Value Objects, no ejecuta InputMappers, no resuelve servicios de otros módulos y no contiene lógica de negocio.

Los identificadores controlados por el servidor (accountId, companyId, tenantId, actorId) no forman parte del RequestDTO ni llegan de body, query o path. Por ejemplo, onboarding usa dto = req.body, obtiene accountId = req.user.userId y ejecuta useCase.execute({ dto, accountId }).

InputMapper de Application

Cuando existe transformación de transporte a Application, el nombre preferido es I<CreateX>InputMapper / CreateXInputMapper. Recibe DTO y contexto, devuelve Result<Props | Params> y puede crear Value Objects, adaptar primitivas, convertir null/undefined a Maybe y acumular ValidationErrorDetail en una ValidationErrorCollection cuando la operación necesita varios errores de validación.

No conoce Express, repositories ni HTTP, y no construye agregados salvo un diseño explícito distinto. Se inyecta nominalmente en el use case desde DI.

RequestMapper opcional

Un RequestMapper solo se usa cuando tiene una responsabilidad HTTP propia, por ejemplo combinar body, params, query o contexto para producir un Command. IssueProformaByIdRequestMapper es el ejemplo actual.

No se crea un RequestMapper solo para transformar snake_case a camelCase si Application volverá a transformar los mismos datos.

Result y Maybe

Los InputMappers, servicios, use cases y repositories usan Result para fallos esperables según sus contratos. La frontera DTO conserva undefined y null; Application decide Maybe.some() o Maybe.none(). Las responses pueden materializar ausencia como null conforme a su DTO.

Para reglas de schema, estructura y naming, véase DTOs y schemas.