Traducción de
docs/en/architecture/request-flow.md, que es el original. Si discrepan, manda el inglés.
Este documento sigue tres caminos que cruzan las fronteras que más importan. Los
nombres de fichero son los de la implementación actual, no las rutas históricas
src/... de Graphify.
#1. Petición de pago de un proveedor
Ejemplo: una integración crea un PaymentIntent de Stripe o una Order de Mercado Pago.
Código del diagrama
sequenceDiagram
participant AUT as Aplicación en pruebas
participant GC as GatewayController
participant GS as GatewayService
participant P as ProviderPlugin
participant PS as PaymentsService
participant DB as PostgreSQL
AUT->>GC: Ruta del proveedor + token
GC->>GS: handle(ruta, petición)
GS->>DB: Resuelve la credencial de la aplicación
GS->>P: Empareja la ruta
GS->>DB: Resuelve el escenario y abre la traza
GS->>P: Valida la petición
GS->>PS: Ejecuta la orden canónica
PS->>DB: Transacción de lock, idempotencia, estado, libro mayor y outbox
PS->>P: toWire(vista canónica)
P-->>AUT: Respuesta con la forma del proveedor
Paso a paso:
apps/api/src/modules/gateway/gateway.controller.tscaptura la ruta del proveedor. El prefijo es opcional; la credencial decide el proveedor y el inquilino.gateway.service.tsresuelve la aplicación conApplicationsService.resolveByAccessTokeny rechaza un prefijo que no coincida.plugin.routesmapea la ruta real apayment.create,payment.confirm,payment.capture,payment.cancel,payment.getopayment.refund.ScenariosService.resolveelige el escenario de la aplicación o el que piseX-Emulator-Scenario. Los eventos de traza anotan esa decisión ya tachada.plugin.validatecomprueba el contrato del proveedor. Todavía no se ha escrito nada relativo al pago.GatewayServiceaplica la latencia, el tiempo de espera o el error HTTP del escenario.plugin.toCanonicalcrea unIntentCommand;PaymentsService.executecomprueba la regla de idempotencia del proveedor y entra en el único camino de escritura.IdempotencyService.runtoma un lock consultivo de PostgreSQL con alcance de transacción, repite el desenlace guardado cuando toca, o corre la transacción de escritura.- El estado del pago, sus transiciones, los apuntes, el recurso de proveedor y la fila de webhook que se deba se confirman juntos.
plugin.toWirecompone la respuesta. Las negativas del núcleo las traduceplugin.errors.shape()en la frontera de la pasarela.
Para cambiar este flujo, decide antes si la regla es propia de un proveedor
(apps/api/src/providers/<id>/) o universal (core/, gateway, payments,
ledger o webhooks). Un if por proveedor dentro de un servicio del núcleo
es un defecto de arquitectura.
#2. El comprador completa un checkout
El enlace del checkout es una capacidad. Autenticarse es opcional: añade el pago con cartera, mientras que tarjeta, transferencia y ticket siguen disponibles de forma anónima.
Código del diagrama
sequenceDiagram
participant B as Navegador del comprador
participant N as Nitro del checkout
participant C as CheckoutService
participant P as PaymentsService
participant DB as PostgreSQL
B->>N: GET de la URL del checkout
N->>C: GET /checkout/:proveedor/:recurso
C->>DB: Carga recurso, intento y sesión de cliente opcional
C-->>B: Importe, métodos y sólo el saldo propio
B->>N: Confirma el método elegido
N->>C: POST /checkout/.../confirm
C->>C: Exige cliente sólo para el método de cartera
C->>P: completeFromCheckout()
P->>DB: Lock, transición, contabilidad, outbox
C-->>B: Vista actualizada
Ficheros implicados:
- Páginas:
apps/checkout/app/pages/mercadopago/checkout/[resourceId].vueyapps/checkout/app/pages/stripe/c/pay/[resourceId].vue. - Kits:
apps/checkout/providers/<id>/Checkout.vueytheme.css. - Proxy de Nitro:
apps/checkout/server/api/checkout/[provider]/[resourceId]/. - Superficie de la API:
apps/api/src/modules/checkout/checkout.controller.tsycheckout.service.ts. - Escritura compartida:
apps/api/src/modules/payments/payments.service.ts.
Para el método de cartera, CheckoutService resuelve una sesión de cliente
válida, toma el walletKey de esa identidad y comprueba el saldo propio de esa
persona. Un customerId que venga en el cuerpo nunca se cree. Para los demás
métodos, fundingSource es external y el libro mayor usa el efectivo del
sistema en vez de una cartera.
PaymentsService.completeFromCheckout toma un lock consultivo y refresca el
intento dentro de él. Ese refresco es esencial: sin él, dos clics concurrentes
pueden leer un estado rancio del identity map y cobrar más de una vez.
#3. Entrega de un webhook
Código del diagrama
sequenceDiagram
participant PS as PaymentsService
participant DB as PostgreSQL
participant OD as OutboxDispatcher
participant Q as Transporte (Postgres, Mongo o Redis)
participant W as Manejador del worker
participant I as Webhook de la integración
PS->>DB: Confirma pago + webhook_event
OD->>DB: Reclama las filas que tocan (SKIP LOCKED)
OD->>Q: Le entrega la entrega
Q->>W: Despacha con reintentos
W->>DB: Lee el evento y la aplicación
W->>W: El plugin firma el cuerpo
W->>I: POST al callback permitido
W->>DB: Anota el intento y el estado final
WebhooksService.schedulecrea laWebhookEventEntitycon el gestor transaccional del pago. Si falla cualquiera de las dos escrituras, no se confirma ninguna.OutboxDispatcher.sweepreclama las filas que tocan o que quedaron rancias conFOR UPDATE SKIP LOCKED, sellaqueued_aty se las entrega al transporte. Con el driverpostgresno corre en absoluto: ese driver lee esas mismas filas, y dos reclamadores sobre una tabla es una carrera.- Un
enqueuefallido no pierde ninguna notificación; el barrido de lo rancio puede reclamar la fila otra vez. - El manejador de
apps/api/src/worker.tscompruebaRUNTIME_OUTBOUND_ENABLED, el protocolo de la URL y que el host resuelva a una direccion publica (WEBHOOK_ALLOWED_HOSTSson las excepciones). - El plugin aporta el asunto, el cuerpo y la firma. El worker aporta el transporte y la política de reintentos.
WebhookAttemptEntityanota estado HTTP, duración o error. Los escenarios pueden retrasar, duplicar o firmar mal un evento a propósito.
El modelo de entrega es al menos una vez. Las integraciones tienen que ser idempotentes; una entrega duplicada es posible en la operación y además se puede provocar a propósito para probarla.
#Peticiones del plano de control
Los controladores del plano de control declaran RolesGuard, y los que tienen
alcance por aplicación declaran además ApplicationScopeGuard. Las peticiones
del navegador de la consola van por apps/console/server/api/;
apps/console/server/utils/api.ts reenvía el token de la persona que entró desde
una cookie sellada. La ordenación, el filtrado y la búsqueda los valida la lista
blanca del endpoint, y siempre se devuelve { data, meta }. Ver
el contrato de listados.
La aprobación de PayPal termina en approved, sin débito ni retención. La
autorización o captura del comercio es otra petición; véase PayPal.