Files
unsupervised-scheduler/docs/features/user-roles.md
T
thatguygriff b5c076c3d6
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 48s
CI / Tests (PHP 8.2) (pull_request) Successful in 49s
CI / Tests (PHP 8.1) (pull_request) Successful in 54s
CI / Coding Standards (pull_request) Successful in 1m5s
CI / PHPStan (pull_request) Successful in 1m11s
CI / Build Plugin Zip (pull_request) Has been skipped
Add Instructors admin page (create + per-capability access)
Completes the instructor-management half of #9: the studio admin can now
create instructor accounts and toggle each instructor's capabilities.

- InstructorController (manage_instructors): list instructors, create a
  us_instructor WP user (emailing a set-password link), and a per-instructor
  capability detail view.
- InstructorCapabilities: pure, unit-tested rules for which managed caps an
  admin may assign and how a submitted form maps to assignments. Managed caps
  are manage_offerings, manage_questions, view_own_payments, export_payments;
  manage_availability and view_own_lessons are core to every instructor.
- A studio admin can never grant a capability it does not itself hold: only
  held caps (checked via current_user_can, so an administrator's dynamic grant
  counts) are offered, and on creation any managed cap the admin lacks is
  denied on the new instructor so they never exceed their creator. The role
  grants the managed caps by default; the page layers per-user overrides.
- AdminMenu: register the Instructors page in the people section.
- Tests for the capability logic; docs/features/user-roles.md updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 17:02:46 -03:00

96 lines
5.7 KiB
Markdown

# Feature: User Roles
## Overview
Three custom WordPress user roles control access to all scheduling features: a studio admin who runs the business, instructors who teach, and students who book.
## Roles
### Studio Admin (`us_studio_admin`)
Runs the studio. Logs in via standard wp-admin. Can:
- Create instructor accounts and set/revoke each instructor's capabilities
- Manage offerings, intake questions, and policies
- Configure Stripe credentials and per-student billing overrides (card / e-transfer / comp)
- View the studio-wide scheduler (all upcoming lessons across instructors)
- View the all-instructor payments report and export it
**Capabilities:** `read`, `manage_instructors`, `manage_offerings`, `manage_questions`, `manage_policies`, `manage_billing`, `view_all_lessons`, `view_all_payments`, `export_payments`
> Any WordPress **administrator** (`manage_options`) implicitly holds every
> studio-admin capability above **and the instructor capabilities** (notably
> `manage_availability`), so a single-instructor studio owner can run the business
> and teach — managing their own availability and lessons — from one account,
> without being assigned the `us_studio_admin` or `us_instructor` role. This is
> applied dynamically via the `user_has_cap` filter
> (`RoleManager::grantStudioCapsToAdministrators()`) — it persists nothing and is
> removed when the plugin is deactivated. The `us_studio_admin` role exists for
> non-administrator staff who manage the studio.
>
> Both grants can be turned off independently on the **Access** admin page
> (`AccessSettings`, options `us_admin_grant_studio` / `us_admin_grant_instructor`,
> both default on) — for example, when dedicated `us_studio_admin` or
> `us_instructor` accounts run the studio and administrators should not appear as
> studio staff. That page is gated on the core `manage_options` capability (which
> the plugin never grants or revokes), so an administrator can always reach it to
> re-enable a grant; disabling one can never lock them out.
### Instructor (`us_instructor`)
Created by the studio admin. Logs in via standard wp-admin. Can:
- Manage their own availability slots (add/delete), including weekly-recurring windows
- Manage their own offerings and intake questions
- View their upcoming confirmed/pending lessons and group enrolments
- View and export their own payments
**Capabilities:** `read`, `manage_availability`, `manage_offerings`, `manage_questions`, `view_own_lessons`, `view_own_payments`, `export_payments`
### Student (`us_student`)
Logs in via the front-end `[us_student_login]` shortcode. Can:
- Browse available lesson slots and offerings from all instructors
- Book a private lesson (single or weekly) and enrol in group classes
**Capabilities:** `read`, `book_lesson`, `view_own_lessons`
## Capability Matrix
| Capability | Studio Admin | Instructor | Student | Used by |
|-----------------------|:------------:|:----------:|:-------:|---------------------------------|
| `manage_instructors` | ✓ | | | Instructor management |
| `manage_availability` | | ✓ | | Availability |
| `manage_offerings` | ✓ | ✓ (own) | | Offerings |
| `manage_questions` | ✓ | ✓ (own) | | Registration questions |
| `manage_policies` | ✓ | | | Policies |
| `manage_billing` | ✓ | | | Payments (Stripe + overrides) |
| `book_lesson` | | | ✓ | Lesson booking / enrolment |
| `view_all_lessons` | ✓ | | | Scheduler dashboard |
| `view_own_lessons` | | ✓ | ✓ | Lesson + group views |
| `view_own_payments` | | ✓ | | Payment reporting |
| `view_all_payments` | ✓ | | | Payment reporting |
| `export_payments` | ✓ | ✓ (own) | | Payment reporting export |
## Instructor Management
The studio admin gets an **Instructors** admin page (gated by `manage_instructors`)
to add an instructor — creating the WP user with the `us_instructor` role and
emailing them a set-password link — and to toggle that instructor's per-capability
access. The managed capabilities are `manage_offerings`, `manage_questions`,
`view_own_payments`, and `export_payments`; `manage_availability` and
`view_own_lessons` are core to every instructor and are not managed here. The
`us_instructor` role grants the managed capabilities by default, and the page
stores per-user overrides on top of the role.
A studio admin cannot grant a capability it does not itself hold: only
capabilities the acting user has (checked via `current_user_can()`, so an
administrator's dynamic grant counts) are offered as toggles, and on creation any
managed capability the admin lacks is denied on the new instructor so they never
exceed the creator. The grantable/assignment rules live in the pure, unit-tested
`Auth\InstructorCapabilities`; `InstructorController` applies the result to the
`WP_User`.
## Implementation
- Class: `Unsupervised\Schedular\Auth\RoleManager`
- Instructor management controller: `Unsupervised\Schedular\Auth\InstructorController`
- Roles are created on `plugins_loaded → init` and on plugin activation via `Installer`.
- Permissions are checked with `current_user_can()` against the capability string, not the role name.
## Tests
- `tests/Unit/Auth/RoleManagerTest.php`
- `tests/Unit/Auth/InstructorCapabilitiesTest.php`