NDSS CRM Manual / Core Platform / Chapter 6: Client Management
V3.8 · 2024/2025

Chapter 6: Client Management

Client Management is the cornerstone of the NDSS CRM platform, providing comprehensive tools for recording, organising, and managing NDIS participant information. This module handles everything from initial client creation through ongoing care plan management, NDIS funding tracking, goal monitoring, and progress documentation. Built on Next.js and React for the interface with Python and PHP microservices handling business logic, and PostgreSQL for data persistence, the Client Management module is designed to support organisations of any size, from small community providers to large multi-site operations.

6.1 Client List View

The Client List View is the primary entry point for client management. It displays a paginated, searchable, and filterable table of all clients within the organisation. The list supports server-side pagination (20 records per page by default), full-text search, and multi-criteria filtering.

6.1.1 Client List Wireframe

Client List View - Main Page
N NDSS CRM
Dashboard
Clients
Staff
Rostering
Finance
Clients
8 total clients
Client NDIS Number Funding Type Location Intake Date Status
JT
James Thompson
ND-00001
430123456789 Plan Managed Parramatta NSW 01 Feb 2023 Active
MG
Maria Garcia
ND-00002
430234567890 NDIS Managed Blacktown NSW 15 Mar 2023 Active
DL
David Liu
ND-00003
430345678901 Plan Managed Liverpool NSW 22 Apr 2023 Active
SW
Sarah Williams
ND-00004
430456789012 Self Managed Penrith NSW 10 May 2023 Active
JA
James Anderson
ND-00005
430987654321 NDIS Managed Blacktown NSW 01 Jun 2023 On Hold
« 1 2 » Showing 1-5 of 8 clients

6.1.2 Client List Table Columns

Column Data Source Sortable Description
Clientfirst_name + last_name + client_idYesClient avatar (initials), full name, and internal client ID (e.g., ND-00001)
NDIS Numberndis_numberYes12-digit NDIS participant number
Funding Typefunding_typeYesPlan Managed, NDIS Managed, or Self Managed
Locationsuburb + stateYesClient's primary suburb and state
Intake Dateintake_dateYesDate the client was registered in the system
StatusstatusYesCurrent client status badge

6.1.3 Client List API Endpoint

# Python API: GET /api/clients
@app.route('/api/clients', methods=['GET'])
def list_clients():
    org_id = get_current_org_id()
    page = int(request.args.get('page', 1))
    per_page = int(request.args.get('per_page', 20))
    search = request.args.get('search', '')
    status = request.args.get('status', '')
    funding_type = request.args.get('funding_type', '')
    sort_by = request.args.get('sort_by', 'last_name')
    sort_dir = request.args.get('sort_dir', 'asc')

    query = """
        SELECT c.id, c.client_id, c.first_name, c.last_name,
               c.ndis_number, c.funding_type, c.suburb, c.state,
               c.intake_date, c.status, c.created_at
        FROM clients c
        WHERE c.org_id = %s AND c.deleted_at IS NULL
    """
    params = [org_id]

    if search:
        query += """ AND (
            c.search_vector @@ plainto_tsquery('english', %s)
            OR c.ndis_number ILIKE %s
        )"""
        params.extend([search, f'%{search}%'])

    if status:
        query += " AND c.status = %s"
        params.append(status)

    if funding_type:
        query += " AND c.funding_type = %s"
        params.append(funding_type)

    # Sorting (whitelist allowed columns)
    allowed_sorts = ['last_name', 'ndis_number', 'funding_type', 'suburb', 'intake_date', 'status']
    if sort_by in allowed_sorts:
        query += f" ORDER BY c.{sort_by} {sort_dir}"

    # Pagination
    offset = (page - 1) * per_page
    query += " LIMIT %s OFFSET %s"
    params.extend([per_page, offset])

    clients = db.execute(query, params)
    total = db.execute_scalar("SELECT COUNT(*) FROM clients WHERE org_id = %s AND deleted_at IS NULL", [org_id])

    return jsonify({
        'data': clients,
        'pagination': {
            'page': page,
            'per_page': per_page,
            'total': total,
            'total_pages': math.ceil(total / per_page)
        }
    })

6.2 Creating a New Client

