mitgliederverwaltung/docs/page-permission-route-coverage.md
Moritz ea1d01fcea Docs: align route matrix with PermissionSets, add Role-Load note
- Table: own_data/read_only/normal_user /users/:id and edit/show/edit; members edit/show/edit
- Integration test sections updated for read_only and normal_user
- Add note on plug reloading role and member_id when needed
2026-01-30 10:22:30 +01:00

92 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` | ✓ (linked only) | ✗ | ✓ | ✓ |
| `/members/:id/show/edit` | ✓ (linked only) | ✗ | ✓ | ✓ |
| `/users` | ✗ | ✗ | ✗ | ✓ |
| `/users/new` | ✗ | ✗ | ✗ | ✓ |
| `/users/:id` | ✓ (own only) | ✓ (own only) | ✓ (own only) | ✓ |
| `/users/:id/edit` | ✓ (own only) | ✓ (own only) | ✓ (own only) | ✓ |
| `/users/:id/show/edit` | ✓ (own only) | ✓ (own only) | ✓ (own only) | ✓ |
| `/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/edit` for 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`, `/users/:id` (own profile), `/users/:id/edit`, `/users/:id/show/edit`, `/groups`, `/groups/:slug`.
**Denied (302 → `/users/:id`):** `/members/new`, `/members/:id/edit`, `/members/:id/show/edit`, `/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, normal_user = Kassenwart)
**Allowed (200):** `/`, `/members`, `/members/new`, `/members/:id`, `/members/:id/edit`, `/members/:id/show/edit`, `/users/:id` (own profile), `/users/:id/edit`, `/users/:id/show/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).
## Role and member_id loading
The plug may reload the user's role (and optionally `member_id`) before checking page permission. Session/`load_from_session` can leave the role unloaded; the plug uses `Mv.Authorization.Actor.ensure_loaded/1` (and, when needed, loads `member_id`) so that permission checks always have the required data. No change to session loading is required; this is documented for clarity.