Kulcare Docs
General

Entity Creation Table Mapping Guide

Purpose: Quick reference for which database tables are populated when creating key entities
Use Case: Understanding database impact, debugging data flow, API testing


Tenant Creation (Foundation)

⚠️ IMPORTANT: Tenant is the Starting Point

EVERYTHING starts with a Tenant. A tenant represents a customer organization (e.g., "Apollo Hospitals", "Fortis Healthcare").

Tables Directly Populated

TableDescriptionRequired Fields
identity.tenantsMUST CREATE FIRSTname, slug, status, plan_tier

SQL Example: Creating Apollo Hospitals Tenant

-- Step 0: Create tenant (MUST EXIST before anything else)
INSERT INTO identity.tenants (
  id, name, slug, status, plan_tier
) VALUES (
  'apollo-tenant-123',
  'Apollo Hospitals Group',
  'apollo-hospitals',
  'active',
  'enterprise'
);

Tables Populated: 1 direct table


Practitioner Creation

⚠️ Prerequisites

REQUIRED: Before creating a practitioner, you MUST have:

  1. Existing Tenant - The tenant_id is REQUIRED in the API
  2. User Management - No facility or practitioner account needed

✅ KEY POINTS

  • Tenant ID is REQUIRED in the creation API
  • Practitioner is created FIRST (independent entity)
  • PractitionerRole is created SECOND (links practitioner to facility)
  • No facility required to create a practitioner

Tables Directly Populated

TableDescriptionExample DataOrder
identity.tenantsMUST EXISTid: "apollo-tenant"0
identity.usersUser login accountid: "user-123", email: "sarah@example.com"1
identity.practitionersPractitioner profile (GLOBAL)id: "practitioner-123"2
identity.user_membershipsTenant membershipuser_id: "user-123", tenant_id: "apollo-tenant"3
identity.practitioner_rolesFacility assignmentspractitioner_id: "practitioner-123", facility_id: "facility-456"4

Tables Indirectly Affected

TableRelationshipAuto-Created?
identity.sessionsLogin sessions✅ Yes (on first login)
connect.professional_profilesProfessional networking❌ Optional
audit.activity_logsCreation audit trail✅ Yes (automatic)

Complete SQL Example: Creating Dr. Sarah Johnson

-- Step 0: Tenant MUST exist (created separately)
-- See "Tenant Creation" section above

-- Step 1: Create user account
INSERT INTO identity.users (
  id, email, phone, first_name, last_name, is_active
) VALUES (
  'user-sarah-123',
  'sarah.johnson@hospital.com',
  '+919876543210',
  'Sarah',
  'Johnson',
  true
);

-- Step 2: Create practitioner record (GLOBAL entity - no tenant_id)
INSERT INTO identity.practitioners (
  id, user_id, first_name, last_name, gender,
  identifiers, qualifications, is_active
) VALUES (
  'practitioner-sarah-123',
  'user-sarah-123',
  'Sarah',
  'Johnson',
  'female',
  '[{"system": "mci", "value": "12345-KA-2010"}]'::jsonb,
  '[{"code": "MBBS", "issuer": "Bangalore Medical College", "year": 2010}]'::jsonb,
  true
);

-- Step 3: Create tenant membership (links user to tenant)
INSERT INTO identity.user_memberships (
  user_id, tenant_id, role, status
) VALUES (
  'user-sarah-123',
  'apollo-tenant-456',  -- REQUIRED: links to tenant
  'practitioner',
  'active'
);

-- Step 4: Create facility role assignment (links practitioner to facility)
-- NOTE: This step requires facility to exist, but can be done later
INSERT INTO identity.practitioner_roles (
  tenant_id, practitioner_id, facility_id, role_type,
  specialty_id, is_primary, is_active
) VALUES (
  'apollo-tenant-456',
  'practitioner-sarah-123',
  'facility-bannerghatta-789',  -- Facility must exist
  'physician',
  'specialty-cardiology-101',
  true,
  true
);

