Mendix Advanced Developer study materials
Mendix Advanced Developer study resources

Meridian Staffing: an empty grid and a leaking export

Mendix Advanced Developer · Put your knowledge to work in context.

All case studies

Meridian Staffing: an empty grid and a leaking export

Meridian Staffing built a Mendix application in which Placement records link a Candidate to a Client. Client is associated with AccountManager, a specialization of System.User. Security is module-role based: the module roles Planner and AccountManager both have access to the page Placement_Overview, and users are routinely granted both roles during the onboarding period.

Entity access on Placement contains exactly one rule: module role AccountManager, read and write, with the XPath constraint [Client_AccountManager = '[%CurrentUser%]']. Planners report that Placement_Overview opens with a completely empty grid and no error message. Separately, account managers discovered that the button ACT_ExportPlacements - a microflow in the same module, triggered from the same page, which retrieves all Placement objects and generates a CSV - returns placements belonging to every client in the database, including ones the user cannot open from the grid. The export has been used to send figures to the finance team.

1. Explain why planners see an empty grid, and give the concrete security-model change required. Address what happens to a user who holds both module roles.

Read the worked answer

Why it is empty. Entity access rules are grants, not filters. A user can only read a Placement if at least one access rule for one of their module roles grants read access. Planner has no rule on Placement at all, so every retrieve for a planner returns zero rows. Mendix does not treat this as an error - an empty result is a legitimate outcome - so there is no exception, no log line and no design-time warning: creating a page for a module role does not imply access to the entities behind it.

The fix. Add a second access rule on Placement for module role Planner: read only, no write, no delete, with its own XPath expressing the planner's scope, e.g. [Client_Region/Planner = '[%CurrentUser%]'] (which requires an association from Region to System.User, or a many-to-many association if several planners share a region). Do not reuse the account-manager rule for planners - the correct scope differs, and copying the XPath gives planners access to another team's clients.

Users with both roles. Access rules across module roles are combined as a union: such a user can see every placement matching either rule. A newly onboarded account manager who is also a planner therefore sees their own clients plus their whole region. That is usually acceptable during onboarding but should be a conscious decision - if it is not acceptable, end the dual-role period, or model a single rule that expresses the union explicitly so the intent is visible to the next developer.

Verify with test accounts per role, not with the administrator account, which is a common cause of 'it works for me'.

2. Explain why `ACT_ExportPlacements` returns records the user cannot see, and give the fix with its trade-offs. What would you add to the delivery process so this class of defect is caught?

Read the worked answer

Root cause. Microflows do not apply entity access by default. A retrieve activity reads the database with the effective user's context, but the access rules and their XPath constraints are only evaluated when 'Apply entity access' is checked on that retrieve. With the default setting, ACT_ExportPlacements reads the whole Placement table - the caller's module roles are irrelevant.

Fix options.

  1. Check 'Apply entity access' on every retrieve in the export. Semantics become identical to the grid, at the cost of extra XPath evaluation per retrieve (measurable on large sets, and the access XPath is added as an AND condition to the query).
  2. Build the filter explicitly in the XPath ([Client_AccountManager = '[%CurrentUser%]']). Faster and more predictable, but duplicates the security rule in a second place - if the entity access rule changes, the export silently diverges.
  3. Move the logic to a Java action using OQL. Note that OQL bypasses entity access entirely, so this makes the problem worse unless you pass the user and filter manually.

Recommendation: option 1 for anything user-triggered, plus a written rule that any microflow producing a file, an email or an API response is reviewed for 'Apply entity access'.

Process additions: a per-role security matrix test (each module role × each entry point, asserting record counts), a test fixture with two clients and two account managers so over-exposure is visible as a number rather than a feeling, and a reviewer checklist item for unapplied retrieves in export and integration microflows. Also note the limitation: 'Apply entity access' uses the current user. A scheduled export has no user context, so it must either deliberately run with a system context and an explicit scope, or pass a user and filter on it.

3. The business now wants planners to also see placements they created themselves, even if the client is outside their region. Model this change and identify the pitfalls you would flag in review.

Read the worked answer

Modeling. Express it as one or two additional read rules for Planner. The scope becomes 'placement in my region OR created by me'. Two details matter:

  • Within a single XPath constraint, combine the alternatives with parentheses so the OR binds as intended: [ (Client_Region/Planner = '[%CurrentUser%]') or (System.owner = '[%CurrentUser%]') ]. A missing parenthesis next to an AND clause silently widens or narrows the scope, and XPath precedence here is not something to leave to memory.
  • System.owner is the runtime-populated owner of the object, which is not necessarily the person who created the placement if a microflow created it on someone's behalf, or if an administrator re-assigned it. For business intent, a dedicated association CreatedBy → System.User set explicitly in the creation microflow is more honest and is not affected by system-attribute behaviour.

Pitfalls to flag:

  1. Union with existing roles. A planner who is also an account manager sees the union of both scopes, which now includes every placement they created anywhere. Confirm this is intended.
  2. Write access. The new rule should grant read only. If copy-paste grants write, a planner can edit a placement from another region, which breaks the regional accountability the original rule encoded.
  3. XPath path validity. The constraint traverses Client → Region → Planner; if any intermediate association is optional, rows with a null client or region will not match - decide whether that is acceptable or add the fallback.
  4. Performance. Security XPath is appended to every query on the entity, including the overview grid and any microflow with 'Apply entity access' on. If it now traverses a many-to-many association, index it and re-measure the page.
  5. Test cases. Add a planner who has created a placement outside their region and one inside, and assert the counts per role.