I think the most important part of source control file structure is mirroring package structure in Studio, since that is the view we spend the most time with. That said it looks something like this:

root/
    Package1/
              Class.cls
              Class2.cls
              Routine.mac
              Include.inc
     Package2/ 
              Class.cls
              Class2.cls
              Routine.mac
              Include.inc

Additionally:

  1. Web app should be stored in a separate repository.
  2. If there's docs/dictionaries/etc, then all sources should be in a /src folder instead of repository root.
  3. All libs/modules/etc should be moved into their separate repositories each and plugged in as a submodules.
  4. Builds, if any should not be stored in a repo but rather meta-managed (releases).
  5. Commit messages and granular commit history is one of the most helpful things when analysing project history, enforce commit message style (title is the most important i.e. PART/SUBPART - thing done in a commit).

You can project collection property as a child table.

Property MyList as list of Object(STORAGEDEFAULT="array");

Note that it changes class storage, so existing data should be moved to the correct new place.

Several months ago I wrote a small utility class to accomplish exactly that.

Or if you don't have a lot of different classes and data dependencies, you can just export to XML, add STORAGEDEFAULT and import XML.

Is it possible to change underlying data model so that 1 row = 1 main object?

Class UserPrefs {

Property Username;

///  Color/Number are keys, and this can be indexed
Property Preferences As Array Of %String(SQLPROJECTION = "table/column");

Parameter ROWLEVELSECURITY = 1;

///Updated for each row when the property 'Preferences' changes
Property %READERLIST As %String [ SqlComputeCode = {set {*} = ##class(Users).%SecurityPolicy()}, SqlComputed, SqlComputeOnChange = Preferences ];

}

You can use SQL to insert into child table. Not sure if it would actually trigger a %READERLIST recalculation (maybe try %%INSERT) but worth a try.

Using SQLComputeCode and SQLComputeOnChange %READERLIST property is stored but gets recalculated on every SQL and Object INSERT/UPDATE/%Save:

Class Utils.RLS Extends %Persistent
{

Parameter ROWLEVELSECURITY = 1;

Property %READERLIST As %String [ SqlComputeCode = {set {*} = ##class(Utils.RLS).GetAccess({%%ID})}, SqlComputed, SqlComputeOnChange = (%%INSERT, %%UPDATE) ];

Property data As %String;

ClassMethod GetAccess(Id) As %String
{
    return:Id>3 "_SYSTEM"
    return "%All"
}

/// do ##class(Utils.RLS).Fill()
ClassMethod Fill(N = 5)
{
    do ..%KillExtent()
    for i=1:1:N {
        &sql(insert into Utils.RLS(data) values(:i))
    }

    zw ^demo.testD,^demo.testI

    do ##class(%SQL.Statement).%ExecDirect(,"select * from "_$classname()).%Display()
}