New clients are created through a comprehensive multi-step form that captures all essential information required for NDIS service delivery. The form includes validation rules that ensure data integrity, including NDIS number format validation, mandatory field enforcement, and duplicate detection.

6.2.1 Client Creation Form Wireframe

New Client Form - Full Layout
Create New Client

Personal Information

First Name *
Last Name *
Date of Birth *
Gender

NDIS Details

NDIS Number *
Funding Type *

Contact Details

Phone
Email

Address

Street Address
Suburb *
State *
Postcode *

Assignment & Status

Primary Coordinator
Status

Additional Notes

Notes

6.2.2 Form Field Specifications

Field Type Required Validation Rules Database Column
First NameTextYesMin 1 char, max 100 chars, alpha + spaces onlyfirst_name VARCHAR(100)
Last NameTextYesMin 1 char, max 100 chars, alpha + spaces onlylast_name VARCHAR(100)
Date of BirthDateYesMust be a valid past date, not futuredate_of_birth DATE
GenderSelectNoEnum: male, female, non_binary, prefer_not_to_saygender VARCHAR(30)
NDIS NumberTextYesExactly 12 digits, must start with 43, unique per orgndis_number VARCHAR(12) UNIQUE
Funding TypeSelectYesEnum: plan_managed, ndis_managed, self_managedfunding_type VARCHAR(30)
PhoneTextNoAustralian phone format validationphone VARCHAR(20)
EmailEmailNoValid email formatemail VARCHAR(255)
Street AddressTextNoMax 255 charsaddress_line1 VARCHAR(255)
SuburbTextYesMax 100 charssuburb VARCHAR(100)
StateSelectYesAustralian state/territory enumstate VARCHAR(3)
PostcodeTextYes4-digit Australian postcodepostcode VARCHAR(4)
Primary CoordinatorSelectNoValid staff member with coordinator rolecoordinator_id UUID FK
StatusSelectYesEnum: active, on_hold, inactive, dischargedstatus VARCHAR(20)
NotesTextareaNoMax 5000 charsnotes TEXT

6.2.3 NDIS Number Validation

// NDIS Number Validation (TypeScript)
export function validateNDISNumber(value: string): ValidationResult {
  // Remove spaces and hyphens
  const cleaned = value.replace(/[\s-]/g, '');

  if (cleaned.length !== 12) {
    return { valid: false, error: 'NDIS number must be exactly 12 digits' };
  }

  if (!/^\d{12}$/.test(cleaned)) {
    return { valid: false, error: 'NDIS number must contain only digits' };
  }

  if (!cleaned.startsWith('43')) {
    return { valid: false, error: 'NDIS number must start with 43' };
  }

  return { valid: true, formatted: cleaned };
}

// Duplicate detection
export async function checkDuplicateNDIS(ndisNumber: string, orgId: string): Promise<boolean> {
  const response = await fetch(`/api/clients/check-ndis?number=${ndisNumber}&org_id=${orgId}`);
  const data = await response.json();
  return data.exists;
}
Duplicate Detection

When creating a new client, the system automatically checks for duplicate NDIS numbers within the organisation. If a match is found, the user is warned and must confirm they want to proceed. This prevents accidental duplicate records that could lead to billing and compliance issues.

6.3 Client Profile

The Client Profile page provides a comprehensive view of all information related to a specific client. It is organised into a tabbed interface with the following sections: Overview, Goals, Progress Notes, Funding, Care Plan, and Documents. The profile page is accessible by clicking on a client's name from the Client List or any other reference to the client throughout the platform.

6.3.1 Client Profile Wireframe

Client Profile - Overview Tab
JT
James Thompson
ND-00001 · NDIS: 430123456789 · DOB: 15 Mar 1985 (41 years)
Active Plan Managed
Overview Goals Progress Notes Funding Care Plan Documents
Personal Information
Full Name James Thompson
Date of Birth 15 Mar 1985
Gender Male
Phone 0412 345 678
Email james.t@email.com
Address 42 Smith St, Parramatta NSW 2150
NDIS Details
NDIS Number 430123456789
Funding Type Plan Managed
Plan Start 01 Feb 2024
Plan End 31 Jan 2027
Coordinator Jane Smith
Intake Date 01 Feb 2023
Emergency Contacts
Name Relationship Phone Email Priority
Robert Thompson Father 0423 456 789 robert.t@email.com Primary
Emily Thompson Sister 0434 567 890 emily.t@email.com Secondary

