Kulcare Docs
DeveloperAuthentication Documentation04 featuresOnboarding

Backend Onboarding API Documentation

Overview

This document details the backend implementation of the user onboarding system, which collects essential information from doctors, clinic owners, and allied health professionals during the signup process. The onboarding data is stored temporarily in the user_flags table until the Kulcare team creates actual profiles.

API Endpoints

GET /user_onboarding

Retrieves the current user's onboarding progress and data.

Authentication: Required (Bearer token)

Purpose:

  • Loads existing onboarding data when user refreshes the page
  • Allows users to continue from where they left off
  • Synchronizes frontend state with backend storage

Data Source:

  • Retrieves data from user_flags.onboarding_data JSONB field
  • Returns structured onboarding progress including completed steps and step-specific data

POST /user_onboarding

Saves onboarding data for the current user.

Authentication: Required (Bearer token)

Purpose:

  • Saves step completion data after each onboarding step
  • Updates user's onboarding progress in real-time
  • Stores all collected information in JSONB format

Data Storage:

  • All data is stored in user_flags.onboarding_data as JSONB
  • Preserves complete onboarding state for later retrieval
  • Enables seamless continuation after page refresh or re-login

Processing Logic:

  1. Validates incoming data structure
  2. Updates or creates user_flags record for the user
  3. Merges new step data with existing onboarding data
  4. Marks step as completed in the completed_steps array
  5. Updates engagement metrics (achievements, alumni count, etc.)

Onboarding Flow Overview

The onboarding flow consists of 10 steps:

  1. Welcome Step - User type selection (doctor, clinic_owner, allied_health)
  2. Value Discovery - Platform value propositions
  3. Basic Info - Personal information (name, email, phone, location, country)
  4. Professional Details - Registration details, specialization, experience, fees
  5. Qualifications - Education, work experience, certifications, memberships
  6. Quick Connect Preview - Profile preview and alumni discovery
  7. Practice Info - Practice settings, consultation types, languages, special interests
  8. Document Upload - Professional documents (licenses, certificates, etc.)
  9. Review & Consent - Terms acceptance and data review
  10. Celebration - Completion with next steps

Elasticsearch Integration

The onboarding system relies on Elasticsearch indices to provide dynamic, searchable data for various dropdowns and selections. All indices follow a naming pattern: {table_name}_{environment} (e.g., basic_degrees_staging).

1. basic_degrees

Purpose: Provides degree options for the Qualifications step

Index Structure:

{
  id: integer,
  name: string,
  abbreviation: string,
  description: string,
  category: string           # 'medical' or 'allied_health'
}

Filtering:

  • Category filter: Returns degrees matching user type
    • medical for doctors
    • allied_health for allied health professionals

Sorting: Alphabetical by name

Usage: Step 5 (Qualifications) - Degree selection dropdown


2. basic_universities

Purpose: Provides institution/university options for education entries

Index Structure:

{
  id: integer,
  name: string,
  city: string,
  state: string,
  country: string,
  alpha_2_code: string       # Country code: 'IN', 'US', 'AE', etc.
}

Filtering:

  • Country filter: Uses alpha_2_code to match selected country from Step 3
  • Provides autocomplete search functionality

Sorting: Alphabetical by name

Usage: Step 5 (Qualifications) - Institution selection with autocomplete


3. default_medical_councils

Purpose: Provides medical council/registration board options

Index Structure:

{
  id: integer,
  name: string,
  alpha_2_code: string,
  council_type: array        # ['medical', 'allied_health'] or both
}

Filtering:

  • Country filter: Uses alpha_2_code
  • Council type filter:
    • Filters by 'medical' for doctors
    • Filters by 'allied_health' for allied health professionals

Key Features:

  • Councils can support both medical and allied_health types (array field)
  • Same council can appear for both user types if applicable
  • Example: "Dubai Health Authority" has council_type: ['medical', 'allied_health']

Sorting: Alphabetical by name

Usage: Step 4 (Professional Details) - Registration council selection


4. default_special_interests

Purpose: Provides special interest/focus area options

Index Structure:

{
  id: integer,
  name: string,
  category: string,
  alpha_2_code: string
}

Filtering:

  • Country filter: Uses alpha_2_code
  • Category filter: Optional categorization of interests

Sorting: Alphabetical by name

Usage: Step 7 (Practice Info) - Special interests multi-select


5. default_professional_memberships

Purpose: Provides professional membership/association options

Index Structure:

