Versión: 4.0 (Alineada con Estándares Master)
Estado: NORMATIVO - DEFINICIÓN TÉCNICA PROFUNDA.
Referencia Obligatoria: ESTANDARES_DESARROLLO.md (La Biblia).
La arquitectura se basa en dos capas de abstracción estrictamente separadas. Simappe es el Framework (Inmutable). Centrica es el Negocio (Extensible).
SimappeModel: DTOs de sistema (Users, Roles, Configs). NO TOCAR.SimappeCommons: Clientes base, Seguridad, Multi-tenancy engine. NO TOCAR.SimappeArchetype: Plantilla base de servicios.CentricaModel (Nuevo): Biblioteca OBLIGATORIA. Contendrá el 100% de los DTOs de intercambio. Gobernanza: Solo Gatekeepers pueden aprobar cambios aquí. Ver Estándares V4.0.CentricaShared (Nuevo): Biblioteca OBLIGATORIA. Contendrá los Clientes Web. Gobernanza: Inner Source restringido.El equipo no implementa multi-tenancy; lo hereda.
Database-Based Multi-tenancy (Oracle) / Collection-Based (Mongo).TenantAwareDataSource intercepta cada transacción. Lee el tenantId del JWT (inyectado por Gateway/Security) y enruta la conexión a la base de datos correcta del tenant.SimappeRepository. El framework inyecta el filtro de tenant automáticamente.@IgnoreTenant (Requiere aprobación).No configuramos beans manualmente en cada microservicio.
@EnableSimappeContext: Anotación maestra en SimappeCommons que levanta:
SecurityConfig: Valida JWT y extrae roles.AuditConfig: Llena createdBy/createdAt automáticamente.SwaggerConfig: Estandariza la documentación API.ExceptionConfig: Global Controller Advice (SimappeException -> JSON Error Standard).La arquitectura no "corre en Tomcat". Corre en Imágenes OCI Distroless.
Dockerfile Standard: Proveeido por el Arquitecto.
Base: eclipse-temurin:25-jre-alpine.
Layering: Dependencias cacheadas separadas del código fuente.
Config: Inyección de variables (DB_URL, KAFKA_BROKER) vía Docker Compose/K8s Secrets.
Patrón Real Simappe (Validado con SimappeClient):
// Controller extends SimappeController
public class MenuConfigurationController extends SimappeController {
private final MenuConfigurationService menuConfigurationService;
public ResponseEntity<MenuCustomizationDTO> get(Long id, HttpServletRequest request) {
var dto = menuConfigurationService.get(id, request); // Solo llama al Service
return new ResponseEntity<>(dto, HttpStatus.OK);
}
}
// Service (simple @Service, NO extiende nada)
@Service
public class MenuConfigurationService {
private final MenuConfigurationComponent menuConfigurationComponent;
public MenuCustomizationDTO get(Long id, HttpServletRequest request) {
return menuConfigurationComponent.get(id, request); // Solo delega al Component
}
}
// Component extends SimappeService - AQUÍ está la lógica de negocio
@Component
@ConnectionContext
@EntityIdSupport
public class MenuConfigurationComponent extends SimappeService {
private final MenuCustomizationRepository menuCustomizationRepository;
public MenuCustomizationDTO get(Long id, HttpServletRequest request) {
// LÓGICA DE NEGOCIO REAL
LongId longId = convertToLongId(id);
Optional<MenuCustomization> optionalEntity = menuCustomizationRepository.findById(longId);
if(optionalEntity.isPresent()) {
return this.loadForEntity(optionalEntity.get()); // Mapeo Entity → DTO
}
return MenuCustomizationDTO.builder().build();
}
}
// Repository extends SimappeRepository
public interface MenuCustomizationRepository
extends SimappeRepository<MenuCustomization, LongId> {
// Custom queries
}
Tabla de Responsabilidades (Según Código Real):
| Capa | Clase | Extiende/Anota | Responsabilidad REAL |
|---|---|---|---|
| Controller | MenuConfigurationController |
extends SimappeController |
✅ Endpoints REST ✅ Validación HTTP ✅ Llama al Service ❌ SIN lógica de negocio |
| Service | MenuConfigurationService |
@Service (simple) |
✅ SOLO DELEGADOR ✅ Llama métodos del Component ✅ Orquestación multi-component (si aplica) ❌ SIN lógica de negocio ❌ NO extiende SimappeService |
| Component | MenuConfigurationComponent |
extends SimappeService@Component@ConnectionContext@EntityIdSupport |
✅ TODA LA LÓGICA DE NEGOCIO ✅ Validaciones ✅ Transformaciones ✅ Mapeo Entity ↔ DTO ✅ CRUD Operations ✅ Usa Repository ✅ Hereda métodos de SimappeService |
| Repository | MenuCustomizationRepository |
extends SimappeRepository<E, LongId> |
✅ Acceso a BD ✅ Custom queries ✅ Integración automática con TenantContext |
Flujo Real (14 pasos validados):
Puntos Clave:
@Service ← Solo delegador, NO extiende nada<dependencies>
<!-- Framework Core (Solo lectura) -->
<dependency>
<groupId>com.catcsoft.simappe</groupId>
<artifactId>simappe-commons</artifactId>
</dependency>
<!-- Business Core (Escritura permitida) -->
<dependency>
<groupId>com.centrica.nebula</groupId>
<artifactId>centrica-model</artifactId> <!-- DTOs NEBULA -->
</dependency>
<dependency>
<groupId>com.centrica.nebula</groupId>
<artifactId>centrica-shared</artifactId> <!-- Clients NEBULA -->
</dependency>
</dependencies>
Request (JSON)
➔ Controller (Nebula)
➔ Mapper (MapStruct: DTO Centrica <-> Entity)
➔ Service (Nebula) extiende SimappeService
➔ @Transactional (Tenant Aware)
➔ Component (Reglas de Negocio Puras)
➔ Repository (Nebula) extiende SimappeRepository
➔ DB (Database Tenant)
Para crear un nuevo endpoint en Nebula:
InvoiceDto en el proyecto CentricaModel. (Requiere PR a Gatekeeper).1.0.1). Prohibido mvn deploy local.InvoiceController en nebula-invoicing usando el DTO importado.InvoiceWebClient en CentricaShared.CentricaModel, no existe. Prohibido crear clases Request/Response internas ("Inner Classes").com.catcsoft.simappe.*. Si hay un bug en el Core, se escala al Arquitecto.ThreadLocal) del tenant; dejar que SimappeCommons lo gestione.| Version | Fecha | Autor | Descripcion |
|---|---|---|---|
| 1.1.0 | 2026-03-04 | Carlos Torres | Revision, sanitizacion y publicacion en Wiki Arquitectura Centrica. |
| 1.0.0 | 2025-12-27 | Carlos Torres | Creacion del documento. |