FactuGES_ERP/docs/architecture/http-request-flow.md

56 lines
3.0 KiB
Markdown
Raw Permalink Normal View History

# Flujo HTTP y entrada a Application
> Estado: **NORMATIVO**. Define la frontera Express/Application para código nuevo y refactors futuros.
## Flujo normal
```text
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](./dto-guidelines.md).