User Registration

The front door of the platform. Owners, managers and travellers all enter through this flow. The goal: friction low enough that real users do not bounce, signals strong enough that fakes do not get through.

Who registers, and where

ABc has two distinct sign-up surfaces. They share an account model but enter through different doors.

Owner / Manager sign-up

From app.abc.com/signup. Asks for business name on step 1 so we know to route them to the KYC flow next. Default role: owner.

Admin console

Public traveller sign-up

From abc.com/signup or inline during checkout. Lighter: just name, email, phone, password. Default role: public_user.

Public site

Required fields

FieldOwnerPublicValidation
Full nameRequiredRequired2–80 chars, no digits
EmailRequiredRequiredRFC 5322, unique, DNS-MX check
PhoneRequiredRequiredE.164 with country code, libphonenumber-validated
PasswordRequiredRequiredMin 10 chars, mixed case, 1 digit, not in HIBP
Business nameRequired2–120 chars
Property typeRequiredhotel · bnb · villa · hostel · other
CityRequiredOptionalFrom dropdown (geo-data seeded)
How did you hear about ABcOptionalFree text · for attribution

Registration flow

  1. User opens the sign-up page

    Front-end loads the form. A hidden honeypot field is added — bots fill it, humans never see it.

  2. User submits the form

    Client-side validation runs first (instant feedback). On submit, we hit POST /auth/signup with the payload + an hCaptcha token.

  3. Server pre-checks

    Honeypot empty? hCaptcha valid? Email not already used? Phone not already used? Email domain not on disposable-email blocklist?

  4. Create user (pending state)

    Insert into users with status = pending_verification, password hashed (Argon2id). No login granted yet.

  5. Send OTP to phone + magic link to email

    Phone gets a 6-digit code (SMS, 10-min expiry). Email gets a one-time link (15-min expiry). Both queued — user must verify both to activate.

  6. User verifies

    On verification, mark the relevant flag true. When email_verified AND phone_verified → flip status = active → issue session.

  7. Route based on role

    Owners land on the property onboarding wizard. Public users land on home with a "complete your profile" nudge.

UI — sign-up form (owner)

app.abc.com/signup
Create your owner account
Takes 90 seconds. Verify by OTP at the end.
Already have an account? Sign in
Hotel lobby

API contract

POST /api/auth/signup
// Request
{
  "name": "Rohan Mehta",
  "email": "rohan@parkviewhotel.in",
  "phone": "+919812345621",
  "password": "••••••••••",
  "role": "owner",
  "business_name": "Park View Hotel",
  "property_type": "hotel",
  "city": "Manali",
  "hcaptcha_token": "...",
  "hp": ""  // honeypot, must be empty
}

// Response — 201 Created
{
  "user_id": "usr_01HW…",
  "status": "pending_verification",
  "next": {
    "email_otp_required": true,
    "phone_otp_required": true,
    "resend_after_seconds": 30
  }
}

// Error — 409 Conflict (email taken)
{ "error": "email_in_use", "message": "That email is already registered." }

Anti-bot & anti-abuse

hCaptcha

Invisible challenge; falls back to interactive on risk score > 0.7. Token verified server-side before user is created.

Honeypot field

Hidden field hp. If filled, return 200 OK with a fake token but skip user creation. Bot wastes its retry budget.

Rate limits

5 sign-ups / IP / hour. 3 OTP sends / phone / hour. Exponential backoff on failed OTP entry.

Disposable email block

Maintain a list (e.g. mailinator.com, tempmail.com) — refuse sign-up with a friendly message.

Phone reuse

One phone can have one owner account. Public-side allows up to 3 to keep family bookings simple.

Risk score on save

If risk score > threshold (new domain + new IP + suspicious UA), flag for manual review before activation.

Common error states & copy

CaseHTTPWhat the user sees
Email already used409"That email is already registered. Sign in or use forgot password."
Phone already used409"This phone number is already on ABc. Use a different number or sign in."
Weak password422"Use at least 10 characters with mixed case and a number."
Disposable email422"Please use your work or personal email — we need to reach you."
Captcha failed400"Verification failed. Please try again."
Rate limited429"Too many sign-ups from this network. Try again in an hour."

Database fields

users
  • iduuid
  • nametext
  • emailtext uniq
  • phonetext
  • password_hashtext
  • roleenum
  • statusenum
  • email_verifiedbool
  • phone_verifiedbool
  • risk_scorefloat
  • created_attimestamp
otp_tokens
  • iduuid
  • user_id→ users
  • channelemail | sms
  • code_hashtext
  • attemptsint
  • expires_attimestamp
  • consumed_attimestamp
Where this leads

After this page, owners proceed to Verification & Anti-Fraud (KYC). The OTP step lives in this page; the KYC document upload lives in the next.