- page-permission-route-coverage.md: route matrix, test coverage per role, reserved segments.
4.7 KiB
Page Permission – Route and Test Coverage
This document lists all protected routes, which permission set may access them, and how they are covered by tests.
Protected Routes (Router scope with CheckPagePermission in :browser)
| Route | own_data | read_only | normal_user | admin |
|---|---|---|---|---|
/ |
✗ | ✓ | ✓ | ✓ |
/members |
✗ | ✓ | ✓ | ✓ |
/members/new |
✗ | ✗ | ✓ | ✓ |
/members/:id |
✓ (linked only) | ✓ | ✓ | ✓ |
/members/:id/edit |
✗ | ✗ | ✓ | ✓ |
/members/:id/show/edit |
✗ | ✗ | ✓ | ✓ |
/users |
✗ | ✗ | ✗ | ✓ |
/users/new |
✗ | ✗ | ✗ | ✓ |
/users/:id |
✓ (own only) | ✗ | ✗ | ✓ |
/users/:id/edit |
✗ | ✗ | ✗ | ✓ |
/users/:id/show/edit |
✗ | ✗ | ✗ | ✓ |
/settings |
✗ | ✗ | ✗ | ✓ |
/membership_fee_settings |
✗ | ✗ | ✗ | ✓ |
/membership_fee_types |
✗ | ✗ | ✗ | ✓ |
/membership_fee_types/new |
✗ | ✗ | ✗ | ✓ |
/membership_fee_types/:id/edit |
✗ | ✗ | ✗ | ✓ |
/groups |
✗ | ✓ | ✓ | ✓ |
/groups/new |
✗ | ✗ | ✗ | ✓ |
/groups/:slug |
✗ | ✓ | ✓ | ✓ |
/groups/:slug/edit |
✗ | ✗ | ✗ | ✓ |
/admin/roles |
✗ | ✗ | ✗ | ✓ |
/admin/roles/new |
✗ | ✗ | ✗ | ✓ |
/admin/roles/:id |
✗ | ✗ | ✗ | ✓ |
/admin/roles/:id/edit |
✗ | ✗ | ✗ | ✓ |
Note: Permission sets define /custom_field_values and related paths, but there are no such routes in the router; those entries are for future use.
Public Paths (no permission check)
/auth*,/register,/reset,/sign-in,/sign-out,/confirm*,/password-reset*,/set_locale
Test Coverage
File: test/mv_web/plugs/check_page_permission_test.exs
Unit tests (plug called directly with mock conn)
- Static: own_data denied
/members; read_only allowed/members; flash on denial. - Dynamic: read_only allowed
/members/123; normal_user allowed/members/456/edit; read_only denied/members/123/edit. - read_only / normal_user: denied
/admin/roles; read_only denied/members/new. - Wildcard: admin allowed
/admin/roles,/members/999/edit. - Unauthenticated: nil user denied, redirect
/sign-in. - Public: unauthenticated allowed
/auth/sign-in,/register. - Error: no role, invalid permission_set_name → denied.
Integration tests (full router, Mitglied = own_data)
Denied (Mitglied gets 302 → /users/:id):
/members,/members/new,/users,/users/new,/settings,/membership_fee_settings,/membership_fee_types,/membership_fee_types/new,/groups,/groups/new,/admin/roles,/admin/roles/new/members/:id/edit,/members/:id/show/edit,/users/:id(other user),/users/:id/edit(other),/users/:id/show/edit(other),/membership_fee_types/:id/edit,/groups/:slug,/admin/roles/:id,/admin/roles/:id/edit
Allowed (Mitglied gets 200):
/users/:id(own profile),/users/:id/edit,/users/:id/show/edit/members/:id,/members/:id/edit,/members/:id/show/editfor linked member (plug unit tests; full-router tests for linked member skipped: session/LiveView constraints)
Root: GET / redirects Mitglied to profile (root not allowed for own_data).
All protected routes above are either covered by integration “denied” tests for Mitglied or by unit tests for the relevant permission set.
Integration tests (full router, read_only = Vorstand/Buchhaltung)
Allowed (200): /, /members, /members/:id, /groups, /groups/:slug.
Denied (302 → /users/:id): /members/new, /members/:id/edit, /users, /users/new, /settings, /membership_fee_settings, /membership_fee_types, /groups/new, /groups/:slug/edit, /admin/roles, /admin/roles/:id.
Integration tests (full router, normal_user = Kassenwart)
Allowed (200): /, /members, /members/new, /members/:id, /members/:id/edit, /groups, /groups/:slug.
Denied (302 → /users/:id): /users, /users/new, /users/:id (other user), /settings, /membership_fee_settings, /membership_fee_types, /groups/new, /groups/:slug/edit, /admin/roles, /admin/roles/:id.
Integration tests (full router, admin)
Allowed (200): All protected routes (sample covered: /, /members, /users, /settings, /membership_fee_settings, /admin/roles, /members/:id, /admin/roles/:id, /groups/:slug).
Plug behaviour: reserved segments
The plug treats "new" as a reserved path segment so that patterns like /members/:id and /groups/:slug do not match /members/new or /groups/new. Thus /groups/new is only allowed when the permission set explicitly lists /groups/new (currently only admin).