06 - Módulos: pedidos y API pública
Hasta aquí la tienda era un solo bloque por capas. Este hito aplica el tema 04 — Monolito modular: se añade el segundo problema de negocio, pedidos, y con él la organización en módulos — cada uno protege su interior y expone una API pública. Los pedidos reservan el stock del catálogo por esa API: la primera colaboración síncrona entre módulos de la práctica.
| Pieza | Cambio en este hito |
|---|---|
| Contrato | v0.2.0: las operaciones de pedidos |
| Estructura | Paquetes catalog y orders como módulos; API pública del catálogo |
| Verificación | Límites entre módulos con Spring Modulith; capas internas con ArchUnit |
1. El contrato se amplía
- Añadir a
openapi.yaml(v0.2.0) las operaciones de pedidos y regenerar:
| Operación | Petición | Respuestas |
|---|---|---|
| Crear pedido | POST /api/orders · OrderRequest | 201 · 400 · 404 · 409 |
| Ficha de pedido | GET /api/orders/{id} | 200 · 404 |
| Cancelar | POST /api/orders/{id}/cancel | 200 · 404 · 409 |
- Esquemas nuevos:
OrderRequest(userIdy líneas),OrderLineRequest(productId,quantity),OrderLine(productId,quantity,unitPrice) yOrder(id,userId,state,lines,total).
El campo
userId de OrderRequest es provisional: no hay usuarios todavía y el comprador se indica en el cuerpo. En el hito 08 la identidad vendrá del token y el campo desaparecerá del contrato.
2. Reorganización en módulos
- Reorganizar los paquetes por módulo de negocio (con
git mv, para conservar el historial): el catálogo queda dentro deshop.catalog; el pedido nace directamente enshop.orders; la raíz de composición —ShopApplicationy la configuración de arranque — queda en el paquete base. - API pública del catálogo: la interfaz
CatalogApidel esquema de la especificación, expuesta encatalog.api. Por ella cruzan al pedido las capacidades que necesita — reservar las unidades de una línea, dejando capturado el precio del momento, y liberar las reservadas al cancelar —, con sus datos y sus errores. La forma exacta de esa API — firmas, datos, qué excepciones cruzan el límite — es diseño de cada quien; lo fijo es el resultado: si una línea falla, el stock queda como estaba y no se crea nada. - El interior de cada módulo queda protegido; lo único que el pedido puede consumir del catálogo es su API pública. Lo que cruza el límite forma parte del contrato público del módulo del catálogo; las excepciones de su dominio interno no salen de él (sección 4).
- El interior de
orderslo compone cada quien con las piezas del tema 04 — REST propio, casos de uso, servicio y persistencia JDBC —. Las tablasordersyorder_linesde la especificación entran en elinit.sql(reiniciar el volumen de MariaDB para recargar la semilla); el precio de cada línea se guarda capturado (unit_pricede la especificación).
3. Reservar stock, sin transacciones
- Al crear el pedido, todas las líneas reservan su stock por la API pública del catálogo; el pedido y sus líneas se guardan con los precios capturados.
- Todavía sin transacciones: sostener la garantía del contrato — si una línea falla, el stock queda como estaba y no se crea el pedido — con JDBC suelto obliga a componer la protección a mano, y el resultado es frágil: si persistir el pedido falla después de reservar, el stock queda reservado sin pedido. Es el punto que el hito 07 resolverá con transacciones; el fallo servirá de pista para valorarlas.
- Cancelar solo cabe desde
CREATED; cancelar un pedido ya cancelado es un estado imposible del dominio de pedidos, que responde 409. También se mapean los errores del catálogo que llegan al pedido: 404 para producto desconocido, 409 para stock insuficiente.
4. Verificación de límites
La verificación de módulos pasa a correr con cada build, según el tema 04: los límites entre módulos con Spring Modulith y las reglas de capas dentro de cada módulo con ArchUnit. Opcional: generar la documentación de módulos con el Documenter del tema.
5. Pruebas
- Módulo orders (aislado, con la API pública del catálogo doblada): crear un pedido reserva el stock de todas las líneas y persiste el pedido; si una línea falla, no queda nada; cancelar libera el stock y pasa el estado a
CANCELLED; cancelar dos veces falla. - Módulo catalog (aislado): la reserva y la liberación por la API pública mantienen el stock coherente.
- Presentación de pedidos (con los módulos doblados): estados 201 / 200 / 404 / 409 según contrato.
- Lo de los hitos anteriores sigue verde: catálogos y productos no cambian de comportamiento con la reorganización.
Comprobación
- La verificación de módulos y las reglas de capas pasan en cada build.
- Los pedidos funcionan de punta a punta: crear, consultar y cancelar desde Swagger UI, con el stock reservado y liberado de verdad.
- Un pedido con una línea sin stock responde 409 y no deja nada reservado.
orderssolo consume la API pública del catálogo: lo comprueba la verificación, no la buena voluntad.- Contrato en v0.2.0; commit y tag
hito-06.
Siguiente hito: hito 07 — Persistencia con JPA.