Diagrama de Componentes - Microservicio de Proveedores
Descripción General
El Microservicio de Proveedores gestiona el ciclo de vida completo del proveedor, incluyendo registro, validación de documentos, participación en subastas e informes de ejecución. Implementa Clean Architecture con patrón CQRS y maneja flujos de trabajo de negocio complejos como el sistema de subastas del marketplace.
El microservicio maneja:
- Registro e incorporación de proveedores
- Carga, validación y gestión de expiración de documentos
- Creación y gestión de subastas
- Envío de ofertas y selección del ganador
- Envío de informes de ejecución
- Calificación y estadísticas de proveedores
Diagrama de Componentes
graph TB
subgraph "Capa de Aplicación"
ProviderController["ProviderController<br/>[REST Controller]<br/>Endpoints de gestión de proveedores"]
AuctionController["AuctionController<br/>[REST Controller]<br/>Endpoints de subasta y marketplace"]
CreateProviderHandler["CreateProviderHandler<br/>[Command Handler]<br/>Registra nuevo proveedor"]
UploadDocumentoHandler["UploadDocumentoHandler<br/>[Command Handler]<br/>Sube documento del proveedor a Azure Blob Storage"]
UpdateDocumentoEstadoHandler["UpdateDocumentoEstadoHandler<br/>[Command Handler]<br/>Aprueba/rechaza documentos del proveedor"]
PublishAuctionHandler["PublishAuctionHandler<br/>[Command Handler]<br/>Publica orden en subasta del marketplace"]
SubmitOfferHandler["SubmitOfferHandler<br/>[Command Handler]<br/>Proveedor envía oferta de subasta"]
SelectWinnerHandler["SelectWinnerHandler<br/>[Command Handler]<br/>Agente selecciona ganador de subasta"]
SubmitQuotationHandler["SubmitQuotationHandler<br/>[Command Handler]<br/>Proveedor envía cotización de ítem"]
SubmitExecutionReportHandler["SubmitExecutionReportHandler<br/>[Command Handler]<br/>Proveedor envía informe de ejecución"]
GetProviderByIdHandler["GetProviderByIdHandler<br/>[Query Handler]<br/>Recupera detalles del proveedor"]
ListProvidersHandler["ListProvidersHandler<br/>[Query Handler]<br/>Lista proveedores con filtros"]
GetProviderDocumentosHandler["GetProviderDocumentosHandler<br/>[Query Handler]<br/>Recupera documentos del proveedor"]
ListAuctionsHandler["ListAuctionsHandler<br/>[Query Handler]<br/>Lista subastas disponibles"]
GetAuctionOffersHandler["GetAuctionOffersHandler<br/>[Query Handler]<br/>Recupera ofertas para subasta"]
ProviderCreatedEventHandler["ProviderCreatedEventHandler<br/>[Event Handler]<br/>Maneja evento ProviderCreated"]
DocumentoEstadoChangedEventHandler["DocumentoEstadoChangedEventHandler<br/>[Event Handler]<br/>Maneja cambios de estado de documento"]
AuctionPublishedEventHandler["AuctionPublishedEventHandler<br/>[Event Handler]<br/>Maneja evento AuctionPublished"]
OfferSubmittedEventHandler["OfferSubmittedEventHandler<br/>[Event Handler]<br/>Maneja evento OfferSubmitted"]
OrderClosedEventHandler["OrderClosedEventHandler<br/>[Event Handler]<br/>Actualiza calificación de proveedor al cerrar orden"]
DocumentoExpiryCheckTask["DocumentoExpiryCheckTask<br/>[Tarea Programada]<br/>Verificación diaria de documentos que expiran/expirados"]
end
subgraph "Capa de Dominio"
ProviderEntity["Provider Entity<br/>[Aggregate Root]<br/>Modelo de dominio de proveedor"]
ProviderDocumentoVO["ProviderDocumento<br/>[Objeto de Valor]<br/>Metadata de documento"]
ProviderEstadoEnum["ProviderEstado<br/>[Enum]<br/>PENDING_DOCUMENTS, ACTIVE, SUSPENDED, REJECTED"]
AuctionEntity["Auction Entity<br/>[Aggregate Root]<br/>Modelo de dominio de subasta"]
AuctionOfferVO["AuctionOffer<br/>[Objeto de Valor]<br/>Oferta del proveedor en subasta"]
AuctionEstadoEnum["AuctionEstado<br/>[Enum]<br/>DRAFT, PUBLISHED, BIDDING, CLOSED, CANCELLED"]
ProviderRepositorio["ProviderRepositorio<br/>[Interface]<br/>Abstracción de repositorio"]
AuctionRepositorio["AuctionRepositorio<br/>[Interface]<br/>Abstracción de repositorio"]
end
subgraph "Capa de Infraestructura"
ProviderRepositorioImpl["ProviderRepositorioImpl<br/>[Implementación Mongoose]<br/>Persistencia MongoDB para proveedores"]
AuctionRepositorioImpl["AuctionRepositorioImpl<br/>[Implementación Mongoose]<br/>Persistencia MongoDB para subastas"]
AzureBlobStorageService["AzureBlobStorageService<br/>[Servicio Externo]<br/>Sube/descarga documentos desde Azure Blob"]
DocumentoValidationService["DocumentoValidationService<br/>[Servicio de Dominio]<br/>Valida tipos de documento y expiración"]
PdfGenerationService["PdfGenerationService<br/>[Servicio de Infraestructura]<br/>Genera informes de proveedor usando Puppeteer"]
MessageBrokerService["MessageBrokerService<br/>[Publicador de Eventos]<br/>Publica eventos a Redis/Kafka"]
end
subgraph "Dependencias Externas"
MongoDB[("MongoDB<br/>[Base de datos]<br/>Base de datos de proveedores")]
BlobStorage[("Azure Blob Storage<br/>[Almacenamiento]<br/>Almacenamiento de documentos")]
RedisKafka[("Redis/Kafka<br/>[Message Broker]<br/>Transmisión de eventos")]
end
ProviderController --> CreateProviderHandler
ProviderController --> UploadDocumentoHandler
ProviderController --> UpdateDocumentoEstadoHandler
ProviderController --> SubmitQuotationHandler
ProviderController --> SubmitExecutionReportHandler
ProviderController --> GetProviderByIdHandler
ProviderController --> ListProvidersHandler
ProviderController --> GetProviderDocumentosHandler
AuctionController --> PublishAuctionHandler
AuctionController --> SubmitOfferHandler
AuctionController --> SelectWinnerHandler
AuctionController --> ListAuctionsHandler
AuctionController --> GetAuctionOffersHandler
CreateProviderHandler --> ProviderEntity
CreateProviderHandler --> ProviderRepositorio
CreateProviderHandler --> MessageBrokerService
UploadDocumentoHandler --> ProviderEntity
UploadDocumentoHandler --> ProviderDocumentoVO
UploadDocumentoHandler --> ProviderRepositorio
UploadDocumentoHandler --> AzureBlobStorageService
UploadDocumentoHandler --> DocumentoValidationService
UpdateDocumentoEstadoHandler --> ProviderRepositorio
UpdateDocumentoEstadoHandler --> MessageBrokerService
PublishAuctionHandler --> AuctionEntity
PublishAuctionHandler --> AuctionRepositorio
PublishAuctionHandler --> MessageBrokerService
SubmitOfferHandler --> AuctionEntity
SubmitOfferHandler --> AuctionOfferVO
SubmitOfferHandler --> AuctionRepositorio
SubmitOfferHandler --> MessageBrokerService
SelectWinnerHandler --> AuctionRepositorio
SelectWinnerHandler --> MessageBrokerService
GetProviderByIdHandler --> ProviderRepositorio
ListProvidersHandler --> ProviderRepositorio
GetProviderDocumentosHandler --> ProviderRepositorio
GetProviderDocumentosHandler --> AzureBlobStorageService
ListAuctionsHandler --> AuctionRepositorio
GetAuctionOffersHandler --> AuctionRepositorio
ProviderCreatedEventHandler --> MessageBrokerService
DocumentoEstadoChangedEventHandler --> ProviderRepositorio
AuctionPublishedEventHandler --> MessageBrokerService
OfferSubmittedEventHandler --> MessageBrokerService
OrderClosedEventHandler --> ProviderRepositorio
DocumentoExpiryCheckTask --> ProviderRepositorio
DocumentoExpiryCheckTask --> MessageBrokerService
ProviderRepositorio --> ProviderRepositorioImpl
AuctionRepositorio --> AuctionRepositorioImpl
ProviderRepositorioImpl --> MongoDB
AuctionRepositorioImpl --> MongoDB
AzureBlobStorageService --> BlobStorage
MessageBrokerService --> RedisKafka
style ProviderController fill:#438dd5,stroke:#2e6295,color:#ffffff
style AuctionController fill:#438dd5,stroke:#2e6295,color:#ffffff
style CreateProviderHandler fill:#85bbf0,stroke:#5a8bc4,color:#000000
style UploadDocumentoHandler fill:#85bbf0,stroke:#5a8bc4,color:#000000
style UpdateDocumentoEstadoHandler fill:#85bbf0,stroke:#5a8bc4,color:#000000
style PublishAuctionHandler fill:#85bbf0,stroke:#5a8bc4,color:#000000
style SubmitOfferHandler fill:#85bbf0,stroke:#5a8bc4,color:#000000
style SelectWinnerHandler fill:#85bbf0,stroke:#5a8bc4,color:#000000
style SubmitQuotationHandler fill:#85bbf0,stroke:#5a8bc4,color:#000000
style SubmitExecutionReportHandler fill:#85bbf0,stroke:#5a8bc4,color:#000000
style GetProviderByIdHandler fill:#a8d5ba,stroke:#7cb99a,color:#000000
style ListProvidersHandler fill:#a8d5ba,stroke:#7cb99a,color:#000000
style GetProviderDocumentosHandler fill:#a8d5ba,stroke:#7cb99a,color:#000000
style ListAuctionsHandler fill:#a8d5ba,stroke:#7cb99a,color:#000000
style GetAuctionOffersHandler fill:#a8d5ba,stroke:#7cb99a,color:#000000
style ProviderCreatedEventHandler fill:#ffd93d,stroke:#ccad30,color:#000000
style DocumentoEstadoChangedEventHandler fill:#ffd93d,stroke:#ccad30,color:#000000
style AuctionPublishedEventHandler fill:#ffd93d,stroke:#ccad30,color:#000000
style OfferSubmittedEventHandler fill:#ffd93d,stroke:#ccad30,color:#000000
style OrderClosedEventHandler fill:#ffd93d,stroke:#ccad30,color:#000000
style DocumentoExpiryCheckTask fill:#ff9ff3,stroke:#cc7fc2,color:#000000
style ProviderEntity fill:#6bcf7f,stroke:#56a466,color:#ffffff
style AuctionEntity fill:#6bcf7f,stroke:#56a466,color:#ffffff
style ProviderRepositorioImpl fill:#ff6b6b,stroke:#cc5555,color:#ffffff
style AuctionRepositorioImpl fill:#ff6b6b,stroke:#cc5555,color:#ffffff
style MongoDB fill:#ff6b6b,stroke:#cc5555,color:#ffffff
style BlobStorage fill:#feca57,stroke:#cb9f46,color:#000000
style RedisKafka fill:#48dbfb,stroke:#2e9cba,color:#000000
Figura: Diagrama de Componentes del Microservicio de Proveedores - Desglose detallado de componentes mostrando las capas de aplicación, dominio e infraestructura con Clean Architecture y patrón CQRS
Auction State Machine Diagram
stateDiagram-v2
[*] --> DRAFT: Agent creates auction
DRAFT --> PUBLISHED: Agent publishes to marketplace
PUBLISHED --> BIDDING: First offer submitted
BIDDING --> BIDDING: More offers submitted
BIDDING --> CLOSED: Agent selects winner
PUBLISHED --> CLOSED: Agent selects winner (early closure)
CLOSED --> [*]: Auction Completod
DRAFT --> CANCELLED: Agent cancels auction
PUBLISHED --> CANCELLED: Agent cancels auction
BIDDING --> CANCELLED: Agent cancels auction
CANCELLED --> [*]: Auction cancelled
note right of PUBLISHED
Auction is visible to eligible providers
Duration: 24-72 hours (configurable)
end note
note right of BIDDING
Anonymous bidding
Providers can submit only one offer
end note
note right of CLOSED
Winner assigned to order
Other providers notified of rejection
end note
Figura: Auction State Machine - State transitions for the auction lifecycle, from draft creation through winner selection or cancellation
Stack Tecnológico
| Dependency | Version | Purpose |
|---|---|---|
@nestjs/core | 11.x | NestJS framework core |
@nestjs/cqrs | 11.x | CQRS pattern Implementación |
@nestjs/mongoose | 11.x | MongoDB integration via Mongoose |
@nestjs/Microservicios | 11.x | Redis/Kafka client for messaging |
@nestjs/schedule | 4.x | Scheduled tasks for Documento expiry checks |
mongoose | 8.x | MongoDB ODM |
@azure/storage-blob | 12.x | Azure Blob Storage SDK |
class-validator | 0.14.x | DTO validation |
class-transformer | 0.5.x | DTO transformation |
puppeteer | 23.x | PDF generation for provider reports |
Key Design Patterns
Clean Architecture with CQRS
Similar to Orders MS, the Provider MS implements Clean Architecture with clear layer separation:
Commands:
CreateProviderCommand- Registers new providerUploadDocumentoCommand- Uploads provider DocumentoUpdateDocumentoEstadoCommand- Approves/rejects DocumentoPublishAuctionCommand- Publishes auction to marketplaceSubmitAuctionOfferCommand- Provider submits offerSelectAuctionWinnerCommand- Agent selects winnerSubmitQuotationCommand- Provider submits quotationSubmitExecutionReportCommand- Provider submits execution report
Queries:
GetProviderByIdQuery- Retrieves provider detailsListProvidersQuery- Lists providers with filtersGetProviderDocumentosQuery- Retrieves provider DocumentosListAuctionsQuery- Lists available auctionsGetAuctionOffersQuery- Retrieves auction offers
Events:
ProviderCreatedEvent- Provider registeredDocumentoUploadedEvent- Document uploadedDocumentoEstadoChangedEvent- Documento approved/rejectedAuctionPublishedEvent- Auction published to marketplaceOfferSubmittedEvent- Provider submitted offerAuctionClosedEvent- Auction closed, winner selectedProviderSelectedEvent- Winner selected (sent to Orders MS)DocumentoExpiringEvent- Documento expiring soonDocumentoExpiredEvent- Documento expired
State Machine Pattern for Auctions
The auction lifecycle is modeled as a state machine with well-defined states and transitions:
States:
DRAFT- Auction created but not publishedPUBLISHED- Auction visible to providers, accepting offersBIDDING- At least one offer submittedCLOSED- Winner selected, auction CompletodCANCELLED- Auction cancelled by agent
Transitions:
- DRAFT → PUBLISHED (publishAuction)
- PUBLISHED → BIDDING (submitFirstOffer)
- BIDDING → CLOSED (selectWinner)
- PUBLISHED → CLOSED (selectWinner - early closure)
- Any → CANCELLED (cancelAuction)
Business Rules:
- Only Activo providers with valid Documentos can submit offers
- Provider can submit only one offer per auction
- Auction has configurable duration (24-72 hours)
- Anonymous bidding (provider names hidden until agent views offer details)
- Minimum 3 offers recommended (configurable)
- Agent can manually close auction early
Documento Validation Strategy
Document validation is handled by a dedicated domain service:
class DocumentValidationService { validateDocumentType(type: DocumentType, file: Express.Multer.File): ValidationResult { // Validate file extension // Validate MIME type // Validate file size return result; }
validateExpiryDate(type: DocumentType, expiryDate: Date): ValidationResult { // Check if document type requires expiry date // Validate expiry date is in future // Check minimum validity period return result; }
isDocumentExpiringSoon(expiryDate: Date, daysThreshold: number): boolean { const daysUntilExpiry = differenceInDays(expiryDate, new Date()); return daysUntilExpiry <= daysThreshold; }}Documento Types and Validation:
| Documento Type | Required | Has Expiry | Validation Criteria |
|---|---|---|---|
| RUT (Tax Registration) | Yes | No | Valid NIT format, PDF only |
| Cámara de Comercio | Yes | Yes | Issued within last 30 days, PDF only |
| ARL (Occupational Risk Insurance) | Yes | Yes | Valid policy number, min 1 year validity |
| Póliza de Responsabilidad Civil | Yes | Yes | Minimum coverage amount, min 1 year validity |
| Certificado Bancario | Yes | No | Valid account number, PDF only |
Scheduled Tasks
Documento Expiry Check Task
The DocumentoExpiryCheckTask runs daily (via @nestjs/schedule) to check for expiring or expired Documentos:
@Injectable()export class DocumentExpiryCheckTask { @Cron('0 0 * * *') // Daily at midnight async handleDocumentExpiry() { // 1. Query all documents with expiryDate const documents = await this.providerRepository.findDocumentsWithExpiry();
// 2. Check documents expiring in 30, 15, 7 days const expiringDocuments = documents.filter(doc => this.isExpiringSoon(doc.expiryDate, [30, 15, 7]) );
// 3. Publish DocumentExpiringEvent for each for (const doc of expiringDocuments) { await this.eventBus.publish(new DocumentExpiringEvent(doc)); }
// 4. Check expired documents const expiredDocuments = documents.filter(doc => isAfter(new Date(), doc.expiryDate) );
// 5. Update document status to EXPIRED // 6. Suspend provider if critical document expired for (const doc of expiredDocuments) { await this.commandBus.execute( new UpdateDocumentStatusCommand(doc.id, 'EXPIRED') ); await this.eventBus.publish(new DocumentExpiredEvent(doc)); } }}Referencias Cruzadas
- Detailed Implementación: provider-Microservicio.md
- Arquitectura Descripción General: backend-microservices-overview.md
- Base de datos Schemas: [Base de datos-schemas.md](/02-architecture/Base de datos-schemas/)
- Data Flow Diagrams: