Referencia: mapa de módulos y puertos¶
Esta página es una referencia (Diátaxis): un mapa consultable de los módulos de la aplicación y de los puertos compartidos a través de los que se comunican. No es un tutorial ni una guía; describe qué hay y quién depende de quién.
La arquitectura es hexagonal modular: cada módulo vive en
app/modules/{modulo}/ con sus capas domain, application, infrastructure e
interface. La regla ADR-004 prohíbe que un módulo importe a otro directamente:
toda comunicación entre módulos pasa por puertos compartidos definidos en
app/shared/application/ports.py, o por eventos de dominio.
Conceptos clave
- Módulo: unidad vertical (
app/modules/{m}/) que posee su dominio, casos de uso, ORM y routers. - Puerto: interfaz abstracta (
ABC) enapp/shared/application/ports.py. Define un contrato que un módulo consume y otro implementa mediante un adaptador. - Registry lazy: cada puerto tiene un par
register_*/get_*. El adaptador concreto se registra en el arranque (app/main.py) y los consumidores lo obtienen víaget_*para evitar imports circulares y cross-module.
Páginas relacionadas: Arquitectura hexagonal.
Módulos¶
Los 16 módulos bajo app/modules/. Los contratos de aislamiento de
backend/.importlinter (capas hexagonales, independencia de módulos y pureza de
dominio) se aplican exactamente a esta misma lista de 16 módulos. La columna
"Arquitectura" enlaza a la página de arquitectura del módulo cuando existe.
| Módulo | Carpeta | Responsabilidad | Arquitectura |
|---|---|---|---|
admin_user |
app/modules/admin_user/ |
Gestión de usuarios administradores (CRUD de staff/manager/super-admin del panel). | Usuarios admin y roles |
analytics |
app/modules/analytics/ |
Analítica de solo lectura para admin y registro de eventos de comportamiento del comensal (behavior_events) de la arquitectura híbrida. |
Servicios de plataforma |
audit |
app/modules/audit/ |
Registro de auditoría: persiste acciones administrativas auditables (AuditLogModel) y las expone al admin. |
Servicios de plataforma |
auth |
app/modules/auth/ |
Autenticación de clientes y administradores: decodifica bearer tokens (JOSE) y resuelve la entidad de usuario. | Seguridad y multitenancy |
chat |
app/modules/chat/ |
Conversación con el camarero IA: conversaciones, mensajes, streaming SSE, motores legacy/híbrido y árboles de decisión (conversation_trees). |
Chat híbrido |
comanda |
app/modules/comanda/ |
Ciclo de vida de la comanda/pedido (orders / order_lines): state machine, validación IA, coursing, agregación del ticket. |
Comanda |
customer |
app/modules/customer/ |
Gestión de la entidad cliente final (perfil del comensal). | Clientes y reseñas |
errors |
app/modules/errors/ |
Recepción y persistencia de logs de error (ErrorLog) reportados por los clientes. |
Servicios de plataforma |
manager |
app/modules/manager/ |
"Control de sala": dashboard de manager en tiempo real, reconciliación del ciclo de vida de mesas y flag de carga de cocina. No posee ORM persistente propio. | Control de sala |
menu |
app/modules/menu/ |
Catálogo: menús, categorías, productos, extras, grupos de opciones, promociones y base de conocimiento. | Menú y catálogo |
payment |
app/modules/payment/ |
Facturación y cobro: construye la cuenta (Bill), gestiona pagos (Payment) e integra el PSP. |
Pago |
recommendation |
app/modules/recommendation/ |
Recomendador determinista (capas 0-2) y artefactos precalculados (recommendation_artifacts); el motor decide, el LLM redacta. |
Recomendación |
restaurant |
app/modules/restaurant/ |
Restaurante y su conocimiento (Restaurant, RestaurantKnowledge), salas (Room), control de acceso multitenant y políticas de aprobación. |
Restaurante, salas y mesas |
review |
app/modules/review/ |
Reseñas: el cliente envía valoración (ReviewModel); el admin las lista por restaurante. |
Clientes y reseñas |
session |
app/modules/session/ |
Sesión de mesa (TableSession): apertura por QR, carrito (CartItem), ciclo de vida de la sesión y llamadas al manager. |
Sesiones y carrito |
table |
app/modules/table/ |
Mesas (Table) y códigos QR; directorio de nombres de mesa. |
Restaurante, salas y mesas |
Modelos compartidos fuera de los módulos
AdminUser vive en app/shared/identity (movido ahí en ARCH02), no en el
módulo admin_user. El rate limiting (app/infrastructure/rate_limiting/) y
el adaptador POS por defecto (app/shared/infrastructure/pos/) tampoco son
módulos: son infraestructura compartida.
Puertos compartidos¶
Puertos definidos en app/shared/application/ports.py. Para cada uno: el par de
funciones register_* / get_*, quién lo implementa (adaptador concreto,
registrado en app/main.py) y quién lo consume.
Patrón de registro
El consumidor llama get_<puerto>(...); si el adaptador no se ha registrado en
el arranque, get_* lanza RuntimeError. Los puertos cuyo factory recibe una
AsyncSession (get_*(db)) devuelven un adaptador ligado a esa sesión; los que
no la reciben (get_*()) devuelven un singleton/stateless.
Puerto (ABC) |
register_* / get_* |
Implementado por | Consumido por |
|---|---|---|---|
IRestaurantAccessChecker |
register_restaurant_access_checker / get_restaurant_access_checker |
restaurant (RestaurantAccessChecker) |
Routers admin con guardas multitenant (check_access, list_accessible_ids) |
IRoomDirectory |
register_room_directory / get_room_directory |
restaurant (RoomDirectoryAdapter) |
table |
IRestaurantInfoGateway |
register_restaurant_info_gateway / get_restaurant_info_gateway |
restaurant (RestaurantInfoGatewayAdapter) |
chat (skill consulta_local) |
IComandaChecker |
register_comanda_checker / get_comanda_checker |
comanda (ComandaCheckerAdapter) |
menu (soft-delete de productos) |
IAuditTrailWriter |
register_audit_trail_writer / get_audit_trail_writer |
audit (AuditTrailWriter) |
Módulos con acciones admin auditables |
IRateLimiter |
register_rate_limiter / get_rate_limiter |
app/infrastructure/rate_limiting/ (RedisRateLimiter o DbRateLimiter) |
Endpoints costosos / middleware de rate limit |
IAdminAuthenticator |
register_admin_authenticator / get_admin_authenticator |
auth (JoseAdminAuthenticator) |
Dependencias HTTP compartidas (get_current_admin_user) |
ICustomerAuthenticator |
register_customer_authenticator / get_customer_authenticator |
auth (JoseCustomerAuthenticator) |
Dependencias HTTP compartidas (get_current_customer) |
IMenuCatalogGateway |
register_menu_catalog_gateway / get_menu_catalog_gateway |
menu (ComandaMenuCatalogGateway) |
comanda (validar productos/extras/grupos de opciones) |
ISessionCartGateway |
register_session_cart_gateway / get_session_cart_gateway |
session (ComandaSessionCartGateway) |
comanda (leer/borrar/upsert carrito + summary de sesión) |
IConversationGateway |
register_conversation_gateway / get_conversation_gateway |
chat (ComandaConversationGateway) |
comanda (tarjetas, fase de conversación, nudges proactivos) |
IRestaurantPolicyGateway |
register_restaurant_policy_gateway / get_restaurant_policy_gateway |
restaurant (RestaurantPolicyGatewayAdapter) |
comanda (order_approval_mode, chat_mode, ai_proactive_enabled) |
ITicketHistoryGateway |
register_ticket_history_gateway / get_ticket_history_gateway |
comanda (ComandaTicketHistoryGateway) |
recommendation (matriz de co-ocurrencia, capa 1) |
IRecommendationEngineGateway |
register_recommendation_engine_gateway / get_recommendation_engine_gateway |
recommendation (RecommendationEngineGateway) |
chat (recomendaciones deterministas, sin LLM) |
ICoursingGateway |
register_coursing_gateway / get_coursing_gateway |
comanda (ComandaCoursingGateway) |
chat (tab, plan de coursing, disparo de cursos) |
IBehaviorEventRecorder |
register_behavior_event_recorder / get_behavior_event_recorder |
analytics (SqlBehaviorEventRecorder) |
chat y comanda (eventos de comportamiento) |
IBillingGateway |
register_billing_gateway / get_billing_gateway |
comanda (ComandaBillingGateway) |
payment (construir la cuenta) |
IPaymentGateway |
register_payment_gateway / (sin get_* en ports.py) |
payment (FakePaymentGateway) |
payment (PayBillUseCase) |
IChatProvisioningGateway |
register_chat_provisioning_gateway / get_chat_provisioning_gateway |
chat (ChatProvisioningGateway) |
session (crear conversación + saludo inicial) |
ITableDirectory |
register_table_directory / get_table_directory |
table (TableDirectoryAdapter) |
session (nombre de mesa en la app del cliente) |
IManagerSessionGateway |
register_manager_session_gateway / get_manager_session_gateway |
session (ManagerSessionGatewayAdapter) |
manager (ciclo de vida de la sesión; list_all_active para el monitor de fondo) |
IManagerCourtesyGateway |
register_manager_courtesy_gateway / get_manager_courtesy_gateway |
comanda (ManagerCourtesyGatewayAdapter) |
manager (ronda de cortesía gratis 0€) |
IManagerOrderGateway |
register_manager_order_gateway / get_manager_order_gateway |
comanda (ManagerOrderGatewayAdapter) |
manager (reconciliar señales de pedido) |
IKitchenLoadGateway |
register_kitchen_load_gateway / get_kitchen_load_gateway |
manager (InMemoryKitchenLoadGateway) |
chat (orientar hacia platos rápidos en pico) |
IPaymentGateway es la excepción al par register_* / get_*
IPaymentGateway se define en app/shared/application/ports.py pero su
register_payment_gateway vive en app.modules.payment.domain.ports, no en el
registry compartido, y no expone un get_* en ports.py. El resto de puertos
(23) siguen el patrón uniforme register_* / get_* del módulo compartido.
Excepciones de cruce de frontera
Algunos puertos definen excepciones propias para que el consumidor pueda
traducirlas a HTTP o frasear el motivo al cliente sin importar el módulo
implementador: CourseFireError (ICoursingGateway) y CourtesyRoundError
(IManagerCourtesyGateway, con missing_ids para 404/422).
Adaptadores ligados a sesión vs. stateless
Reciben la AsyncSession en el factory (get_*(db)): IMenuCatalogGateway,
ISessionCartGateway, IConversationGateway, IRestaurantPolicyGateway,
ITicketHistoryGateway, IRecommendationEngineGateway, ICoursingGateway,
IBehaviorEventRecorder, IBillingGateway, IChatProvisioningGateway,
IManagerSessionGateway, IManagerCourtesyGateway, IManagerOrderGateway.
Son singleton/stateless (get_*() sin sesión): IRestaurantAccessChecker,
IRoomDirectory, IRestaurantInfoGateway, IComandaChecker,
IAuditTrailWriter, IRateLimiter, IAdminAuthenticator,
ICustomerAuthenticator, ITableDirectory, IKitchenLoadGateway.
Dónde se registra todo¶
Los adaptadores se cablean en el composition root, app/main.py, tras importar
todos los módulos. Es el único sitio (junto a app/core/event_wiring.py y
app/worker/runner.py) autorizado por ADR-004 a conocer varios módulos a la vez.
El cumplimiento de ADR-004 y de las capas hexagonales se verifica con
import-linter (backend/.importlinter, vía make lint-arch), que es un gate duro
en CI. Sus cuatro contratos son:
hexagonal-layers: en cada módulo,interface> (application|infrastructure) >domain;applicationeinfrastructureson hermanos independientes.module-independence: los 16 módulos no se importan entre sí (ADR-004).domain-purity: ningúndomainimportasqlalchemy,fastapinipydantic.no-app-old: prohíbe resucitar imports deapp.old(retirado en OLDKILL13).