Access: a row-level condition that follows a reference, so an instructor reads only their classes' students
- Dominant language
- C#
- Stars
- 6
- Forks
- 7
- Avg merge
- 4h 42m
- Merged PRs (30d)
- 307
Description
Arnel, 14 September 2026: an instructor signs in, sees their class schedule, opens a class and sees its students. The page is blocks (BaryoDev/barakoPress#33, #26, #7). Who may read which rows has to be decided here, not by a filter on the page.
## What works today
Row-level conditions on a permission rule compare a field of the row being read, with `$CURRENT_USER` substituted (docs/access-control.md, Layer 2). So "an Instructor reads classes where `InstructorUser` equals the signed-in user" is configuration now, provided the class stores the instructor's user id.
## The gap
Enrollments do not name the instructor; they reference a class. "An Instructor reads enrollments whose class they teach" needs the condition to follow a reference:
```json
{ "Read": { "Enabled": true, "Conditions": { "Class.InstructorUser": { "_eq": "$CURRENT_USER" } } } }
```
Today the only way is to copy the instructor's id onto every enrollment and keep it in step when a class changes hands, which is exactly the kind of copy that drifts.
## Change
- A condition key may follow one reference field to the referenced entry's field: `Reference.Field`. One hop only, and only through a field declared as `reference` with its `referenceType`, so the path is checked when the role is saved.
- Evaluated in the database for list endpoints, so paging and totals count only rows the reader may see, never filtered after the page is loaded.
- Evaluated the same way for get, update, delete and transitions.
- A referenced entry the reader cannot read does not leak through the condition: the condition only decides access to the row being read, and resolving the reference for display still applies the reader's own permissions.
## Done when
- An Instructor lists only enrollments of classes whose `InstructorUser` is them, with correct totals across pages, and gets 404 on another class's enrollment by id.
- A condition naming a field that is not a reference, or two hops, is refused when the role is saved.
- An existing single-field condition behaves exactly as before.
## Where it lives
Core: `PermissionResolver` and `ConditionEvaluator`. Access rules are the core's job, and a module must not be able to widen them.
Contributor guide
Research direction
Start with the core PermissionResolver and ConditionEvaluator, then read Layer 2 in docs/access-control.md to understand existing single-field conditions. Trace list, get, update, delete, and transition authorization paths, and use the stated done criteria to verify one-hop reference validation, database-level paging and totals, 404 behavior, and unchanged single-field conditions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- authorization, backend-api-design, databases
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100