# DOMAIN MODEL: Assets Context **Version:** 1.0.0 **Fecha:** 2025-12-05 **Modulos:** MAE-015 --- ## Descripcion El contexto de Assets gestiona el ciclo de vida completo de activos de construccion: maquinaria pesada, vehiculos, equipos y herramientas. Incluye control de ubicacion, asignaciones a proyectos, mantenimiento preventivo/correctivo y calculo de TCO. --- ## Agregados ### 1. Asset Aggregate ``` Asset (Aggregate Root) | +-- AssetAssignment (Entity) | +-- Period (Value Object) | +-- AssetUsageLog (Entity) | +-- GPSTracking (Entity) | +-- DepreciationSchedule (Value Object) ``` #### Asset (Root) ```typescript interface Asset { id: UUID; tenantId: UUID; assetCode: string; name: string; description?: string; // Classification assetType: AssetType; categoryId?: UUID; subcategory?: string; // Specifications brand?: string; model?: string; serialNumber?: string; year?: number; capacity?: string; specifications?: Record; // Current location currentLocation?: string; currentProjectId?: UUID; assignedTo?: UUID; // GPS/IoT gpsDeviceId?: string; lastGPSLocation?: Location; lastGPSUpdate?: Timestamp; // Financial purchaseDate?: Date; purchaseValue: Money; currentValue: Money; depreciationMethod?: DepreciationMethod; usefulLifeYears?: number; salvageValue: Money; accumulatedDepreciation: Money; // Operational operatingHours: number; odometerReading?: number; fuelType?: string; hourlyCost: Money; status: AssetStatus; imageUrl?: string; documentsUrls?: string[]; assignments: AssetAssignment[]; usageLogs: AssetUsageLog[]; maintenancePlans: MaintenancePlan[]; } enum AssetType { HEAVY_EQUIPMENT = 'heavy_equipment', VEHICLE = 'vehicle', TOOL = 'tool', EQUIPMENT = 'equipment', COMPUTER = 'computer', FURNITURE = 'furniture', OTHER = 'other' } enum AssetStatus { AVAILABLE = 'available', IN_USE = 'in_use', MAINTENANCE = 'maintenance', REPAIR = 'repair', OUT_OF_SERVICE = 'out_of_service', DISPOSED = 'disposed' } enum DepreciationMethod { STRAIGHT_LINE = 'straight_line', DECLINING_BALANCE = 'declining_balance', UNITS_OF_PRODUCTION = 'units_of_production' } ``` #### AssetAssignment (Entity) ```typescript interface AssetAssignment { id: UUID; assetId: UUID; projectId?: UUID; assignedTo?: UUID; department?: string; startDate: Date; endDate?: Date; plannedEndDate?: Date; location?: string; locationCoordinates?: Location; status: AssignmentStatus; // Usage tracking initialHours?: number; finalHours?: number; initialOdometer?: number; finalOdometer?: number; notes?: string; } enum AssignmentStatus { ACTIVE = 'active', COMPLETED = 'completed', CANCELLED = 'cancelled' } ``` #### AssetUsageLog (Entity) ```typescript interface AssetUsageLog { id: UUID; assetId: UUID; assignmentId?: UUID; logDate: Date; startTime?: Time; endTime?: Time; hoursUsed?: number; distanceTraveled?: number; fuelConsumed?: number; projectId?: UUID; activityDescription?: string; operatorId?: UUID; operatorName?: string; // Readings odometerStart?: number; odometerEnd?: number; hourMeterStart?: number; hourMeterEnd?: number; notes?: string; } ``` --- ### 2. Maintenance Aggregate ``` MaintenancePlan (Aggregate Root) | +-- MaintenanceSchedule (Value Object) | +-- NextDueCalculation (Value Object) WorkOrder (Aggregate Root) | +-- WorkOrderTask (Entity) +-- WorkOrderPart (Entity) +-- WorkOrderLabor (Entity) ``` #### MaintenancePlan (Root) ```typescript interface MaintenancePlan { id: UUID; tenantId: UUID; assetId: UUID; planName: string; description?: string; maintenanceType: MaintenanceType; // Frequency frequencyType: FrequencyType; frequencyValue: number; toleranceValue: number; // Last and next lastPerformedAt?: Timestamp; lastPerformedHours?: number; lastPerformedDistance?: number; nextDueAt?: Timestamp; nextDueHours?: number; nextDueDistance?: number; // Tasks tasksChecklist?: TaskChecklistItem[]; estimatedDurationHours?: number; estimatedCost: Money; isActive: boolean; } enum MaintenanceType { PREVENTIVE = 'preventive', CORRECTIVE = 'corrective', PREDICTIVE = 'predictive', INSPECTION = 'inspection', CALIBRATION = 'calibration' } enum FrequencyType { HOURS = 'hours', DAYS = 'days', DISTANCE = 'distance', CALENDAR = 'calendar' } interface TaskChecklistItem { id: string; description: string; isMandatory: boolean; estimatedMinutes?: number; } ``` #### WorkOrder (Root) ```typescript interface WorkOrder { id: UUID; tenantId: UUID; assetId: UUID; woNumber: string; maintenanceType: MaintenanceType; priority: MaintenancePriority; title: string; description?: string; problemReported?: string; // Origin maintenancePlanId?: UUID; reportedBy?: UUID; reportedAt: Timestamp; // Assignment assignedTo?: UUID; assignedTeam?: string; // Schedule scheduledDate?: Date; scheduledStartTime?: Time; estimatedDurationHours?: number; actualStartAt?: Timestamp; actualEndAt?: Timestamp; // Location workLocation?: string; projectId?: UUID; // Costs estimatedCost: Money; actualLaborCost: Money; actualPartsCost: Money; actualTotalCost: Money; status: WorkOrderStatus; // Result workPerformed?: string; rootCause?: string; recommendations?: string; // Readings at time of work hoursAtWork?: number; odometerAtWork?: number; tasks: WorkOrderTask[]; parts: WorkOrderPart[]; labor: WorkOrderLabor[]; } enum MaintenancePriority { LOW = 'low', MEDIUM = 'medium', HIGH = 'high', CRITICAL = 'critical' } enum WorkOrderStatus { DRAFT = 'draft', SCHEDULED = 'scheduled', IN_PROGRESS = 'in_progress', ON_HOLD = 'on_hold', COMPLETED = 'completed', CANCELLED = 'cancelled' } ``` #### WorkOrderTask (Entity) ```typescript interface WorkOrderTask { id: UUID; workOrderId: UUID; taskNumber: number; description: string; isCompleted: boolean; completedAt?: Timestamp; completedBy?: UUID; result?: string; notes?: string; sortOrder: number; } ``` #### WorkOrderPart (Entity) ```typescript interface WorkOrderPart { id: UUID; workOrderId: UUID; productId?: UUID; productCode?: string; productName: string; quantity: number; unitCode?: string; unitCost: Money; totalCost: Money; warehouseId?: UUID; purchaseOrderId?: UUID; } ``` #### WorkOrderLabor (Entity) ```typescript interface WorkOrderLabor { id: UUID; workOrderId: UUID; technicianId?: UUID; technicianName: string; workDate: Date; hoursWorked: number; overtimeHours: number; hourlyRate: Money; overtimeRate: Money; totalCost: Money; workDescription?: string; } ``` --- ### 3. Geofence Aggregate ``` Geofence (Aggregate Root) | +-- GeofenceEvent (Entity) | +-- AlertRecipient (Value Object) ``` #### Geofence (Root) ```typescript interface Geofence { id: UUID; tenantId: UUID; name: string; description?: string; boundary: Polygon; centerPoint?: Location; radiusMeters?: number; projectId?: UUID; alertOnEntry: boolean; alertOnExit: boolean; alertRecipients?: UUID[]; isActive: boolean; } ``` #### GeofenceEvent (Entity) ```typescript interface GeofenceEvent { id: UUID; assetId: UUID; geofenceId: UUID; eventType: GeofenceEventType; eventTime: Timestamp; location?: Location; notificationSent: boolean; notificationSentAt?: Timestamp; } enum GeofenceEventType { ENTRY = 'entry', EXIT = 'exit' } ``` --- ## Value Objects ### Location ```typescript interface Location { latitude: number; longitude: number; altitude?: number; heading?: number; speed?: number; } ``` ### Money ```typescript interface Money { amount: number; currency: string; } ``` ### TCOResult ```typescript interface TCOResult { purchaseCost: Money; depreciationCost: Money; maintenanceCost: Money; fuelCost: Money; operatingHours: number; costPerHour: Money; totalTCO: Money; } ``` ### DepreciationSchedule ```typescript interface DepreciationSchedule { method: DepreciationMethod; purchaseValue: Money; salvageValue: Money; usefulLifeYears: number; currentYear: number; annualDepreciation: Money; accumulatedDepreciation: Money; bookValue: Money; } ``` --- ## Domain Events ### Asset Lifecycle Events ```typescript interface AssetCreated { assetId: UUID; assetCode: string; assetType: AssetType; purchaseValue: Money; timestamp: Timestamp; } interface AssetStatusChanged { assetId: UUID; previousStatus: AssetStatus; newStatus: AssetStatus; reason?: string; timestamp: Timestamp; } interface AssetAssigned { assetId: UUID; assignmentId: UUID; projectId?: UUID; assignedTo?: UUID; startDate: Date; timestamp: Timestamp; } interface AssetDisposed { assetId: UUID; disposalReason: string; disposalValue: Money; timestamp: Timestamp; } ``` ### Maintenance Events ```typescript interface MaintenanceDue { assetId: UUID; maintenancePlanId: UUID; dueAt: Timestamp; dueHours?: number; maintenanceType: MaintenanceType; timestamp: Timestamp; } interface WorkOrderCreated { workOrderId: UUID; assetId: UUID; woNumber: string; maintenanceType: MaintenanceType; priority: MaintenancePriority; timestamp: Timestamp; } interface WorkOrderCompleted { workOrderId: UUID; assetId: UUID; actualCost: Money; laborHours: number; timestamp: Timestamp; } ``` ### GPS/Geofence Events ```typescript interface LocationUpdated { assetId: UUID; location: Location; speed?: number; timestamp: Timestamp; } interface GeofenceViolation { assetId: UUID; geofenceId: UUID; eventType: GeofenceEventType; location: Location; timestamp: Timestamp; } ``` --- ## Business Rules ### Asset Rules 1. Un activo solo puede estar asignado a un proyecto a la vez 2. El status cambia automaticamente al crear orden de trabajo 3. La depreciacion no puede exceder el valor de compra menos salvage 4. Activos con status 'disposed' no pueden modificarse ### Maintenance Rules 1. El mantenimiento preventivo genera ordenes automaticamente 2. La tolerancia de frecuencia permite variacion sin alerta 3. Ordenes criticas requieren atencion en 24 horas 4. Las tareas obligatorias deben completarse para cerrar orden ### Usage Rules 1. Los registros de uso no pueden tener horas negativas 2. El odometro final debe ser >= inicial 3. Las horas de operacion acumulan en el activo 4. El consumo de combustible se usa para TCO ### Geofence Rules 1. Las geocercas requieren al menos 3 puntos de poligono 2. Los eventos se registran incluso si notificacion falla 3. Solo activos con GPS activo generan eventos --- ## Invariantes 1. `Asset.currentValue = purchaseValue - accumulatedDepreciation` 2. `Asset.accumulatedDepreciation <= purchaseValue - salvageValue` 3. `WorkOrder.actualTotalCost = actualLaborCost + actualPartsCost` 4. `AssetUsageLog.hoursUsed = hourMeterEnd - hourMeterStart` 5. `Asset.operatingHours += SUM(usageLogs.hoursUsed)` --- ## Integraciones ### Con Project Context - Activos asignados a proyectos - Costos de maquinaria en presupuestos - Ubicacion en obra ### Con Finance Context - Depreciacion genera polizas - Costos de mantenimiento como gastos - TCO para analisis financiero ### Con Inventory Context - Repuestos desde almacen - Consumibles para mantenimiento ### Con GPS/IoT (Externo) - Tracking en tiempo real - Telemetria de activos - Alertas de geocerca --- ## Referencias - [DDL-SPEC-assets.md](../database-design/schemas/DDL-SPEC-assets.md) --- *Ultima actualizacion: 2025-12-05*