# Hierarchical Access Control Implementation

## Overview
This document describes the hierarchical access control system implemented across all modules (Attendance, Patrol, Geofencing, Transit, and Reports) to ensure employees can only access data based on their assigned state, zone, district, and school.

## Architecture

### Hierarchy Levels
The system follows a 4-level hierarchy:
1. **State** (highest level) - State Managers
2. **Zone** - Zone Managers  
3. **District** - District Managers
4. **School** (lowest level) - School HM/HR and Employees

### Core Components

#### 1. HierarchicalAccessService (`app/Services/HierarchicalAccessService.php`)
Central service for managing hierarchical access control.

**Key Methods:**
- `getHierarchyLevel(User $user)` - Returns the hierarchy level (1-6) for a user
- `canViewUser(User $viewer, User $target)` - Checks if viewer can see target user's data
- `canEditUser(User $viewer, User $target)` - Checks if viewer can edit target user's data
- `isInScope(User $viewer, User $target)` - Checks if target is within viewer's scope
- `applySchoolScope(Builder $query, User $viewer)` - Applies school-level filtering to queries
- `getAccessibleSchoolIds(User $user)` - Returns array of accessible school IDs
- `getAccessibleDistrictIds(User $user)` - Returns array of accessible district IDs
- `getAccessibleZoneIds(User $user)` - Returns array of accessible zone IDs
- `getAccessibleStateIds(User $user)` - Returns array of accessible state IDs

#### 2. HasHierarchicalScope Trait (`app/Traits/HasHierarchicalScope.php`)
Trait that can be applied to models to automatically apply hierarchical filtering.

**Usage:**
```php
use App\Traits\HasHierarchicalScope;

class Attendance extends Model
{
    use HasHierarchicalScope;
}

// In controller:
$attendances = Attendance::byHierarchicalAccess(auth()->user())->get();
```

#### 3. CheckHierarchicalAccess Middleware (`app/Http/Middleware/CheckHierarchicalAccess.php`)
Validates that the authenticated user has proper hierarchical access to requested resources.

**Usage in Routes:**
```php
Route::middleware(['hierarchical.access:user'])->group(function () {
    Route::get('/users/{user}', [UserController::class, 'show']);
});

Route::middleware(['hierarchical.access:school'])->group(function () {
    Route::get('/schools/{school}', [SchoolController::class, 'show']);
});
```

#### 4. EnforceSchoolScope Middleware (`app/Http/Middleware/EnforceSchoolScope.php`)
Automatically filters data to only show records from schools accessible to the current user.

**Usage in Routes:**
```php
Route::middleware(['enforce.school.scope'])->group(function () {
    Route::resource('attendance', AttendanceController::class);
});
```

## User Model Integration

The User model (`app/Models/User.php`) includes:

### Hierarchical Fields
- `state_id` - Assigned state
- `zone_id` - Assigned zone
- `district_id` - Assigned district
- `school_id` - Assigned school

### Key Methods
- `scopeByHierarchicalAccess($query, User $viewer)` - Filters users based on hierarchy
- `getAllowedServiceIds()` - Returns accessible service IDs based on hierarchy
- `getHierarchyLevelAttribute()` - Returns hierarchy level number

## Module-Specific Implementation

### 1. Attendance Module (`app/Http/Controllers/AttendanceController.php`)

**Updated Methods:**
- `index()` - Filters attendance records by accessible schools
- `details()` - Filters attendance details by accessible schools
- `requests()` - Filters attendance requests by accessible schools
- `create()` - Filters employee dropdown by accessible schools
- `edit()` - Filters employee dropdown by accessible schools
- `dailyLogs()` - Already had hierarchical filtering
- `export()` - Already had hierarchical filtering

**Filtering Pattern:**
```php
$currentUser = auth()->user();
$accessService = new \App\Services\HierarchicalAccessService();
$accessibleSchoolIds = $accessService->getAccessibleSchoolIds($currentUser);

if (!empty($accessibleSchoolIds)) {
    $query->whereHas('user', function ($q) use ($accessibleSchoolIds) {
        $q->whereIn('school_id', $accessibleSchoolIds);
    });
}
```

