Best way to handle Gun Firerate?

I’m working on a gun right now and I’m currently wondering what the best way to handle fire-rate is? Ideally I wanna handle it on the server but I’m not sure how the client-side would work for that.

Here is an example of code, where you can use debounce on the server side:

local Players = game:GetService("Players")
local replicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")

local gunRange = 500
local HeadShotMulti = 2 -- Change on your discression
local Debounce = 0.3 -- Change for the amount of time inbetween shots

local DebounceTable= {}

Players.PlayerAdded:Connect(function(Player)
	if not DebounceTable[Player] then
		DebounceTable[Player] = false
	end
end)

Players.PlayerRemoving:Connect(function(Player)
	if DebounceTable[Player] then
		DebounceTable[Player] = nil
	end
end)

replicatedStorage.Shoot.OnServerEvent:Connect(function(Player, MousePosition, Target)
	if not DebounceTable[Player] then
		DebounceTable[Player] = true
		
		local Gun = Player.Character:FindFirstChildOfClass("Tool")

		if Gun == nil then return end

		local Damage = Gun.Damage.Value

		local Direction = (MousePosition- Gun.Handle.Position) * gunRange

		local RayParams = RaycastParams.new()
		RayParams.FilterDescendantsInstances = {Player.Character}
		RayParams.FilterType = Enum.RaycastFilterType.Exclude

		local Result = workspace:Raycast(Gun.Handle.Position, Direction, RayParams)

		local Bullet = replicatedStorage.Bullet:Clone()
		Bullet.CFrame = Gun.Handle.CFrame
		Bullet.Parent = workspace

		local BulletDuration = 0.3 * ((Direction/gunRange).Magnitude)/50

		TweenService:Create(Bullet, TweenInfo.new(BulletDuration), {CFrame = CFrame.new(MousePosition)}):Play()

		if not Target then
			task.delay(BulletDuration, function()
				Bullet:Destroy()
			end)
		else
			task.delay(1, function()
				Bullet:Destroy()
			end)
		end
		
		task.delay(Debounce, function()
			if DebounceTable[Player] then
				DebounceTable[Player] = false
			end
		end)

		if Result == nil then return end

		local Humanoid = Result.Instance.Parent:FindFirstChild("Humanoid")

		if Humanoid == nil then return end

		task.wait(BulletDuration)

		if Result.Instance.Name == "Head" then
			Humanoid.Health -= Damage * HeadShotMulti
		else
			Humanoid.Health -= Damage
		end
	end
end)

Server would be your best bet when handling verification/validation such at this. You could measure the tick() and the tick() when the player shot. If it exceeds your RPM then you invalidate the shot, if it does not then you continue with your code.