A moderation list endpoint on a payment platform took about three seconds, and the query log said nothing useful. The queries were small and indexed. The slow part was authorization.
The access model was the piece I trusted most. Roles, tiers, assignment scope: tests covered all of it. It just answered one question at a time, though: can this user see this object. So the endpoint loaded a page of cases, then asked that question per row, and each answer went off looking for role and assignment data of its own.
Two hundred rows meant hundreds of correct, well-tested checks inside one request. Fast everywhere, slow in aggregate.
The cost was worse than the number. Compliance moderators page through queues all day (that is the job), so the slowest screen in the product was the one people used most, and the obvious suspects (database, serialization, the provider calls) were all innocent...
I did not make the check faster. I made the same rules expressible as a filter, so the database returned only visible rows and the page stopped asking row by row. Getting to around 200ms was mostly deleting a loop.
What I do differently now: when I design an access model, every scope rule has to be stateable as a query predicate, not only as a yes/no on an object already loaded. Per-object checks stay on single-object endpoints, where they belong.
I wrote up how I approach permissions and payment-side data access here: https://polycratia.com/c/0d9d31a3
If you have hit this: did you push authorization into the query, or precompute visibility?