Skip to content

Designing LedgerSMB's data store structure

Erik Huelsmann edited this page Jan 2, 2022 · 3 revisions

Designing LedgerSMB's data store structure

This document was created to have a common understanding of the structure of the (Vue) client application and how it should divide its data across data stores.

By extension, if the structure works well for the client, it should be investigated if a similar structure works equally well for the server -- keeping client and server structure in line (where possible) will increase maintainability of the overall code base.

When referring to "data", this document means "data entity": the concept of a specific data element, which can be instantiated by means of records or (in the context of the web) "resources".

Concepts

In order to understand how to distribute data and data responsibilities across the application, we'll need to understand which concepts play a role in the administration and use of data as well as the impact of changes to the data.

Classification

Following DAMA's DMBOK[1], there are three classes of data to be distinguished:

  • Reference data
    Data in this class is used to categorize data. It's maintained outside the organization and changes in this data are likely to have high impact on the execution of the business process.
    Examples: Lists of currencies, languages or SIC(NAICS/NACE/ANSZIC/...).

  • Master data
    Data in this class describes business entities. It's maintained as part of the business process, although changes are infrequent.
    Examples: Customers, products or locations.

  • Transactional data
    Data in this category describes business events or transactions. It's the direct result of the execution of the business process.

For the purpose of this design, we should consider a fourth category:

  • Configuration data
    Data in this class has no relation to the business process; instead it determines the way the application behaves.
    Examples: Separation of duties enforcement, password validity duration and the maximum number of items in drop-down widgets.

Scope

Next to the class of data, the scope of its use could be a criterion for allocation of data to a specific data store.

One way to understand scope could be to use the existing concept of "modules" in the LedgerSMB code base. Examples of modules that are currently recognized include "GL" and "AR".

Some functionalities are fundamental to the application: their use is widespread among (almost) all modules. These functionalities aren't in any specific module: they're "global". Examples of global functionalities include: authentication and authorization, application theming (presentation), application integration (e-mail, printers, etc) and security (TLS, password policy etc). The data that these functionalities require (e.g. users, roles, printer configuration, e-mail server configuration) necessarily follows these functionalities and won't be allocated to any specific module ("it will be global").

In some cases, modules don't directly share the same data (i.e. HR, AR and AP don't share employees, vendors and customers), but they can refer to the same physical entity: an employee can be a customer at the same time. Here, it's important to add a common generalized data element (e.g. an Actor) which will be global as well; in this specific example, the Actor could be assigned to a module by virtue of being assigned a "role" of sorts that is governed by the module. E.g. the "AR" module would have a data entity called "customer" which is managed as part of that module; it references a global data entity "actor".

Some modules build on others. E.g. the subledgers "AR", "AP", "Inventory" or "Fixed Assets" build on the "GL" module. The data entity "GL Account" is allocated to the "GL" module. The other modules may add data to GL accounts which is adopted by the GL module and presented as part of its own "GL Account" data.

Allocation of data to stores

Transactional data will be allocated to the store of the module that serves its business process: "payroll payments" go to "HR / Payroll". Master data (employees, payroll taxes) go to "HR / Payroll" as well.

For the purpose of allocation of data to stores, "modules" will be considered a stack of layers, all building on the global functionalities and zero or more modules. In case of "HR", for the purpose of "Payroll", it builds on "GL" for accounting of wage disbursement.

In this stack, data will be allocated to the first highest module which directly uses the data. E.g. "vendor" will be allocated to "AP" while "GL Account" will be allocated to "GL" (and used by both "AR" and "AP").

In case multiple modules use similar concepts (e.g. "AR" and "AP" having "customer" and "vendor"), common functionality will be abstracted and allocated to a module that's commonly depended upon. If no common module exists, one may be created. E.g. "AR" and "AP" share "GL", but abstracting the "actor" into "GL" makes no sense, business wise. A common "AA" module could be created to hold "actor" and other shared functionality and data. Taking the experiment one step further, "HR" has an "actor"-like concept too: the employee. There is no (other) shared functionality between "HR" and "AA" than "actor". From here, there are two possible solutions: the "actor" concept is created as a global concept underlying all parts of the application, or, an artificial module specifically for managing the "actor" concept, can be created.

References

[1] DMBOK: Data Management Body Of Knowledge