# WEEK 3: GROUP/BATCH MANAGEMENT IMPLEMENTATION STATUS

## Implementation Checklist

### ✅ COMPLETED - All Required Endpoints Implemented

---

## Endpoint Status

### 1. ✅ GET /api/v2/tutor/groups - List All Batches
**Status:** FULLY IMPLEMENTED  
**Location:** `GroupController@index()` (Line 25)

**Features:**
- ✅ Pagination support (per_page, page parameters)
- ✅ Authorization check (role_id = 3, tutor only)
- ✅ School filtering (school_id matching)
- ✅ Counts included (student_count, test_count)
- ✅ Subject details mapped
- ✅ Enrollment info included
- ✅ Proper error handling (401, 403, 500)

**Request Example:**
```bash
curl -X GET "http://127.0.0.1:8000/api/v2/tutor/groups?per_page=15&page=1" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

**Response Example:**
```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,
      "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"
        }
      ],
      "enrollment_info": {
        "enrollment_code": "ABC123XYZ9",
        "expires_at": "2025-11-20T10:30:00Z",
        "is_expired": false,
        "is_active": true,
        "expires_at_human": "5 days from now"
      }
    }
  ],
  "pagination": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 15,
    "total": 42
  }
}
```

---

### 2. ✅ GET /api/v2/tutor/groups/{id} - Get Batch Details
**Status:** FULLY IMPLEMENTED  
**Location:** `GroupController@show()` (Line 143)

**Features:**
- ✅ Detailed group information
- ✅ Authorization check (ownership verification)
- ✅ Student count and test count
- ✅ Recent activity logs (last 10 entries)
- ✅ Enrollment status breakdown (active/inactive/withdrawn)
- ✅ Subject details
- ✅ Proper error handling (401, 403, 404, 500)

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

**Response Example:**
```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,
      "enrollment_code": "ABC123XYZ9",
      "expires_at": "2025-11-20T10:30:00Z",
      "created_at": "2025-11-13T10:30:00Z",
      "updated_at": "2025-11-13T10:30:00Z",
      "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"
        }
      ]
    },
    "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
- 403: Forbidden (group not owned by user)
- 404: Group not found
- 500: Internal server error

---

### 3. ✅ PUT /api/v2/tutor/groups/{id} - Update Batch
**Status:** FULLY IMPLEMENTED  
**Location:** `GroupController@update()` (Line 291)

**Features:**
- ✅ Update batch name, class, subjects, status
- ✅ Validation rules (UpdateGroupRequest)
- ✅ Authorization check (ownership verification)
- ✅ Transaction management for data consistency
- ✅ Activity logging to group_activity_log
- ✅ Change tracking (before/after values)
- ✅ Proper error handling (401, 403, 404, 422, 500)

**Request Validation Rules:**
```php
'name' => 'sometimes|required|string|max:255',
'class_id' => 'sometimes|required|integer|exists:classes,id',
'subject_ids' => 'sometimes|required|array',
'subject_ids.*' => 'integer|exists:lk_category,id',
'status' => 'sometimes|boolean',
```

**Request Example:**
```bash
curl -X PUT "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer {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],
    "status": true
  }'
```

**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,
    "student_count": 25,
    "test_count": 5,
    "class": { "id": 10, "name": "Class 10" },
    "school": { "id": 5, "school_name": "ABC High School" },
    "subjects": [...]
  }
}
```

**Validation Error Response (422):**
```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"
}
```

**Error Responses:**
- 401: Unauthenticated
- 403: Forbidden (group not owned by user)
- 404: Group not found
- 422: Validation error
- 500: Internal server error

---

### 4. ✅ DELETE /api/v2/tutor/groups/{id} - Delete Batch
**Status:** FULLY IMPLEMENTED  
**Location:** `GroupController@destroy()` (Line 587)

**Features:**
- ✅ Authorization check (ownership verification)
- ✅ Prevents deletion if has active students
- ✅ Prevents deletion if has assigned tests
- ✅ Soft delete (sets status = 0)
- ✅ Activity logging before deletion
- ✅ Transaction management
- ✅ Proper error handling (400, 401, 403, 404, 500)

**Safety Checks:**
1. Checks for active students (type=2, status='active')
2. Checks for assigned tests (group_test_series)
3. Logs deletion to group_activity_log
4. Sets status = 0 (soft delete)

**Request Example:**
```bash
curl -X DELETE "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer {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 Response - Has Active Students (400):**
```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
  }
}
```

**Error Response - Has Assigned Tests (400):**
```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
  }
}
```

**Error Responses:**
- 400: Cannot delete (has students/tests)
- 401: Unauthenticated
- 403: Forbidden (group not owned by user)
- 404: Group not found
- 500: Internal server error

---

## ✅ GroupLog Integration

**Status:** FULLY INTEGRATED

All CRUD operations log to `group_activity_log` table with:

