Provide a view of all the access controls for a user within the current app
Context & Background
Currently administrators must navigate between three separate admin pages (Manage Users, User Roles, User Access Controls) to piece together a complete picture of a user's effective permissions. This is error-prone and time-consuming, especially when debugging why a user can or cannot access a specific resource.
The access control resolution in ReStructure is non-trivial: the evaluate_access_for method in Admin::UserAccessControl applies a first-match-wins strategy over records ordered by priority_order (app-type-specific before global defaults; user-specific → role-based → fallback). Multiple overlapping entries can exist, and the effective permission on a given resource depends on this ordering. Without a consolidated view, admins cannot easily see which rule "won" for each resource.
Requirements
Provide one or more new admin pages (or seeded admin reports) that present all access controls for a selected user within an app type, from four complementary perspectives.
Perspective Views
-
User → Roles / "Direct" → User Access Controls
- Show the user, then group by how access was granted (each role name, or "direct" for
user_id-based UACs), then list the individual UAC entries (resource type, resource name, access level).
-
User → User Access Controls → Roles / "Direct"
- Show the user, then group by resource (resource type + resource name + access level), then show which role(s) or "direct" assignment granted that access.
-
User → Resolved Access Controls
- Show the effective (winning) UAC for each resource, after applying the standard
priority_order resolution. For each resource, indicate which role or direct assignment was the source of the winning rule. This is the most useful view for debugging "what access does this user actually have?"
-
User → Roles only
- Show the user's assigned roles in the selected app type (from
Admin::UserRole), with links to the role's UAC entries.
Filtering
All views must support filtering by:
| Filter |
Source |
Notes |
| App type |
Admin::AppType |
Required; scopes all results |
| User |
Active User records |
Required; the user under inspection |
| Resource type |
UAC resource_type enum (table, report, general, activity_log_type, standalone_page, limited_access) |
Optional; narrows results |
| Resource name |
UAC resource_name values for the selected resource type |
Optional; narrows results |
Linking & Navigation
- Each item in the results must link back to the relevant admin page:
- User →
admin_manage_users_path filtered to that user
- User Access Control entry →
admin_user_access_controls_path filtered by resource type / resource name / app type
- User Role →
admin_user_roles_path filtered by user / app type / role name
- The new page(s) should be accessible from the Users & Access section of the admin index page (
app/views/pages/_index_admin.html.erb), gated by current_admin.can_admin?(:user_access_controls).
Ordering
Results within each view must follow the standard UAC priority_order:
app_type_id ASC NULLS LAST,
CASE
WHEN user_id IS NOT NULL THEN user_id::varchar
WHEN (role_name IS NOT NULL AND role_name <> '') THEN role_name
ELSE user_id::varchar
END
Within each grouping, secondary sort by resource_type ASC, resource_name ASC.
Acceptance Criteria
Technical Considerations
Implementation Approach — Options
Option A: Seeded Admin Reports (lower effort, leveraging existing infrastructure)
- Define SQL-based reports seeded via
db/seeds/ (similar to report_user_notifications.rb).
- Use
search_attrs with type: user and type: config_selector (or defined_selector) filters for app type, resource type, resource name.
- Use the existing
reports_tree.js tree view (data-tt-tree-cols) for hierarchical display in Perspectives 1 and 2.
- Perspective 3 (Resolved) would require a more complex SQL query using
DISTINCT ON or window functions to select the first-match per resource following priority_order.
- Links in report results could use report
column_options with hide_link or custom link formatting.
- Pros: Reuses existing report infrastructure, filterable out of the box, no new controllers/views needed.
- Cons: Complex SQL for resolved view; linking from report cells to admin pages may require custom column formatting; limited control over presentation.
Option B: Dedicated Controller & Views (more effort, full control)
- New
Admin::UserAccessOverviewController with a dedicated view.
- Query
Admin::UserAccessControl and Admin::UserRole using existing scopes (scope_user_and_role, where_user_and_role) and priority_order.
- Render the tree hierarchy using a pattern similar to the protocol tree view (
app/views/admin/protocols/_tree_list.html.erb) with collapsible <ul> lists.
- Pros: Full control over presentation, linking, and UX; can reuse model methods directly.
- Cons: More code to maintain; new controller, views, routes, and tests.
Option C: Hybrid — Report-backed with custom rendering
- Use seeded report SQL for data retrieval, but render with a custom partial rather than the standard report table.
- Pros: SQL-driven data, custom UX.
- Cons: More complex wiring.
Key Models & Methods Involved
| Component |
File |
Purpose |
Admin::UserAccessControl |
app/models/admin/user_access_control.rb |
UAC records; evaluate_access_for, valid_resources |
UserAndRoles concern |
app/models/concerns/user_and_roles.rb |
priority_order, scope_user_and_role, where_user_and_role |
Admin::UserRole |
app/models/admin/user_role.rb |
Role assignments; active_app_roles |
Admin::AppType |
app/models/admin/app_type.rb |
App type scoping; associated_* methods |
Resources::Models |
app/models/resources/models.rb |
Resource name → class registry |
Resources::UserAccessControl |
app/models/resources/user_access_control.rb |
resource_descriptions_for_* methods for resource name listings |
Database Considerations
- No schema changes required — all data exists in
user_access_controls, user_roles, and users tables.
- For the Resolved view (Perspective 3), a query like the following would select the winning UAC per resource:
SELECT DISTINCT ON (resource_type, resource_name)
resource_type, resource_name, access, role_name, user_id, app_type_id
FROM ml_app.user_access_controls
WHERE disabled IS NOT TRUE
AND (user_id = :user_id
OR (app_type_id = :app_type_id AND role_name IN (:role_names))
OR (user_id IS NULL AND (role_name IS NULL OR role_name = '')))
AND (app_type_id = :app_type_id OR app_type_id IS NULL)
ORDER BY resource_type, resource_name,
app_type_id ASC NULLS LAST,
CASE WHEN user_id IS NOT NULL THEN 0
WHEN role_name IS NOT NULL AND role_name <> '' THEN 1
ELSE 2 END
UI Placement
- Add link in
app/views/pages/_index_admin.html.erb under the "Users & Access" section, after "User Access Controls".
- Gate with
current_admin.can_admin?(:user_access_controls).
Edge Cases & Risks
- Users with no roles or UACs: The page should display an informative "No access controls found" message rather than a blank or error page.
- Disabled UACs/roles: Disabled entries should be excluded by default but optionally shown (with visual distinction) if an "include disabled" filter is provided.
- Global (NULL app_type) UACs: These apply across all app types and must appear in results when viewing any specific app type, clearly marked as "global default".
- Large number of UAC entries: Some app types may have hundreds of UAC entries across many roles. Ensure the view remains performant — consider pagination or lazy-loading of sub-trees.
- Role with no UAC entries: A role assigned to a user that has no corresponding UAC entries should still appear in Perspective 4 (Roles only) but be flagged as "no access controls defined".
- Conflicting access levels: When multiple roles grant different access levels to the same resource, the Resolved view must clearly show which one won and why (i.e., which role/assignment had higher priority).
- Template users and roles (
@template email users, Settings::AppTemplateRole): These should be excluded from normal user lists but could appear in UAC results if filtering by resource — consider filtering them out by default.
Non-Functional Requirements
- Performance: Page load for any perspective should complete within 2 seconds for a user with up to 500 UAC entries across roles.
- Accessibility: Follow existing admin page HTML structure and ARIA patterns; collapsible tree sections should be keyboard-navigable.
- Security: Gated by
can_admin?(:user_access_controls) — no user-facing access. UAC data is admin-only and should not leak to non-admin users.
- Maintainability: If implemented as seeded reports, SQL must be versioned in
db/seeds/ and idempotent (use find_or_initialize_by).
- Consistency: The ordering and resolution logic must exactly match
UserAndRoles#priority_order and evaluate_access_for — any divergence would produce misleading results.
Provide a view of all the access controls for a user within the current app
Context & Background
Currently administrators must navigate between three separate admin pages (Manage Users, User Roles, User Access Controls) to piece together a complete picture of a user's effective permissions. This is error-prone and time-consuming, especially when debugging why a user can or cannot access a specific resource.
The access control resolution in ReStructure is non-trivial: the
evaluate_access_formethod inAdmin::UserAccessControlapplies a first-match-wins strategy over records ordered bypriority_order(app-type-specific before global defaults; user-specific → role-based → fallback). Multiple overlapping entries can exist, and the effective permission on a given resource depends on this ordering. Without a consolidated view, admins cannot easily see which rule "won" for each resource.Requirements
Provide one or more new admin pages (or seeded admin reports) that present all access controls for a selected user within an app type, from four complementary perspectives.
Perspective Views
User → Roles / "Direct" → User Access Controls
user_id-based UACs), then list the individual UAC entries (resource type, resource name, access level).User → User Access Controls → Roles / "Direct"
User → Resolved Access Controls
priority_orderresolution. For each resource, indicate which role or direct assignment was the source of the winning rule. This is the most useful view for debugging "what access does this user actually have?"User → Roles only
Admin::UserRole), with links to the role's UAC entries.Filtering
All views must support filtering by:
Admin::AppTypeUserrecordsresource_typeenum (table,report,general,activity_log_type,standalone_page,limited_access)resource_namevalues for the selected resource typeLinking & Navigation
admin_manage_users_pathfiltered to that useradmin_user_access_controls_pathfiltered by resource type / resource name / app typeadmin_user_roles_pathfiltered by user / app type / role nameapp/views/pages/_index_admin.html.erb), gated bycurrent_admin.can_admin?(:user_access_controls).Ordering
Results within each view must follow the standard UAC
priority_order:Within each grouping, secondary sort by
resource_type ASC, resource_name ASC.Acceptance Criteria
priority_order), clearly indicating the source (role name or "direct").UserRoleentries for the selected app type, each linking to their associated UAC entries.priority_orderdefined inUserAndRoles#priority_order.can_admin?(:user_access_controls)permission.Technical Considerations
Implementation Approach — Options
Option A: Seeded Admin Reports (lower effort, leveraging existing infrastructure)
db/seeds/(similar toreport_user_notifications.rb).search_attrswithtype: userandtype: config_selector(ordefined_selector) filters for app type, resource type, resource name.reports_tree.jstree view (data-tt-tree-cols) for hierarchical display in Perspectives 1 and 2.DISTINCT ONor window functions to select the first-match per resource followingpriority_order.column_optionswithhide_linkor custom link formatting.Option B: Dedicated Controller & Views (more effort, full control)
Admin::UserAccessOverviewControllerwith a dedicated view.Admin::UserAccessControlandAdmin::UserRoleusing existing scopes (scope_user_and_role,where_user_and_role) andpriority_order.app/views/admin/protocols/_tree_list.html.erb) with collapsible<ul>lists.Option C: Hybrid — Report-backed with custom rendering
Key Models & Methods Involved
Admin::UserAccessControlapp/models/admin/user_access_control.rbevaluate_access_for,valid_resourcesUserAndRolesconcernapp/models/concerns/user_and_roles.rbpriority_order,scope_user_and_role,where_user_and_roleAdmin::UserRoleapp/models/admin/user_role.rbactive_app_rolesAdmin::AppTypeapp/models/admin/app_type.rbassociated_*methodsResources::Modelsapp/models/resources/models.rbResources::UserAccessControlapp/models/resources/user_access_control.rbresource_descriptions_for_*methods for resource name listingsDatabase Considerations
user_access_controls,user_roles, anduserstables.UI Placement
app/views/pages/_index_admin.html.erbunder the "Users & Access" section, after "User Access Controls".current_admin.can_admin?(:user_access_controls).Edge Cases & Risks
@templateemail users,Settings::AppTemplateRole): These should be excluded from normal user lists but could appear in UAC results if filtering by resource — consider filtering them out by default.Non-Functional Requirements
can_admin?(:user_access_controls)— no user-facing access. UAC data is admin-only and should not leak to non-admin users.db/seeds/and idempotent (usefind_or_initialize_by).UserAndRoles#priority_orderandevaluate_access_for— any divergence would produce misleading results.