{
  id: integer,
  name: string,
  abbreviation: string,
  description: text,
  alpha_2_code: string,
  profession_type: string,           # 'medical' or 'allied_health'
  specialization_category: string
}

Filtering:

  • Country filter: Uses alpha_2_code
  • Profession type filter:
    • profession_type = 'medical' for doctors
    • profession_type = 'allied_health' for allied health professionals

Sorting: Alphabetical by name

Usage: Step 5 (Qualifications) - Professional memberships multi-select


6. default_allied_health_professions

Purpose: Provides allied health profession options (for allied_health user type only)

Index Structure:

{
  id: integer,
  name: string,
  alpha_2_code: string,
  category: string
}

Filtering:

  • Country filter: Uses alpha_2_code
  • Category filter: Optional profession categorization

Sorting: Alphabetical by name

Usage: Step 4 (Professional Details) - Profession selection for allied_health users


7. default_allied_health_specializations

Purpose: Provides specialization options for allied health professionals

Index Structure:

{
  id: integer,
  name: string
}

Filtering: None (returns all specializations)

Sorting: Alphabetical by name

Usage: Step 4 (Professional Details) - Specialization selection for allied_health users


8. basic_languages

Purpose: Provides language options for the Practice Info step

Index Structure:

{
  id: integer,
  name: string,
  default_name: string,
  native_name: string,
  alpha_2_code: string
}

Filtering:

  • Country filter: Uses alpha_2_code
  • Returns languages commonly spoken in the selected country

Sorting: Alphabetical by name

Usage: Step 7 (Practice Info) - Languages spoken multi-select


Data Population and Seeding

All Elasticsearch indices are populated from JSON files and seeded into PostgreSQL tables, then indexed to Elasticsearch.

Seed File Locations

  • backend/lib/data/basic_degrees.json
  • backend/lib/data/basic_universities.json
  • backend/lib/data/medical_councils.json
  • backend/lib/data/special_interests.json
  • backend/lib/data/professional_memberships.json
  • backend/lib/data/allied_health_professions.json
  • backend/lib/data/allied_health_specializations.json
  • backend/lib/data/languages.json

