Access controls · live on Postgres
Try to see what you shouldn't.
Pick a persona and a purpose. The database decides what comes back, the same way for this screen, the API and the AI analyst. Every request is logged.
Asking the database…
Contracted aggregates, small cells suppressed
Each metric maps to a contract clause. The database hides any cell with fewer than 25 cardholders, value and count both.
Why this result
Every layer the database applied to this request, in order.
- PassPurpose grant (RLS)The stated purpose is granted to this persona.
- BlocksConsumption grant (View)Aggregate-only under the partner contract: no cardholder rows.
- FiltersProgram scope (RLS)Partner persona: only its own program's rows.
- MasksColumn masking (View)Email and phone masked.
- LogsAccess log (Audit)Request recorded in the hash-chained access log.
Independent check
A second implementation of the same rules re-judges every row the database returned. Drift would show here in red.
checking…
Your access log
Every read is recorded and hash-chained. You see your own events only.
- Your reads will appear here.
The policy SQL3 policies · show
create policy cust_base on atlas.customers for select to public using (true);
Baseline visibility for cardholder rows.
create policy cust_purpose_granted on atlas.customers as restrictive for select to public using ((select atlas.ctx_purpose_granted()));
No cardholder rows unless the stated purpose is granted to the persona.
create policy cust_partner_scope on atlas.customers
as restrictive for select to public
using ((select atlas.ctx_partner_scope()) is null
or partner_scope = (select atlas.ctx_partner_scope()));A partner persona only ever reaches its own program's cardholders.
Masking and the rows-versus-aggregates grant live in the security-barrier views every read goes through, including the AI analyst.
How it is enforcedtechnical detail
One door, least privilege
The public API key can read catalog metadata and nothing else. Every read of cardholder data is a database function that only the server can call. Each function runs as a role that cannot bypass Row Level Security, so the key that authorises the call does not decide what it sees.
Rows in policy, columns in views
Program scope, purpose grants and the fraud-detail gate are restrictive RLS policies on every fact table. Masking and the rows-versus-aggregates grant live in security-barrier views that are the only row-level read surface, for the simulator and the AI analyst alike.
Purpose-bound unmasking
A persona sees clear contact data only when its role AND the stated purpose allow it. The platform admin never does. A purpose that is not granted returns nothing at all, for every table.
Tested every time, logged every time
A self-test asserts the rules for every persona, purpose and data product against the live database (the badge above). Every read writes a hash-chained log row; recomputing the chain detects any edited row.