### 2. Patrol Module (`app/Http/Controllers/PatrolController.php`)

**Updated Methods:**
- `schedules()` - Already had hierarchical filtering
- `checkpoints()` - Filters checkpoints by accessible schools via service location
- `logs()` - Filters patrol logs by accessible schools via service location
- `violations()` - Filters patrol violations by accessible schools via service location
- `createSchedule()` - Filters services and users dropdowns
- `createCheckpoint()` - Filters services dropdown
- `editCheckpoint()` - Filters services dropdown
- `services()` - Filters services by accessible schools
- `createService()` - Filters clients and employees dropdowns

**Filtering Pattern:**
```php
$query->whereHas('service', function ($q) use ($accessibleSchoolIds) {
    $q->whereHas('location', function ($locQ) use ($accessibleSchoolIds) {
        $locQ->whereIn('school_id', $accessibleSchoolIds);
    });
});
```

### 3. Transit Module (`app/Http/Controllers/TransitController.php`)

**Updated Methods:**
- `index()` - Filters transit records by accessible schools via from/to service locations
- `history()` - Filters transit history by accessible schools
- `exportHistory()` - Filters exported transit data by accessible schools

**Filtering Pattern:**
```php
$query->where(function ($q) use ($accessibleSchoolIds) {
    $q->whereHas('fromService', function ($sq) use ($accessibleSchoolIds) {
        $sq->whereHas('location', function ($locQ) use ($accessibleSchoolIds) {
            $locQ->whereIn('school_id', $accessibleSchoolIds);
        });
    })->orWhereHas('toService', function ($sq) use ($accessibleSchoolIds) {
        $sq->whereHas('location', function ($locQ) use ($accessibleSchoolIds) {
            $locQ->whereIn('school_id', $accessibleSchoolIds);
        });
    });
});
```

### 4. Geofence Module (`app/Http/Controllers/GeofenceController.php`)

**Updated Methods:**
- `index()` - Filters geofences by accessible schools via service location
- `violations()` - Filters geofence violations by accessible schools
- `exportViolations()` - Filters exported violations by accessible schools
- `create()` - Filters services dropdown
- `edit()` - Filters services dropdown

**Filtering Pattern:**
```php
$query->whereHas('service', function ($q) use ($accessibleSchoolIds) {
    $q->whereHas('location', function ($locQ) use ($accessibleSchoolIds) {
        $locQ->whereIn('school_id', $accessibleSchoolIds);
    });
});
```

### 5. Reports Module (`app/Http/Controllers/ReportController.php`)

**Updated Methods:**
- `attendance()` - Filters dropdowns and passes accessible_school_ids to report service
- `transit()` - Filters dropdowns and passes accessible_school_ids to report service
- `geofence()` - Filters dropdowns and passes accessible_school_ids to report service
- `employeePerformance()` - Filters employees by accessible schools
- `clientPerformance()` - Filters clients by accessible schools
- `getAllEmployeesPerformance()` - Added $accessibleSchoolIds parameter
- `getAllClientsPerformance()` - Added $accessibleSchoolIds parameter

**Filtering Pattern:**
```php
// Filter dropdown options
$clientsQuery = \App\Models\Client::byTenant()->active();
if (!empty($accessibleSchoolIds)) {
    $clientsQuery->whereHas('services', function ($q) use ($accessibleSchoolIds) {
        $q->whereHas('location', function ($locQ) use ($accessibleSchoolIds) {
            $locQ->whereIn('school_id', $accessibleSchoolIds);
        });
    });
}
$clients = $clientsQuery->get();

// Pass to report service
$filters['accessible_school_ids'] = $accessibleSchoolIds;
$report = $this->reportService->generateAttendanceReport($startDate, $endDate, $filters);
```

