package equipment import "time" type Equipment struct { ID uint `gorm:"primaryKey" json:"id"` UserID uint `gorm:"not null;index" json:"user_id"` Name string `gorm:"not null" json:"name"` Type string `gorm:"not null" json:"type"` // "bike", "shoes", "helmet", etc. Brand string `gorm:"default:''" json:"brand"` Model string `gorm:"default:''" json:"model"` Weight float64 `gorm:"default:0" json:"weight"` // grams Notes string `gorm:"default:''" json:"notes"` Active bool `gorm:"default:true" json:"active"` TotalDistance float64 `gorm:"default:0" json:"total_distance"` // km TotalDuration int `gorm:"default:0" json:"total_duration"` // seconds TotalRides int `gorm:"default:0" json:"total_rides"` ServiceIntervalDistance float64 `gorm:"default:0" json:"service_interval_distance"` // km, 0 = no reminder ServiceIntervalDuration int `gorm:"default:0" json:"service_interval_duration"` // hours, 0 = no reminder LastServiceDate *time.Time `json:"last_service_date"` DistanceSinceService float64 `gorm:"default:0" json:"distance_since_service"` // km since last service DurationSinceService int `gorm:"default:0" json:"duration_since_service"` // seconds since last service CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // ServiceStatus indicates whether equipment needs servicing. type ServiceStatus struct { NeedsService bool `json:"needs_service"` DistanceDue bool `json:"distance_due"` DurationDue bool `json:"duration_due"` DistanceSinceService float64 `json:"distance_since_service"` // km DurationSinceService int `json:"duration_since_service"` // hours ServiceIntervalDist float64 `json:"service_interval_distance"` ServiceIntervalDur int `json:"service_interval_duration"` } // GetServiceStatus checks if the equipment is due for service. func (e *Equipment) GetServiceStatus() ServiceStatus { status := ServiceStatus{ DistanceSinceService: e.DistanceSinceService, DurationSinceService: e.DurationSinceService / 3600, ServiceIntervalDist: e.ServiceIntervalDistance, ServiceIntervalDur: e.ServiceIntervalDuration, } if e.ServiceIntervalDistance > 0 && e.DistanceSinceService >= e.ServiceIntervalDistance { status.DistanceDue = true status.NeedsService = true } if e.ServiceIntervalDuration > 0 && e.DurationSinceService >= e.ServiceIntervalDuration*3600 { status.DurationDue = true status.NeedsService = true } return status } type TrainingZone struct { ID uint `json:"id"` Name string `json:"name"` Min int `json:"min"` Max int `json:"max"` Color string `json:"color"` } type HRZones struct { Zone1 TrainingZone `json:"zone_1"` // Recovery Zone2 TrainingZone `json:"zone_2"` // Endurance Zone3 TrainingZone `json:"zone_3"` // Tempo Zone4 TrainingZone `json:"zone_4"` // Threshold Zone5 TrainingZone `json:"zone_5"` // VO2 Max } type PowerZones struct { Zone1 TrainingZone `json:"zone_1"` // Active Recovery Zone2 TrainingZone `json:"zone_2"` // Endurance Zone3 TrainingZone `json:"zone_3"` // Sweet Spot Zone4 TrainingZone `json:"zone_4"` // Threshold Zone5 TrainingZone `json:"zone_5"` // VO2 Max Zone6 TrainingZone `json:"zone_6"` // Anaerobic Zone7 TrainingZone `json:"zone_7"` // Neuromuscular }