There is no such thing as “Perfect” when it comes to this stuff unfortunately. If i were you i would have the client ask the server to fire a shot(s). Send that to the server, validate the args (Is the origin of the shot close to the shooter?) and store that shot in a table until they shoot again (You will want to store it on the client too). Here you can also store ammo and what not and just subtract what you need when they shoot as well as verifying the rate of fire. Reloads are also something you will want to do on the server. You can always do these checks on the client as well to prevent unneeded firing of remotes by normal players.
When it comes to validating a hit you can just tell the server what object you hit and the shot object you hit them with. Remember this is also stored on the server so you can easily check the validity of the shot using Shots[Player]. Because we have that shot safe we should be able to assume that its okay to use when validating a hit as we already verified the shot. This might sound kind of confusing upfront so I’d reccomend you check out [OS Game] Ruddev's Battle Royale Open Sourced as it can give you really good insight on validating shots and hits on the server in a relatively efficient way. There is a script called “GunScript” located in ServerScriptService > ItemHandlers.
You will see how they store each shot on the server along with the position it was shot at and the direction (or directions if its a shotgun) were fired in.