# Ratings & Reviews API — Trainer Portal & Reputation

How ratings, trainee feedback, and reviews integrate into the Trainer role across performance statistics, public consultant profiles, and course feedback.

- **Base path:** `{{base_url}}/trainer` and `{{base_url}}/user`
- **Headers:**
  - `Accept: application/json`
  - `Accept-Language: {{locale}}` (`ar` or `en`)
  - `Authorization: Bearer {{trainer_token}}`
- **Source files:**
  - Controller: [TrainerStatisticsController.php](file:///media/ghoneim/Storage/backend/bateel/app/Http/Controllers/Api/V1/Trainer/TrainerStatisticsController.php)
  - Service: [StatisticsService.php](file:///media/ghoneim/Storage/backend/bateel/app/Services/Trainer/StatisticsService.php)
  - Model: [TrainerProfile.php](file:///media/ghoneim/Storage/backend/bateel/app/Models/TrainerProfile.php)
  - Trait: [HasReviews.php](file:///media/ghoneim/Storage/backend/bateel/app/Traits/HasReviews.php)
  - Test: [TrainerStatisticsApiTest.php](file:///media/ghoneim/Storage/backend/bateel/tests/Feature/Education/TrainerStatisticsApiTest.php)

---

## Trainer Rating Architecture & Boundaries

1. **Reputation Rollup:** All reviews submitted for items taught by the trainer automatically populate `trainer_id`:
   - Courses assigned to the trainer (`Course.trainer_id`)
   - Training programs led by the trainer (`TrainingProgram.trainer_id`)
   - One-on-one consultation bookings (`ConsultationBooking -> TrainerConsultant.trainer_id`)
2. **Read-Only Separation of Concerns:**
   - **Trainers cannot moderate reviews:** Hiding or approving reviews is an Admin-only duty (see [ratings-admin.md](./ratings-admin.md)).
   - **Trainers cannot review their own items:** Review submission is restricted to paying clients who completed the offering (see [ratings-user.md](./ratings-user.md)).
3. **Smart Cache System:** The trainer's `average_rating` is computed via `$trainer->ratingAvg()` and cached in Redis/Cache store tagged with `reviews`. Whenever an admin moderates a review or a student posts a new review, the cache tag is invalidated immediately.

---

## Error Codes Reference

| HTTP Status | error_code | Trigger |
|---|---|---|
| `401 Unauthorized` | *(Unauthenticated)* | Missing or expired trainer bearer token |
| `403 Forbidden` | `PERMISSION_DENIED` | Non-trainer user attempting to access trainer statistics |
| `404 Not Found` | *(Data not found)* | Trainer profile or assigned course not found |

---

## Endpoints

### 1. `GET /trainer/statistics` — Trainer Dashboard Statistics

Returns the aggregated KPIs for the authenticated trainer, including their cumulative `average_rating`.

#### Headers
| Key | Type | Value |
|---|---|---|
| `Accept` | string | `application/json` |
| `Authorization` | string | `Bearer {{trainer_token}}` |
| `Accept-Language` | string | `{{locale}}` |

#### Payload
No request body.

#### Response `200 OK`
```json
{
    "status": "success",
    "message": "Statistics retrieved successfully",
    "data": {
        "total_trainees": 42,
        "assigned_programs": 3,
        "published_courses": 6,
        "completion_rate": 88,
        "certificates_issued": 35,
        "average_rating": 4.8
    }
}
```

#### Field Specifications
| Key | Type | Description |
|---|---|---|
| `total_trainees` | integer | Unique count of students enrolled across all courses & programs taught by this trainer |
| `assigned_programs` | integer | Count of training programs assigned to this trainer |
| `published_courses` | integer | Count of approved courses created by or assigned to this trainer |
| `completion_rate` | integer | Percentage (0–100) of enrollments that achieved `completed` status |
| `certificates_issued` | integer | Total certificates awarded across the trainer's courses and programs |
| `average_rating` | float | Aggregated average rating (1.0 to 5.0) of all visible reviews received by this trainer |

---

### 2. `GET /user/consultants/{trainer}/reviews` — Public Consultant Reviews

How potential clients view feedback and ratings for this trainer's 1-on-1 consultations.

#### Headers
| Key | Type | Value |
|---|---|---|
| `Accept` | string | `application/json` |
| `Accept-Language` | string | `{{locale}}` |

#### Path Parameters
| Parameter | Type | Description |
|---|---|---|
| `trainer` | string (uuid) | Trainer Profile UUID |

#### Query Parameters
| Key | Type | Example | Description |
|---|---|---|---|
| `page` | integer | `1` | Page number |
| `per_page` | integer | `15` | Results per page (default: 15, max: 100) |

#### Response `200 OK`
```json
{
    "status": "success",
    "message": "Data retrieved successfully",
    "data": {
        "reviews": [
            {
                "id": "b2c3d4e5-f6a7-8b9c-0d1e-2f3a4b5c6d7e",
                "rating": 5,
                "comment": "Exceptional clarity on financial restructuring and cash flow management.",
                "reviewer": "Sara Al-Mansouri",
                "created_at": "2026-09-13T14:45:00+00:00"
            },
            {
                "id": "c3d4e5f6-a7b8-9c0d-1e2f-3a4b5c6d7e8f",
                "rating": 4,
                "comment": "Very helpful consultation, answered all our tax compliance queries.",
                "reviewer": "Omar Al-Ghamdi",
                "created_at": "2026-09-10T11:00:00+00:00"
            }
        ],
        "links": {
            "first": "http://localhost:8000/api/v1/user/consultants/t1b2c3d4/reviews?page=1",
            "last": "http://localhost:8000/api/v1/user/consultants/t1b2c3d4/reviews?page=1",
            "prev": null,
            "next": null
        },
        "meta": {
            "current_page": 1,
            "from": 1,
            "last_page": 1,
            "path": "http://localhost:8000/api/v1/user/consultants/t1b2c3d4/reviews",
            "per_page": 15,
            "to": 2,
            "total": 2
        }
    }
}
```

---

### 3. Course & Program Reviews Visibility

Trainers can view feedback submitted by enrolled students on their assigned courses and programs:

- **Course Reviews:** `GET /user/courses/{course}/reviews`
- **Training Program Reviews:** `GET /user/programs/{program}/reviews`

#### Catalog Card Display
In course listings (`/user/courses`), program listings (`/user/programs`), and consultant listings (`/user/consultants`), the trainer's ratings appear in the public payload:

```json
{
    "id": "c1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
    "name": "Financial Modelling Fundamentals",
    "rating": {
        "average": 4.8,
        "count": 25
    },
    "trainer": {
        "id": "t1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
        "name": "Dr. Farooq Al-Bateel",
        "rating_avg": 4.8
    }
}
```

---

## Trainer Profile Rating Mechanics

In the underlying database schema and Eloquent model:

```php
// In App\Models\TrainerProfile:

// Cumulative average of visible reviews across all taught offerings
public function ratingAvg(): ?float
{
    return round((float) $this->reviews()->visible()->avg('rating'), 1) ?: null;
}

// Total count of visible reviews across all taught offerings
public function ratingCount(): int
{
    return (int) $this->reviews()->visible()->count();
}

// Reviews specifically for one-on-one consultation bookings
public function consultationReviews(): HasMany
{
    return $this->reviews()->where('reviewable_type', ConsultationBooking::class);
}
```
