# Kế hoạch theo dõi và loại bỏ User đã Enroll thành công

## Tổng quan

Kế hoạch này mô tả cách theo dõi các user đã enroll thành công dựa trên data hiện tại trong bảng `users_enrollment_moodle_speakup` và bảng `course_student`, sau đó loại bỏ chúng khỏi bảng `users_enrollment_moodle_speakup` sau khi import data mới.

**Lưu ý**: API `enroll-users-from-speakup` đã chạy thành công trước đó, và đã có API `get-enrollment-report` để check báo cáo. Kế hoạch này sẽ dựa vào data hiện tại để tracking.

## Mục tiêu

1. **Theo dõi**: Dựa vào data hiện tại, xác định các user đã enroll thành công (có trong `course_student` table) và lưu vào tracking table
2. **Lưu trữ**: Lưu danh sách này vào một bảng riêng để tham chiếu sau
3. **Làm sạch**: Sau khi import data mới vào `users_enrollment_moodle_speakup`, loại bỏ các user đã enroll thành công (đã tracking) khỏi bảng này

## Logic xác định User đã Enroll thành công

Dựa vào logic của API `get-enrollment-report`, một user được coi là **đã enroll thành công** khi:

1. User có trong bảng `users_enrollment_moodle_speakup_{course_id}` với `user_moodle_id` hợp lệ
2. User có trong bảng `students` với `user_moodle_id_old` = `user_moodle_id` từ speakup table
3. Student đó có trong bảng `course_student` với `course_id` tương ứng và `deleted_at IS NULL`

## Cấu trúc Database

### Bảng mới: `speakup_enrolled_users_tracking`

Bảng này sẽ lưu trữ các user đã enroll thành công theo từng course.

