Architecture of an action multiplayer game from scratch

Not sure whether it's a good place to ask (do point me to a better one if it's not), but since what we're developing is a game - here it goes.

So this is a "real-time" action multiplayer game. I have familiarized myself with concepts like lag compensation, view interpolation, input prediction and pretty much everything that I need for this. I have also prepared a set of prototypes to confirm that I understood everything correctly.

My question is about the situation when game engine must be rewind to the past to find out whether there was a "hit" (sometimes it may involve the whole 'recomputation' of the world from that moment in the past up to the present moment. I already have a piece of code that does it, but it's not as neat as I need it to be. The domain logic of the app (the physics of the game) must be separated from the presentation (render) and infrastructure tools (e.g. the remote server interaction specifics).

How do I organize all this? :) Is there any worthy implementation with open sources I can take a look at?

What I'm thinking is something like this:

-> Render / User Input
-> Game Engine (this is the so called service layer)
-> Processing User Commands & Remote Server
-> Domain (Physics)


How would you add into this scheme the concept of "ticks" or "interactions" with the possibility to rewind and recalculate "the game"? Remember, I cannot change the Domain/Physics but only the Game Engine. Should I store an array of "World's States"? Should they be just some representations of the world, optimized for this purpose somehow (how?) or should they be actual instances of the world (i.e. including behavior and all that).

(never worked on a game before if that matters)

What I do for my game is, every tick, save only the positions of all networked entities. When I turn lag compensation on, I use the client's ping and interpolation amount to rewind to what the client was seeing at that time. In this rewinded state I only run commands that query the world, not mutate it (e.g. DetectHit, FindInRange). I store the results of these queries, then revert all the positions back to the current time. Then I move forward as if those queries were run in the current tick.