## Role-Based Access Rules

### Super Admin
- **Level:** 6
- **Access:** All data across all states, zones, districts, and schools
- **No filtering applied**

### State Manager
- **Level:** 5
- **Access:** All data within assigned state
- **Can see:** Users, schools, districts, zones in their state

### Zone Manager
- **Level:** 4
- **Access:** All data within assigned zone
- **Can see:** Users, schools, districts in their zone

### District Manager
- **Level:** 3
- **Access:** All data within assigned district
- **Can see:** Users, schools in their district

### School HM/HR
- **Level:** 2
- **Access:** Only data within their assigned school
- **Can see:** Users, records in their school

### Employee
- **Level:** 1
- **Access:** Only their own records and records from their assigned school(s)
- **Can see:** Their own data, plus school data if assigned to specific schools via user_service_access

## Service Access Model

The `UserServiceAccess` model provides granular access control:
- Direct service access via `service_id`
- Zone-level access via `zone_id` (all services in zone)
- State-level access via `state_id` (all services in state via zones)

## Data Flow

1. **User Login:** User authenticates and their hierarchical fields are loaded
2. **Request:** User makes a request to access data
3. **Access Check:** Controller gets accessible school IDs using `HierarchicalAccessService`
4. **Query Filtering:** Query is filtered to only include records from accessible schools
5. **Dropdown Filtering:** Filter dropdowns are populated with only accessible options
6. **Response:** User sees only data they have access to

## Testing Recommendations

### Test Cases
1. **State Manager:** Create a state manager, assign to a state, verify they see all data in that state only
2. **Zone Manager:** Create a zone manager, assign to a zone, verify they see all data in that zone only
3. **District Manager:** Create a district manager, assign to a district, verify they see all data in that district only
4. **School HM/HR:** Create a school HM/HR, assign to a school, verify they see only that school's data
5. **Employee:** Create an employee, assign to a school, verify they see only their data and school data
6. **Cross-level Access:** Verify that higher-level users can see lower-level data, but not vice versa

### Test Modules
- Attendance: Check attendance logs, requests, and details
- Patrol: Check schedules, checkpoints, logs, and violations
- Transit: Check active transits and history
- Geofence: Check geofences and violations
- Reports: Check all report types

## Security Considerations

1. **Always filter on server-side** - Never rely on client-side filtering
2. **Use middleware for route-level protection** - Apply `CheckHierarchicalAccess` middleware to sensitive routes
3. **Validate access on edit/delete operations** - Check user has permission before modifying data
4. **Log access violations** - Consider logging when users try to access data outside their scope
5. **Regular audits** - Review user access assignments regularly

## Future Enhancements

1. **Caching:** Cache accessible school IDs for performance
2. **API Integration:** Apply same filtering to API endpoints
3. **Audit Logging:** Add comprehensive audit logging for all access attempts
4. **Dynamic Permissions:** Add more granular permissions beyond hierarchy
5. **Bulk Assignment:** Improve bulk user assignment with hierarchical validation

## Troubleshooting

### Issue: User sees no data
**Solution:** Verify user has hierarchical fields (state_id, zone_id, district_id, school_id) assigned

### Issue: User sees data they shouldn't
**Solution:** Check that the controller method is applying hierarchical filtering correctly

### Issue: Dropdowns show all options
**Solution:** Ensure dropdown queries are filtered by accessible school IDs

### Issue: Reports show incorrect data
**Solution:** Verify that `accessible_school_ids` is being passed to the report service

## Related Files
- `app/Services/HierarchicalAccessService.php` - Core access control service
- `app/Traits/HasHierarchicalScope.php` - Model trait for automatic filtering
- `app/Http/Middleware/CheckHierarchicalAccess.php` - Route-level access validation
- `app/Http/Middleware/EnforceSchoolScope.php` - Automatic scope enforcement
- `app/Models/User.php` - User model with hierarchical fields
- `app/Models/UserServiceAccess.php` - Granular service access model