```sql
CREATE TABLE `speakup_enrolled_users_tracking` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `course_id` INT NOT NULL COMMENT 'Course ID (38, 39, 45, 46, 47, 68)',
  `user_moodle_id` BIGINT UNSIGNED NOT NULL COMMENT 'user_moodle_id từ users_enrollment_moodle_speakup',
  `zeus_id` BIGINT UNSIGNED NOT NULL COMMENT 'zeus_id từ users_enrollment_moodle_speakup',
  `username` VARCHAR(255) NOT NULL COMMENT 'username của user',
  `email` VARCHAR(255) NOT NULL COMMENT 'Email của user',
  `firstname` VARCHAR(255) NOT NULL COMMENT 'firstname của user',
  `lastname` VARCHAR(255) NOT NULL COMMENT 'lastname của user',
  `tenant_connection` VARCHAR(255) NULL COMMENT 'Tenant connection name',
  `enrolled_at` TIMESTAMP NOT NULL COMMENT 'Thời điểm enroll thành công',
  `enrolled_by_api` VARCHAR(255) NULL COMMENT 'API đã enroll (tracked_from_current_data, etc.)',
  `created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_course_user` (`course_id`, `user_moodle_id`),
  KEY `idx_course_id` (`course_id`),
  KEY `idx_user_moodle_id` (`user_moodle_id`),
  KEY `idx_email` (`email`),
  KEY `idx_tenant_connection` (`tenant_connection`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

## Flow Diagram

```
┌─────────────────────────────────────────────────────────────────┐
│ 0. Data hiện tại (đã có)                                         │
│    - users_enrollment_moodle_speakup_{course_id} có data        │
│    - enroll-users-from-speakup đã chạy thành công               │
│    - course_student có các student đã enroll                    │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│ 1. Check báo cáo enrollment (optional)                           │
│    API: get-enrollment-report                                    │
│    POST /api/speakup/get-enrollment-report                       │
│    Input: course_id                                              │
│    Output: Báo cáo chi tiết về enrollment status                │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│ 2. Tracking các user đã enroll thành công                        │
│    API: trackEnrolledUsersFromCurrentData                        │
│    POST /api/speakup/track-enrolled-users-from-current-data     │
│    Input: course_id                                              │
│    Logic:                                                        │
│    - Lấy users từ users_enrollment_moodle_speakup               │
│    - Tìm students có user_moodle_id_old match                   │
│    - Tìm students đã enroll (có trong courseStudent)            │
│    - Lưu vào tracking table                                     │
│    Output: Số lượng users đã tracking                           │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│ 3. Import data mới từ CSV                                        │
│    API: importUsersEnrollment                                    │
│    POST /api/speakup/import-users-enrollment-csv                 │
│    Input: course_id, file (CSV)                                  │
│    Output: Số lượng records đã insert                           │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│ 4. Loại bỏ enrolled users (đã tracking) khỏi speakup table      │
│    API: removeTrackedEnrolledUsersFromSpeakup                    │
│    POST /api/speakup/remove-tracked-enrolled-users-from-speakup │
│    Input: course_id                                              │
│    Logic:                                                        │
│    - Lấy danh sách user_moodle_id từ tracking table             │
│    - Xóa các user này khỏi users_enrollment_moodle_speakup      │
│    Output: Số lượng users đã xóa                                │
└─────────────────────────────────────────────────────────────────┘
```

## APIs cần tạo

### 1. API tracking enrolled users từ data hiện tại

**Endpoint**: `POST /api/speakup/track-enrolled-users-from-current-data`

**Mục đích**: Dựa vào data hiện tại, xác định và lưu các user đã enroll thành công vào tracking table

**Logic**:
1. Lấy tất cả `user_moodle_id` từ `users_enrollment_moodle_speakup_{course_id}`
2. Tìm `students` có `user_moodle_id_old` trong danh sách trên
3. Tìm `students` đã enroll (có trong `course_student` với `course_id` tương ứng và `deleted_at IS NULL`)
4. Lưu các user đã enroll thành công vào `speakup_enrolled_users_tracking`

**Request**:
```json
{
  "course_id": 45
}
```

**Response**:
```json
{
  "success": true,
  "message": "Tracked 150 enrolled users from current data",
  "course_id": 45,
  "course_api_id": 563,
  "summary": {
    "total_speakup_users": 200,
    "users_created_in_students": 180,
    "users_enrolled_successfully": 150,
    "tracked_count": 150,
    "skipped_count": 0
  }
}
```

### 2. API loại bỏ tracked enrolled users khỏi speakup table

**Endpoint**: `POST /api/speakup/remove-tracked-enrolled-users-from-speakup`

**Mục đích**: Xóa các user đã enroll thành công (đã lưu trong tracking table) khỏi bảng `users_enrollment_moodle_speakup_{course_id}`

**Logic**:
1. Lấy danh sách `user_moodle_id` từ `speakup_enrolled_users_tracking` theo `course_id`
2. Xóa các records trong `users_enrollment_moodle_speakup_{course_id}` có `user_moodle_id` trong danh sách trên

**Request**:
```json
{
  "course_id": 45
}
```

**Response**:
```json
{
  "success": true,
  "message": "Removed 150 tracked enrolled users from users_enrollment_moodle_speakup table",
  "course_id": 45,
  "removed_count": 150,
  "remaining_count": 50
}
```

### 3. API lấy danh sách enrolled users đã tracking

**Endpoint**: `POST /api/speakup/get-enrolled-users-tracking`

**Mục đích**: Xem danh sách các user đã enroll thành công đã được lưu trong tracking table

**Request**:
```json
{
  "course_id": 45
}
```

**Response**:
```json
{
  "success": true,
  "course_id": 45,
  "total_count": 150,
  "enrolled_users": [
    {
      "id": 1,
      "course_id": 45,
      "user_moodle_id": 123,
      "email": "user1@example.com",
      "tenant_connection": "tenant1",
      "enrolled_at": "2025-01-15 10:30:00",
      "enrolled_by_api": "tracked_from_current_data",
      "created_at": "2025-01-15 10:30:00"
    }
  ]
}
```

### 4. API xóa tracking data (optional)

**Endpoint**: `POST /api/speakup/clear-enrolled-users-tracking`

**Mục đích**: Xóa dữ liệu tracking cho một course (khi cần reset)

**Request**:
```json
{
  "course_id": 45
}
```

**Response**:
```json
{
  "success": true,
  "message": "Cleared tracking data for course 45",
  "course_id": 45,
  "deleted_count": 150
}
```

## Các bước Implementation

### Bước 1: Tạo Migration

Tạo file migration để tạo bảng `speakup_enrolled_users_tracking`:

```bash
php artisan make:migration create_speakup_enrolled_users_tracking_table
```

### Bước 2: Tạo Model

Tạo model `SpeakupEnrolledUsersTracking`:

```bash
php artisan make:model SpeakupEnrolledUsersTracking
```

### Bước 3: Tạo Controller Methods

Thêm các methods vào `SpeakupActivitySyncController`:
1. `trackEnrolledUsersFromCurrentData()` - Xác định và lưu enrolled users từ data hiện tại
2. `removeTrackedEnrolledUsersFromSpeakup()` - Xóa tracked enrolled users khỏi speakup table
3. `getEnrolledUsersTracking()` - Xem danh sách tracking
4. `clearEnrolledUsersTracking()` - Xóa tracking data (optional)

### Bước 4: Thêm Routes

Thêm các routes vào `routes/api.php` trong prefix `speakup`:

```php
Route::prefix('speakup')->controller(SpeakupActivitySyncController::class)->group(function () {
    // ... existing routes ...
    
    // API mới để tracking từ data hiện tại
    Route::post('/track-enrolled-users-from-current-data', 'trackEnrolledUsersFromCurrentData')
        ->name('speakup.trackEnrolledUsersFromCurrentData');
    
    Route::post('/remove-tracked-enrolled-users-from-speakup', 'removeTrackedEnrolledUsersFromSpeakup')
        ->name('speakup.removeTrackedEnrolledUsersFromSpeakup');
    
    Route::post('/get-enrolled-users-tracking', 'getEnrolledUsersTracking')
        ->name('speakup.getEnrolledUsersTracking');
    
    Route::post('/clear-enrolled-users-tracking', 'clearEnrolledUsersTracking')
        ->name('speakup.clearEnrolledUsersTracking');
});
```

### Bước 5: Implement logic trong Controller

**Method `trackEnrolledUsersFromCurrentData()`** sẽ sử dụng logic tương tự `getEnrollmentReport()`:

1. Lấy users từ `users_enrollment_moodle_speakup_{course_id}`
2. Tìm students có `user_moodle_id_old` match với `user_moodle_id`
3. Tìm students đã enroll (có trong `course_student` với `course_id` tương ứng)
4. Lưu vào `speakup_enrolled_users_tracking` với:
   - `course_id`
   - `user_moodle_id`
   - `email` (từ speakup table)
   - `tenant_connection`
   - `enrolled_at` = now()
   - `enrolled_by_api` = 'tracked_from_current_data'

**Method `removeTrackedEnrolledUsersFromSpeakup()`**:

1. Lấy danh sách `user_moodle_id` từ `speakup_enrolled_users_tracking` theo `course_id`
2. Xóa records trong `users_enrollment_moodle_speakup_{course_id}` có `user_moodle_id` trong danh sách trên
3. Sử dụng batch delete hoặc chunk để tối ưu performance

## Workflow sử dụng

### Quy trình chuẩn (dựa trên data hiện tại):

1. **Bước 0** (Optional): Check báo cáo enrollment hiện tại
   ```bash
   POST /api/speakup/get-enrollment-report
   {
     "course_id": 45
   }
   ```
   → Xem báo cáo về trạng thái enrollment hiện tại

2. **Bước 1**: Tracking các user đã enroll thành công từ data hiện tại
   ```bash
   POST /api/speakup/track-enrolled-users-from-current-data
   {
     "course_id": 45
   }
   ```
   → API sẽ tự động:
   - Tìm các user đã enroll thành công (có trong course_student)
   - Lưu vào tracking table
   → Output: Số lượng users đã tracking

3. **Bước 2**: Import data mới từ CSV
   ```bash
   POST /api/speakup/import-users-enrollment-csv
   {
     "course_id": 45,
     "file": <csv_file>
   }
   ```
   → Import data mới vào `users_enrollment_moodle_speakup_{course_id}`

4. **Bước 3**: Loại bỏ tracked enrolled users khỏi speakup table
   ```bash
   POST /api/speakup/remove-tracked-enrolled-users-from-speakup
   {
     "course_id": 45
   }
   ```
   → Xóa các user đã tracking (đã enroll thành công) khỏi speakup table
   → Chỉ giữ lại các user chưa enroll hoặc user mới từ CSV

### Quy trình lặp lại:

Sau khi xóa, có thể:
- Chạy lại `enroll-users-from-speakup` để enroll các user còn lại
- Tracking lại sau khi enroll thành công
- Import CSV mới và lặp lại quy trình

## Lưu ý quan trọng

1. **Unique constraint**: Bảng tracking có unique constraint trên `(course_id, user_moodle_id)` để tránh duplicate. Khi tracking lại, sẽ skip các user đã có.
2. **Performance**: 
   - Khi xóa nhiều records, nên sử dụng batch delete hoặc chunk để tránh timeout
   - Có thể sử dụng `whereIn()` với chunk để xử lý số lượng lớn
3. **Transaction**: Nên sử dụng database transaction cho các operations quan trọng
4. **Logging**: Log đầy đủ các thao tác để debug (số lượng users tracked, removed, etc.)
5. **Tenant connection**: 
   - Bảng tracking có thể lưu trong master DB (default connection) để dễ quản lý
   - Hoặc có thể lưu trong tenant DB nếu cần tách biệt theo tenant
6. **Data consistency**: Đảm bảo `user_moodle_id` trong tracking table match với `user_moodle_id` trong speakup table

## Migration File Template

```php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('speakup_enrolled_users_tracking', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('course_id')->comment('Course ID (38, 39, 45, 46, 47, 68)');
            $table->unsignedBigInteger('user_moodle_id')->comment('user_moodle_id từ users_enrollment_moodle_speakup');
            $table->string('email');
            $table->string('tenant_connection')->nullable();
            $table->timestamp('enrolled_at');
            $table->string('enrolled_by_api')->nullable();
            $table->timestamps();
            
            $table->unique(['course_id', 'user_moodle_id'], 'unique_course_user');
            $table->index('course_id');
            $table->index('user_moodle_id');
            $table->index('email');
            $table->index('tenant_connection');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('speakup_enrolled_users_tracking');
    }
};
```

## Model Template

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class SpeakupEnrolledUsersTracking extends Model
{
    use HasFactory;

    protected $table = 'speakup_enrolled_users_tracking';

    protected $fillable = [
        'course_id',
        'user_moodle_id',
        'email',
        'tenant_connection',
        'enrolled_at',
        'enrolled_by_api',
    ];

    protected $casts = [
        'course_id' => 'integer',
        'user_moodle_id' => 'integer',
        'enrolled_at' => 'datetime',
    ];
}
```

## Testing Checklist

- [ ] Test tracking enrolled users từ data hiện tại
- [ ] Test unique constraint (không lưu duplicate khi tracking lại)
- [ ] Test xóa tracked enrolled users khỏi speakup table
- [ ] Test với nhiều course_id khác nhau
- [ ] Test với tenant connection
- [ ] Test performance với số lượng lớn users (1000+)
- [ ] Test rollback khi có lỗi (transaction)
- [ ] Test xem danh sách tracking
- [ ] Test xóa tracking data (clear)
- [ ] Test với data empty (không có enrolled users)
- [ ] Test với user không có trong course_student (không được tracking)

## Future Enhancements

1. **Auto-tracking**: Tự động tracking sau khi enroll thành công trong `enrollUsersFromSpeakup`
2. **Batch operations**: Hỗ trợ batch tracking/remove cho nhiều courses cùng lúc
3. **Statistics**: Thêm API để xem thống kê enrolled users theo course, tenant, thời gian
4. **Retention policy**: Tự động xóa tracking data cũ sau một thời gian nhất định
5. **Export/Import**: Hỗ trợ export/import tracking data
6. **Dry-run mode**: Thêm mode để preview các users sẽ bị xóa trước khi thực sự xóa