Sign-up & Email Verification
Overview
Sign-up is a self-service flow that creates an organization and its first user in a single request, with no invitation required. It is aimed at new customers who want to start evaluating the platform on their own.
The flow spans two pages:
/register— the form for organization and user details, with real-time duplicate-email checking and a password strength meter./verify-email— the page users land on from the email link, where the token is confirmed.
Both are public pages that require no token and render inside the authentication layout, without the sidebar or top bar.
A successful sign-up does not sign the user in automatically. The email must be verified first, and the newly created organization still needs administrator approval before it can be used.
Business Flow
Signing up
- The user opens
/registerand fills in:- Organization name (required)
- First and last name (required)
- Email (required, must be a valid email address)
- Password (required, at least 8 characters)
- Confirm password (must match the password)
- As the email is typed, the app checks availability with a 600 ms debounce via
GET /auth/check-emailand shows a status below the field: checking, available, or already taken. The check only fires once the value passes a basic email-format test. - Password strength is computed client-side from four criteria — at least 8 characters, an uppercase letter, a digit, and a special character — and rendered as a four-level colored bar (Weak / Fair / Good / Strong).
- On submit, the app first verifies that the email status is not "taken". If it is, an inline error is shown on the email field and no request is sent.
- Otherwise the details are posted to
POST /auth/register, which creates the organization and its first user together. - On success the form is replaced by a confirmation screen telling the user to check their inbox, with a link back to the login page.
- On failure a modal shows the server's message; when the server returns several validation errors they are joined into a single message.
Verifying the email
- The user clicks the link in the email, which opens
/verify-emailwith a token parameter. - The page calls
GET /auth/verify-emailas soon as it loads, showing a verifying state while it waits. - If no token is present in the URL, an error is displayed immediately without contacting the server.
- Success — a green confirmation icon and a button that takes the user to the login page.
- Failure — a red error icon with the server's message, or a standard "invalid link" message, plus a button back to the sign-up page.
- Once verified, the user can sign in. If the organization has not been approved yet, login is rejected with a "pending approval" message.
Key Screens & Components
Sign-up screen
/register separates concerns into a container that owns all logic — debounced email checking, form submission, switching to the result screen, and the error modal — and a presentational form that renders the input fields, the email status label and the password strength bar.
On success, the container swaps the form for the result screen while staying on the same URL.
Email verification screen
/verify-email is a single page that handles three states — verifying, success and error — each with its own icon, message and follow-up action.
Registration service layer
The registration service (src/services/registration.service.ts) groups three functions: creating the account, checking email availability, and verifying the email.
Notably, this service uses its own dedicated axios instance rather than the application's shared one, because no token exists at this stage and the shared HTTP 401 interceptor would otherwise force an unnecessary sign-out.
Public routes
/register and /verify-email are listed among the application's public paths, so they bypass the token check entirely.
Dependencies
- Login — every sign-up path ends at
/login, and sign-in only succeeds once the email is verified and the organization is approved. - Password Management — uses the same style of server-encoded token, with an
isNewAccountflag distinguishing users setting a password for the first time. - Organization Module Settings — newly registered organizations must have their modules enabled and quotas assigned by a super administrator before real use.
- Password rule caveat — the four-criteria strength meter on the sign-up page differs from the six-item checklist used on the reset-password page and in the change-password modal.
Backend Details (CMS API)
The registration module in cms-api never uses the authenticated route group. Every endpoint is public, because at this stage the user has no token.
Endpoints used by this screen
| Frontend action | Endpoint | Notes |
|---|---|---|
| Real-time duplicate email check | GET /api/auth/check-email | email passed as a query parameter |
| Submit the sign-up form | POST /api/auth/register | returns 201 on success |
| Verify the email from the link | GET /api/auth/verify-email | token passed as a query parameter |
What the backend does on a sign-up request
A single call to POST /api/auth/register performs several steps in sequence:
- Hashes the password with bcrypt before storing it — no plaintext password is ever kept.
- Creates rows in the
organizationandusertables, automatically attaching the default customer role to the first user, so nobody has to assign a role before the account can work. - Generates a random verification token using a cryptographic generator and encodes it as a hex string.
- Returns 201, which is the signal the frontend uses to swap the form for the result screen.
The verification email is then sent through the system-wide shared mailer (configured from the MAIL_SMTP_* environment variables) rather than a transport created per module.
Things worth knowing
- The duplicate-email check is a UX aid, not a reservation.
GET /api/auth/check-emailreports the state at the moment it is asked but does not hold the address. While the user spends another half minute filling in the form, someone else can still register it — so submission can fail even though the badge said "available". - A successful sign-up does not mean access is granted. The backend creates the organization in a state that cannot be used yet; sign-in is rejected until a super administrator activates the organization and assigns its modules and quotas. That is why the login page shows a distinct "pending approval" message rather than a generic error.
- Email verification only flips the user's status.
GET /api/auth/verify-emailmarks the user as verified; it does not issue a token. The user must sign in at/loginthemselves, which is where the button on the verification screen leads. - The
password_historytable is written from sign-up onward. The very first password is recorded in history too, so the reuse-prevention mechanism reaches all the way back to the initial password. - Backend password rules are not the frontend meter. The Weak/Fair/Good/Strong bar is a client-side hint for the user; the rules that actually gate the request are the ones the backend validates on receipt.