# CuraHealthLine - Unified Search & Filter Architecture

## ✅ COMPLETED COMPONENTS

### 1. Core Filter Architecture
- **BaseFilter** (`app/Filters/BaseFilter.php`) - Abstract base class with:
  - Parameter extraction & normalization
  - Common filter methods (keyword search, exact match, LIKE, boolean, range)
  - Validation framework
  - Active filter labels for UI

- **SearchFilterInterface** (`app/Contracts/SearchFilterInterface.php`) - Contract ensuring consistent behavior

### 2. Domain-Specific Filters (All Implemented)

#### JobFilters (`app/Filters/JobFilters.php`)
Supports: keyword, country, city, state, specialty, job_type, shift, experience_min/max, salary_min/max, visa_sponsorship, relocation_support, sign_on_bonus, licensure_support, health_insurance, paid_pto, housing, employer_id, license, work_mode, sort

#### NurseFilters (`app/Filters/NurseFilters.php`)
Supports: keyword, country, city, specialty, secondary_specialty, experience_min/max, nclex_status, ready_to_relocate, visa_needed, language, license_country, preferred_shift, ielts_min, oet_min, sort

#### ConnectPostFilters (`app/Filters/ConnectPostFilters.php`)
Supports: feed (all/network/mine), keyword, category_id, specialty, country, nclex_status, sort (recent/top/trending/most_liked/most_commented)

#### EmployerFilters (`app/Filters/EmployerFilters.php`)
Supports: keyword, country, city, type, industry, reputation_min, risk_max, status, verified_only, sort

### 3. Search Services (All Implemented)

#### JobSearchService (`app/Services/JobSearchService.php`)
- Paginated search with optimized queries
- Eager loads employer relationships
- Available filter options for UI
- Metadata (count, active filters)
- Helper methods: getTrending(), byEmployer(), getSimilar()

#### NurseSearchService (`app/Services/NurseSearchService.php`)
- Paginated nurse directory search
- Filters only completed, active profiles
- Available options for dropdowns
- Helper methods: getRecentlyJoined(), bySpecialty(), byCountry(), readyToRelocate()
- Statistics method

#### ConnectPostSearchService (`app/Services/ConnectPostSearchService.php`)
- Feed mode support (all/network/mine)
- Engagement-based sorting
- Category filtering
- Helper methods: getTrending(), getTop(), byCategory(), byUser()
- Statistics method

#### EmployerSearchService (`app/Services/EmployerSearchService.php`)
- Employer directory with reputation filtering
- Active jobs count
- Helper methods: getTopRated(), getVerified(), byCountry(), getMostActive()
- Statistics method

### 4. Database Migration (`database/migrations/2025_12_02_164843_add_comprehensive_search_indexes_to_all_tables.php`)
Comprehensive indexes for:
- **job_postings**: 19 indexes (single + composite + fulltext)
- **nurse_profiles**: 15 indexes
- **nurse_posts**: 11 indexes
- **employers**: 11 indexes
- **users**: 2 indexes
- **nurse_connections**: 5 indexes (for network feed)
- **forum_categories**: 2 indexes

## 🚧 REMAINING TASKS

### 5. Refactor Controllers (NOT YET DONE)

You need to update these controllers to use the new architecture:

#### JobController (`app/Http/Controllers/JobController.php`)
```php
use App\Filters\JobFilters;
use App\Services\JobSearchService;

public function index(Request $request)
{
    $filters = new JobFilters($request);
    $searchService = new JobSearchService($filters);
    
    $jobs = $searchService->perPage(20)->search();
    $availableOptions = $searchService->getAvailableOptions();
    $metadata = $searchService->getMetadata();
    
    return view('jobs.index', [
        'jobs' => $jobs,
        'filters' => $filters->toArray(),
        'activeFilters' => $filters->getActiveFilterLabels(),
        'availableCountries' => $availableOptions['countries'],
        'availableSpecialties' => $availableOptions['specialties'],
        'availableLicenses' => $availableOptions['licenses'],
        'availableWorkModes' => $availableOptions['work_modes'],
        'availableJobTypes' => $availableOptions['job_types'],
        'metadata' => $metadata,
    ]);
}
```

#### NurseController (Create if doesn't exist, or update existing)
```php
use App\Filters\NurseFilters;
use App\Services\NurseSearchService;

public function index(Request $request)
{
    $filters = new NurseFilters($request);
    $searchService = new NurseSearchService($filters);
    
    $nurses = $searchService->perPage(24)->search();
    $availableOptions = $searchService->getAvailableOptions();
    
    return view('nurses.index', [
        'nurses' => $nurses,
        'filters' => $filters->toArray(),
        'activeFilters' => $filters->getActiveFilterLabels(),
        'availableCountries' => $availableOptions['countries'],
        'availableSpecialties' => $availableOptions['specialties'],
        'nclexStatuses' => $availableOptions['nclex_statuses'],
        'metadata' => $searchService->getMetadata(),
    ]);
}
```