6.3.2 Profile Tab Summary

Tab Content Key Features
OverviewPersonal info, NDIS details, emergency contacts, recent activityQuick edit, status badge, coordinator info
GoalsActive and completed goals with progress trackingProgress bars, goal categories, review dates
Progress NotesChronological notes from shifts and interactionsNote types, linked shifts, author tracking
FundingNDIS budget allocation and utilisationCategory breakdowns, utilisation bars, alerts
Care PlanActive care plan with support categoriesRisk assessments, review scheduling, version history
DocumentsUploaded files and generated documentsFile categories, upload/download, expiry tracking

6.4 NDIS Funding Management

The NDIS Funding Management section within the client profile provides detailed tracking of the client's NDIS plan budget, category allocations, and utilisation rates. This is critical for ensuring that service delivery stays within budget and that funding is optimally distributed across support categories.

6.4.1 Funding Overview Wireframe

NDIS Funding - Client Profile Funding Tab
NDIS Plan Funding - James Thompson Plan Period: 01 Feb 2024 – 31 Jan 2027
$85,200
Total Plan Budget
$52,430
Spent to Date
$32,770
Remaining
61.5%
Utilisation

Category Breakdown

Category Budget Spent Remaining Utilisation
Core Supports $52,000 $38,480 $13,520
74%
Capacity Building $25,000 $11,200 $13,800
45%
Capital Supports $8,200 $2,750 $5,450
34%

6.4.2 Funding Alert Thresholds

Utilisation Level Colour Indicator Alert Behaviour
0% – 60%GreenNo alert - normal utilisation
61% – 80%AmberInformational notice to coordinator
81% – 95%OrangeWarning alert to coordinator and admin
96% – 100%RedCritical alert - immediate review required
> 100%Red (Overspent)System blocks new service bookings, escalates to finance

6.4.3 Funding Calculation Logic

# PHP Funding Calculation Service
class FundingCalculator
{
    public function calculateUtilisation(string $clientId, string $categoryId): array
    {
        $plan = $this->planRepository->getActivePlan($clientId);

        if (!$plan) {
            throw new PlanNotFoundException("No active NDIS plan found for client {$clientId}");
        }

        $budget = $this->budgetRepository->getCategoryBudget($plan->id, $categoryId);
        $spent = $this->invoiceRepository->getTotalSpentByCategory($plan->id, $categoryId);

        $remaining = $budget->amount - $spent;
        $utilisation = ($budget->amount > 0) ? ($spent / $budget->amount) * 100 : 0;

        // Calculate projected utilisation at plan end
        $daysElapsed = now()->diffInDays($plan->start_date);
        $totalDays = $plan->end_date->diffInDays($plan->start_date);
        $dailyBurnRate = ($daysElapsed > 0) ? $spent / $daysElapsed : 0;
        $projectedTotal = $dailyBurnRate * $totalDays;
        $projectedUtilisation = ($budget->amount > 0)
            ? ($projectedTotal / $budget->amount) * 100
            : 0;

        return [
            'budget' => $budget->amount,
            'spent' => $spent,
            'remaining' => $remaining,
            'utilisation_percent' => round($utilisation, 1),
            'projected_utilisation' => round($projectedUtilisation, 1),
            'daily_burn_rate' => round($dailyBurnRate, 2),
            'alert_level' => $this->getAlertLevel($utilisation),
        ];
    }

    private function getAlertLevel(float $utilisation): string
    {
        return match(true) {
            $utilisation > 100 => 'overspent',
            $utilisation > 95  => 'critical',
            $utilisation > 80  => 'warning',
            $utilisation > 60  => 'notice',
            default            => 'normal',
        };
    }
}

6.5 Goal Tracking

Goal Tracking enables support coordinators and clinicians to define, monitor, and review client goals as part of their NDIS plan. Each goal has a measurable target, progress percentage, category, and review schedule.

6.5.1 Goals List Wireframe

Client Goals - Goals Tab
Goals
Goal Category Progress Status Review Date
Improve daily living independence Core Supports
65%
Active 15 May 2024
Community participation - weekly social group Capacity Building
40%
Active 01 Jun 2024
Mobility improvement - walking 500m Core Supports
100%
Completed 01 Mar 2024
Employment readiness skills Capacity Building
10%
On Hold 01 Aug 2024

