Kulcare Docs

UHI Stage 1 Discovery — Manual Test Plan

Scope: Physical consultation only (nic2004:85111). Booking deferred to Stage 2. Apps: CMS, Patient. Backend: Rails dev server + migrations.


Auth System — Phone + Password

Kulcare uses phone number + password for login (not email). The sign-in form accepts either:

phone_country_code: "91"
phone_number:      "5555555558"
password:          "FacilityAdmin123!"

Or email + password:

email:    "lisa.admin@cityhospital.com"
password: "FacilityAdmin123!"

Both are supported by Identity::UserSignInForm. For testing, phone is recommended as all seeded users have verified phone numbers.


Test Credentials

All seeded users are in backend/db/seeds/identity/04_users.rb and already in your kulcare_dev database.

CMS (Owner/Admin for UHI Settings TC-1 to TC-5)

NameEmailPhonePasswordRoleTenant
Lisa Andersonlisa.admin@cityhospital.com+91 5555555558FacilityAdmin123!adminTenant 1 (City Hospital)
Sarah Johnsonsarah.johnson@cityhospital.com+91 5551234567Admin123!adminTenant 1 (City Hospital)
James Wilsondr.james.wilson@smith.com+91 5555555557Facility123!ownerTenant 3 (Smith Clinic)
Raj Kumardr.raj.kumar@example.com+91 9876543210Doctor123!practitionerTenant 1 (City Hospital)

Recommended for TC-1 to TC-5: +91 5555555558 / FacilityAdmin123! (Lisa Anderson, admin role, City Hospital).

To log in via phone (recommended):

phone_country_code: 91
phone_number:       5555555558
password:          FacilityAdmin123!

To log in via email:

email:    lisa.admin@cityhospital.com
password: FacilityAdmin123!

Patient (for UHI Search TC-9 to TC-16)

NameEmailPhonePasswordNotes
John Doejohn.doe.patient@gmail.com+91 9876543211Patient123!Patient + practitioner. Has patient profile.

To log in via phone (recommended):

phone_country_code: 91
phone_number:       9876543211
password:          Patient123!

CMS Staff (for TC-8 — limited access)

NameEmailPhonePasswordRole
Rani Singhrani.nurse@cityhospital.com+91 9876543212Nurse123!staff

Prerequisites

1. Run Migrations

cd backend
bundle exec rails db:migrate

2. Verify Test Data

Confirm the test users exist in your database:

# In Rails console (cd backend && rails console):
Identity::User.find_by(phone_number: '5555555558')&.active  # => true
Identity::User.find_by(phone_number: '9876543211')&.active  # => true

3. Start Services

# Backend (if not already running)
cd backend && bundle exec rails server -p 3000

# Typesense (if not already running)
# Check backend/config/initializers/typesense.rb for host/port

# Ably (if not already running)
# Check backend/config/initializers/ably.rb

Test Cases

TC-1: CMS — UHI Settings Tab Exists

Route: /cms/settings/practiceSettings/uhi
Login: CMS owner/admin

  1. Sign in to CMS as facility owner
  2. Navigate to Settings → Practice Settings
  3. Confirm the UHI tab appears alongside Communication, Online Booking, Availability, AI Scribe
  4. Click the UHI tab

Expected: UHI tab renders without errors. Shows facility-level enable toggle and practitioner opt-in section.


TC-2: CMS — Enable UHI Discovery

Route: /cms/settings/practiceSettings/uhi
Login: CMS owner/admin

  1. On the UHI tab, find the Enable UHI Discovery toggle
  2. Toggle it ON
  3. Click Save
  4. Refresh the page
  5. Confirm the toggle is still ON

Expected:

  • Success toast appears after save
  • After refresh, toggle remains ON
  • Stats cards (searches count, views count) appear below the form

TC-3: CMS — Set Default Fee

Route: /cms/settings/practiceSettings/uhi
Login: CMS owner/admin

  1. Ensure UHI is already enabled (from TC-2)
  2. In the Default Consultation Fee field, enter 500
  3. Click Save
  4. Refresh the page
  5. Confirm the fee is 500

Expected: Fee persists after page refresh.


TC-4: CMS — Per-Practitioner Opt-In

Route: /cms/settings/practiceSettings/uhi
Login: CMS owner/admin

  1. Ensure UHI is already enabled (from TC-2)
  2. Scroll to Practitioner Opt-In section
  3. Confirm at least one practitioner role is listed with a toggle
  4. Toggle a role OFF → Save
  5. Refresh → confirm the toggle is OFF
  6. Toggle the same role back ON → Save
  7. Refresh → confirm the toggle is ON