### Logged Actions:
1. **ACTION_GROUP_CREATED** - When a group is created
2. **ACTION_GROUP_UPDATED** - When a group is updated (logs all changes)
3. **ACTION_GROUP_DELETED** - When a group is deleted
4. **ACTION_STUDENT_ADDED** - When a student is added
5. **ACTION_STUDENT_REMOVED** - When a student is removed
6. **ACTION_TEST_SERIES_ADDED** - When a test is assigned
7. **ACTION_TEST_SERIES_REMOVED** - When a test is unassigned

### Log Entry Structure:
```json
{
  "id": 123,
  "group_id": 1,
  "user_id": 50,
  "student_id": null,
  "action": "group_updated",
  "performed_by": 50,
  "metadata": {
    "changes": {
      "name": {
        "old": "Old Name",
        "new": "New Name"
      },
      "status": {
        "old": true,
        "new": false
      }
    },
    "updated_at": "2025-11-13 10:35:00"
  },
  "created_at": "2025-11-13T10:35:00Z"
}
```

### Retrieving Activity Logs:
**Endpoint:** GET /api/v2/tutor/groups/{id}/activity
```bash
curl -X GET "http://127.0.0.1:8000/api/v2/tutor/groups/1/activity" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

---

## ✅ Authorization Checks

**Status:** FULLY IMPLEMENTED AND VERIFIED

### Authorization Logic:
1. User must be authenticated (401 if not)
2. User must have role_id = 3 (tutor) (403 if not)
3. User must own the group:
   - **School Mode:** User's school_id must match group's school_id
   - **Freelance Mode:** User's ID must match group's created_by
   - **Mixed Mode:** Freelance tutors can only access groups they created

### Code Example (from all methods):
```php
$hasAccess = false;

if ($user->school_id && $group->school_id) {
    // Both have school_id, must match
    $hasAccess = ($group->school_id === $user->school_id);
} elseif (!$user->school_id && !$group->school_id) {
    // Both are freelance, check if user created it
    $hasAccess = ($group->created_by === $user->id);
} elseif (!$user->school_id) {
    // Freelance tutor accessing their own group
    $hasAccess = ($group->created_by === $user->id);
}

if (!$hasAccess) {
    return response()->json([
        'status' => false,
        'message' => 'Forbidden: You do not own this group',
        'error_code' => 'FORBIDDEN'
    ], 403);
}
```

---

## Database Schema

### groups table
```sql
CREATE TABLE groups (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL,
  school_id BIGINT UNSIGNED,
  class_id BIGINT UNSIGNED,
  subject_ids JSON,
  status BOOLEAN DEFAULT 1,
  enrollment_code VARCHAR(20) UNIQUE,
  expires_at DATETIME,
  created_at TIMESTAMP,
  updated_at TIMESTAMP,
  KEY idx_groups_school_id (school_id),
  KEY idx_groups_class_id (class_id),
  KEY idx_groups_enrollment_code (enrollment_code),
  KEY idx_groups_expires_at (expires_at)
);
```

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

### group_test_series table (junction table)
```sql
CREATE TABLE group_test_series (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  group_id BIGINT UNSIGNED NOT NULL,
  test_series_id BIGINT UNSIGNED NOT NULL,
  created_at TIMESTAMP,
  updated_at TIMESTAMP,
  UNIQUE KEY (group_id, test_series_id),
  KEY idx_group_test_series_group_id (group_id)
);
```

### group_activity_log table
```sql
CREATE TABLE group_activity_log (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  group_id BIGINT UNSIGNED NOT NULL,
  user_id BIGINT UNSIGNED,
  student_id BIGINT UNSIGNED,
  action VARCHAR(100),
  performed_by BIGINT UNSIGNED,
  metadata JSON,
  created_at TIMESTAMP,
  KEY idx_group_activity_log_group_id (group_id),
  KEY idx_group_activity_log_action (action)
);
```

---

## Routes Configuration

**File:** `routes/api.php` (Lines 162-169)

```php
Route::middleware('auth:sanctum')->prefix('groups')->group(function () {
    Route::get('/', [GroupControllerV2::class, 'index']);                              // GET /api/v2/tutor/groups
    Route::get('/{id}', [GroupControllerV2::class, 'show']);                           // GET /api/v2/tutor/groups/{id}
    Route::put('/{id}', [GroupControllerV2::class, 'update']);                         // PUT /api/v2/tutor/groups/{id}
    Route::delete('/{id}', [GroupControllerV2::class, 'destroy']);                     // DELETE /api/v2/tutor/groups/{id}
    Route::get('/{id}/activity', [GroupControllerV2::class, 'activity']);              // GET /api/v2/tutor/groups/{id}/activity
    Route::post('/{id}/regenerate-code', [GroupControllerV2::class, 'regenerateCode']); // POST /api/v2/tutor/groups/{id}/regenerate-code
    Route::get('/{id}/enrollment-status', [GroupControllerV2::class, 'enrollmentStatus']); // GET /api/v2/tutor/groups/{id}/enrollment-status
});
```

---

## Related Endpoints (Not Part of This Week)

Additional group management endpoints available:

### Activity Logs
- **GET** `/api/v2/tutor/groups/{id}/activity` - Get activity logs for a group
- **GET** `/api/v2/tutor/groups/{id}/enrollment-status` - Get enrollment status

### Enrollment Code Management
- **POST** `/api/v2/tutor/groups/{id}/regenerate-code` - Regenerate enrollment code
- **Response:** Logs to `ACTION_ENROLLMENT_CODE_REGENERATED`

### Test Series Management
- **POST** `/api/v2/tutor/test-series/{id}/assign-to-groups` - Assign tests to groups
- **GET** `/api/v2/tutor/test-series/{id}/groups` - Get assigned groups
- **DELETE** `/api/v2/tutor/test-series/{testId}/groups/{groupId}` - Unassign batch

---

## Testing Guide

### Prerequisites:
1. Tutor user with authentication token
2. Existing groups with at least one group
3. Optional: Students enrolled in a group

### Test Steps:

**Step 1: List all batches**
```bash
curl -X GET "http://127.0.0.1:8000/api/v2/tutor/groups" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```
**Expected:** Returns paginated list of groups

**Step 2: Get batch details**
```bash
curl -X GET "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```
**Expected:** Returns complete group details with activity logs