API Request Example

IMPORTANT: tenant_id is REQUIRED in the request body

POST /identity/practitioners
{
  "tenant_id": "apollo-tenant-123",  # ✅ REQUIRED - cannot be omitted
  "user": {
    "email": "sarah.johnson@hospital.com",
    "phone": "+919876543210",
    "first_name": "Sarah",
    "last_name": "Johnson"
  },
  "practitioner": {
    "gender": "female",
    "identifiers": [
      {"system": "mci", "value": "12345-KA-2010"}
    ],
    "qualifications": [
      {"code": "MBBS", "issuer": "Bangalore Medical College", "year": 2010}
    ]
  },
  "roles": [  # Optional - can be created separately via PractitionerRole API
    {
      "facility_id": "facility-bannerghatta-789",
      "role_type": "physician",
      "specialty_id": "specialty-cardiology-101",
      "is_primary": true
    }
  ]
}

Backend Validation Rules

# Backend MUST enforce these rules:
1. tenant_id presence: true  # REQUIRED field
2. tenant must exist in identity.tenants
3. user email must be unique across all tenants
4. practitioner record created without tenant_id (global entity)
5. user_membership created to link user to tenant
6. practitioner_roles only created if facility exists

Tables Populated: 4 direct tables


Facility Creation

⚠️ Prerequisites

REQUIRED: Before creating a facility, you MUST have:

  1. Existing Tenant - The tenant_id is REQUIRED in the API
  2. Existing Organization - The organization_id is REQUIRED in the API

✅ KEY POINTS

  • Tenant ID is REQUIRED in the creation API
  • Organization ID is REQUIRED in the creation API
  • NO practitioner required to create a facility
  • Facility is completely independent from practitioners

Tables Directly Populated

TableDescriptionExample DataOrder
identity.tenantsMUST EXISTid: "apollo-tenant"0
identity.organizationsLegal entity ownerid: "org-123", tenant_id: "apollo-tenant"1
identity.facilitiesPhysical locationid: "facility-456", organization_id: "org-123"2
identity.facility_locationsAddress/contact infofacility_id: "facility-456"3

Tables Indirectly Affected

TableRelationshipAuto-Created?
identity.healthcare_servicesServices offered❌ Optional (created separately)
identity.practitioner_rolesStaff assignments❌ Optional (created when assigning staff)
clinical.patient_facilitiesPatient associations❌ Optional (created when patients register)

❌ NO Practitioner Tables Involved

IMPORTANT: Creating a facility does NOT populate any practitioner-related tables:

  • ❌ identity.users - NOT created
  • ❌ identity.practitioners - NOT created
  • ❌ identity.practitioner_roles - NOT created
  • ❌ identity.user_memberships - NOT created

Complete SQL Example: Creating Apollo Bannerghatta Hospital

-- Step 0: Tenant MUST exist (created separately)
-- See "Tenant Creation" section above

-- Step 1: Create organization (legal entity)
INSERT INTO identity.organizations (
  id, tenant_id, name, organization_type, is_active
) VALUES (
  'org-apollo-main',
  'apollo-tenant-123',  -- REQUIRED: links to tenant
  'Apollo Hospital System',
  'hospital_system',
  true
);

-- Step 2: Create facility (physical location)
INSERT INTO identity.facilities (
  id, tenant_id, organization_id, name, service_level,
  bed_count, has_opd, has_ipd, operational_status
) VALUES (
  'facility-bannerghatta-456',
  'apollo-tenant-123',           -- REQUIRED: links to tenant
  'org-apollo-main',             -- REQUIRED: links to organization
  'Apollo Hospital Bannerghatta',
  'opd_ipd_surgery',
  350,
  true,
  true,
  'active'
);

