# Registration approval flow

This document is the lifecycle contract for new TakafulHub and VastPro registrations. It intentionally separates **email verification**, **Admin approval**, and **operational account access**.

## New registrations

| Stage | TakafulHub account | VastPro application | Who can act | Operational access |
|---|---|---|---|---|
| Submitted | `pending_email_verification` | `pending_email_verification` | Applicant | No |
| OTP verified | `pending_admin_approval` | `pending_admin_approval` | Admin reviewer | No |
| Approved | `approved` | `approved` | System creates the VastPro user/profile exactly once | Yes, if the account is not later administratively deactivated |
| Rejected | `rejected` | `rejected` | Applicant may correct and resubmit the same record | No |

New registrations use a six-digit email OTP. The code is hashed at rest, scoped to the trusted server-side subject and purpose, expires, is single-use, and is invalidated when a resend or email change supersedes it. Rate limits are recorded only after a mail hand-off succeeds. If the mail hand-off fails, the recorded code is invalidated, the applicant keeps a restricted resume context, and the UI offers a safe retry without exposing technical mail details.

## Legacy compatibility and the RC5 migration

Existing TakafulHub accounts whose `registration_verification_version` is `NULL` retain the legacy signed-link verification path. Existing verified/pending/rejected records are not rewritten into OTP records.

The VastPro OTP migration is additive. It maps only existing persisted VastPro `pending` applications to:

```text
status = pending_admin_approval
registration_verification_version = legacy
email_verified_at = NULL
```

This preserves their reviewability without inventing a verification timestamp, and it does not create a `users` row, `agent_profiles` row, OTP row, membership, Lead Credit, payment or referral relationship. Legacy VastPro applications can be approved through the normal Admin review path.

## Admin review and resubmission

Administrators review verified registrations oldest first. Approval records the reviewer and timestamp. Rejection requires a reason, records reviewer/timestamp, and leaves the applicant record in place.

A rejected TakafulHub applicant resumes through their existing signed recovery link; a rejected VastPro applicant resumes through the restricted portal context. Resubmission preserves the existing trusted relationship/hierarchy. If the email is unchanged, it returns to Admin review; if the email changes, it requires a fresh OTP. Rejection history is retained for VastPro; no operational account is created until Admin approval.

## Access boundary

`is_account_active` is an administrative enable/disable flag, not a substitute for registration approval. Login and portal middleware require an approved lifecycle state as well as an active account. Pending, rejected, unverified and restricted-resume states cannot access Agent or VastPro operational routes.

The independent registration pages never accept browser-supplied OTP subject identifiers, verification versions, hierarchy IDs, reviewer IDs, approval states, or operational-access flags.
