Onboarding Analytics Admin
Base URL: https://api.fursahub.com/api/v1
Short Description: AdminOnboarding flow endpoints for analyzingFursa userHub. demographicsGuides new users through phone verification, preference selection, and onboardingprofile data.completion. ProvidesAll summarycontent statistics,is detailedtranslated breakdownsbased byon preferenceuser's page,preferredLanguage and user segmentation capabilities. Data collected here powers recommendations and business insights.setting.
Hints:
AllOnboardingendpointsstepsrequiremustADMINbeorcompletedSUPER_ADMINinroleorder - skipping ahead returns 412 PRECONDITION_FAILEDDemographicsPhonedataverificationcomesusesfromOTPusersentresponsesviatoSMS (supports TZ, KE, UG, RW, BI country codes)- Preference pages are dynamic - admin can add/remove/reorder without code changes
- User's preferredLanguage determines translation of all onboarding
preference pagescontent UseEmailtheseverificationendpointsisforoptional/skippableadminbydashboards,defaultreports,(Firebaseandhandlesrecommendationactualengine inputInternal service methods available for social media and recommendation featuresverification)
AnalyticsComplete DataOnboarding Flow
┌─────────────────────────────────────────────────────────────────────────┐
│ ANALYTICSCOMPLETE DATAONBOARDING FLOW │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ DATAAfter COLLECTIONPOST (During/auth/firebase/authenticate: Onboarding):│
│ └── Check response.data.onboarding.currentStep │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ UserSTEP completes1: preferencePENDING_EMAIL_VERIFICATION pages:(Optional/Skippable) │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ • Firebase handles actual email verification │ │
│ │ • "interests"Check: →GET ["jobs", "funding", "events"]/onboarding/email-verification/status │ │
│ │ • "goals"Skip: →POST ["find_job", "start_business"]/onboarding/email-verification/skip │ │
│ │ • "experience"Or →wait ["student",for "0-2_years"]user to verify email in Firebase │ │
│ │ │• │Auto-transitions │when │Firebase Storedreports in:email user_onboarding_response tableverified │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ DATA ANALYSIS (Admin Dashboard): │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ GETSTEP 2: PENDING_PHONE_VERIFICATION (Required) │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ • POST /onboarding/analytics/summaryauth-phone/request-otp │ │
│ │ └── User enters phone number (+255...) │ │
│ │ └── Backend sends OTP via SMS │ │
│ │ └── Returns token for verification │ │
│ │ • TotalPOST users,/onboarding/auth-phone/verify completion│ rates│
│ │ └── User enters 6-digit OTP │ │
│ │ └── On success: phone saved, transitions to next step │ │
│ │ • Breakdown by status, auth provider, language, theme │ │
│ │ │ │
│ │ GETPOST /onboarding/analytics/demographicsauth-phone/resend-otp │(if │
│ │ • Per-page option counts and percentages │ │
│ │ • "60% of users interested in jobs" │ │
│ │ • "45% want to start a business"needed) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ DATA USAGE (Internal Systems): │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ RecommendationSTEP Engine:3: PENDING_PREFERENCES (Required) │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ • GET /onboarding/pages?current=true │ │
│ │ └── Get current preference page │ │
│ │ • getUserSelections(userId,Loop "interests")through pages: │ │
│ │ └── Display options (translated to user's language) │ │
│ │ └── User selects options │ │
│ │ └── POST /onboarding/pages/{pageId}/response │ │
│ │ └── Or POST /onboarding/pages/{pageId}/skip (if skippable) │ │
│ │ └── Move to next page until all complete │ │
│ │ • getUsersWithSimilarPreferences(userId)Auto-transitions when all pages completed │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ STEP 4: PENDING_PROFILE_COMPLETION (Required) │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ • GET /profile │ │
│ │ └── Get current profile (some data from Firebase) │ │
│ │ • ShowPUT relevant opportunities based on user interests/profile │ │
│ │ └── fullName (required) │ │
│ │ Content└── Personalization:username (required, unique) │ │
│ │ └── bio (required) │ │
│ │ └── gender, link (optional) │ │
│ │ • On save: auto-completes onboarding │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ STEP 5: COMPLETED ✓ │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ • Navigate to home screen │ │
│ │ • User interestedcan innow "funding"access →all Showapp grants first │ │
│ │ • User goal is "learn_skills" → Prioritize courses │ │
│ │ │ │
│ │ User Segmentation: │ │
│ │ • getUsersBySelection("goals", "start_business") │ │
│ │ • Target campaigns to specific user groupsfeatures │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Phone Verification Endpoints
1. GetRequest Summary StatisticsOTP
Purpose: GetSend high-levelOTP onboardingcode statisticsto user's phone number for admin dashboard.verification.
Endpoint: GETPOST {base_url}/onboarding/analytics/summaryauth-phone/request-otp
Access Level: 🔒 Protected (Admin Only)
Authentication: Bearer Token
Prerequisite: orUser ROLE_SUPER_ADMIN)must be at PENDING_PHONE_VERIFICATION step
Request HeadersJSON Sample:
{
"phoneNumber": "+255712345678"
}
Request Body Parameters:
| Type | Required | Description | Validation | |
|---|---|---|---|---|
| phoneNumber | string | Yes | Phone number with country code | E.164 format: +255XXXXXXXXX |
Supported Country Codes:
+255- Tanzania+254- Kenya+256- Uganda+250- Rwanda+257- Burundi
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "OTP sent successfully",
"action_time": "2025-01-05T10:30:45",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"phoneNumber": "+255****678",
"expiresInSeconds": 600,
"resendAvailableIn": 120
}
}
Success Response Fields:
| Field | Description |
|---|---|
| Temporary token for verify/resend endpoints | |
| phoneNumber | Masked phone number for display |
| expiresInSeconds | OTP validity period (10 minutes) |
| resendAvailableIn | Seconds until resend allowed (2 minutes) |
Error Responses:
Wrong Onboarding Step (412):
{
"success": false,
"httpStatus": "PRECONDITION_FAILED",
"message": "Onboarding step required",
"action_time": "2025-01-05T10:30:45",
"data": {
"message": "Complete email verification first",
"currentStep": "PENDING_EMAIL_VERIFICATION",
"requiredStep": "PENDING_EMAIL_VERIFICATION"
}
}
Rate Limit Exceeded (429):
{
"success": false,
"httpStatus": "TOO_MANY_REQUESTS",
"message": "Too many OTP requests. Try again in 10 minutes.",
"action_time": "2025-01-05T10:30:45",
"data": "Too many OTP requests. Try again in 10 minutes."
}
Phone Already Registered (409):
{
"success": false,
"httpStatus": "CONFLICT",
"message": "Phone number already registered",
"action_time": "2025-01-05T10:30:45",
"data": "Phone number already registered"
}
2. Verify OTP
Purpose: Verify OTP code and complete phone verification.
Endpoint: POST {base_url}/onboarding/auth-phone/verify
Access Level: 🔒 Protected
Authentication: Bearer Token
Request JSON Sample:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"otp": "123456"
}
Request Body Parameters:
| Parameter | Type | Required | Description | Validation |
|---|---|---|---|---|
| token | string | Yes | from request-otp response |
Must be valid, non-expired |
| otp | string | Yes | 6-digit OTP code | Exactly 6 digits |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "SummaryPhone retrieved"verified successfully",
"action_time": "2025-01-05T14:00:05T10:35:00",
"data": {
"totalUsers"verified": 5000,true,
"completedOnboarding"phoneNumber": 4200,"+255****678",
"completionRate"onboardingStatus": 84.0,
"totalPagesConfigured": 3,
"byStatus": {
"COMPLETED": 4200,
"PENDING_PHONE_VERIFICATION": 300, "PENDING_PREFERENCES": 350,
"PENDING_PROFILE_COMPLETION": 100,
"PENDING_EMAIL_VERIFICATION": 50
},
"byAuthProvider"nextStep": {
"GOOGLE": 3500,
"APPLE": 800,
"EMAIL": 700
},
"byLanguage": {
"en": 2000,
"sw": 2500,
"fr": 400,
"zh": 100
},
"byTheme": {
"SYSTEM": 3000,
"DARK": 1200,
"LIGHT": 800/api/v1/onboarding/pages"
}
}
Error Responses:
Invalid OTP (403):
{
"success": false,
"httpStatus": "FORBIDDEN",
"message": "Invalid OTP. 2 attempt(s) remaining.",
"action_time": "2025-01-05T10:35:00",
"data": "Invalid OTP. 2 attempt(s) remaining."
}
Expired OTP (403):
{
"success": false,
"httpStatus": "FORBIDDEN",
"message": "OTP has expired. Please request a new one.",
"action_time": "2025-01-05T10:35:00",
"data": "OTP has expired. Please request a new one."
}
Max Attempts Reached (403):
{
"success": false,
"httpStatus": "FORBIDDEN",
"message": "Maximum attempts reached. Please request a new OTP.",
"action_time": "2025-01-05T10:35:00",
"data": "Maximum attempts reached. Please request a new OTP."
}
3. Resend OTP
Purpose: Request a new OTP code using the existing token.
Endpoint: POST {base_url}/onboarding/auth-phone/resend-otp
Access Level: 🔒 Protected
Authentication: Bearer Token
Request JSON Sample:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Success Response Fields: Same as Request OTP endpoint
2.Email Verification Endpoints
4. Get DemographicsEmail Verification Status
Purpose: GetCheck detailedemail breakdownverification ofstatus userand responses per preference page.options.
Endpoint: GET {base_url}/onboarding/analytics/demographicsemail-verification/status
Access Level: 🔒 Protected (Admin Only)
Authentication: Bearer Token
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "DemographicsEmail verification status",
"action_time": "2025-01-05T10:00:00",
"data": {
"verified": false,
"email": "jo***@example.com",
"required": false,
"canSkip": true,
"currentStep": "PENDING_EMAIL_VERIFICATION"
}
}
5. Skip Email Verification
Purpose: Skip email verification step (if allowed by config).
Endpoint: POST {base_url}/onboarding/email-verification/skip
Access Level: 🔒 Protected
Authentication: Bearer Token
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Email verification skipped",
"action_time": "2025-01-05T10:05:00",
"data": {
"verified": false,
"skipped": true,
"nextStep": "PENDING_PHONE_VERIFICATION"
}
}
Preference Pages Endpoints
6. Get Onboarding Progress
Purpose: Get overall onboarding progress with all steps.
Endpoint: GET {base_url}/onboarding/progress
Access Level: 🔒 Protected
Authentication: Bearer Token
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Progress retrieved",
"action_time": "2025-01-05T14:05:05T10:40:00",
"data": {
"totalUsersAnalyzed"percentage": 4200,45.0,
"generatedAt"currentStage": "PENDING_PREFERENCES",
"currentStageLabel": "Complete your preferences",
"steps": [
{
"key": "registration",
"label": "Registration",
"completed": true,
"weight": 15.0,
"skippable": false
},
{
"key": "phone_verification",
"label": "Phone Verification",
"completed": true,
"weight": 15.0,
"skippable": false
},
{
"key": "page_interests",
"label": "Your Interests",
"completed": true,
"weight": 13.33,
"skippable": false
},
{
"key": "page_goals",
"label": "Your Goals",
"completed": false,
"weight": 13.33,
"skippable": true
},
{
"key": "page_experience",
"label": "Your Experience",
"completed": false,
"weight": 13.33,
"skippable": false
},
{
"key": "profile_completion",
"label": "Complete Profile",
"completed": false,
"weight": 15.0,
"skippable": false
}
],
"nextStep": {
"key": "page_goals",
"label": "Your Goals",
"endpoint": "/api/v1/onboarding/pages?page=2",
"skippable": true
}
}
}
7. Get All Pages
Purpose: Get all preference pages with completion status.
Endpoint: GET {base_url}/onboarding/pages
Access Level: 🔒 Protected
Authentication: Bearer Token
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| all | boolean | No | Return all pages (default behavior) |
| page | integer | No | Get specific page by order (1, 2, 3...) |
| category | string | No | Get page by category key |
| current | boolean | No | Get first incomplete page |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "All pages retrieved",
"action_time": "2025-01-05T14:05:05T10:45:00",
"data": {
"totalPages": 3,
"completedPages": 1,
"isOnboardingComplete": false,
"pages": [
{
"pageId"id": "550e8400-e29b-41d4-a716-446655440001",
"pageOrder": 1,
"categoryKey": "interests",
"title": "YourMaslahi Interests"Yako",
"pageOrder"description": "Chagua mambo yanayokuvutia",
"bannerImages": ["https://cdn.fursahub.com/onboarding/interests.jpg"],
"isSkippable": false,
"minSelections": 1,
"totalResponses"maxSelections": 4200,
"skippedCount": 0,
"responseRate": 100.0,5,
"options": [
{ "key": "jobs", "label": "Jobs"Kazi", "count"icon": 2520, "percentage": 60.0briefcase" },
{ "key": "funding", "label": "Funding"Ufadhili", "count"icon": 1890, "percentage": 45.0dollar" },
{ "key": "events", "label": "Events"Matukio", "count"icon": 1260, "percentage": 30.0calendar" },
{ "key": "skills", "label": "Skills Training"Ujuzi", "count"icon": 1680, "percentage": 40.0book" },
{ "key": "networking", "label": "Networking"Mitandao", "count"icon": 840, "percentage": 20.0users" }
],
"isCompleted": true
},
{
"pageId"id": "550e8400-e29b-41d4-a716-446655440002",
"pageOrder": 2,
"categoryKey": "goals",
"title": "YourMalengo Goals"Yako",
"pageOrder"description": 2,"Unataka kufikia nini?",
"totalResponses"isSkippable": 4100,true,
"skippedCount"minSelections": 100,1,
"responseRate"maxSelections": 97.6,3,
"options": [
{ "key": "find_job", "label": "FindKupata a Job"kazi", "count"icon": 2460, "percentage": 60.0search" },
{ "key": "start_business", "label": "StartKuanzisha Business"biashara", "count"icon": 1845, "percentage": 45.0store" },
{ "key": "learn_skills", "label": "LearnKujifunza Skills"ujuzi", "count"icon": 1640, "percentage": 40.0graduation" },
{ "key": "get_funding", "label": "GetKupata Funding"ufadhili", "count"icon": 1230, "percentage": 30.0money" }
]
},
{
"pageId": "550e8400-e29b-41d4-a716-446655440003",
"categoryKey"isCompleted": "experience",
"title": "Your Experience",
"pageOrder": 3,
"totalResponses": 4050,
"skippedCount": 150,
"responseRate": 96.4,
"options": [
{ "key": "student", "label": "Student", "count": 1215, "percentage": 30.0 },
{ "key": "0-2_years", "label": "0-2 Years", "count": 1012, "percentage": 25.0 },
{ "key": "3-5_years", "label": "3-5 Years", "count": 810, "percentage": 20.0 },
{ "key": "5+_years", "label": "5+ Years", "count": 607, "percentage": 15.0 },
{ "key": "business_owner", "label": "Business Owner", "count": 405, "percentage": 10.0 }
]false
}
]
}
}
Success Response Fields:
3.8. Get Current Page Analytics
Purpose: Get detailedthe analyticsfirst for a specificincomplete preference page.
Endpoint: GET {base_url}/onboarding/analytics/page/pages?current=true
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Current page retrieved",
"action_time": "2025-01-05T10:50:00",
"data": {
"page": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"pageOrder": 2,
"categoryKey": "goals",
"title": "Malengo Yako",
"description": "Unataka kufikia nini?",
"isSkippable": true,
"minSelections": 1,
"maxSelections": 3,
"options": [...]
},
"progress": {
"current": 2,
"total": 3,
"nextPage": 3,
"isLast": false,
"isCompleted": false
}
}
}
9. Submit Page Response
Purpose: Save user's selections for a preference page.
Endpoint: POST {base_url}/onboarding/pages/{pageId}/response
Access Level: 🔒 Protected
Authentication: Bearer Token
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| pageId | UUID | Yes | Page identifier |
Request JSON Sample:
{
"selectedOptions": ["find_job", "learn_skills"]
}
Request Body Parameters:
| Parameter | Type | Required | Description | Validation |
|---|---|---|---|---|
| selectedOptions | array | Yes | Array of selected option keys | Must match page's min/max selections |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Response saved",
"action_time": "2025-01-05T10:55:00",
"data": {
"saved": true,
"progress": {
"current": 2,
"total": 3,
"nextPage": 3,
"isLast": false,
"isCompleted": false
}
}
}
Error Responses:
Too Few Selections (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Minimum 1 selection(s) required",
"action_time": "2025-01-05T10:55:00",
"data": "Minimum 1 selection(s) required"
}
Invalid Option (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Invalid option: unknown_key",
"action_time": "2025-01-05T10:55:00",
"data": "Invalid option: unknown_key"
}
10. Skip Page
Purpose: Skip a preference page (only if page is skippable).
Endpoint: POST {base_url}/onboarding/pages/{pageId}/skip
Access Level: 🔒 Protected
Authentication: Bearer Token
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Page skipped",
"action_time": "2025-01-05T11:00:00",
"data": {
"saved": true,
"progress": {
"current": 2,
"total": 3,
"nextPage": 3,
"isLast": false,
"isCompleted": false
}
}
}
Error Response (Page Not Skippable):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "This page cannot be skipped",
"action_time": "2025-01-05T11:00:00",
"data": "This page cannot be skipped"
}
Language Preference Endpoint
11. Set Language Preference
Purpose: Update user's language preference (can be called anytime during onboarding).
Endpoint: POST {base_url}/onboarding/language-preference
Access Level: 🔒 Protected
Authentication: Bearer Token
Request JSON Sample:
{
"code": "sw"
}
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Language preference updated",
"action_time": "2025-01-05T11:05:00",
"data": {
"code": "sw",
"name": "Swahili",
"nativeName": "Kiswahili"
}
}
Admin: Manage Onboarding Pages
These endpoints allow admins to create, edit, reorder, and manage onboarding preference pages without code changes.
12. Get All Pages (Admin)
Purpose: Get all onboarding pages with full details for admin management.
Endpoint: GET {base_url}/onboarding/pages/manage
Access Level: 🔒 Protected (Admin/Moderator)
Authentication: Bearer Token (ROLE_ADMIN, ROLE_SUPER_ADMIN, ROLE_MODERATOR)
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Pages retrieved",
"action_time": "2025-01-05T12:00:00",
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"categoryKey": "interests",
"pageOrder": 1,
"isActive": true,
"isSkippable": false,
"minSelections": 1,
"maxSelections": 5,
"bannerImages": ["https://cdn.fursahub.com/onboarding/interests.jpg"],
"translations": {
"en": {
"title": "Your Interests",
"description": "Select what interests you"
},
"sw": {
"title": "Maslahi Yako",
"description": "Chagua mambo yanayokuvutia"
}
},
"options": [
{
"key": "jobs",
"icon": "briefcase",
"translations": {
"en": "Jobs",
"sw": "Kazi"
}
},
{
"key": "funding",
"icon": "dollar",
"translations": {
"en": "Funding",
"sw": "Ufadhili"
}
}
],
"createdAt": "2025-01-01T00:00:00",
"updatedAt": "2025-01-05T10:00:00"
}
]
}
13. Get Page by ID (Admin)
Purpose: Get single page details for editing.
Endpoint: GET {base_url}/onboarding/pages/manage/{pageId}
Access Level: 🔒 Protected (AdminAdmin/Moderator)
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| pageId | UUID | Yes | Page identifier |
Success Response: Same structure as single item in Get All Pages
14. Create Page
Purpose: Create a new onboarding preference page.
Endpoint: POST {base_url}/onboarding/pages/manage
Access Level: 🔒 Protected (Admin/Moderator)
Authentication: Bearer Token
Request JSON Sample:
{
"categoryKey": "location",
"pageOrder": 4,
"isActive": true,
"isSkippable": true,
"minSelections": 1,
"maxSelections": 1,
"bannerImages": ["https://cdn.fursahub.com/onboarding/location.jpg"],
"translations": {
"en": {
"title": "Your Location",
"description": "Where are you based?"
},
"sw": {
"title": "Mahali Ulipo",
"description": "Unaishi wapi?"
}
},
"options": [
{
"key": "dar_es_salaam",
"icon": "map-pin",
"translations": {
"en": "Dar es Salaam",
"sw": "Dar es Salaam"
}
},
{
"key": "arusha",
"icon": "map-pin",
"translations": {
"en": "Arusha",
"sw": "Arusha"
}
},
{
"key": "mwanza",
"icon": "map-pin",
"translations": {
"en": "Mwanza",
"sw": "Mwanza"
}
},
{
"key": "other",
"icon": "map",
"translations": {
"en": "Other",
"sw": "Nyingine"
}
}
]
}
Request Body Parameters:
| Parameter | Type | Required | Description | Validation |
|---|---|---|---|---|
| categoryKey | string | Yes | Unique category identifier | Lowercase, no spaces |
| pageOrder | integer | Yes | Display order (1, 2, 3...) | Min: 1 |
| isActive | boolean | No | Page is active | Default: true |
| isSkippable | boolean | No | User can skip this page | Default: false |
| minSelections | integer | No | Minimum options to select | Default: 1 |
| maxSelections | integer | No | Maximum options to select | Default: 10 |
| bannerImages | array | No | Banner image URLs | Array of URLs |
| translations | object | Yes | Title/description per language | Must include "en" |
| translations.{lang}.title | string | Yes | Page title | Max 100 chars |
| translations.{lang}.description | string | No | Page description | Max 500 chars |
| options | array | Yes | Selectable options | Min 2 options |
| options[].key | string | Yes | Unique option key | Lowercase, no spaces |
| options[].icon | string | No | Icon name | From icon library |
| options[].translations | object | Yes | Label per language | Must include "en" |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "CREATED",
"message": "Page created",
"action_time": "2025-01-05T12:05:00",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440004",
"categoryKey": "location",
"pageOrder": 4,
"isActive": true,
...
}
}
Error Responses:
Duplicate Category Key (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Category key already exists: interests",
"action_time": "2025-01-05T12:05:00",
"data": "Category key already exists: interests"
}
15. Update Page
Purpose: Update an existing onboarding page.
Endpoint: PUT {base_url}/onboarding/pages/manage/{pageId}
Access Level: 🔒 Protected (Admin/Moderator)
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| pageId | UUID | Yes | Page identifier |
Request JSON Sample: Same as Create Page
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Page updated",
"action_time": "2025-01-05T12:10:00",
"data": { ... }
}
16. Delete Page
Purpose: Delete an onboarding page (soft delete recommended - use deactivate instead).
Endpoint: DELETE {base_url}/onboarding/pages/manage/{pageId}
Access Level: 🔒 Protected (Admin/Moderator)
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| pageId | UUID | Yes | Page identifier |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Page analytics retrieved"deleted",
"action_time": "2025-01-05T14:10:05T12:15:00",
"data": {
"pageId": "550e8400-e29b-41d4-a716-446655440001",
"categoryKey": "interests",
"title": "Your Interests",
"pageOrder": 1,
"totalResponses": 4200,
"skippedCount": 0,
"responseRate": 100.0,
"options": [
{ "key": "jobs", "label": "Jobs", "count": 2520, "percentage": 60.0 },
{ "key": "funding", "label": "Funding", "count": 1890, "percentage": 45.0 }
]
}null
}
4.17. GetActivate Page Analytics by Category
Purpose: Get analytics forActivate a pagedeactivated using category key instead of UUID.page.
Endpoint: GETPATCH {base_url}/onboarding/analytics/category/pages/manage/{categoryKey}pageId}/activate
Access Level: 🔒 Protected (Admin Only)Admin/Moderator)
PathSuccess Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Page activated",
"action_time": "2025-01-05T12:20:00",
"data": null
}
18. Deactivate Page
Purpose: Deactivate a page (hides from users without deleting).
Endpoint: PATCH {base_url}/onboarding/pages/manage/{pageId}/deactivate
Access Level: 🔒 Protected (Admin/Moderator)
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Page deactivated",
"action_time": "2025-01-05T12:25:00",
"data": null
}
19. Reorder Pages
Purpose: Change the display order of all pages at once.
Endpoint: PATCH {base_url}/onboarding/pages/manage/reorder
Access Level: 🔒 Protected (Admin/Moderator)
Request JSON Sample:
{
"pageIds": [
"550e8400-e29b-41d4-a716-446655440002",
"550e8400-e29b-41d4-a716-446655440001",
"550e8400-e29b-41d4-a716-446655440003",
"550e8400-e29b-41d4-a716-446655440004"
]
}
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
Success Response: Same as Get Page Analytics
5. Get User Demographics
Purpose: Get all preference selections for a specific user.
Endpoint: GET {base_url}/onboarding/analytics/user/{userId}
Access Level: 🔒 Protected (Admin Only)
Path Parameters:
| Yes | Must include all active page IDs |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "UserPages demographics retrieved"reordered",
"action_time": "2025-01-05T14:15:05T12:30:00",
"data": {
"userId": "550e8400-e29b-41d4-a716-446655440000",
"preferences": {
"interests": ["jobs", "funding", "skills"],
"goals": ["find_job", "learn_skills"],
"experience": ["3-5_years"]
}
}null
}
6. Get Users by Selection
Purpose: Find all users who selected a specific option in a category.
Endpoint: GET {base_url}/onboarding/analytics/users/by-selection
Access Level: 🔒 Protected (Admin Only)
QueryImplementation Parameters:
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Users retrieved",
"action_time": "2025-01-05T14:20:00",
"data": {
"categoryKey": "interests",
"optionKey": "jobs",
"count": 2520,
"userIds": [
"550e8400-e29b-41d4-a716-446655440000",
"550e8400-e29b-41d4-a716-446655440001",
"550e8400-e29b-41d4-a716-446655440002"
]
}
}
7. Get Most Popular Options
Purpose: Get top selected options for a category.
Endpoint: GET {base_url}/onboarding/analytics/popular-options/{categoryKey}
Access Level: 🔒 Protected (Admin Only)
Path Parameters:
Query Parameters:
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Popular options retrieved",
"action_time": "2025-01-05T14:25:00",
"data": {
"categoryKey": "interests",
"options": ["jobs", "funding", "skills", "events", "networking"]
}
}
8. Get Similar Users
Purpose: Find users with similar preferences (for recommendation testing).
Endpoint: GET {base_url}/onboarding/analytics/user/{userId}/similar
Access Level: 🔒 Protected (Admin Only)
Path Parameters:
Query Parameters:
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Similar users retrieved",
"action_time": "2025-01-05T14:30:00",
"data": {
"userId": "550e8400-e29b-41d4-a716-446655440000",
"similarUsers": [
"550e8400-e29b-41d4-a716-446655440010",
"550e8400-e29b-41d4-a716-446655440011",
"550e8400-e29b-41d4-a716-446655440012"
],
"count": 3
}
}
Internal Service Methods
These methods are available in OnboardingAnalyticsService for use by other backend services (recommendation engine, social media features, etc.):
// Get user's selections for a specific category
List<String> getUserSelections(UUID userId, String categoryKey);
// Example: getUserSelections(userId, "interests") → ["jobs", "funding"]
// Get complete user demographics
UserDemographicDto getUserDemographics(UUID userId);
// Returns all preferences across all categories
// Find users who selected specific option
List<UUID> getUsersBySelection(String categoryKey, String optionKey);
// Example: getUsersBySelection("goals", "start_business") → [userId1, userId2, ...]
// Find users who selected any of multiple options
List<UUID> getUsersBySelections(String categoryKey, List<String> optionKeys);
// Check if user selected a specific option
boolean hasUserSelected(UUID userId, String categoryKey, String optionKey);
// Example: hasUserSelected(userId, "interests", "jobs") → true
// Find users with similar preferences (for recommendations)
List<UUID> getUsersWithSimilarPreferences(UUID userId, int limit);
// Get most popular options in a category
List<String> getMostPopularOptions(String categoryKey, int limit);
Admin Dashboard UsageGuide
SummaryPage CardsList View
GET /onboarding/analytics/summarypages/manage
├── CardDisplay 1:table Totalwith: UsersOrder, Category, Title (totalUsers)en), Status, Actions
├── CardActions: 2:Edit, CompletionActivate/Deactivate, Rate (completionRate%)Delete
├── CardDrag-and-drop 3:for Activereorder Today→ (calculatePATCH from other data)/onboarding/pages/manage/reorder
└── Card"Add 4:New PendingPage" Verification (byStatus.PENDING_*)button
PieCreate/Edit ChartsPage Form
Fields:
├── Category Key (text, required, unique)
├── Page Order (number)
├── Is Skippable (checkbox)
├── Min/Max Selections (numbers)
├── Banner Images (file upload → Files API)
├── Translations (tabs for each language)
│ ├── Title (text)
│ └── Description (textarea)
└── Options (repeater)
├── Key (text, unique within page)
├── Icon (icon picker)
└── Translations (text per language)
On Save:
├── New: POST /onboarding/pages/manage
└── Edit: PUT /onboarding/pages/manage/{pageId}
Quick Actions
Activate: PATCH /onboarding/pages/manage/{pageId}/activate
Deactivate: PATCH /onboarding/pages/manage/{pageId}/deactivate
Delete: DELETE /onboarding/pages/manage/{pageId} (with confirmation)
Frontend Implementation Guide
Phone Verification Screen
1. Show phone input with country code selector
2. On submit: POST /onboarding/auth-phone/request-otp
3. Save token from response
4. Navigate to OTP input screen
5. Show countdown for resendAvailableIn
6. On OTP submit: POST /onboarding/auth-phone/verify
7. On success: Navigate based on nextStep
Preference Pages Loop
1. GET /onboarding/pages?current=true
2. If page is null → All done, navigate to profile
3. Display page with:
├── Title, description (translated)
├── Banner image
├── Options as selectable chips/cards
└── Skip button (if isSkippable)
4. On submit: POST /onboarding/pages/{pageId}/response
5. Check progress.isCompleted
├── true → Navigate to profile completion
└── false → GET /onboarding/pages?current=true (loop)
Progress Indicator
GET /onboarding/analytics/summaryprogress
├── ChartUse 1:percentage Usersfor byprogress Auth Provider (byAuthProvider)
├── Chart 2: Users by Language (byLanguage)
└── Chart 3: Users by Theme (byTheme)
Demographics Bar Charts
GET /onboarding/analytics/demographics
For each page:
├── Chart: Option distributionbar
├── Show percentagesteps barsas └dots/icons
├── Highlight topcurrent selections
User Lookup
GET /onboarding/analytics/user/{userId}
├── Show all user preferences
├── Link to full profilestep
└── Show similarcompleted userssteps with checkmarks