6.5.2 Goal Data Model

-- PostgreSQL: client_goals table
CREATE TABLE client_goals (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  client_id       UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
  org_id          UUID NOT NULL REFERENCES organisations(id),
  title           VARCHAR(500) NOT NULL,
  description     TEXT,
  category        VARCHAR(50) NOT NULL,  -- 'core_supports', 'capacity_building', 'capital'
  progress        INTEGER DEFAULT 0 CHECK (progress >= 0 AND progress <= 100),
  status          VARCHAR(20) DEFAULT 'active',  -- 'active', 'completed', 'on_hold', 'cancelled'
  target_date     DATE,
  review_date     DATE,
  created_by      UUID REFERENCES users(id),
  completed_at    TIMESTAMPTZ,
  notes           TEXT,
  created_at      TIMESTAMPTZ DEFAULT NOW(),
  updated_at      TIMESTAMPTZ DEFAULT NOW()
);

6.6 Progress Notes

Progress Notes are chronological records of interactions, observations, and service delivery details for a client. They are typically created during or after a shift and serve as the primary documentation trail for NDIS compliance and auditing purposes.

6.6.1 Note Types

Note Type Description Required Fields Created By
GeneralStandard shift or interaction notesContent, date, authorSupport Workers, Coordinators
MedicalHealth-related observations and updatesContent, date, author, severityClinical Staff, Support Workers
BehaviouralBehavioural observations and incidentsContent, date, author, behaviour type, intensitySupport Workers, Clinicians
IncidentNotes linked to formal incident reportsContent, date, author, incident IDAll staff
Goal UpdateProgress updates on specific goalsContent, date, author, goal ID, progress changeCoordinators, Clinicians
Family CommunicationRecords of communication with family/guardiansContent, date, author, contact personCoordinators

6.6.2 Progress Notes Wireframe

Progress Notes - Notes Tab
Progress Notes
All Notes General Medical Behavioural Incident
04 Apr 2024, 2:30 PM
General Shift #SH-0234
Client participated well in morning routine. Showed improved independence with meal preparation. Required minimal prompting for personal hygiene tasks.
By: Mark Wilson (Support Worker)
03 Apr 2024, 11:00 AM
Medical
Blood pressure reading: 130/85. Slightly elevated. Advised client to rest and will monitor at next visit. GP appointment scheduled for 10 Apr.
By: Sarah Chen (Clinical Lead)
01 Apr 2024, 4:00 PM
Goal Update
Updated "Daily living independence" goal from 60% to 65%. Client successfully cooked a simple meal (pasta) with only verbal prompts. Major milestone achieved.
By: Jane Smith (Coordinator)

6.7 Care Plan Management

Care Plans define the comprehensive support framework for each client, including support categories, service schedules, risk assessments, and review timelines. Care plans are versioned documents that are reviewed and updated at regular intervals in line with NDIS plan review cycles.

6.7.1 Care Plan Components

Component Description Review Frequency
Support CategoriesThe NDIS support categories covered (Core, Capacity Building, Capital) with specific line itemsQuarterly
Service ScheduleRegular service delivery schedule including days, times, and service typesMonthly
Risk AssessmentIdentified risks (health, behavioural, environmental) with mitigation strategiesQuarterly or on change
Goals & OutcomesLinked goals from the Goals module with expected outcomesQuarterly
Communication PreferencesHow the client prefers to communicate, language needs, accessibility requirementsAnnually
Emergency ProtocolsSpecific emergency response procedures for this clientAnnually
Medication ManagementCurrent medications, administration instructions, pharmacy detailsMonthly or on change
Dietary RequirementsAllergies, dietary restrictions, meal preferencesAnnually or on change

6.7.2 Care Plan Versioning

Every modification to a care plan creates a new version. The system maintains a complete version history for audit purposes. Previous versions are read-only but can be viewed for comparison. The versioning is implemented using a combination of PostgreSQL row versioning and a PHP service that manages version diffs.