Seeding Process

  1. Load JSON data: Read from lib/data/*.json
  2. Create database records: Insert into respective PostgreSQL tables
  3. Trigger Elasticsearch indexing: After-save callbacks reindex data
  4. Verify indices: Ensure all records are searchable

Reindexing Commands

# Reindex all onboarding-related indices
bundle exec rake es_reindex_basic_degrees
bundle exec rake es_reindex_basic_universities
bundle exec rake es_reindex_default_medical_councils
bundle exec rake es_reindex_default_special_interests
bundle exec rake es_reindex_default_professional_memberships
bundle exec rake es_reindex_default_allied_health_professions
bundle exec rake es_reindex_default_allied_health_specializations
bundle exec rake es_reindex_basic_languages

User Type Handling

User Type Values

The system recognizes three user types set during Step 1 (Welcome):

  1. doctor

    • Full medical professional onboarding
    • Access to medical councils, degrees, and memberships
    • Shows registration number and council fields (country-dependent)
  2. clinic_owner

    • Clinic management focused onboarding
    • Similar to doctor flow with clinic-specific fields
    • Shows registration fields (country-dependent)
  3. allied_health

    • Allied health professional onboarding (therapists, nutritionists, etc.)
    • Access to allied health specific professions, councils, and specializations
    • Different data filtering throughout the flow

Conditional Data Fetching

The backend API and Elasticsearch queries adapt based on user_type:

Step 4 - Professional Details:

  • user_type === 'allied_health': Fetches from allied health indices
  • user_type !== 'allied_health': Fetches from medical indices

Step 5 - Qualifications:

  • Degrees filtered by category matching user_type
  • Memberships filtered by profession_type matching user_type

Medical Councils:

  • Filters council_type array based on user_type
  • user_type === 'allied_health': Returns councils with 'allied_health' in council_type
  • user_type === 'doctor': Returns councils with 'medical' in council_type

Country-Based Dynamic Behavior

Several fields and data sources update dynamically based on the country selected in Step 3 (Basic Info).

Country Code Values

  • IN: India
  • US: United States
  • AE: United Arab Emirates

Dynamic Updates by Step

Step 4 (Professional Details):

  • Registration number field visibility
  • Registration council field visibility
  • Medical councils list filtered by alpha_2_code

Step 5 (Qualifications):

  • Degrees list filtered by category
  • Universities list filtered by alpha_2_code
  • Professional memberships filtered by alpha_2_code and profession_type

Step 7 (Practice Info):

  • Languages list filtered by alpha_2_code
  • Special interests filtered by alpha_2_code

Step 9 (Review & Consent):

  • Terms and agreements visibility
  • HIPAA compliance (US-specific)

Achievement System

Achievements provide engagement milestones throughout the onboarding process.

Achievement Types

  1. profile-discoverable: Unlocked after completing Basic Info (Step 3)
  2. referral-eligible: Unlocked after completing Professional Details (Step 4)
  3. alumni-unlocked: Unlocked after completing Qualifications (Step 5)

Backend Storage

  • Achievements are stored in user_flags.onboarding_data.achievements as an array
  • Each achievement is stored as a string identifier

Onboarding Completion

Completion Process

  1. User completes all 10 steps
  2. Final POST to /user_onboarding with celebration step data
  3. System marks onboarding as complete in user_flags
  4. User authentication context updated with cmsOnboardingComplete: true
  5. User redirected to /connect dashboard

Post-Completion State

  • No Profiles Created: User accounts and profiles are NOT automatically created
  • Data Preservation: All onboarding data stored in user_flags.onboarding_data
  • Connect Platform Access: Users can access Connect with limited functionality
  • Pending Status: Users are in "pending approval" state until Kulcare team creates profiles

Manual Profile Creation

When the Kulcare team is ready to create the actual profile:

  1. Retrieve onboarding data from user_flags.onboarding_data
  2. Create appropriate user_account record
  3. Create doctor/clinic profile with onboarding data
  4. Create associated records (educations, experiences, memberships, etc.)
  5. Mark profile as active
  6. Notify user of profile activation

Database Schema

user_flags Table

create_table :user_flags do |t|
  t.bigint :user_id, null: false
  t.jsonb :onboarding_data, default: {}
  t.boolean :onboarding_complete, default: false
  t.timestamps
end

add_index :user_flags, :user_id, unique: true

doctor_medical_councils Table

create_table :doctor_medical_councils do |t|
  t.integer :doctor_id, null: false
  t.string :name
  t.integer :default_medical_council_id
  t.timestamps
end

add_index :doctor_medical_councils, :doctor_id
add_index :doctor_medical_councils, :default_medical_council_id
add_foreign_key :doctor_medical_councils, :doctors
add_foreign_key :doctor_medical_councils, :default_medical_councils

Recent Implementation Changes

Elasticsearch Service Reorganization

  • Location Change: Moved from frontend/apps/shell/src/data/ to frontend/apps/shell/src/services/onboarding/
  • Purpose: Better code organization and service-oriented architecture

Professional Memberships Filtering

  • Enhancement: Added profession_type parameter to Elasticsearch queries
  • Backend Change: Updated getProfessionalMemberships method to accept professionType parameter
  • Filtering Logic:
    • Medical users: profession_type = 'medical'
    • Allied health users: profession_type = 'allied_health'

Medical Councils Array Type

  • Database Change: Converted council_type from string to PostgreSQL array
  • Data Consolidation: Merged duplicate councils (e.g., Dubai Health Authority)
  • Index Update: Added GIN index for array field queries
  • Query Update: Modified scopes to use PostgreSQL array operators

Universities Alpha Code

  • Seed Update: Added alpha_2_code to seed script
  • Issue Fixed: Universities were returning empty due to missing country codes
  • Reindexing Required: Database reseed and Elasticsearch reindex needed

Doctor Medical Councils Table

  • New Table: Created doctor_medical_councils join table
  • Purpose: Support multiple medical council registrations per doctor
  • Associations: Belongs to doctor and optionally to default_medical_council

References

  • Frontend Onboarding Flow: frontend/docs/features/onboarding/new_onboarding_flow.md
  • Authentication System: backend/docs/04-features/authentication-system.md

Model Files

  • backend/parts/core/models/user_flag.rb
  • backend/parts/core/models/default_medical_council.rb
  • backend/parts/core/models/basic_language.rb
  • backend/parts/doctor/models/doctor.rb
  • backend/parts/doctor/models/doctor_medical_council.rb

Seed Files

  • backend/db/seeds/seed_basic_degrees.rb
  • backend/db/seeds/seed_universities.rb
  • backend/db/seeds/seed_default_medical_councils.rb
  • backend/db/seeds/seed_default_special_interests.rb
  • backend/db/seeds/seed_default_professional_memberships.rb
  • backend/db/seeds/seed_default_allied_health_professions.rb
  • backend/db/seeds/seed_default_allied_health_specializations.rb

On this page