Saltar a contenido

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) en app/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ía get_* 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; application e infrastructure son hermanos independientes.
  • module-independence: los 16 módulos no se importan entre sí (ADR-004).
  • domain-purity: ningún domain importa sqlalchemy, fastapi ni pydantic.
  • no-app-old: prohíbe resucitar imports de app.old (retirado en OLDKILL13).