Session 8: Add Patient & Booking Flow
Date: 2026-06-11 Module: Add Patient - Federated Search URL:
- Add Patient: https://practice-stg-new.kulcare.com/cms/patients
- Appointment Booking: https://practice-stg-new.kulcare.com/cms/queue Tester: [Your Name] Status: 🔄 In Progress
📊 Test Results Summary
| Category | Tested | ✅ Passed | ❌ Failed |
|---|---|---|---|
| Federated Search - Name | 2 | 1 | 1 |
| Federated Search - Phone | 1 | 1 | 0 |
| Import from Kulcare | 4 | 3 | 1 |
| Create Patient - Happy Path | 3 | 3 | 0 |
| Create Patient - Validation | 7 | 2 | 5 |
| Patient List | 1 | 1 | 0 |
| Total | 18 | 11 | 7 |
🐛 Bugs Found
| Bug # | Description | Severity | Status |
|---|---|---|---|
| 31 | Federated Search - partial name works, full name doesn't | 🟡 High | Open |
| 32 | DOB not auto-filled when importing from Kulcare | 🟡 High | Open |
| 34 | No validation for patient form (Frontend + Backend) | 🟠 Medium | Open |
| 34b | Backend accepts empty/whitespace for last_name | 🟠 Medium | Open |
| 34c | Backend accepts whitespace for phone_number | 🟠 Medium | Open |
| 35 | Patient list date range filter not working | 🟠 Medium | Open |
🔍 Detailed Test Results
Federated Search - Name Search
| # | Test Case | Result | Bug | Notes |
|---|---|---|---|---|
| FS-04 | Search by partial name ("mohit") | ✅ PASS | - | Returns results |
| FS-05 | Search by full name ("mohit goyal") | ❌ FAIL | #31 | No results returned |
Federated Search - Phone
| # | Test Case | Result | Bug | Notes |
|---|---|---|---|---|
| FS-01 | Search by phone | ✅ PASS | - | Works correctly |
Import from Kulcare
| # | Test Case | Result | Bug | Notes |
|---|---|---|---|---|
| SP-03 | Import in-Kulcare patient - check DOB | ❌ FAIL | #32 | DOB not auto-filled |
| SP-04 | Import in-Kulcare patient - check name | ✅ PASS | - | Name auto-fills |
| SP-05 | Import in-Kulcare patient - check phone | ✅ PASS | - | Phone auto-fills |
| SP-06 | Import in-Kulcare patient - check gender | ✅ PASS | - | Gender auto-fills |
Create Patient - Happy Path
| # | Test Case | Result | Notes |
|---|---|---|---|
| CP-01 | Create with all required fields | ✅ PASS | Patient created successfully |
| CP-02 | Create with required only | ✅ PASS | Patient created successfully |
| CP-03 | Create with all fields | ✅ PASS | Patient created with all data |
Create Patient - Validation
| # | Test Case | Result | Bug | Notes |
|---|---|---|---|---|
| CP-04 | Empty first name | ✅ PASS | Backend gives error: "First name can't be blank" | |
| CP-05 | Empty last name | ❌ FAIL | Bug #34b | Backend accepts empty/whitespace |
| CP-06 | Empty phone | ✅ PASS | Phone is required | |
| CP-07 | Invalid phone (letters) | ❌ FAIL | Bug #34 | Form accepts invalid data |
| CP-07b | Phone with whitespace | ❌ FAIL | Bug #34c | Backend accepts whitespace " " |
| CP-08 | Long name (100+ chars) | ❌ FAIL | Bug #34 | Form accepts invalid data |
| CP-09 | Future DOB | ❌ FAIL | Bug #34 | Form accepts invalid data |
| CP-10 | Missing gender | ✅ PASS | Gender is optional | |
| CP-11 | Invalid gender | ✅ PASS | Handled correctly |
Patient List & Management
| # | Test Case | Result | Bug | Notes |
|---|---|---|---|---|
| PL-01 | View patient list | ✅ PASS | - | Shows patients with pagination |
| PL-02 | Search patient | ✅ PASS | - | Returns matching patients by name/phone |
| PL-06 | Multi-clinic patient visibility | ✅ PASS | - | Confirmed with dev team - expected behavior |
🐛 Bug Details
Bug #31: Federated Search - Partial Name Works, Full Name Doesn't
| Field | Value |
|---|---|
| Severity | 🟡 High |
| Bug # | 31 |
| Area | Add Patient - Federated Search |
| Session | 08-add-patient-booking |
| Status | Open |
Description: Search by partial name (e.g., "mohit") returns results, but search by full name (e.g., "mohit goyal") returns no results.
Steps to Reproduce:
- Search by "mohit" → ✅ Results found
- Search by "mohit goyal" → ❌ No results
Expected: Full name search should return results Actual: Only partial name search works
API Evidence:
# Partial name - WORKS
curl 'https://api-stg.kulcare.com/clinical/patients/federated_search?name=mohit' \
-H 'Authorization: Bearer ...'
# Returns: Patient "Mohit Goyal" found
# Full name - FAILS
curl 'https://api-stg.kulcare.com/clinical/patients/federated_search?name=mohit%20goyal' \
-H 'Authorization: Bearer ...'
# Returns: No resultsRoot Cause (Suspected):
The name search uses LIKE with % prefix, which matches partial names but not multi-word full names correctly.
Recommendation:
Investigate the name search logic in FederatedSearchService#apply_name_filter:
def apply_name_filter(scope)
scope.where('LOWER(first_name) LIKE :q OR LOWER(last_name) LIKE :q', q: safe_like_term(@name))
endThe current implementation searches first_name OR last_name separately, not full name as a phrase.
Bug #32: DOB Not Auto-filled When Importing from Kulcare
| Field | Value |
|---|---|
| Severity | 🟡 High |
| Bug # | 32 |
| Area | Add Patient - Import from Kulcare |
| Session | 08-add-patient-booking |
| Status | Open |
Description: When importing a patient from Kulcare network (in_kulcare bucket), the DOB is not auto-filled even though the patient has DOB set in their Patient App profile.
Steps to Reproduce:
- Patient "Mohit Goyal" has DOB set in Patient App
- Search in Clinic App → Find in "Elsewhere on Kulcare"
- Click "Import" → Form auto-fills
- Check DOB field → ❌ Empty
Expected: DOB should be auto-filled from Kulcare profile Actual: DOB field is empty (phone, name, gender are auto-filled correctly)
Root Cause (Suspected):
The serialize_in_kulcare method in FederatedSearchService doesn't include birth_date in the response.
Recommendation:
Add birth_date to the serialize_in_kulcare method:
def serialize_in_kulcare(identity_patient)
{
identity_patient_id: identity_patient.id,
name: identity_patient.display_name,
phone: identity_patient.phone_number,
phone_country_code: identity_patient.phone_country_code,
age: identity_patient.respond_to?(:age) ? identity_patient.age : nil,
gender: identity_patient.gender,
birth_date: identity_patient.birth_date, # Add this line
registered_via: identity_patient.user_id.present? ? 'patient_app' : 'another_clinic'
}
endBug #34: No Validation for Patient Form (Frontend + Backend)
| Field | Value |
|---|---|
| Severity | 🟠 Medium |
| Bug # | 34 |
| Area | Add Patient - Form Validation |
| Session | 08-add-patient-booking |
| Status | Open |
Description: Patient form accepts invalid data without validation. BOTH frontend AND backend accepted:
| Field | Invalid Input | Expected | Actual |
|---|---|---|---|
| first_name | 100+ characters | Error | Accepted ✅ |
| last_name | 100+ characters | Error | Accepted ✅ |
| phone_number | "dsadasdsadsads" (letters) | Error | Accepted ✅ |
| birth_date | 2026-06-15 (future) | Error | Accepted ✅ |
Steps to Reproduce:
- Open Add Patient form
- Enter very long name (100+ chars)
- Enter letters in phone field
- Select future DOB
- Submit → ❌ Form accepts invalid data
- API stores invalid data → ❌ Backend accepts it
API Request That Succeeded:
curl 'https://api-stg.kulcare.com/clinical/patients' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer ...' \
--data-raw '{
"first_name":"ddasdsadsadasdsadsadsadsadsafsdfsdfsdfdsfsdfsfdsfdsfdsfdsfdfadsfdsfadsfdsdsadsadsadsadsadsadsa",
"last_name":"dsadsadsadsadsadsadfdsfdsfdsfdsfdsfdsfdsfdsfdsfdsfdsfdsfdsfdsfdsfdsfdsf",
"phone_number":"dsadasdsadsads",
"phone_country_code":"91",
"gender":"male",
"birth_date":"2026-06-15"
}'API Response: 200 OK - Patient created successfully
Issues Found:
-
Frontend (
AddPatientModal.tsx):- No validation for name length
- No validation for phone format (letters accepted)
- No validation for DOB (future dates allowed)
-
Backend (
Clinical::PatientsController#patient_params):- No length validation on name fields
- No format validation on phone
- No date validation on birth_date
Recommendation:
Frontend - Add validation in AddPatientModal:
const validationSchema = z.object({
first_name: z.string().min(2, "Min 2 chars").max(50, "Max 50 chars"),
last_name: z.string().min(2, "Min 2 chars").max(50, "Max 50 chars"),
phone_number: z.string().regex(/^\d{10}$/, "Must be 10 digits"),
birth_date: z.string().refine(
(date) => new Date(date) <= new Date(),
"DOB cannot be in future"
),
});Backend - Add validation in Clinical::Patient model:
validates :first_name, length: { minimum: 2, maximum: 50 }
validates :last_name, length: { minimum: 2, maximum: 50 }
validates :phone_number, format: { with: /\A\d{10}\z/ }
validate :birth_date_not_in_future
def birth_date_not_in_future
errors.add(:birth_date, "cannot be in future") if birth_date.present? && birth_date > Date.current
endBug #34b: Backend Accepts Empty/Whitespace for last_name
| Field | Value |
|---|---|
| Severity | 🟠 Medium |
| Bug # | 34b |
| Area | Add Patient - Form Validation |
| Session | 08-add-patient-booking |
| Status | Open |
Description:
Backend accepts empty/whitespace for last_name field. first_name is correctly validated, but last_name allows empty strings.
API Evidence:
# Empty last_name - ACCEPTS
curl 'https://api-stg.kulcare.com/clinical/patients' \
--data-raw '{
"first_name":"Harsh",
"last_name":"",
"phone_number":"1234567890",
"phone_country_code":"91",
"gender":"male",
"birth_date":"2026-06-15"
}'
# Response: 200 OK - Patient created with last_name: ""Recommendation:
Frontend - Add validation:
last_name: z.string().min(1, "Required").transform(val => val?.trim())Backend - Add validation:
validates :last_name, presence: true, unless: -> { last_name.nil? }
before_validation :normalize_names
def normalize_names
self.last_name = last_name&.strip
endBug #34c: Backend Accepts Whitespace for phone_number
| Field | Value |
|---|---|
| Severity | 🟠 Medium |
| Bug # | 34c |
| Area | Add Patient - Form Validation |
| Session | 08-add-patient-booking |
| Status | Open |
Description:
Backend accepts whitespace for phone_number field. Empty spaces pass validation.
API Evidence:
# Whitespace phone - ACCEPTS
curl 'https://api-stg.kulcare.com/clinical/patients' \
--data-raw '{
"first_name":"Chugh",
"last_name":"",
"phone_number":" ",
"phone_country_code":"91",
"gender":"male",
"birth_date":"2026-06-15"
}'
# Response: 200 OK - Patient created with phone_number: " "Recommendation:
Frontend - Add validation:
phone_number: z.string()
.min(10, "Min 10 digits")
.max(10, "Max 10 digits")
.regex(/^\d+$/, "Only digits allowed")Backend - Add validation:
before_validation :normalize_phone
def normalize_phone
self.phone_number = phone_number&.gsub(/\D/, '')
end
validates :phone_number, presence: true, format: { with: /\A\d{10}\z/ }Add phone validation to strip whitespace and validate format:
before_validation :normalize_phone
def normalize_phone
self.phone_number = phone_number&.strip
end
validates :phone_number, presence: true, format: { with: /\A\d{10}\z/ }📋 Validation Summary - Bugs #34, #34b, #34c
All three bugs require validation on BOTH frontend AND backend:
| Bug | Issue | Frontend Fix | Backend Fix |
|---|---|---|---|
| #34 | No validation for name/phone/DOB | Add Zod schema validation | Add model validations |
| #34b | Empty/whitespace for last_name | Trim input, show error if empty | Strip whitespace, add presence validation |
| #34c | Whitespace for phone_number | Only allow digits, show error | Strip whitespace, format validation |
Bug #35: Patient List Date Range Filter Not Working
| Field | Value |
|---|---|
| Severity | 🟠 Medium |
| Bug # | 35 |
| Area | Patient List |
| Session | 08-add-patient-booking |
| Status | Open |
Description: Patient list page has a date range filter UI, but it is NOT being passed to the API query params.
Root Cause:
In PatientsPage.tsx, the date filter state is not included in queryParams:
const queryParams = {
search: debouncedSearch || undefined,
page: filters.page,
per_page: filters.perPage,
// dateRange NOT included here
};Recommendation: Add date range params to queryParams:
birth_date_from: filters.dateRange?.from,
birth_date_to: filters.dateRange?.to,✅ Confirmed Working Features
| Feature | Status | Notes |
|---|---|---|
| Federated Search - Phone | ✅ Works | Phone search works correctly |
| Federated Search - Partial Name | ✅ Works | Partial name search returns results |
| Import from Kulcare - Name | ✅ Works | Name auto-fills |
| Import from Kulcare - Phone | ✅ Works | Phone auto-fills |
| Import from Kulcare - Gender | ✅ Works | Gender auto-fills |
| Multi-clinic Patient Visibility | ✅ Works | Expected behavior - patients shared in same tenant |
| Create Patient - Happy Path | ✅ Works | CP-01, CP-02, CP-03 all pass |
| Create Patient - first_name validation | ✅ Works | Backend rejects empty first_name |
| Create Patient - gender optional | ✅ Works | Gender is optional, works correctly |
| Create Patient - invalid gender | ✅ Works | Handled correctly |
📋 Test Data Used
| Patient | Phone | DOB | Source | Notes | |
|---|---|---|---|---|---|
| Mohit Goyal | 9988776655 | - | Set | Patient App | Has DOB set, used for import testing |
✅ Recommendations
| Priority | Recommendation | Bug |
|---|---|---|
| P0 | Investigate name search logic in federated_search API | #31 |
| P0 | Include DOB in InKulcareIdentityPatient response | #32 |
| P1 | Add frontend validation for patient form | #34 |
| P1 | Add backend validation for patient form | #34 |
📝 Pending Tests
| Section | Test Cases | Status |
|---|---|---|
| Federated Search - Email | FS-06 | Pending |
| Federated Search - Edge cases | FS-07, FS-08, FS-09, FS-10 | Pending |
| Create New Patient Form | CP-01 to CP-06 | Pending |
| Patient List | PL-01 to PL-05 | Pending |
| Appointment Booking | AB-01 to QM-05 | Pending |
Session Status: 🔄 In Progress Last Updated: 2026-06-11