You can drive yourself crazy documenting things with Ignition as it's not a pure code environment like you would have if you programmed everything from scratch.
I think the most straightforward way is to document how certain processes work. How do you add a recipe? Load a recipe? What tags handle that, and what values on those tags mean what semantically(1=Run, 2=Stop, 4=Fault, or whatever it is)?
Anything that your gateway shells out to some other software - definitely document that because even if you don't document everything within Ignition most advanced users can figure out what the intent was, but when you shell out to 3rd party software that may not be well known or have co-workers are less familiar with it, this most definitely needs to be documented.
In terms of documenting windows, I try to just make every window follow a similar setup, and then I document those conventions. Any popup that allows INSERT/UPDATE of a database table should look relatively similar, have some initial data payload that populates the window, and the relatively similar code pattern to run your db actions. Obviously exceptions exist but most CRUD operations end up looking similar (CRUD meaning Create Read Update Delete actions on a database).
For documenting scripts I follow the google style
def myImportantFunction(arg1, arg2, keyword1=False):
"""
This function does important stuff!
Args:
arg1: int, if 1, then we do x, if 2 we do y, else we throw an error
arg2: str, the message that populates the header/banner of a GUI while this runs
keyword1: bool, if False, modifies function behavior by doing A, if true modifies funciton behavior by doing B
Returns:
(bool, str) - bool - true if everything was succesfull false if it was not
str - None if no error occurred, otherwise an error message
"""
pass
Personally I think when starting a new project you should start in the project script library. Write your business logic functions, document those as I just showed above, and then all your GUI should ever do is gather the arguments that you then feed the functions your wrote. Same thing with any Gateway timer scripts or gateway scoped logic. The project library and scripts in it are the most straightforward thing to document and also happen to be the easiest thing to do version control on since it's plain text, unlike windows etc. An additional benefit is that if you need to call some existing business logic now in a second location, you already are setup to do that, and you don't have to copy and paste a long script from a button into a script library and rework it.