Reglas de arquitectura hexagonal — Backend
Capas y dependencias
- domain/: solo entidades y errores de dominio. No puede importar
infrastructure,adaptersnirepository. - adapters/: handlers HTTP y WS. Pueden usar
crate::repository(re-export de infrastructure) ycrate::domain::entitiespara DTOs/validaciones. Objetivo a medio plazo: que los handlers llamen a una capa de aplicación (use cases) y no a repos directamente. - infrastructure/: persistencia, config, email, activity_log. Puede importar
domain::entitiespara tipos. No debe importaradapters.
Lógica de negocio
- Reglas de negocio (validaciones, cálculos, permisos) no deben vivir solo en handlers. Mover a funciones en módulos de dominio o a un futuro módulo
application/(commands/queries). - Handlers: extraer parámetros, llamar a aplicación/dominio, mapear a respuesta HTTP. No poner algoritmos complejos (ej. auto_assign) dentro del handler; extraer a módulo dedicado que el handler solo invoque.
❌ Prohibido (lógica en handler)
// Dentro de time_control_handler.rs
if req.staff_id.is_some() && req.actor_session_id.is_none() {
repository::place::check_place_manage(...).await?;
}
// + toda la lógica de distancia, resolución de actor, etc.
// Handler solo orquesta
let result = time_control::clock_in(&state.pool, &req, auth.user_id).await?;
Ok(Json(TimeControlResponse::from(result)))
time_control o en domain/application.)
Imports
- En handlers:
use crate::repository::*,use crate::db::AppState,use crate::error::AppError, y si aplicause crate::domain::entities::*. No importar rutas deinfrastructure::persistence::postgres::*directamente; usar siemprecrate::repository. - En domain: solo módulos bajo
domain/y tipos estándar. Sincrate::repository,crate::infrastructure,crate::adapters.
Repos y SQLx
- Los repos pueden devolver structs propios (ej.
ShiftRow) que contengan datos de fila. Evitar filtrar datos por tenant (place_id) solo en el handler; el repo debe recibirplace_idcuando corresponda y filtrar en la query.