Row-level Access Control on a Unified Customer Graph Across Business Units

Published
Length
3 min read

Luis Felipe Dias

All posts

You set up row level access control on a unified customer graph across business units by matching user roles to record tags. The database checks these tags before it returns any customer rows. Most teams start by sharing one broad database role across several apps and teams. That shortcut lets every group read customer rows from other business units. One bad query can expose private emails, phone numbers, or card numbers across the company. How row level access control on a unified customer gr

Row-Level Security + Customer Support Access to Production: the complete guide

Architecture patterns, implementation strategies, and security best practices. Delivered to your inbox.

Free white paper. No spam. Unsubscribe anytime.

You set up row level access control on a unified customer graph across business units by matching user roles to record tags. The database checks these tags before it returns any customer rows. Most teams start by sharing one broad database role across several apps and teams. That shortcut lets every group read customer rows from other business units. One bad query can expose private emails, phone numbers, or card numbers across the company.

How row level access control on a unified customer graph across business units works

A unified customer graph links records from sales, support, and billing into one shared store. Each customer node or edge holds a tag for its owning business unit. To isolate this data, engineers turn on row-level security rules inside the database engine. These rules compare the current database user or session tag against the row tag.

When an analyst runs a read query, the database engine checks the active role first. It filters out any customer rows that belong to other business units. If a customer buys from two units, a mapping table holds both unit tags. The engine checks this mapping table during every read or write query.

Teams also need to set session values when an app or user logs in. The app passes the user role or group claim into the database session state. The database engine reads that session state and applies the matching row filter. This setup keeps teams from writing custom filter clauses in every single app query.

What native row rules solve and what they leave open

Native row rules work well when every human and app uses a unique database role. They stop an analyst in one unit from reading full tables from another unit. They also keep filter logic inside the database instead of scattering it across many apps.

Still, native database rules have clear limits during daily work. Many apps pool database sessions and log in with one shared service role. When engineers debug issues, they often log in with high-level admin roles that bypass row rules. Database setup rules decide who logs in, not what individual statements do in flight.

Row-Level Security + Customer Support Access to Production: architecture patterns and best practices

Continue reading? Get the full guide.

Free. No spam. Unsubscribe anytime.

Even within an allowed business unit, a user often does not need raw sensitive fields. Native row rules return the whole row once the unit tag matches the user role. If an allowed user runs a broad read query, they get raw emails and card numbers. Masking rewrites matched fields in results so teams work safely without exposing raw customer details.

Managing shared customers and cross-unit queries

A unified customer graph gets tricky when two business units share the same person. One unit might own the billing record while another unit owns the support ticket history. If row rules are too strict, support agents miss context they need to fix problems. If row rules are too loose, one unit reads sensitive payment fields from another unit.

To fix this, data teams split core identity rows from unit-specific activity rows. Every unit can read the shared customer ID, but each unit only reads its own activity. For shared fields like phone numbers or national IDs, teams apply field masking on read results. This keeps the graph unified for analytics while keeping private unit details apart.

Check database and API queries on the wire

Identity tools, roles, and network rules decide who opens a session. Setup alone cannot check what each query does or mask sensitive values in a response once a session starts. When workflows touch Postgres, MySQL, SQL Server, MongoDB, ClickHouse, Kubernetes APIs, SSH, or internal HTTP APIs, hoop.dev sits inline in the wire protocol beside those services as an open-source proxy, a sidecar for your Postgres or API. On every query an AI agent or engineer runs against production, hoop.dev decides to pass, mask, block, or hold it for human review.

Your login details and client tools stay as they are while hoop.dev guardrails refuse bad deletes or drops before they run, and hoop.dev data masking rewrites matched sensitive values in responses in memory. Furthermore, hoop.dev holds SOC 2 Type II, is MIT licensed, and writes every query and decision to an audit trail that generates evidence for HIPAA, GDPR, and PCI DSS. See the source on GitHub.

Frequently asked questions

How do you handle a customer who belongs to two business units?

Store an array of business unit tags or use a separate mapping table for ownership. The row rule checks if the user role matches at least one tag on that record.

Why do shared app roles break database row rules?

Shared app roles log in with the same database identity for every single web request. Unless the app sets a fresh session tag per query, the database cannot tell users apart.

How does data masking help alongside row-level rules?

Row rules filter which records a user gets, while masking rewrites emails or card numbers in results. Together, they limit both the number of rows returned and the sensitive fields shown.

Save the open-source gateway.

hoop is MIT-licensed infrastructure for controlling how AI agents reach production data. Star hoophq/hoop so you can inspect it, deploy it, or share it when your team starts governing agent access.