**Step 3: Update batch**
```bash
curl -X PUT "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Updated Batch Name",
    "class_id": 10,
    "subject_ids": [1, 2, 3]
  }'
```
**Expected:** Returns updated group, entry added to group_activity_log

**Step 4: Try to delete batch**
```bash
curl -X DELETE "http://127.0.0.1:8000/api/v2/tutor/groups/1" \
  -H "Authorization: Bearer {token}"
```
**Expected:** 
- Returns 400 if has active students/tests
- Returns 200 if successful (status set to 0)
- Entry added to group_activity_log with ACTION_GROUP_DELETED

---

## File References

### Controller
- **File:** `app/Http/Controllers/Api/V2/GroupController.php` (982 lines)
- **Methods:** `index()`, `show()`, `update()`, `destroy()`, `activity()`, `regenerateCode()`, `enrollmentStatus()`

### Model
- **File:** `app/Models/Group.php` (217 lines)
- **Relationships:** school, class, subjects, groupUsers, students, teachers, testSeries, activityLogs

### Request Validation
- **File:** `app/Http/Requests/UpdateGroupRequest.php` (78 lines)

### Service
- **File:** `app/Services/GroupLogService.php` (243 lines)

### Activity Log Model
- **File:** `app/Models/GroupActivityLog.php` (264 lines)

---

## Summary

✅ **All required endpoints are implemented and tested:**
- GET /api/v2/tutor/groups (List)
- GET /api/v2/tutor/groups/{id} (Details)
- PUT /api/v2/tutor/groups/{id} (Update)
- DELETE /api/v2/tutor/groups/{id} (Delete)

✅ **GroupLog Integration:** All operations automatically log to group_activity_log

✅ **Authorization:** All endpoints verify ownership and role

✅ **Database:** All required tables and columns exist

✅ **Validation:** UpdateGroupRequest validates all input

✅ **Error Handling:** Proper error codes and messages

✅ **Documentation:** Comprehensive API documentation available

---

## Next Steps (Week 3 Continuation)

1. **Day 3-4:** Test Series Assignment to Groups
   - POST /api/v2/tutor/test-series/{id}/assign-to-groups
   - GET /api/v2/tutor/test-series/{id}/groups
   - DELETE /api/v2/tutor/test-series/{testId}/groups/{groupId}

2. **Day 5:** Student Management in Groups
   - POST /api/v2/tutor/groups/{id}/add-student
   - DELETE /api/v2/tutor/groups/{id}/remove-student/{studentId}
   - PUT /api/v2/tutor/groups/{id}/students/{studentId}

3. **Day 6-7:** Batch Analytics & Reporting
   - GET /api/v2/tutor/groups/{id}/analytics
   - GET /api/v2/tutor/groups/{id}/performance
   - GET /api/v2/tutor/groups/{id}/attendance

---

## Support & Troubleshooting

### Common Issues:

**Issue:** 403 Forbidden error
- **Solution:** Ensure user's school_id matches group's school_id, or user is freelance tutor who created the group

**Issue:** 422 Validation Error
- **Solution:** Check that class_id exists in classes table, subject_ids exist in lk_category table

**Issue:** 400 Cannot delete
- **Solution:** Remove all active students and assigned tests before deletion

**Issue:** Activity logs not appearing
- **Solution:** Check group_activity_log table and ensure log entries are being created during operations

### Debug Info:
- Check logs: `storage/logs/laravel.log`
- Database: Verify tables exist and have data
- Authentication: Ensure valid sanctum token in Authorization header

---

*Last Updated: November 25, 2025*
*Implementation Status: ✅ COMPLETE*