#### ConnectController (`app/Http/Controllers/NurseConnect/ConnectController.php` or similar)
```php
use App\Filters\ConnectPostFilters;
use App\Services\ConnectPostSearchService;

public function index(Request $request)
{
    $filters = new ConnectPostFilters($request);
    $filters->setCurrentUserId(auth()->id());
    
    $searchService = new ConnectPostSearchService($filters);
    $posts = $searchService->perPage(15)->search();
    $availableOptions = $searchService->getAvailableOptions();
    
    return view('connect.index', [
        'posts' => $posts,
        'filters' => $filters->toArray(),
        'activeFilters' => $filters->getActiveFilterLabels(),
        'categories' => $availableOptions['categories'],
        'feedModes' => $availableOptions['feed_modes'],
        'sortOptions' => $availableOptions['sort_options'],
        'metadata' => $searchService->getMetadata(),
    ]);
}
```

#### EmployerController (Create new or update)
```php
use App\Filters\EmployerFilters;
use App\Services\EmployerSearchService;

public function index(Request $request)
{
    $filters = new EmployerFilters($request);
    $searchService = new EmployerSearchService($filters);
    
    $employers = $searchService->perPage(20)->search();
    $availableOptions = $searchService->getAvailableOptions();
    
    return view('employers.index', [
        'employers' => $employers,
        'filters' => $filters->toArray(),
        'activeFilters' => $filters->getActiveFilterLabels(),
        'availableCountries' => $availableOptions['countries'],
        'availableTypes' => $availableOptions['types'],
        'availableStatuses' => $availableOptions['statuses'],
        'metadata' => $searchService->getMetadata(),
    ]);
}
```

### 6. Run Migration
```bash
php artisan migrate
```

This will add all the performance indexes to your database.

### 7. Update Blade Views

Update your views to use the standardized data structure:

**jobs/index.blade.php** - Already exists, update to use new filter structure
**nurses/index.blade.php** - Create new or update
**connect/index.blade.php** - Update existing
**employers/index.blade.php** - Create if public listing needed

All views should receive:
- `$results` (paginated collection)
- `$filters` (current filter values array)
- `$activeFilters` (array of label strings for "active filter chips")
- `$available[X]` (dropdown options)
- `$metadata` (total count, etc.)

### 8. Testing

Create test scripts to validate:
- URL parameters work correctly
- Filters combine properly (AND logic)
- Sorting works
- Pagination maintains filters
- Database uses indexes (run EXPLAIN on queries)

## 📊 BENEFITS OF THIS ARCHITECTURE

1. **Scalable** - Easy to add new filters (just add to `$allowedFilters` array)
2. **Consistent** - Same pattern across all domains
3. **Performant** - Proper indexes, eager loading, no N+1
4. **Clean URLs** - `/jobs?country=US&specialty=ICU&visa_sponsorship=1`
5. **Maintainable** - No duplicated query logic
6. **Testable** - Services and filters are unit-testable
7. **Type-safe** - Proper validation and normalization

## 🔧 HOW TO EXTEND

### Adding a New Filter

1. Add to `$allowedFilters` array
2. Add to appropriate category (`$booleanFilters`, `$numericFilters`)
3. Add filter logic in `apply()` method
4. Add label in `getActiveFilterLabels()`
5. Add validation in `validate()` if needed

### Example: Adding "remote" filter to jobs

```php
// In JobFilters.php
protected array $allowedFilters = [
    // ... existing filters
    'remote',
];

protected array $booleanFilters = [
    // ... existing
    'remote',
];

// In apply() method
$this->applyBooleanFilter($query, 'remote', $this->get('remote'));

// In getActiveFilterLabels()
if ($this->get('remote') === true) {
    $labels[] = 'Remote work';
}
```

## 📚 NEXT STEPS FOR YOU

1. ✅ Run the migration to add indexes
2. ✅ Refactor JobController to use JobSearchService
3. ✅ Create/update NurseController for nurse directory
4. ✅ Update ConnectController for feed
5. ✅ Create EmployerController if needed
6. ✅ Update all Blade views with new data structure
7. ✅ Test all filters with real data
8. ✅ Monitor query performance with database profiling
9. ✅ Consider adding caching for dropdown options if needed
10. ✅ Document API for any public-facing endpoints

## 🎯 URL EXAMPLES

Jobs: `/jobs?country=US&specialty=ICU&experience_min=2&visa_sponsorship=1&sort=salary_desc`

Nurses: `/nurses?country=UK&specialty=Pediatrics&nclex_status=Passed&ready_to_relocate=1`

Connect: `/connect?feed=network&category_id=2&sort=trending`

Employers: `/employers?country=US&type=hospital&reputation_min=80&verified_only=1`