-- Step 3: Create facility location (address)
INSERT INTO identity.facility_locations (
  id, tenant_id, facility_id, name, location_type,
  address_line_1, city, state, postal_code, country_code,
  is_primary, is_active
) VALUES (
  'location-bannerghatta-main-789',
  'apollo-tenant-123',           -- REQUIRED: links to tenant
  'facility-bannerghatta-456',   -- REQUIRED: links to facility
  'Main Campus',
  'building',
  '154/11, Bannerghatta Road',
  'Bangalore',
  'Karnataka',
  '560076',
  'IN',
  true,
  true
);

API Request Example

IMPORTANT: Both tenant_id and organization_id are REQUIRED

POST /identity/facilities
{
  "tenant_id": "apollo-tenant-123",      # ✅ REQUIRED - cannot be omitted
  "organization_id": "org-apollo-456",    # ✅ REQUIRED - cannot be omitted
  "facility": {
    "name": "Apollo Hospital Bannerghatta",
    "service_level": "opd_ipd_surgery",
    "bed_count": 350,
    "has_opd": true,
    "has_ipd": true
  },
  "location": {
    "name": "Main Campus",
    "address_line_1": "154/11, Bannerghatta Road",
    "city": "Bangalore",
    "state": "Karnataka",
    "postal_code": "560076",
    "country_code": "IN",
    "is_primary": true
  }
}

Backend Validation Rules

# Backend MUST enforce these rules:
1. tenant_id presence: true       # REQUIRED field
2. organization_id presence: true # REQUIRED field
3. tenant must exist in identity.tenants
4. organization must exist and belong to tenant
5. NO practitioner validation required

Tables Populated: 3 direct tables (NO practitioner tables)


Facility vs Practitioner Creation Comparison

AspectFacilityPractitioner
Tenant Required✅ Yes✅ Yes
Organization Required✅ Yes❌ No
Practitioner Required❌ No❌ N/A
Can Stand Alone✅ Yes✅ Yes
Global vs ScopedTenant-scopedGlobal entity
Requires User Account❌ No✅ Yes

Creation Independence

✅ Facility can be created WITHOUT any practitioners
✅ Practitioner can be created WITHOUT any facilities
✅ PractitionerRole links them together (created separately)

Patient Creation

⚠️ Prerequisites

REQUIRED: Before creating a patient, you MUST have:

  1. Existing Tenant - The tenant_id is REQUIRED in the API
  2. Existing Facility - The facility_id is REQUIRED in the API

Tables Directly Populated

TableDescriptionExample Data
identity.tenantsMUST EXISTid: "apollo-tenant"
identity.usersPatient login (optional)id: "user-patient-123"
clinical.patientsPatient medical recordid: "patient-456", tenant_id: "apollo-tenant"
clinical.patient_facilitiesFacility registrationpatient_id: "patient-456", facility_id: "facility-789"

Tables Indirectly Affected

TableRelationshipAuto-Created?
clinical.episodes_of_careCare episodes❌ Optional (created during visits)
billing.invoicesBilling records❌ Optional (created after services)
audit.phi_access_logsPHI access tracking✅ Yes (automatic)

SQL Example: Creating Patient Raj Kumar

-- Step 0: Tenant and Facility MUST exist (created separately)

-- Step 1: Create user account (optional - for patient portal)
INSERT INTO identity.users (
  id, email, phone, first_name, last_name, is_active
) VALUES (
  'user-raj-123',
  'raj.kumar@gmail.com',
  '+919876543211',
  'Raj',
  'Kumar',
  true
);

-- Step 2: Create patient record (TENANT SCOPED)
INSERT INTO clinical.patients (
  id, tenant_id, user_id, mrn, first_name, last_name,
  gender, birth_date, blood_type, is_active
) VALUES (
  'patient-raj-456',
  'apollo-tenant-789',  -- REQUIRED: links to tenant
  'user-raj-123',       -- Optional: links to user
  'APOLLO-2024-001234',
  'Raj',
  'Kumar',
  'male',
  '1980-03-20',
  'O+',
  true
);

