Modular monolith boundaries
Shared database access is still an authority decision
Modules in one application may share infrastructure without sharing unrestricted permission to mutate every table. Make data ownership and enforcement explicit.
In this article
Identify the writer for each business record
Assign a module responsibility for changing orders, invoices or other domain records. Other modules should request supported operations rather than updating those tables for convenience.
This ownership is a code and business-rule boundary. If all modules run under one database identity, the database may not enforce that separation itself. Be honest about which controls are conventions, build checks or runtime permissions.
Where stronger isolation is required, consider the database roles, schemas or process boundaries appropriate to the system. A folder name cannot provide a security guarantee.
Distinguish read models from mutation paths
A reporting screen may need a join across several modules. That can be a deliberate design if the query's purpose and dependencies are understood. It does not imply permission to write to every joined table.
Keep shared read models separate from domain entities used for mutation. Returning a tracked or mutable persistence object can let a caller change state without invoking the owning module's operation.
Review background imports and administrative scripts as well. They often have broad credentials and can bypass rules enforced in normal request handlers.
Apply user authority inside the business operation
Module ownership does not replace caller-level access checks. The order module still needs to determine whether this user may change this order.
Resolve target organisation and permissions from trusted records. A command carrying a tenant identifier should not be able to define its own access scope.
If an administrative exception exists, make it a separate operation with a narrow purpose, appropriate authority and an audit record. Avoid a generic bypass parameter that ordinary callers can set.
Test the actual enforcement layers
Attempt a prohibited internal import, an unauthorised public operation and a direct write through each runtime identity. The expected outcome should match the documented control at that layer.
Inspect database grants against the intended deployment. PostgreSQL privileges, for example, can constrain database objects, but their value depends on which role the application actually uses and which privileges it holds.
Record remaining broad access as a conscious limitation with an owner. A useful review explains how module rules and user permissions are preserved today, rather than describing shared storage as either automatically safe or automatically unacceptable.
Primary sources
PostgreSQL: privilegesOWASP: authorisation guidanceReferences checked 11 September 2026.