Application Architecture and Reusable Module Design
Module boundaries
A module owns its domain model. Other modules should reach it through microflows that form a published interface, or through entities explicitly designed as shared contracts - never by editing another module's attributes directly. Pass non-persistent DTO entities across boundaries to keep coupling low.
Dependencies and roles
Keep the module dependency graph acyclic; cyclic dependencies make modules impossible to export and reuse independently. Each module defines its own module roles, and the application maps user roles to module roles, so a module shipping User and Admin roles can be dropped into another app. Constants belong to the module that owns the behaviour they configure.
Reuse and versioning
Export a module as a package and version it. Treat its public microflows and entities as an API: renaming or deleting them breaks consumers on the next import. Keep UI assets (layouts, snippets) and integration assets (mappings, consumed services) in separate modules so the domain module can be reused headless.
Worked example
Payment logic is copied in three modules. Extract a Payments module exposing Payments_Charge(Payments_ChargeRequest) returning Payments_ChargeResult, both non-persistent. Sales and Subscriptions call it and cannot read Payments.Transaction. Reasoning: one place to change the provider, and consumers keep compiling because only DTOs cross the boundary.
Traps
Cross-module XPath over another module's associations (fragile and rights-dependent); a Common module everything depends on, which can never be versioned independently; forgetting to map a new module role in app security so pages vanish for users; changing an exported module's entity without a major version bump.