# Batch Management CRUD APIs Documentation

Complete REST API endpoints for managing batches (groups) in the Pathshalaa system.

## Overview

This API provides full CRUD operations for batch management with:
- Authorization checks (school_id matching)
- Transaction management for data consistency
- Audit trail logging to `group_activity_log` table
- Proper Eloquent relationships across all 4 tables

### Database Tables

1. **groups** - Main batches table (has school_id, class_id, subject_ids)
2. **group_users** - Student/teacher enrollments (with type: 1=teacher, 2=student)
3. **group_activity_log** - Audit trail for all changes
4. **group_test_series** - Test assignments to batches

---

## Migration Required

Before using these APIs, run the migration to add new columns:

```bash
php artisan migrate
```

This adds `class_id` and `subject_ids` columns to the `groups` table.

---

## Authentication

All endpoints require authentication via Laravel Sanctum token.

**Authorization Header:**
```
Authorization: Bearer {your_access_token}
```

**User Requirements:**
- Must be authenticated
- Must have `role_id = 3` (Tutor)
- Must have a valid `school_id` associated

---

## API Endpoints

### Base URL
```
http://127.0.0.1:8000/api/v2/tutor/groups
```

---

## 1. List All Batches

Get a paginated list of all batches for the authenticated tutor's school.

**Endpoint:** `GET /api/v2/tutor/groups`

**Query Parameters:**
- `per_page` (optional, default: 15) - Number of results per page
- `page` (optional, default: 1) - Page number

**Response Fields:**
- Group details with class and school relationships
- `student_count` - Count of active students in the batch
- `test_count` - Count of assigned tests
- `subjects` - Array of subject details

**cURL Example:**
```bash
curl -X GET "http://127.0.0.1:8000/api/v2/tutor/groups?per_page=10&page=1" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
```

**Success Response (200):**
```json
{
  "status": true,
  "message": "Groups retrieved successfully",
  "data": [
    {
      "id": 1,
      "name": "Class 10 Science Batch A",
      "school_id": 5,
      "class_id": 10,
      "subject_ids": [1, 2, 3],
      "status": true,
      "created_at": "2025-11-13T10:30:00.000000Z",
      "updated_at": "2025-11-13T10:30:00.000000Z",
      "student_count": 25,
      "test_count": 5,
      "class": {
        "id": 10,
        "name": "Class 10"
      },
      "school": {
        "id": 5,
        "school_name": "ABC High School"
      },
      "subjects": [
        {
          "id": 1,
          "name": "Physics"
        },
        {
          "id": 2,
          "name": "Chemistry"
        },
        {
          "id": 3,
          "name": "Biology"
        }
      ]
    }
  ],
  "pagination": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 10,
    "total": 25
  }
}
```

**Error Responses:**
- **401 Unauthenticated:** User not logged in
- **403 Forbidden:** User is not a tutor
- **400 Bad Request:** Tutor not associated with any school

---

## 2. Get Batch Details

Get detailed information about a specific batch including statistics and recent activity.

**Endpoint:** `GET /api/v2/tutor/groups/{id}`

**Path Parameters:**
- `id` (required) - The batch/group ID

**Response Fields:**
- Complete group details
- `student_count` - Active students count
- `test_count` - Assigned tests count
- `recent_activity` - Last 10 activity log entries
- `enrollment_status` - Breakdown by status (active/inactive/withdrawn)

**cURL Example:**
```bash
curl -X GET "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
```

**Success Response (200):**
```json
{
  "status": true,
  "message": "Group details retrieved successfully",
  "data": {
    "group": {
      "id": 1,
      "name": "Class 10 Science Batch A",
      "school_id": 5,
      "class_id": 10,
      "subject_ids": [1, 2, 3],
      "status": true,
      "created_at": "2025-11-13T10:30:00.000000Z",
      "updated_at": "2025-11-13T10:30:00.000000Z",
      "student_count": 25,
      "test_count": 5,
      "class": {
        "id": 10,
        "name": "Class 10"
      },
      "school": {
        "id": 5,
        "school_name": "ABC High School"
      },
      "subjects": [
        {
          "id": 1,
          "name": "Physics"
        }
      ]
    },
    "recent_activity": [
      {
        "id": 123,
        "action": "group_updated",
        "performed_by": "John Doe",
        "performed_at": "2025-11-13 10:35:00",
        "metadata": {
          "changes": {
            "name": {
              "old": "Class 10 Science",
              "new": "Class 10 Science Batch A"
            }
          }
        }
      }
    ],
    "enrollment_status": {
      "active": 25,
      "inactive": 3,
      "withdrawn": 2,
      "total": 30
    }
  }
}
```

**Error Responses:**
- **401 Unauthenticated:** User not logged in
- **403 Forbidden:** User doesn't own this group
- **404 Not Found:** Group doesn't exist

---

## 3. Update Batch

Update batch details (name, class_id, subject_ids, status).

**Endpoint:** `PUT /api/v2/tutor/groups/{id}`

**Path Parameters:**
- `id` (required) - The batch/group ID

**Request Body:** (all fields optional, send only what needs to be updated)
```json
{
  "name": "Class 10 Science Batch B",
  "class_id": 10,
  "subject_ids": [1, 2, 3, 4],
  "status": true
}
```

**Validation Rules:**
- `name`: string, max 255 characters
- `class_id`: integer, must exist in `classes` table
- `subject_ids`: array of integers, each must exist in `lk_category` table
- `status`: boolean

**Features:**
- Validates school_id ownership (ensures tutor owns this batch)
- Logs all changes to `group_activity_log` table
- Uses database transactions for data consistency
- Returns updated batch with student count

**cURL Example:**
```bash
curl -X PUT "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "Class 10 Science Batch B",
    "class_id": 10,
    "subject_ids": [1, 2, 3, 4]
  }'
```

**Success Response (200):**
```json
{
  "status": true,
  "message": "Group updated successfully",
  "data": {
    "id": 1,
    "name": "Class 10 Science Batch B",
    "school_id": 5,
    "class_id": 10,
    "subject_ids": [1, 2, 3, 4],
    "status": true,
    "created_at": "2025-11-13T10:30:00.000000Z",
    "updated_at": "2025-11-13T11:45:00.000000Z",
    "student_count": 25,
    "test_count": 5,
    "class": {
      "id": 10,
      "name": "Class 10"
    },
    "school": {
      "id": 5,
      "school_name": "ABC High School"
    },
    "subjects": [
      {
        "id": 1,
        "name": "Physics"
      },
      {
        "id": 2,
        "name": "Chemistry"
      },
      {
        "id": 3,
        "name": "Biology"
      },
      {
        "id": 4,
        "name": "Mathematics"
      }
    ]
  }
}
```

**Error Responses:**
- **401 Unauthenticated:** User not logged in
- **403 Forbidden:** User doesn't own this group
- **404 Not Found:** Group doesn't exist
- **422 Validation Error:** Invalid input data
  ```json
  {
    "status": false,
    "message": "Validation error",
    "errors": {
      "class_id": ["The selected class does not exist"],
      "subject_ids.0": ["One or more selected subjects do not exist"]
    },
    "error_code": "VALIDATION_ERROR"
  }
  ```

---

## 4. Delete Batch

Soft delete a batch (sets status to 0).

**Endpoint:** `DELETE /api/v2/tutor/groups/{id}`

**Path Parameters:**
- `id` (required) - The batch/group ID

**Features:**
- Checks for active students in `group_users` (prevents deletion if found)
- Checks for assigned tests in `group_test_series` (prevents deletion if found)
- Logs deletion to `group_activity_log` before deleting
- Ensures school_id ownership
- Soft delete (sets status = 0, doesn't actually delete record)

**cURL Example:**
```bash
curl -X DELETE "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
```

**Success Response (200):**
```json
{
  "status": true,
  "message": "Group deleted successfully",
  "data": {
    "group_id": 1,
    "deleted_at": "2025-11-13 12:00:00"
  }
}
```

**Error Responses:**

**400 Bad Request - Has Active Students:**
```json
{
  "status": false,
  "message": "Cannot delete group with 25 active student(s). Please withdraw or deactivate all students first.",
  "error_code": "HAS_ACTIVE_STUDENTS",
  "data": {
    "active_student_count": 25
  }
}
```

**400 Bad Request - Has Assigned Tests:**
```json
{
  "status": false,
  "message": "Cannot delete group with 5 assigned test(s). Please remove all test assignments first.",
  "error_code": "HAS_ASSIGNED_TESTS",
  "data": {
    "test_count": 5
  }
}
```

**Other Error Responses:**
- **401 Unauthenticated:** User not logged in
- **403 Forbidden:** User doesn't own this group
- **404 Not Found:** Group doesn't exist

---

## Activity Logging

All create, update, and delete operations are automatically logged to the `group_activity_log` table with:

- `group_id` - The affected group
- `user_id` - The user who performed the action
- `action` - Action type (e.g., "group_updated", "group_deleted")
- `performed_by` - User ID of who performed the action
- `metadata` - JSON with detailed change information
- `created_at` - Timestamp of the action

**Example Log Entry:**
```json
{
  "id": 123,
  "group_id": 1,
  "user_id": 50,
  "action": "group_updated",
  "performed_by": 50,
  "metadata": {
    "changes": {
      "name": {
        "old": "Class 10 Science",
        "new": "Class 10 Science Batch A"
      },
      "subject_ids": {
        "old": [1, 2],
        "new": [1, 2, 3]
      }
    },
    "updated_at": "2025-11-13 10:35:00"
  },
  "created_at": "2025-11-13T10:35:00.000000Z"
}
```

---

## Error Codes Reference

| Error Code | HTTP Status | Description |
|------------|-------------|-------------|
| `UNAUTHENTICATED` | 401 | User not authenticated |
| `FORBIDDEN` | 403 | User doesn't have permission |
| `GROUP_NOT_FOUND` | 404 | Group doesn't exist |
| `VALIDATION_ERROR` | 422 | Invalid input data |
| `NO_SCHOOL_ASSOCIATION` | 400 | Tutor not linked to a school |
| `HAS_ACTIVE_STUDENTS` | 400 | Cannot delete group with active students |
| `HAS_ASSIGNED_TESTS` | 400 | Cannot delete group with assigned tests |
| `INTERNAL_ERROR` | 500 | Server error |

---

## Testing with Postman

### 1. Login to get access token
```bash
POST http://127.0.0.1:8000/api/v2/tutor/login
Content-Type: application/json

{
  "email": "tutor@example.com",
  "password": "password123"
}
```

### 2. Save the token from response
```json
{
  "status": true,
  "token": "1|abc123def456...",
  "user": { ... }
}
```

### 3. Use token in subsequent requests
Add to Headers:
```
Authorization: Bearer 1|abc123def456...
Accept: application/json
```

---

## Complete Testing Flow

### Step 1: List all batches
```bash
curl -X GET "http://127.0.0.1:8000/api/v2/tutor/groups" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

### Step 2: Get details of a specific batch
```bash
curl -X GET "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

### Step 3: Update the batch
```bash
curl -X PUT "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "Updated Batch Name",
    "class_id": 10,
    "subject_ids": [1, 2, 3]
  }'
```

### Step 4: Try to delete (will fail if has students/tests)
```bash
curl -X DELETE "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"
```

---

## Database Schema

### groups table
```sql
CREATE TABLE groups (
  id BIGINT UNSIGNED PRIMARY KEY,
  name VARCHAR(255),
  school_id BIGINT UNSIGNED,
  class_id BIGINT UNSIGNED,      -- NEW COLUMN
  subject_ids JSON,               -- NEW COLUMN
  status BOOLEAN DEFAULT 1,
  created_at TIMESTAMP,
  updated_at TIMESTAMP,
  INDEX idx_groups_school_id (school_id),
  INDEX idx_groups_class_id (class_id)
);
```

### group_users table
```sql
CREATE TABLE group_users (
  id BIGINT UNSIGNED PRIMARY KEY,
  group_id BIGINT UNSIGNED,
  user_id BIGINT UNSIGNED,
  type INT,                       -- 1=teacher, 2=student
  enrolled_at TIMESTAMP,
  status ENUM('active', 'inactive', 'withdrawn'),
  created_at TIMESTAMP,
  updated_at TIMESTAMP,
  UNIQUE KEY (group_id, user_id, type),
  INDEX idx_group_users_group_id (group_id),
  INDEX idx_group_users_user_id (user_id),
  INDEX idx_group_users_type (type),
  INDEX idx_group_users_status (status)
);
```

### group_test_series table
```sql
CREATE TABLE group_test_series (
  id BIGINT UNSIGNED PRIMARY KEY,
  group_id BIGINT UNSIGNED,
  test_series_id BIGINT UNSIGNED,
  created_at TIMESTAMP,
  updated_at TIMESTAMP,
  UNIQUE KEY (group_id, test_series_id),
  INDEX idx_group_test_series_group_id (group_id),
  INDEX idx_group_test_series_test_series_id (test_series_id)
);
```

### group_activity_log table
```sql
CREATE TABLE group_activity_log (
  id BIGINT UNSIGNED PRIMARY KEY,
  group_id BIGINT UNSIGNED,
  user_id BIGINT UNSIGNED,
  student_id BIGINT UNSIGNED,
  action VARCHAR(100),
  performed_by BIGINT UNSIGNED,
  metadata TEXT,                  -- JSON
  created_at TIMESTAMP,
  INDEX idx_group_activity_log_group_id (group_id),
  INDEX idx_group_activity_log_user_id (user_id),
  INDEX idx_group_activity_log_student_id (student_id),
  INDEX idx_group_activity_log_performed_by (performed_by)
);
```

---

## Notes

1. **Foreign Keys:** Currently disabled for performance. See `database/migrations/README_FOREIGN_KEYS.md` for enablement procedure.

2. **Soft Delete:** Delete operation sets `status = 0` instead of removing the record.

3. **Authorization:** All endpoints verify that the authenticated tutor's `school_id` matches the group's `school_id`.

4. **Transaction Safety:** Update and Delete operations use database transactions to ensure data consistency.

5. **Audit Trail:** All changes are logged to `group_activity_log` with complete before/after values.

6. **Subject IDs:** Stored as JSON array in the database, automatically cast to PHP array by the model.

---

## Support

For issues or questions, check the logs at `storage/logs/laravel.log` for detailed error information.
