Implements #16: invite-only student self-registration through a front-end page, accepting signup-scoped policies at account creation. Policy domain: - us_policies.acceptance_scope (signup/booking/both); Policy::appliesTo(); PolicyRepository::findForScope(); scope threaded through PolicyService, the REST create, the admin controller, and the Policies form. - PolicyAcceptance::REG_ACCOUNT (registration_id = the new user's ID). Auth: - Invite value object + InviteRepository; us_invites table. - RegistrationController + Invites admin page (manage_students): invite an email, share the registration link, revoke. - RegistrationPage ([us_student_register] shortcode): validates the invite token, collects name/password, renders signup-scoped published policies with required acceptance, creates the us_student user, records account-type acceptances, marks the invite accepted, and logs the user in. - RoleManager: manage_students cap added to STUDIO_ADMIN_CAPS. Invite-only is implemented; the us_registration_mode self_approval path is a documented future seam. Docs: docs/features/account-registration.md; policies.md updated. Tests: tests/Unit/Auth/ (Invite, InviteRepository) plus Policy scope updates. composer test (104), cs, and PHPStan level 6 all pass. Refs #16 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.8 KiB
Feature: Account Registration
Overview
People register for a student account through a front-end page, accepting any
signup-scoped policies at that time. Registration is invite-only by default: a
studio admin sends an invite, and the invitee completes signup via a tokenised
link. A settings seam (us_registration_mode) allows switching to open
self-registration with approval later.
Registration Modes
Stored in the us_registration_mode option (default invite):
invite— only a valid, pending invite token grants access to the registration form. (implemented)self_approval— anyone may register; the account is created in a pending state until a studio admin approves it. (reserved for a later iteration)
Data Model — {prefix}us_invites
| Column | Type | Notes |
|---|---|---|
id |
BIGINT UNSIGNED | Primary key |
email |
VARCHAR(191) | Invited email address |
token |
VARCHAR(64) | Opaque token embedded in the registration link |
role |
VARCHAR(32) | Role granted on acceptance (default us_student) |
status |
VARCHAR(20) | pending / accepted / revoked |
invited_by |
BIGINT UNSIGNED | WordPress user ID of the studio admin who invited |
accepted_user_id |
BIGINT UNSIGNED | The created user's ID once accepted; NULL while pending |
created_at |
DATETIME | Insertion time |
accepted_at |
DATETIME | When accepted; NULL while pending |
Policy Acceptance Scope
Policies declare when they must be accepted via us_policies.acceptance_scope:
signup, booking, or both (see policies.md). The registration form requires
acceptance of every published policy scoped signup or both. Acceptances are
recorded in us_policy_acceptances with registration_type = account and
registration_id = <new user ID>.
Flow (invite mode)
- Studio admin opens Invites (
manage_students) and invites an email; an invite row is created with a token and a registration link. - The invitee opens
[us_student_register]with the token (?us_invite=<token>). - The form pre-fills the email and collects a display name and password, and renders the signup-scoped published policies, each with a required acceptance checkbox.
- On submit, the token is re-validated; a
us_studentuser is created, the policy acceptances are recorded (accounttype), the invite is markedaccepted, and the user is logged in.
Admin Interface
Invites in wp-admin (manage_students, studio admin only):
- Invite an email (creates a pending invite + link)
- List pending invites; revoke an invite
Frontend Shortcode
[us_student_register]— the registration page. Shows the form for a valid pending invite; otherwise shows an "by invitation only" message (ininvitemode).
Capabilities
manage_students— manage invites (studio admin; administrators inherit it via theuser_has_capfilter). Added toRoleManager::STUDIO_ADMIN_CAPS.
Implementation
- Models:
Unsupervised\Schedular\Auth\Invite - Repository:
Unsupervised\Schedular\Auth\InviteRepository - Admin controller:
Unsupervised\Schedular\Auth\RegistrationController - Frontend:
Unsupervised\Schedular\Auth\RegistrationPage - Reuses
Policy\PolicyRepository,Policy\PolicyVersionRepository,Policy\AcceptanceRepository - Schema:
us_invites;us_policies.acceptance_scope
Tests
tests/Unit/Auth/InviteTest.phptests/Unit/Auth/InviteRepositoryTest.php