Expected: Per-role uhi_enabled flag persists independently.


TC-5: CMS — Disable UHI Discovery

Route: /cms/settings/practiceSettings/uhi
Login: CMS owner/admin

  1. Toggle Enable UHI Discovery OFF
  2. Click Save
  3. Refresh the page
  4. Confirm toggle is OFF and stats cards are hidden

Expected: Facility returns to non-UHI state.


TC-6: API — Read UHI Catalog

Prerequisite: CMS admin token via phone auth.

Generate a token via Rails console:

# cd backend && rails console
result = Identity::Sessions::AuthenticationOrganizer.call(
  form: Identity::UserSignInForm.new(
    phone_country_code: '91',
    phone_number: '5555555558',
    password: 'FacilityAdmin123!'
  ),
  device_details: {}
)
puts result[:access_token] if result.success?

Or via curl (phone auth):

TOKEN=$(curl -s -X POST http://localhost:3000/api/identity/session \
  -H "Content-Type: application/json" \
  -d '{"user_signin_form":{"phone_country_code":"91","phone_number":"5555555558","password":"FacilityAdmin123!"}}' \
  | jq -r '.token')

echo "Token: $TOKEN"

# Then use the token:
curl -s -H "Authorization: Bearer $TOKEN" \
  http://localhost:3000/api/uhi/hspa/catalog | jq

Or via email:

TOKEN=$(curl -s -X POST http://localhost:3000/api/identity/session \
  -H "Content-Type: application/json" \
  -d '{"user_signin_form":{"email":"lisa.admin@cityhospital.com","password":"FacilityAdmin123!"}}' \
  | jq -r '.token')

curl -s -H "Authorization: Bearer $TOKEN" \
  http://localhost:3000/api/uhi/hspa/catalog | jq

Expected Response:

{
  "success": true,
  "data": {
    "facility": {
      "id": 123,
      "name": "ABC Clinic",
      "uhi_enabled": false,
      "uhi_default_fee": null,
      "uhi_searches_count": 0,
      "uhi_views_count": 0
    },
    "practitioner_roles": [
      {
        "id": 456,
        "specialty": "Cardiology",
        "role_type": "doctor",
        "uhi_enabled": false,
        "uhi_discoverable": false
      }
    ]
  }
}

TC-7: API — Enable UHI via PUT

# Get token first
TOKEN=$(curl -s -X POST http://localhost:3000/api/identity/session \
  -H "Content-Type: application/json" \
  -d '{"user_signin_form":{"phone_country_code":"91","phone_number":"5555555558","password":"FacilityAdmin123!"}}' \
  | jq -r '.token')

curl -s -X PUT \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"facility":{"uhi_enabled":true,"uhi_default_fee":500}}' \
  http://localhost:3000/api/uhi/hspa/catalog | jq

Expected: Returns updated catalog with uhi_enabled: true, uhi_default_fee: 500.


TC-8: CMS — UHI Tab Only Visible to Staff

Route: /cms/settings/practiceSettings/uhi
Login: Non-admin CMS user

  1. Sign in as a staff member (not owner/admin)
  2. Navigate to Settings → Practice Settings
  3. Observe available tabs

Expected: UHI tab may or may not appear depending on role permissions. No errors.


TC-9: Patient — UHI Search Page Loads

Route: /uhi/search (patient app)
Login: Patient user

  1. Sign in to patient app
  2. Navigate to UHI Network in the sidebar
  3. Confirm the page renders with the search form

Expected:

  • Page title: "UHI Network Search"
  • Form has: City dropdown, Specialty dropdown, Doctor Name input, Search button
  • Stage 1 notice visible

TC-10: Patient — Search Form Validation

Route: /uhi/search (patient app)
Login: Patient user

  1. Click Search UHI Network without selecting a city

Expected: Form submission is blocked. City field shows a validation error (red asterisk or similar).


TC-11: Patient — City Dropdown Options

Route: /uhi/search (patient app)
Login: Patient user

  1. Open the City dropdown
  2. Confirm it contains Indian cities (Delhi, Mumbai, Chennai, Bangalore, etc.)

Expected: At least 15 Indian cities present.


TC-12: Patient — Search Request Sent

Route: /uhi/search (patient app)
Login: Patient user

  1. Select a city (e.g., Chandigarh)
  2. Click Search UHI Network
  3. Open browser dev tools → Network tab
  4. Observe the POST request to /api/uhi/eua/search