-- Step 3: Link patient to facility
INSERT INTO clinical.patient_facilities (
  patient_id, facility_id, registration_date, is_primary
) VALUES (
  'patient-raj-456',
  'facility-bannerghatta-101',  -- REQUIRED: links to facility
  '2026-01-15',
  true
);

Tables Populated: 3-4 direct tables (user is optional)


Complete Entity Creation Flow

Scenario: Onboarding a New Doctor to a Hospital

Step-by-Step Process:

  1. Create Tenant (if doesn't exist)

    INSERT INTO identity.tenants (id, name, slug, status, plan_tier)
    VALUES ('apollo-tenant', 'Apollo Hospitals', 'apollo', 'active', 'enterprise');
  2. Create Organization (if doesn't exist)

    INSERT INTO identity.organizations (id, tenant_id, name, organization_type)
    VALUES ('org-apollo', 'apollo-tenant', 'Apollo Hospital System', 'hospital_system');
  3. Create Facility (if doesn't exist)

    INSERT INTO identity.facilities (id, tenant_id, organization_id, name)
    VALUES ('facility-main', 'apollo-tenant', 'org-apollo', 'Apollo Main Hospital');
  4. Create User Account (for practitioner)

    INSERT INTO identity.users (id, email, first_name, last_name)
    VALUES ('user-sarah', 'sarah@hospital.com', 'Sarah', 'Johnson');
  5. Create Practitioner Record (global entity)

    INSERT INTO identity.practitioners (id, user_id, first_name, last_name, gender)
    VALUES ('practitioner-sarah', 'user-sarah', 'Sarah', 'Johnson', 'female');
  6. Create UserMembership (links user to tenant)

    INSERT INTO identity.user_memberships (user_id, tenant_id, role, status)
    VALUES ('user-sarah', 'apollo-tenant', 'practitioner', 'active');
  7. Create PractitionerRole (assigns to facility)

    INSERT INTO identity.practitioner_roles (tenant_id, practitioner_id, facility_id, role_type)
    VALUES ('apollo-tenant', 'practitioner-sarah', 'facility-main', 'physician');

Tables Affected: 7 tables total

  1. identity.tenants
  2. identity.organizations
  3. identity.facilities
  4. identity.users
  5. identity.practitioners
  6. identity.user_memberships
  7. identity.practitioner_roles

Data Flow Diagram

For BOTH Facilities and Practitioners:

TENANT (Foundation)
    ↓
    ├─→ ORGANIZATION (Legal Entity)
    │       ↓
    │   FACILITY (Physical Location)
    │       ↓
    │   FACILITY LOCATION (Address/Contact)
    │
    └─→ USER (Login Account)
            ↓
        PRACTITIONER (Global Profile)
            ↓
        USER MEMBERSHIP (Tenant Access)
            ↓
        PRACTITIONER ROLE (Links to Facility)

Key Points:

  • TENANT is the foundation for everything
  • FACILITIES and PRACTITIONERS are independent branches
  • PRACTITIONER ROLE is the bridge that links them together
  • User account is only needed for practitioners, not facilities

Common Issues & Solutions

Issue 1: Practitioner without User Account

Problem: Practitioner created but no login access
Solution: Create identity.users record first, then link to practitioner

Issue 2: Facility without Organization

Problem: Facility created without organization parent
Solution: Always create organization first, then facility with organization_id

Issue 3: Patient not linked to Facility

Problem: Patient record exists but can't be found at facility
Solution: Create clinical.patient_facilities link record

Issue 4: Practitioner can't access tenant data

Problem: Practitioner profile exists but no tenant membership
Solution: Create identity.user_memberships record with appropriate role

Issue 5: Missing tenant_id in API requests

Problem: API returns "tenant_id is required"
Solution: Always include tenant_id in creation requests for facilities, practitioners, patients


This mapping guide helps developers understand exactly which tables are affected when creating entities, useful for debugging, testing, and understanding system data flow.

On this page