Therapist Management
Therapist Management provides comprehensive therapist profile management, approval workflows, and child assignment capabilities. This system handles therapist lifecycle management with critical business logic for verification, specialization matching, and performance tracking.
Core Concepts
- Approval Workflow: Pending, approved, and rejected therapist statuses
- Specialization Management: Therapist specializations and skill matching
- Document Verification: Upload and verify professional documents
- Child Assignment: Assign therapists to children based on specialization
- Performance Tracking: Monitor therapist performance and client satisfaction
Web/Admin Capabilities
1) List & Filter by Status
Business Rules:
- Status Tabs: All therapists and Pending approval tabs
- Filter Options: Filter by gender, approval status, activity status, and specialization
- Search Capabilities: Search by name, unique code, or therapist ID
- Sorting: Sort by name, contact, experience, and other fields
- Approval Management: Handle pending therapist approvals and rejections
Implementation:
// Status-based tab organization
enum TherapistListingTabs {
all,
pending,
}
const validTab = useCallback(
(
currentTab: string | undefined | null,
): keyof typeof TherapistListingTabs => {
if (currentTab) {
const validCurrentTab =
Object.keys(TherapistListingTabs).includes(currentTab);
if (validCurrentTab) {
return currentTab as keyof typeof TherapistListingTabs;
} else {
return TherapistListingTabs[0] as keyof typeof TherapistListingTabs;
}
} else {
return TherapistListingTabs[0] as keyof typeof TherapistListingTabs;
}
},
[],
);
// Search implementation with UUID detection
const search: Therapist_Bool_Exp = isUUID(searchString)
? {
_or: [
{ user: { name: { _ilike: `%${searchString}%` } } },
{ id: { _eq: searchString } },
{ unique_code: { _ilike: `%${searchString}%` } },
],
}
: {
_or: [
{ user: { name: { _ilike: `%${searchString}%` } } },
{ unique_code: { _ilike: `%${searchString}%` } },
],
};
2) Therapist Profile Management
Therapist Management Business Rules:
- Profile Creation: Create new therapist profiles with professional details
- Document Upload: Upload and verify professional documents
- Specialization Assignment: Assign relevant specializations to therapists
- Approval Workflow: Review and approve/reject therapist applications
- Status Management: Manage therapist active/inactive status
Therapist Profile Logic:
// Therapist profile validation
const validateTherapistProfile = (therapist: TherapistInput) => {
const errors: string[] = [];
if (!therapist.user_id) {
errors.push('User association is required');
}
if (!therapist.specializations || therapist.specializations.length === 0) {
errors.push('At least one specialization is required');
}
if (!therapist.experience_years || therapist.experience_years < 0) {
errors.push('Valid experience years is required');
}
if (!therapist.qualification) {
errors.push('Qualification is required');
}
return errors;
};
// Document verification workflow
const verifyDocuments = (therapistId: string, documents: DocumentInput[]) => {
return updateTherapistMutation({
variables: {
therapist_id: therapistId,
documents: documents,
verification_status: 'VERIFIED',
},
});
};
GraphQL Implementation:
import { gql, ApolloClient } from '@apollo/client';
const GET_THERAPIST_LIST = gql`
query GetTherapistList(
$limit: Int
$offset: Int
$where: therapist_bool_exp
$order_by: [therapist_order_by!]
) {
therapists(
limit: $limit
offset: $offset
where: $where
order_by: $order_by
) {
id
unique_code
experience_years
qualification
approval_status
status
created_at
user {
id
name
email
phone
gender
last_active
}
therapist_specialities {
speciality {
id
title
}
}
documents {
id
document_type
file_url
verification_status
}
}
therapists_aggregate(where: $where) {
aggregate {
count
}
}
}
`;
const DELETE_THERAPISTS = gql`
mutation DeleteTherapists($therapist_ids: [uuid!]!) {
deleteTherapists(therapist_ids: $therapist_ids) {
success
message
}
}
`;
const UPDATE_THERAPIST_STATUS = gql`
mutation UpdateTherapistStatus(
$therapist_id: uuid!
$approval_status: approval_status_enum!
) {
update_therapist(
where: { id: { _eq: $therapist_id } }
_set: { approval_status: $approval_status }
) {
affected_rows
}
}
`;
const ASSIGN_CHILD_TO_THERAPIST = gql`
mutation AssignChildToTherapist($therapist_id: uuid!, $child_id: uuid!) {
insert_therapist_child_assignment(
objects: { therapist_id: $therapist_id, child_id: $child_id }
) {
affected_rows
}
}
`;
async function getTherapistList(
client: ApolloClient<unknown>,
variables: {
limit: number;
offset: number;
where?: Therapist_Bool_Exp;
order_by?: Therapist_Order_By[];
},
) {
const { data } = await client.query({
query: GET_THERAPIST_LIST,
variables,
fetchPolicy: 'cache-and-network',
});
return {
therapists: data.therapists,
totalCount: data.therapists_aggregate.aggregate?.count || 0,
};
}
async function updateTherapistStatus(
client: ApolloClient<unknown>,
therapistId: string,
approvalStatus: Approval_Status_Enum,
) {
const { data } = await client.mutate({
mutation: UPDATE_THERAPIST_STATUS,
variables: {
therapist_id: therapistId,
approval_status: approvalStatus,
},
});
return data.update_therapist?.affected_rows || 0;
}
3) Approval Workflow Management
Approval Workflow Business Rules:
- Document Review: Review uploaded professional documents
- Approval Decision: Approve or reject therapist applications
- Rejection Reasons: Provide specific reasons for rejection
- Status Tracking: Track approval status and timeline
- Notification System: Notify therapists of approval decisions
Approval Logic:
// Approval workflow validation
const validateApprovalDecision = (
therapistId: string,
decision: 'APPROVED' | 'REJECTED',
reason?: string,
) => {
const errors: string[] = [];
if (!therapistId) {
errors.push('Therapist ID is required');
}
if (decision === 'REJECTED' && !reason?.trim()) {
errors.push('Rejection reason is required');
}
// Check if therapist has required documents
// Check if therapist meets minimum requirements
return errors;
};
// Process approval decision
const processApprovalDecision = (
therapistId: string,
decision: 'APPROVED' | 'REJECTED',
reason?: string,
) => {
return updateTherapistStatus(therapistId, decision).then(() => {
if (decision === 'REJECTED' && reason) {
return addRejectionReason(therapistId, reason);
}
});
};
// Get pending therapists for review
const getPendingTherapists = () => {
return getTherapistList({
where: { approval_status: { _eq: 'PENDING' } },
order_by: [{ created_at: 'asc' }],
});
};
4) Child Assignment Management
Child Assignment Business Rules:
- Specialization Matching: Match therapists with children based on specializations
- Workload Management: Consider therapist current workload and capacity
- Assignment History: Track assignment history and changes
- Performance Monitoring: Monitor therapist-child relationship effectiveness
- Bulk Assignment: Assign multiple children to therapists
Assignment Logic:
// Child assignment validation
const validateChildAssignment = (therapistId: string, childId: string) => {
const errors: string[] = [];
if (!therapistId) {
errors.push('Therapist ID is required');
}
if (!childId) {
errors.push('Child ID is required');
}
// Check if therapist is approved and active
// Check if therapist has appropriate specializations
// Check if assignment already exists
// Check therapist workload capacity
return errors;
};
// Get available therapists for child
const getAvailableTherapists = (childId: string) => {
return getTherapistList({
where: {
_and: [
{ approval_status: { _eq: 'APPROVED' } },
{ status: { _eq: 'ACTIVE' } },
// Add specialization matching logic
],
},
});
};
// Bulk child assignment
const assignMultipleChildren = (therapistId: string, childIds: string[]) => {
return Promise.all(
childIds.map((childId) => assignChildToTherapist(therapistId, childId)),
);
};
5) Therapist Performance & Analytics
Performance Tracking Business Rules:
- Session Tracking: Track therapy sessions and attendance
- Client Satisfaction: Monitor parent and child satisfaction ratings
- Outcome Measurement: Measure therapy outcomes and progress
- Performance Metrics: Calculate performance indicators and KPIs
- Reporting: Generate performance reports and analytics
Performance Analytics Implementation:
// Therapist performance metrics
interface TherapistPerformance {
therapist_id: string;
total_sessions: number;
completed_sessions: number;
attendance_rate: number;
average_rating: number;
client_satisfaction: number;
outcome_scores: OutcomeScore[];
monthly_stats: MonthlyStats[];
}
// Calculate performance metrics
const calculatePerformanceMetrics = (
therapistId: string,
dateRange: DateRange,
) => {
return Promise.all([
getSessionStats(therapistId, dateRange),
getClientRatings(therapistId, dateRange),
getOutcomeScores(therapistId, dateRange),
]).then(([sessions, ratings, outcomes]) => {
return {
therapist_id: therapistId,
total_sessions: sessions.total,
completed_sessions: sessions.completed,
attendance_rate: (sessions.completed / sessions.total) * 100,
average_rating: ratings.average,
client_satisfaction: ratings.satisfaction,
outcome_scores: outcomes,
};
});
};
// Generate performance report
const generatePerformanceReport = (therapistId: string, period: string) => {
return getTherapistDetails(therapistId).then((therapist) => {
return calculatePerformanceMetrics(therapistId, getDateRange(period)).then(
(metrics) => {
return {
therapist: therapist,
metrics: metrics,
period: period,
generated_at: new Date().toISOString(),
};
},
);
});
};
Data Flow (Web ↔ Backend)
Critical Business Logic Flow:
- Therapist Listing: Load therapists → Apply status filtering → Search → Sort → Paginate
- Profile Management: Create/Edit therapist → Validate data → Upload documents → Assign specializations
- Approval Workflow: Review documents → Make approval decision → Update status → Notify therapist
- Child Assignment: Select therapist → Choose children → Validate compatibility → Create assignments
GraphQL Operations with Business Rules:
| Action | Operation | Business Rules |
|---|---|---|
| List Therapists | getTherapistList(where, order_by) | Status-based filtering, search capabilities |
| Create Therapist | createTherapist(input) | Document validation, specialization assignment |
| Update Status | updateTherapistStatus(therapist_id, status) | Approval workflow validation |
| Assign Child | assignChildToTherapist(therapist_id, child_id) | Specialization matching, workload validation |
| Delete Therapists | deleteTherapists(therapist_ids) | Bulk deletion with confirmation |
Error Handling & Validation:
- Therapist Not Found: "Therapist not found or access denied"
- Invalid Specialization: "Therapist specialization does not match requirements"
- Document Missing: "Required documents not uploaded"
- Assignment Conflict: "Therapist already assigned to this child"
- Workload Exceeded: "Therapist workload capacity exceeded"
Security & Access Control
- Admin-Only Access: Only admins can manage therapist profiles and assignments
- Document Security: Professional documents protected by access controls
- Approval Workflow: Multi-step approval process with audit trail
- Data Privacy: Therapist data protected by role-based permissions
- Assignment Controls: Child assignments require proper validation and authorization