Expected:

  • A POST request is sent with { intent: { city, fulfillment_type: "Physical" } }
  • A transaction_id is returned or pending
  • Loading state appears

TC-13: Patient — No Booking in Stage 1

Route: /uhi/search (patient app)
Login: Patient user

  1. Perform a search and wait for results
  2. On a provider card, look for a Book button

Expected: No Book button. Only "View Profile" and "Contact" actions. Footer text says "Stage 1 — Physical consultation".


TC-14: Patient — Provider Card Displays Data

Route: /uhi/search (patient app)
Login: Patient user

  1. Perform a search (may be empty if no HSPAs are enrolled)
  2. If results appear, inspect a provider card

Expected:

  • Provider name visible
  • Specialty badge shown
  • Location displayed (city/state)
  • Fee shown or "Fee on request"
  • "UHI Network" badge
  • "Stage 1 — Physical consultation" label

TC-15: Patient — Empty Results State

Route: /uhi/search (patient app)
Login: Patient user

  1. Perform a search for a city unlikely to have UHI providers
  2. Wait for the 30-second polling timeout

Expected:

  • Loading spinner appears during search
  • After timeout, "No providers found" message with "Try a different search" button

TC-16: Patient — New Search Resets Results

Route: /uhi/search (patient app)
Login: Patient user

  1. Perform a search, wait for completion
  2. Click "New search" or the link to try again

Expected: Results area clears and form resets to initial state.


TC-17: Backend — Ably Event Publishing (Manual Mock)

Setup: Requires Ably running locally or a sandbox key.

# In Rails console:
Uhi::RealtimePublisher.publish_on_search(
  user_id: 123,
  transaction_id: "tx_test_001",
  provider: {
    id: "prov_001",
    descriptor: { name: "Dr. Sharma Clinic" },
    items: [{ descriptor: { name: "Cardiology" }, price: { currency: "INR", value: "500" } }]
  }
)

Expected: An Ably message is published to channel private:user:123 with event on_search and the provider payload.


TC-18: Backend — Typesense uhi_enabled Index

Check: Run in Rails console or via rails runner

schema = Identity::Typesense::PractitionersCollection.schema
field = schema['fields'].find { |f| f['name'] == 'uhi_enabled' }
puts field.inspect

Expected: {"name"=>"uhi_enabled", "type"=>"bool", "optional"=>true}


TC-19: Backend — uhi_discoverable Logic

Check: Run in Rails console

f = Identity::Facility.last
p = Identity::PractitionerRole.last

f.update!(uhi_enabled: true)
p.update!(uhi_enabled: true)
puts p.uhi_discoverable?  # => true

f.update!(uhi_enabled: false)
puts p.uhi_discoverable?  # => false

f.update!(uhi_enabled: true)
p.update!(uhi_enabled: false)
puts p.uhi_discoverable?  # => false

Expected: uhi_discoverable? is true only when both facility AND role have uhi_enabled: true.


TC-20: Backend — Increment UHI Counters

Check: Run in Rails console

f = Identity::Facility.last
f.increment_uhi_search_count!
f.increment_uhi_view_count!
f.increment_uhi_view_count!

puts f.uhi_searches_count  # => 1
puts f.uhi_views_count     # => 2

Expected: Counters increment correctly.


Cleanup Checklist

After testing, reset the test facility (run in Rails console):

# Disable UHI on City Hospital Main (Tenant 1)
f = Identity::Facility.find_by(name: 'City Hospital Main')
f.update!(uhi_enabled: false, uhi_default_fee: nil)

# Disable UHI on all practitioner roles at that facility
f.practitioner_roles.update_all(uhi_enabled: false)

# Verify
puts "Facility: #{f.uhi_enabled?}"
puts "Roles: #{f.practitioner_roles.pluck(:uhi_enabled).uniq}"

Or via API (replace $TOKEN with your CMS admin token from phone login):

TOKEN=$(curl -s -X POST http://localhost:3000/api/identity/session \
  -H "Content-Type: application/json" \
  -d '{"user_signin_form":{"phone_country_code":"91","phone_number":"5555555558","password":"FacilityAdmin123!"}}' \
  | jq -r '.token')

curl -s -X PUT \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"facility":{"uhi_enabled":false}}' \
  http://localhost:3000/api/uhi/hspa/catalog | jq

Defect Reporting Template

If you find a bug, use this format:

Test Case: TC-XX
Environment: [local / staging]
Steps:
  1.
  2.
  3.
Expected:
  [what should happen]
Actual:
  [what actually happened]
Screenshots: [attach]
Console/Network Errors: [copy relevant error]

On this page