-- PostgreSQL: care_plan_versions table
CREATE TABLE care_plan_versions (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  care_plan_id    UUID NOT NULL REFERENCES care_plans(id),
  version_number  INTEGER NOT NULL,
  content         JSONB NOT NULL,
  change_summary  TEXT,
  created_by      UUID REFERENCES users(id),
  approved_by     UUID REFERENCES users(id),
  approved_at     TIMESTAMPTZ,
  created_at      TIMESTAMPTZ DEFAULT NOW(),

  UNIQUE(care_plan_id, version_number)
);

6.8 Client Status Management

Client status determines the operational state of a client within NDSS CRM and affects what actions can be performed on their record.

6.8.1 Status Definitions

Status Badge Description Allowed Actions
Active Active Client is currently receiving services. All modules are fully functional. All: shift booking, invoicing, goal tracking, notes
On Hold On Hold Temporarily paused. No new shifts can be booked but existing scheduled shifts remain. View only, notes, goal updates. No new shifts or invoices.
Inactive Inactive No longer actively receiving services but record is retained for reference. View only. No operational actions.
Discharged Discharged Formally discharged from the service. Record is archived. View only. Requires admin to reactivate.

6.8.2 Status Transition Rules

From To Required By Conditions
ActiveOn HoldCoordinator or AdminNo active shifts in next 24 hours, or admin override
ActiveInactiveAdmin onlyAll pending invoices resolved, no upcoming shifts
ActiveDischargedAdmin onlyDischarge form completed, all billing finalised
On HoldActiveCoordinator or AdminNone (immediate)
On HoldInactiveAdmin onlyOn hold for more than 90 days, or admin decision
InactiveActiveAdmin onlyValid NDIS plan required, coordinator assigned
DischargedActiveSuper Admin onlyRequires new intake process and approval

6.9 Client Search & Filtering

The Client Management module supports comprehensive search and filtering capabilities to help users quickly locate client records. Searching leverages PostgreSQL full-text search with GIN indexes for fast, relevant results.

6.9.1 Search Capabilities

Search Method Examples Implementation
Name Search"James", "Thompson", "James Thompson"Full-text search on first_name, last_name
NDIS Number"430123456789", "4301234"ILIKE prefix match on ndis_number
Client ID"ND-00001"Exact match on client_id
Suburb"Parramatta", "Blacktown"Full-text search on suburb
Phone"0412345678"Normalised phone number match
Email"james.t@email.com"ILIKE match on email

6.9.2 Filter Options

Filter Options Default Multi-select
StatusActive, On Hold, Inactive, DischargedAllYes
Funding TypePlan Managed, NDIS Managed, Self ManagedAllYes
CoordinatorList of active coordinatorsAllYes
Location (State)NSW, VIC, QLD, WA, SA, TAS, ACT, NTAllYes
Intake Date RangeCustom date range pickerAll timeN/A
Plan ExpiryExpiring in 30/60/90 days, ExpiredAllNo

6.9.3 Full-Text Search Index Configuration

-- PostgreSQL: Full-text search configuration for clients
ALTER TABLE clients ADD COLUMN search_vector tsvector;

CREATE FUNCTION update_client_search_vector() RETURNS trigger AS $$
BEGIN
  NEW.search_vector :=
    setweight(to_tsvector('english', COALESCE(NEW.first_name, '')), 'A') ||
    setweight(to_tsvector('english', COALESCE(NEW.last_name, '')), 'A') ||
    setweight(to_tsvector('english', COALESCE(NEW.ndis_number, '')), 'B') ||
    setweight(to_tsvector('english', COALESCE(NEW.suburb, '')), 'C') ||
    setweight(to_tsvector('english', COALESCE(NEW.email, '')), 'D') ||
    setweight(to_tsvector('english', COALESCE(NEW.notes, '')), 'D');
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER client_search_vector_update
  BEFORE INSERT OR UPDATE ON clients
  FOR EACH ROW EXECUTE FUNCTION update_client_search_vector();

CREATE INDEX idx_clients_search ON clients USING GIN(search_vector);
Performance Tip

The full-text search index is updated automatically via the PostgreSQL trigger shown above. For organisations with more than 10,000 clients, consider implementing a dedicated search service using Elasticsearch or a similar tool, with the Python microservice handling the indexing pipeline. The GIN index provides excellent performance for most use cases up to that threshold.

← Chapter 5: Dashboard & Navigation Chapter 7: Staff Management →