# πŸ—οΈ SeparaciΓ³n de Capas y OrganizaciΓ³n de LΓ³gica de Negocio ## 🎯 Objetivo Estudiar y definir cΓ³mo separar las capas de la aplicaciΓ³n y organizar la lΓ³gica de negocio siguiendo Clean Architecture. --- ## πŸ“ Arquitectura en Capas ### Estructura Propuesta ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ PRESENTATION LAYER (Routes) β”‚ β”‚ - Express Routes β”‚ β”‚ - Middleware (auth, validation, rate-limit) β”‚ β”‚ - Request/Response DTOs β”‚ β”‚ - NO lΓ³gica de negocio β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ APPLICATION LAYER (Use Cases) β”‚ β”‚ - Services (orquestaciΓ³n) β”‚ β”‚ - Use Cases (casos de uso especΓ­ficos) β”‚ β”‚ - DTOs de aplicaciΓ³n β”‚ β”‚ - Validaciones de aplicaciΓ³n β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DOMAIN LAYER (Core) β”‚ β”‚ - Entities (entidades de negocio) β”‚ β”‚ - Value Objects (objetos de valor) β”‚ β”‚ - Domain Services (lΓ³gica de dominio pura) β”‚ β”‚ - Repository Interfaces (contratos) β”‚ β”‚ - Domain Events β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ INFRASTRUCTURE LAYER (ImplementaciΓ³n) β”‚ β”‚ - Repository Implementations β”‚ β”‚ - Database Access β”‚ β”‚ - File Storage β”‚ β”‚ - External Services β”‚ β”‚ - Cache β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ“ OrganizaciΓ³n de Carpetas ``` backend/src/ β”œβ”€β”€ domain/ # 🎯 DOMAIN LAYER β”‚ β”œβ”€β”€ entities/ # Entidades de negocio β”‚ β”‚ β”œβ”€β”€ ContentItem.ts β”‚ β”‚ β”œβ”€β”€ Drug.ts β”‚ β”‚ β”œβ”€β”€ Protocol.ts β”‚ β”‚ β”œβ”€β”€ GlossaryTerm.ts β”‚ β”‚ └── MedicalReview.ts β”‚ β”‚ β”‚ β”œβ”€β”€ value-objects/ # Objetos de valor inmutables β”‚ β”‚ β”œβ”€β”€ ContentStatus.ts β”‚ β”‚ β”œβ”€β”€ ContentPriority.ts β”‚ β”‚ β”œβ”€β”€ DoseRange.ts β”‚ β”‚ β”œβ”€β”€ PatientAge.ts β”‚ β”‚ β”œβ”€β”€ PatientWeight.ts β”‚ β”‚ └── Version.ts β”‚ β”‚ β”‚ β”œβ”€β”€ services/ # Servicios de dominio β”‚ β”‚ β”œβ”€β”€ CriticalErrorDetector.ts β”‚ β”‚ β”œβ”€β”€ DoseCalculator.ts β”‚ β”‚ └── ProtocolValidator.ts β”‚ β”‚ β”‚ β”œβ”€β”€ repositories/ # Interfaces de repositorios β”‚ β”‚ β”œβ”€β”€ IContentRepository.ts β”‚ β”‚ β”œβ”€β”€ IDrugRepository.ts β”‚ β”‚ β”œβ”€β”€ IGlossaryRepository.ts β”‚ β”‚ └── IMediaRepository.ts β”‚ β”‚ β”‚ └── events/ # Eventos de dominio β”‚ β”œβ”€β”€ ContentSubmitted.ts β”‚ β”œβ”€β”€ ContentApproved.ts β”‚ └── ContentPublished.ts β”‚ β”œβ”€β”€ application/ # πŸ”§ APPLICATION LAYER β”‚ β”œβ”€β”€ services/ # Servicios de aplicaciΓ³n β”‚ β”‚ β”œβ”€β”€ ContentService.ts β”‚ β”‚ β”œβ”€β”€ DrugService.ts β”‚ β”‚ β”œβ”€β”€ DoseValidationService.ts β”‚ β”‚ β”œβ”€β”€ ProtocolValidationService.ts β”‚ β”‚ β”œβ”€β”€ MedicalValidationService.ts β”‚ β”‚ └── MediaService.ts β”‚ β”‚ β”‚ β”œβ”€β”€ use-cases/ # Casos de uso especΓ­ficos β”‚ β”‚ β”œβ”€β”€ content/ β”‚ β”‚ β”‚ β”œβ”€β”€ CreateContentUseCase.ts β”‚ β”‚ β”‚ β”œβ”€β”€ UpdateContentUseCase.ts β”‚ β”‚ β”‚ β”œβ”€β”€ SubmitForReviewUseCase.ts β”‚ β”‚ β”‚ └── PublishContentUseCase.ts β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ drugs/ β”‚ β”‚ β”‚ β”œβ”€β”€ CalculateDoseUseCase.ts β”‚ β”‚ β”‚ β”œβ”€β”€ ValidateDoseUseCase.ts β”‚ β”‚ β”‚ └── CreateDrugUseCase.ts β”‚ β”‚ β”‚ β”‚ β”‚ └── protocols/ β”‚ β”‚ β”œβ”€β”€ ExecuteProtocolUseCase.ts β”‚ β”‚ └── ValidateProtocolSequenceUseCase.ts β”‚ β”‚ β”‚ └── dto/ # Data Transfer Objects β”‚ β”œβ”€β”€ CreateContentDTO.ts β”‚ β”œβ”€β”€ UpdateContentDTO.ts β”‚ └── DoseCalculationDTO.ts β”‚ β”œβ”€β”€ infrastructure/ # πŸ”Œ INFRASTRUCTURE LAYER β”‚ β”œβ”€β”€ repositories/ # Implementaciones de repositorios β”‚ β”‚ β”œβ”€β”€ ContentRepository.ts β”‚ β”‚ β”œβ”€β”€ DrugRepository.ts β”‚ β”‚ β”œβ”€β”€ GlossaryRepository.ts β”‚ β”‚ └── MediaRepository.ts β”‚ β”‚ β”‚ β”œβ”€β”€ database/ # Acceso a base de datos β”‚ β”‚ β”œβ”€β”€ Database.ts β”‚ β”‚ β”œβ”€β”€ migrations/ β”‚ β”‚ └── queries/ β”‚ β”‚ β”‚ β”œβ”€β”€ storage/ # Almacenamiento de archivos β”‚ β”‚ β”œβ”€β”€ FileStorage.ts β”‚ β”‚ └── MediaStorage.ts β”‚ β”‚ β”‚ β”œβ”€β”€ cache/ # Sistema de cachΓ© β”‚ β”‚ └── CacheService.ts β”‚ β”‚ β”‚ └── external/ # Servicios externos β”‚ └── NotificationService.ts β”‚ └── presentation/ # 🌐 PRESENTATION LAYER β”œβ”€β”€ routes/ # Rutas Express β”‚ β”œβ”€β”€ content.ts β”‚ β”œβ”€β”€ drugs.ts β”‚ β”œβ”€β”€ glossary.ts β”‚ β”œβ”€β”€ media.ts β”‚ └── validation.ts β”‚ β”œβ”€β”€ middleware/ # Middleware β”‚ β”œβ”€β”€ auth.ts β”‚ β”œβ”€β”€ validate.ts β”‚ └── rate-limit.ts β”‚ └── validators/ # Validadores Zod β”œβ”€β”€ content.ts β”œβ”€β”€ drugs.ts └── glossary.ts ``` --- ## πŸ”„ Flujo de Datos ### Ejemplo: Crear Contenido ``` 1. Request β†’ Route (presentation/routes/content.ts) ↓ 2. Validar con Zod (presentation/validators/content.ts) ↓ 3. Llamar Use Case (application/use-cases/content/CreateContentUseCase.ts) ↓ 4. Use Case llama Service (application/services/ContentService.ts) ↓ 5. Service usa Domain Entities (domain/entities/ContentItem.ts) ↓ 6. Service llama Repository Interface (domain/repositories/IContentRepository.ts) ↓ 7. Repository Implementation (infrastructure/repositories/ContentRepository.ts) ↓ 8. Database (infrastructure/database/Database.ts) ↓ 9. Response ← Route ``` --- ## πŸ“ Reglas de SeparaciΓ³n ### βœ… Domain Layer - **SÍ:** Entidades, Value Objects, LΓ³gica de negocio pura - **SÍ:** Interfaces de repositorios - **NO:** Acceso a base de datos - **NO:** Dependencias externas - **NO:** Frameworks (Express, etc.) ### βœ… Application Layer - **SÍ:** Casos de uso, OrquestaciΓ³n - **SÍ:** Validaciones de aplicaciΓ³n - **SÍ:** DTOs de aplicaciΓ³n - **NO:** LΓ³gica de dominio (debe estar en Domain) - **NO:** Acceso directo a base de datos ### βœ… Infrastructure Layer - **SÍ:** Implementaciones de repositorios - **SÍ:** Acceso a base de datos - **SÍ:** Servicios externos - **NO:** LΓ³gica de negocio - **NO:** Validaciones de dominio ### βœ… Presentation Layer - **SÍ:** Routes, Middleware - **SÍ:** ValidaciΓ³n de entrada (Zod) - **SÍ:** TransformaciΓ³n Request/Response - **NO:** LΓ³gica de negocio - **NO:** Acceso directo a repositorios --- ## 🎯 Ejemplo de ImplementaciΓ³n ### Domain Entity (Inmutable) ```typescript // domain/entities/ContentItem.ts export class ContentItem { private constructor( readonly id: string, readonly type: ContentType, readonly title: string, readonly status: ContentStatus, readonly createdAt: Date, readonly updatedAt: Date ) {} static create( id: string, type: ContentType, title: string ): ContentItem { // Validaciones de dominio if (!title || title.trim().length === 0) { throw new Error('TΓ­tulo es obligatorio'); } return new ContentItem( id, type, title, ContentStatus.DRAFT, new Date(), new Date() ); } submitForReview(): ContentItem { if (this.status !== ContentStatus.DRAFT) { throw new Error('Solo contenido en borrador puede enviarse a revisiΓ³n'); } return new ContentItem( this.id, this.type, this.title, ContentStatus.IN_REVIEW, this.createdAt, new Date() ); } // Inmutable: siempre retorna nueva instancia } ``` ### Use Case ```typescript // application/use-cases/content/CreateContentUseCase.ts export class CreateContentUseCase { constructor( private readonly contentRepository: IContentRepository, private readonly validator: ContentValidator ) {} async execute(input: CreateContentDTO): Promise { // 1. Validar entrada this.validator.validateCreate(input); // 2. Crear entidad de dominio const content = ContentItem.create( crypto.randomUUID(), input.type, input.title ); // 3. Persistir await this.contentRepository.save(content); // 4. Retornar return content; } } ``` ### Repository Interface (Domain) ```typescript // domain/repositories/IContentRepository.ts export interface IContentRepository { findById(id: string): Promise; findAll(filters: ContentFilters): Promise; save(content: ContentItem): Promise; delete(id: string): Promise; } ``` ### Repository Implementation (Infrastructure) ```typescript // infrastructure/repositories/ContentRepository.ts export class ContentRepository implements IContentRepository { constructor(private readonly db: Database) {} async findById(id: string): Promise { const result = await this.db.query( 'SELECT * FROM tes_content.content_items WHERE id = $1', [id] ); if (result.rows.length === 0) return null; return this.mapToDomain(result.rows[0]); } async save(content: ContentItem): Promise { // Mapear de dominio a persistencia const row = this.mapToPersistence(content); await this.db.query( `INSERT INTO tes_content.content_items (...) VALUES (...)`, [row] ); return content; } private mapToDomain(row: any): ContentItem { // Mapear de persistencia a dominio } private mapToPersistence(content: ContentItem): any { // Mapear de dominio a persistencia } } ``` ### Route (Presentation) ```typescript // presentation/routes/content.ts router.post( '/', authenticate, requirePermission('content:write'), validateBody(createContentSchema), async (req: AuthRequest, res: Response) => { try { const useCase = new CreateContentUseCase( contentRepository, contentValidator ); const content = await useCase.execute(req.body); res.status(201).json({ id: content.id, title: content.title, status: content.status.toString() }); } catch (error) { handleError(error, res); } } ); ``` --- ## πŸ”’ Reglas de Dependencias ### Regla de Dependencia - **Domain:** No depende de nadie - **Application:** Solo depende de Domain - **Infrastructure:** Depende de Domain y Application - **Presentation:** Depende de Application y Domain ### Diagrama de Dependencias ``` Presentation β†’ Application β†’ Domain ↓ ↓ Infrastructure β†’ Domain ``` --- ## βœ… Checklist de SeparaciΓ³n Al crear nuevo cΓ³digo, verificar: - [ ] ΒΏEstΓ‘ en la capa correcta? - [ ] ΒΏDepende solo de capas inferiores? - [ ] ΒΏLa lΓ³gica de negocio estΓ‘ en Domain? - [ ] ΒΏLos casos de uso estΓ‘n en Application? - [ ] ΒΏLas implementaciones estΓ‘n en Infrastructure? - [ ] ΒΏLas rutas estΓ‘n en Presentation? --- **Fin del documento**