TSD - User registration
Document Control
| Version | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2025-08-19 | BA Team | Initial Version |
| 1.1. | 2025-09-03 | BA Team | Added Admin User Creation |
Table of Contents
- Overview
- Technology Stack
- System Architecture Overview
- Functional Overview
- 4.1 Self-Registration Flow
- 4.1.1 Mobile Number Input
- 4.1.2 OTP Delivery Method Selection
- 4.1.3 OTP Generation and Management
- 4.1.4 OTP Verification Process
- 4.1.5 Profile Completion
- 4.1.6 Account Creation
- 4.2 Admin-Assisted Registration Flow
- 4.2.1 Admin Mobile Entry & OTP Delivery
- 4.2.2 Admin OTP Verification
- 4.2.3 Admin Profile Completion
- 4.2.4 Admin Account Creation
- 4.1 Self-Registration Flow
- User Interface
- 5.1 Self-Registration Screens
- 5.1.1 Mobile Number Entry
- 5.1.2 OTP Verification Screen
- 5.1.3 Profile Completion Screen
- 5.2 Admin Registration Modal
- 5.2.1 Modal Design Approach
- 5.2.2 Mobile Number Entry
- 5.2.3 OTP Verification
- 5.2.4 Profile Completion
- 5.1 Self-Registration Screens
- Technical Specification
- 6.1 Frontend Implementation
- 6.1.1 Mobile Number Input Screen
- 6.1.2 OTP Verification Screen
- 6.1.3 Complete Registration Screen
- 6.2 Backend Implementation
- 6.2.1 Database Schema
- 6.2.2 GraphQL Schema
- 6.1 Frontend Implementation
- Integration Requirements
- Authentication
- Security Considerations
- Error Handling
- Performance Considerations
- Testing Strategy
- 12.1 Unit Testing
- 12.2 Integration Testing
- 12.3 User Acceptance Testing
- Monitoring and Analytics
- 13.1 Key Metrics
- 13.2 Alerting
- 13.3 Logging
- Deployment Considerations
- 14.1 Environment Variables
- 14.2 Feature Flags
- 14.3 Rollback Strategy
- Future Enhancements
1. Overview
This document outlines the functional and technical specifications for the user registration process in the OX Agry Platform. The system supports two registration workflows: self-registration for users with digital access, and admin-assisted registration for users visiting offices in person. Both processes use phone number verification via OTP and integrate with JWT-based authentication.
1.1 Purpose
To provide a secure, user-friendly registration process that verifies user identity and integrates seamlessly with the application's technology stack.
1.2 Scope
Self-Registration:
- User registration via phone number
- OTP verification via SMS or WhatsApp
- Get minimum user details (name) for registration
- Profile completion with Terms & Privacy Policy acceptance
- JWT-based authentication post-registration
Admin-Assisted Registration:
- In-office registration assistance for visiting users
- Duplicate user checking and existing user assistance
- Admin-supervised OTP verification with privacy protection
- Consent confirmation for Terms & Privacy Policy
2. Technology Stack
- Frontend: React, Tanstack Router, Tanstack Form, Apollo Client
- Backend: NestJS, GraphQL, Prisma ORM
- Database: PostgreSQL
- SMS Gateway: Third-party SMS service
- Authentication: JWT Tokens
3. System Architecture Overview
3.1 Component Interaction Flow
Web App (Tanstack Router) → GraphQL API (NestJS) → Database (PostgreSQL)
↓
SMS Gateway Service
3.2 High-Level Process Flow
Self-Registration:
- User enters phone number with country code (dial code, e.g., +91)
- System validates input and checks for existing users
- OTP is generated and sent via SMS/WhatsApp
- User enters OTP for verification
- System validates OTP
- System request User name for new users
- User needs to agree Terms and Privacy Policy
- Creates user account
- JWT tokens are issued for authenticated session
Admin-Assisted Registration:
- Admin checks for existing user by mobile number
- If new user, admin initiates OTP process
- OTP sent to users's device via selected method
- User provides OTP to admin for verification
- User provides Name to admin for new users
- Admin completes profile with verbal consent confirmation
- Account created with admin audit trail
4. Functional Overview
4.1 Self-Registration Flow
4.1.1 Mobile Number Input (FR-01)
Required Fields
- Phone Number: Primary identifier (with dial code picker)
- Country Code: Dropdown selection (default +91 for India)
Validation Rules
- Phone number must be valid international format (+1234567890)
- Length 15 digits
- Numeric only (0-9)
- Check if mobile number already exists in system
Form Behaviour
- Real-time validation with error messages
- Loading state during form submission
- Error handling for network failures
4.1.2 OTP Delivery Method Selection (FR-02)
Available Options
- SMS: Traditional text message delivery
- WhatsApp: WhatsApp Business API integration
Selection Logic
- User can toggle between SMS/WhatsApp for Indian numbers
- Fallback to SMS if WhatsApp delivery fails
- For International numbers, user can select only WhatsApp option
4.1.3 OTP Generation and Management
OTP Characteristics
- Length: 6 digits
- Numeric only (0-9)
- Expiration: 15 minutes from generation
- Single-use: Invalidated after successful verification
OTP Storage
- Encrypted storage in database
- Associated with phone number and timestamp
- Automatic cleanup of expired OTPs
Rate Limiting
- Maximum 5 OTP requests per phone number in 30 mins
- 30-second cooldown between consecutive requests
- Progressive delay for repeated failed attempts
4.1.4 OTP Verification Process (FR-03)
Verification Constraints
- Maximum 5 verification attempts per OTP
- Case-sensitive numeric input
- Automatic account lockout after 5 failed attempts for 30 mins
Security Measures:
- Attempt tracking per phone number
- IP-based rate limiting
- Automatic session cleanup
- Failed attempt logging for security monitoring
4.1.5 Profile Completion (FR-04)
Required Fields
- Name: Input Field for name
- Checkbox: For agreeing to Terms and Privacy Policy
- Terms & Privacy policy: Link to Terms of Service and Privacy Policy
- "Complete Registration" button
Validation Rules
- Length: 1-100 characters
- Characters: Letters, spaces, hyphens, apostrophes allowed
- Required: Cannot be empty or whitespace only
- Terms & Privacy Policy: User need to Accept
- "Complete Registration" button: work only when the name field is filled and Terms & Privacy policy is agreed
4.1.6 Account Creation (FR-05)
Post-Verification Actions
- Create user record in database
- Mark phone number as verified
- Generate initial JWT access and refresh tokens
- Send welcome notification
- Redirect to onboarding flow
User Profile Setup
- Set account status to 'active'
- Record registration timestamp and method
- Initialize user preferences with defaults
4.2 Admin-Assisted Registration Flow
4.2.1 Admin Mobile Entry & OTP Delivery (AFR-02)
Required Fields:
- Dial code selection (dropdown with country codes)
- Mobile number (10-digit format for primary Indian market)
- Delivery method (SMS/WhatsApp radio buttons)
Validation Rules:
- E.164 international format validation
- Real-time format checking with visual feedback
- Check if mobile number already exists in system
- Admin role permission verification
OTP Generation:
- Same security characteristics as self-registration
- Admin-initiated but user-received
- Delivery confirmation tracking
- Fallback method handling
4.2.2 Admin OTP Verification (AFR-03)
Security Constraints:
- Maximum 5 verification attempts per OTP
- 15-second cooldown between resend requests
- User enters OTP directly (privacy protection)
Privacy Protection:
- User provides OTP verbally or enters directly
- No OTP display in admin interface
- Screen privacy measures in office environment
- Audit logging without sensitive data exposure
4.2.3 Admin Profile Completion (AFR-04)
Required Information:
- Full name (minimum 2 characters)
- Verbal consent confirmation
Consent Management:
- Admin checkbox: "I confirm that the user agrees to the Privacy Policy & Terms of Use"
- Represents in-person verbal agreement
- Compliance with data protection regulations
- Audit trail for consent confirmation
4.2.4 Admin Account Creation (AFR-05)
Post-Verification Actions
- Create user record in database
- Mark phone number as verified
- Generate initial JWT access and refresh tokens
- Send welcome notification
- Redirect to onboarding flow
User Profile Setup
- Set account status to 'active'
- Record registration timestamp and method
- Initialize user preferences with defaults
- Comprehensive audit log entry
- Admin daily creation limit tracking
5. User Interface
5.1 Self-Registration Screens
5.1.1 Mobile Number Entry
- Input field for phone number with country code picker
- Buttons for choosing delivery method "SMS" or "WhatsApp"
- "Send OTP" button
5.1.2 OTP Verification Screen
- 6-digit input field for OTP
- "Verify OTP" button
- Resend button with countdown timer
- Back button for number correction
5.1.3 Profile Completion Screen
- Input field for name
- Check box to accept Terms and Privacy Policy
- "Complete Registration" button
5.2 Admin Registration Modal
5.2.1 Modal Design Approach
Location: "Add User" button above user list table
5.2.2 Mobile Number Entry
- Country code dropdown (default +91 for India)
- Mobile number input with format validation
- Delivery method buttons
5.2.3 OTP Verification
- 6-digit input field for OTP
- "Verify OTP" button
- Resend button with countdown timer
- Back button for number correction
5.2.4 Profile Completion
- Name input field with validation
- Consent confirmation checkbox
- Terms & Privacy Policy reference
- "Complete Registration" button
6. Technical Specification
6.1 Frontend Implementation
6.1.1 Mobile Number Input Screen (FR-01)
Form Fields
| Field | Type | Validation |
|---|---|---|
| countryCode | Dropdown | Required (e.g., +91, +1) |
| phoneNumber | Text Input | Required, numeric only |
| Delivery Method ("SMS", "WhatsApp") | Radio group | Conditionally required & enabled |
| Send OTP | Button | Call GraphQL sendOtp mutation |
Validation Rules
- Combine countryCode + phoneNumber and validate as E.164
- Length: 15 digits
- OTP method:
- If +91: allow SMS and WhatsApp
- Else: only allow WhatsApp
UX Behavior Matrix
| Input | Expected Behavior |
|---|---|
| +91 + 9999999999 | Enable both SMS & WhatsApp options |
| +1 + 4155552671 | Only WhatsApp enabled |
| Invalid phone | ❌ Form shows error before submit |
| Select disabled | ❌ Validation blocks submission |
Validation Flow
| Step | Validation | Result |
|---|---|---|
| Phone format | Must match E.164 regex | Error if invalid |
| Dial code check | SMS allowed only for +91 | Disable otherwise |
| Method selection | Must match available options | Error on invalid selection |
| On submit | Apollo mutation fires | Navigate to OTP screen on success |
Background Process Flow
- Validate mobile number format (dial code, numbers only)
- Check for existing UserRegistration with same mobile number
- Validate send attempts
- Create/Update UserRegistration record
- Set stage: MOBILE_NUMBER_ENTERED
- Increment otpSendAttempts
- Set lastOtpSentAt timestamp
- Collect silently during registration steps.
- Generate 6-digit numeric OTP
- Send OTP via SMS/WhatsApp
- Update record with OTP details
- Set stage: OTP_SENT
- Set lastOtpExpiresAt (now + 15 minutes)
- Set otpDeliveryMethod: SMS/WhatsApp
- Set otpDeliveryStatus: SENT/PENDING
- Return success response with expiry time
6.1.2 OTP Verification Screen (FR-02 and FR-03)
Form Fields
| Field Name | Type | Description |
|---|---|---|
| otp | Text input | 6-digit numeric code entered by the user |
| method | Hidden/Input | The delivery method used for the OTP |
Validation Rules
-
otp
- Type: text, numeric
- Validation:
- Required
- Must be 6 numeric digits
- Regex:
/^\d{6}$/
-
phoneNumber
- Type: Typically passed as:
- A query parameter:
/verify-otp?phone=+9198xxxxxx - Or hidden field in the form
- A query parameter:
- Validation: Must be present and valid E.164 number
- Type: Typically passed as:
-
method
- Type: Hidden input or stored in component state
- Values: 'SMS' or 'WHATSAPP'
- Used for: Resending OTP through the same medium
Behavior Summary
| State | UI |
|---|---|
| 0-30 seconds after load | ✅ Verify button, ⏳ Resend countdown |
| After 30 seconds | ✅ Verify button, ✅ Resend OTP enabled |
Test Scenarios
| Input / Action | Expected Result |
|---|---|
| Empty OTP | ❌ Show "OTP is required" |
| abc123 | ❌ Show "must be digits" |
| 12345 | ❌ Show "must be 6 digits" |
| 123456 + valid phone | ✅ Submit to server |
| Resend OTP before 30s | ⛔ Button hidden |
| Resend OTP after 30s | ✅ Button visible and working |
Security Notes
- JWT token stored in localStorage after successful verification
- Consider using SecureStore or httpOnly cookies for web/mobile
Backend Process Flow
- Find UserRegistration by dialCode + mobileNumber
- Validate current stage is OTP_SENT
- Check OTP expiry (lastOtpExpiresAt > now)
- Validate verification attempts (max 5 per OTP session)
- Compare provided OTP with stored value
- Update verification tracking
- Increment otpVerifyAttempts
- Set lastOtpVerifiedAt (if successful)
- Update stage to OTP_VERIFIED (if successful)
- Return verification status
6.1.3 Complete Registration Screen (FR-04)
Form Fields
| Field | Type | Validation |
|---|---|---|
| name | Text input | Minimum 2 characters |
| termsAccepted | Checkbox | Must be true to proceed |
| Complete Registration | Button | Call GraphQL CompleteRegistration mutation |
UX Behavior Summary
| Field | Validation | Feedback |
|---|---|---|
| name | Required, ≥ 2 characters | Inline error shown if invalid |
| termsAccepted | Required (true) | Error if unchecked on submit |
| Button enabled | Only when both fields are valid | Disabled otherwise |
Backend Process Flow
- Find UserRegistration
- Query by
dialCode+mobileNumber
- Query by
- Validate Current Stage
- Ensure stage is
OTP_VERIFIED
- Ensure stage is
- Validate Name Format
- Length: 1–100 characters
- Required: Yes
- Validate Terms and Policy acceptance
- Required: Yes
- Begin Database Transaction
- Create User Record
- Generate
publicId(CUID) - Set
name - set
userstatus:ACTIVE - set
kycstatus:NOT_STARTED - set
kyclevel:BASIC - Set timestamps
- Generate
- Create UserContact Record
- Link to
UserviauserId - Set
contactType:MOBILE - Set
isPrimary:true - Set
isVerified:true - Copy
dialCodeandmobileNumber
- Link to
- Update UserRegistration
- Link to
UserviauserId - Set
stage:USER_CREATED - Set
enteredName
- Link to
6.2 Backend Implementation
6.2.1 Database Schema
CREATE TABLE user_registrations (
id BIGSERIAL PRIMARY KEY,
stage VARCHAR(30) NOT NULL DEFAULT 'MOBILE_NUMBER_ENTERED',
user_id BIGINT UNIQUE REFERENCES users(id),
dial_code VARCHAR(5) NOT NULL,
mobile_number VARCHAR(15) NOT NULL,
entered_name VARCHAR(100),
registration_type VARCHAR(20) DEFAULT 'SELF' CHECK (registration_type IN ('SELF', 'ADMIN_ASSISTED')),
created_by_admin_id BIGINT REFERENCES users(id),
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
UNIQUE(dial_code, mobile_number)
);
model OtpAttempt {
id BigInt @id @default(autoincrement())
dialCode String @db.VarChar(5)
mobileNumber String @db.VarChar(15)
otpHash String @db.VarChar(255)
purpose OtpPurpose
deliveryMethod DeliveryMethod
deliveryStatus DeliveryStatus @default(PENDING)
deliveryProvider DeliveryProvider
expiresAt DateTime @db.Timestamptz(3)
isUsed Boolean @default(false)
usedAt DateTime? @db.Timestamptz(3)
verificationAttempts Int @default(0) @db.SmallInt
createdAt DateTime @default(now()) @db.Timestamptz(3)
updatedAt DateTime @updatedAt @db.Timestamptz(3)
userId BigInt?
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
@@map("otp_attempts")
@@index([dialCode, mobileNumber, purpose], name: "idx_phone_otp_attempts")
@@index([userId, purpose, isUsed], name: "idx_user_otp_attempts")
@@index([expiresAt, isUsed], name: "idx_otp_cleanup")
}
enum OtpPurpose {
REGISTRATION
LOGIN
}
enum DeliveryMethod {
SMS
WHATSAPP
}
enum DeliveryProvider {
MSG91
WHATSAPP
}
enum DeliveryStatus {
PENDING
SENT
DELIVERED
FAILED
}
-- Users table enhancements
ALTER TABLE users ADD COLUMN IF NOT EXISTS created_by_admin_id BIGINT REFERENCES users(id);
ALTER TABLE users ADD COLUMN IF NOT EXISTS registration_type VARCHAR(20) DEFAULT 'SELF';
ALTER TABLE users ADD COLUMN IF NOT EXISTS consent_confirmed_at TIMESTAMPTZ;
6.2.2 GraphQL Schema
Types
enum OtpPurpose {
REGISTRATION
LOGIN
}
enum DeliveryMethod {
SMS
WHATSAPP
}
enum DeliveryStatus {
PENDING
SENT
DELIVERED
FAILED
}
type OtpAttempt {
id: ID!
dialCode: String!
mobileNumber: String!
deliveryStatus: DeliveryStatus!
expiresAt: String!
verificationAttempts: Int!
createdAt: String!
}
type User {
id: ID!
mobileNumber: String!
name: String!
devices: [DeviceInfo!]!
}
type AuthResponse {
token: String!
user: User!
}
type Mutation {
sendOtp(dialCode: String!, mobileNumber: String!, deliveryMethod: DeliveryMethod!): OtpAttempt!
verifyOtp(otp: String!, otpAttemptId: ID!): OtpAttempt!
completeRegistration(otpAttemptId: ID!, name: String!): AuthResponse!
}
7. Integration Requirements
- SMS/WhatsApp Gateway:
- Integrate with Msg91/Twilio for SMS; WhatsApp API for WhatsApp
- Update deliveryStatus via provider callbacks
- GraphQL:
- Expose mutations for OTP sending, verification, and registration completion
- JWT:
- Validate tokens on protected resolvers using NestJS guards
8. Authentication
JWT Tokens:
- Issued after successful OTP verification
- Signed with a secret key, stored in environment variables
- Expiry: Configurable (e.g., 7 days)
Storage: Frontend stores JWT in secure storage (e.g., AsyncStorage for React Native) Authorization: Include JWT in Authorization: Bearer "Token" header for protected API calls
9. Security Considerations
OTP Security
- Generate cryptographically secure OTPs
- Limit OTP attempts (e.g., 5 failed attempts lock out the phone number for 30 minutes)
- Encrypt sensitive data (e.g., phone numbers, OTP) in transit and at rest
Rate Limiting
- Implement rate limiting on OTP requests to prevent abuse
- Use NestJS rate-limiting middleware or SMS gateway limits
Data Validation
- Validate phone numbers on both frontend (Tanstack Form) and backend
- Sanitize inputs to prevent injection attacks
Communication Security
- HTTPS encryption for all API communications
- SMS delivery confirmation tracking
- WhatsApp Business API with end-to-end encryption
- Message template compliance with carrier regulations
JWT Security
- Use strong secret keys and refresh tokens for long-lived sessions
- Implement token revocation mechanisms
10. Error Handling
Frontend:
- Display user-friendly error messages (e.g., "Invalid phone number" or "OTP expired")
- Handle network errors with retry logic in Apollo Client
Backend:
- Return descriptive GraphQL errors (e.g., INVALID_OTP, EXPIRED_OTP)
- Log errors for debugging without exposing sensitive information
11. Performance Considerations
Database:
- Index phone column in User and Otp tables for faster lookups
- Periodically clean up expired OTPs to optimize storage
SMS Gateway:
- Cache API responses where applicable to reduce costs
- Use bulk SMS APIs for high-volume scenarios
GraphQL:
- Optimize queries to avoid over-fetching (e.g., select only required fields)
- Use DataLoader for batching database queries
12. Testing Strategy
12.1 Unit Testing
- Form validation logic coverage > 90%
- OTP generation and verification functions
- Rate limiting algorithm validation
- Password hashing and encryption utilities
12.2 Integration Testing
- GraphQL mutation end-to-end testing
- Database transaction rollback scenarios
- SMS gateway mock service integration
- JWT token generation and validation
12.3 User Acceptance Testing
- Registration completion rates
- OTP delivery success rates across carriers
- Cross-device compatibility testing
- Accessibility compliance validation
13. Monitoring and Analytics
13.1 Key Metrics
- Registration completion rate
- OTP delivery success rate by method
- Time to complete registration flow
- Failed verification attempt patterns
13.2 Alerting
- High failure rates for OTP delivery
- Unusual spikes in registration attempts
- Database connection issues
- SMS gateway service degradation
13.3 Logging
- Structured logging for all registration events
- PII-safe error logging with correlation IDs
- Audit trail for successful account creations
- Performance metrics for optimization insights
14. Deployment Considerations
14.1 Environment Variables
- SMS gateway API credentials
- WhatsApp Business API configuration
- JWT signing keys and expiration settings
- Database connection strings and pool settings
14.2 Feature Flags
- OTP delivery method availability toggles
- Rate limiting thresholds per environment
- A/B testing for form layout variations
- Emergency registration disable switch
14.3 Rollback Strategy
- Database migration rollback procedures
- API version compatibility maintenance
- SMS template reversion capabilities
- Client-side feature flag coordination
15. Future Enhancements
NA