# 1. Tổng quan tính năng (liệt kê theo module)

## 1.1 Campaigns
- **Mô tả**: Quản lý chiến dịch thi (campaign) cho từng tenant, cấu hình thông tin chiến dịch và liên kết với đề thi.
- **Routes**:
  - `GET /campaigns` → `CampaignController@index`
  - `GET /campaigns/create` → `CampaignController@create`
  - `POST /campaigns/store` → `CampaignController@store`
  - `GET /campaigns/{id}/edit` → `CampaignController@edit`
  - `PUT /campaigns/{id}` → `CampaignController@update`
  - `DELETE /campaigns/{id}` → `CampaignController@destroy`
- **Controllers**:
  - `App\Http\Controllers\CampaignController`
- **Models**:
  - `App\Models\Campaign`
  - Liên quan: `App\Models\CampaignExam`, `App\Models\Exam`
- **Views**:
  - `resources/views/campaigns/index.blade.php`
  - `resources/views/campaigns/create.blade.php`
  - `resources/views/campaigns/edit.blade.php`

## 1.2 Exams
- **Mô tả**: Quản lý đề thi nội bộ (exam) của tenant, liên kết với EMS và campaign.
- **Routes**:
  - `GET /exams` → `ExamController@index`
  - `GET /exams/create` → `ExamController@create`
  - `POST /exams/store` → `ExamController@store`
  - `GET /exams/{id}` → `ExamController@show`
  - `GET /exams/{id}/edit` → `ExamController@edit`
  - `PUT /exams/{id}` → `ExamController@update`
  - `DELETE /exams/{id}` → `ExamController@destroy`
  - `GET /exams/ems-exams/list` → `ExamController@getEmsExams`
- **Controllers**:
  - `App\Http\Controllers\ExamController`
- **Models**:
  - `App\Models\Exam`
  - `App\Models\CampaignExam`
  - `App\Models\CommonEms`
- **Views**:
  - `resources/views/exams/index.blade.php`
  - `resources/views/exams/create.blade.php`
  - `resources/views/exams/edit.blade.php`
  - `resources/views/exams/show.blade.php` (nếu có)

## 1.3 Exam Mapping
- **Mô tả**: Gán đề thi (`Exam`) cho từng campaign và domain, cấu hình `exam_final`, `show_result`, `grading_type`.
- **Routes**:
  - `GET /exam-mapping` → `ExamMappingController@index`
  - `POST /exam-mapping/assign` → `ExamMappingController@assignExam`
  - `POST /exam-mapping/remove` → `ExamMappingController@removeExam`
  - `POST /exam-mapping/update-show-result` → `ExamMappingController@updateShowResult`
  - `POST /exam-mapping/update-grade-type` → `ExamMappingController@updateGradeType`
- **Controllers**:
  - `App\Http\Controllers\ExamMappingController`
- **Models**:
  - `App\Models\Campaign`
  - `App\Models\Exam`
  - `App\Models\CampaignExam`
  - `App\Models\HocmaiTenantDomain` (domain theo tenant)
- **Views**:
  - `resources/views/exam-mapping/index.blade.php`

## 1.4 Exam Configs
- **Mô tả**: Cấu hình chi tiết cho exam/campaign (thời lượng, number of attempts, cấu hình hiển thị...), dùng cho FE & EMS.
- **Routes (web)**:
  - `GET /exam-configs` → `ExamConfigController@index`
  - `GET /exam-configs/create` → `ExamConfigController@create`
  - `POST /exam-configs/store` → `ExamConfigController@store`
  - `GET /exam-configs/{id}` → `ExamConfigController@show`
  - `GET /exam-configs/{id}/edit` → `ExamConfigController@edit`
  - `PUT /exam-configs/{id}` → `ExamConfigController@update`
  - `DELETE /exam-configs/{id}` → `ExamConfigController@destroy`
  - `GET /exam-configs/exam/{examId}` → `ExamConfigController@showExamConfigs`
- **Routes (api)**:
  - `GET /api/exam-configs/get-configs` → `ExamConfigController@getExamCampaignConfigs`
  - `POST /api/exam-configs/store-config` → `ExamConfigController@storeExamCampaignConfig`
  - `POST /api/exam-configs/update-config` → `ExamConfigController@updateExamCampaignConfig`
  - `POST /api/exam-configs/delete-config` → `ExamConfigController@deleteExamCampaignConfig`
  - `POST /api/exam-configs/update-order` → `ExamConfigController@updateOrder`
- **Controllers**:
  - `App\Http\Controllers\ExamConfigController`
- **Models**:
  - `App\Models\ExamConfig` (suy luận từ context, kiểm tra trong code khi cần)
- **Views**:
  - `resources/views/exam-configs/*.blade.php`

## 1.5 Student Exam History & Assessment
- **Mô tả**: Quản lý lịch sử làm bài thi của học sinh, chi tiết bài thi, chấm lại (re-score), phân công giáo viên chấm, export báo cáo.
- **Routes (web)**:
  - `GET /student-exam-history` → `StudentExamHistoryController@index`
  - `GET /student-exam-history/myAssessment` → `StudentExamHistoryController@myAssessment`
  - `GET /student-exam-history/{id}/detail` → `StudentExamHistoryController@detail`
  - `GET /student-exam-history/{id}/edit` → `StudentExamHistoryController@edit`
  - `GET /student-exam-history/export` → `StudentExamHistoryController@exportExcel`
  - `POST /student-exam-history/assign-teacher` → `StudentExamController@assignTeacher`
- **Routes (api)**:
  - `GET /api/exam-detail/{idHistory}` → `StudentExamHistoryController@getPartDetail`
  - `GET /api/student-exam-detail/data-rescored/{idHistory}` → `StudentExamDetailController@getDataRescored`
  - `POST /api/student-exam-detail/update-data-rescored` → `StudentExamDetailController@updateDataRescored`
- **Controllers**:
  - `App\Http\Controllers\StudentExamHistoryController`
  - `App\Http\Controllers\StudentExamController`
  - `App\Http\Controllers\StudentExamDetailController`
- **Models**:
  - `App\Models\StudentExamHistory`
  - `App\Models\StudentExam`
  - `App\Models\StudentExamDetail`
  - Liên quan: `StudentScore`, `Students`, `Teachers`, `Exam`, `Campaign`, `CampaignExam`
- **Views**:
  - `resources/views/student-exam-history/index.blade.php`
  - `resources/views/student-exam-history/assessment.blade.php`
  - `resources/views/student-exam-history/detail.blade.php`
  - `resources/views/student-exam-history/edit.blade.php`

## 1.6 Tracking (UTM & lead)
- **Mô tả**: Báo cáo tracking UTM (campaign, term, source, medium, phone, consultation) cho lead/học sinh.
- **Routes**:
  - `GET /tracking` → `TrackingController@index`
  - `GET /tracking/export` → `TrackingController@exportExcel`
- **Controllers**:
  - `App\Http\Controllers\TrackingController`
- **Models**:
  - `App\Models\StudentTracking`
- **Views**:
  - `resources/views/tracking/index.blade.php`

## 1.7 EMS API & Mock Test / Exam
- **Mô tả**: Nhận/gửi dữ liệu thi với hệ thống EMS & AIHub: mock contest, exam, scoring, token, history.
- **Routes (api)**: (tiêu biểu)
  - `POST /api/fe/ems/get-data-mocktest` → `ApiEmsController@getDataMocktest`
  - `GET /api/fe/ems/list-contest` → `ApiEmsController@listAllContestType`
  - `POST /api/fe/ems/get-content-course` → `ApiEmsController@getDataContentCourse`
  - `POST /api/fe/ems/v1/exam/start` → `ApiEmsController@startExam`
  - `POST /api/fe/ems/v1/exam/save` → `ApiEmsController@saveExam`
  - `POST /api/fe/ems/v1/exam/submit` → `ApiEmsController@submitExam`
  - `POST /api/fe/ems/v1/exam/score` → `ApiEmsController@calculateExamScore`
  - `POST /api/fe/ems/api_server/thirdparty/aihub/resultWritingTask1` → `ApiEmsController@resultWritingTask1`
  - `POST /api/fe/ems/api_server/thirdparty/aihub/resultWritingTask2` → `ApiEmsController@resultWritingTask2`
- **Controllers**:
  - `App\Http\Controllers\ApiEmsController`
- **Models / Services**:
  - `App\Models\CommonEms`
  - `App\ApiService\FeService` (service gọi EMS, sử dụng trong `ApiEmsController`)

## 1.8 Tenant & Permission
- **Mô tả**: Chọn/switch tenant, gán user ↔ tenant, quản lý domain theo tenant, phân quyền theo tenant.
- **Routes (web)**:
  - Tenant selection/switch: `/auth/tenant-selection`, `/auth/select-tenant`, `/auth/switch-tenant`, `/auth/current-tenant`
  - Tenant assignment: `/tenant-assignment*`
  - Tenant management: `/tenant-management*`
  - Tenant domain: `/tenant-domain*`
  - Role & permission: `/role*`, `/permission*`, `/role/roles-by-tenant`
- **Controllers**:
  - `App\Http\Controllers\TenantController`
  - `App\Http\Controllers\TenantAssignmentController`
  - `App\Http\Controllers\TenantManagementController`
  - `App\Http\Controllers\TenantDomainController` (web & api namespace)
  - `App\Http\Controllers\RoleController`
- **Middleware**:
  - `App\Http\Middleware\CheckPermission`
  - Các middleware auth/admin trong `routes/web.php`
- **Models**:
  - Tenant / TenantDomain (suy luận từ controllers)
  - `Role`, `Permission`, bảng pivot user-role, role-permission (từ `RoleController`)

---

# 2. Sơ đồ luồng xử lý (Mermaid Sequence Diagram)

## 2.1 Luồng: Xem danh sách Campaigns

```mermaid
sequenceDiagram
    participant User
    participant Route as Route (/campaigns)
    participant MW as Middleware (auth + check.permission)
    participant C as CampaignController
    participant M as Campaign Model
    participant V as View (campaigns/index)

    User->>Route: GET /campaigns
    Route->>MW: Check authentication & permission
    MW-->>Route: OK
    Route->>C: index()
    C->>M: query() with tenant connection<br/>paginate campaigns
    M-->>C: Collection<Campaign>
    C->>V: render('campaigns.index', data)
    V-->>User: HTML page (list campaigns)
```

## 2.2 Luồng: Tạo mới Exam và đồng bộ EMS

```mermaid
sequenceDiagram
    participant User
    participant Route as Route (/exams/store)
    participant MW as Middleware (auth + check.permission)
    participant C as ExamController
    participant M as Exam Model
    participant EMS as CommonEms/FeService
    participant V as View (redirect)

    User->>Route: POST /exams/store
    Route->>MW: Check authentication & permission
    MW-->>Route: OK
    Route->>C: store(Request)
    C->>EMS: (optional) fetch EMS exam info / validate
    EMS-->>C: EMS exam data
    C->>M: create([...]) using tenant connection
    M-->>C: Exam instance
    C->>V: redirect()->route('exams.index') with flash message
    V-->>User: Redirect + success message
```

## 2.3 Luồng: Gán Exam vào Campaign (Exam Mapping)

```mermaid
sequenceDiagram
    participant User
    participant Route as Route (/exam-mapping/assign)
    participant MW as Middleware (auth + check.permission)
    participant C as ExamMappingController
    participant CE as CampaignExam Model
    participant E as Exam Model
    participant CM as Campaign Model
    participant V as View/JSON

    User->>Route: POST /exam-mapping/assign (campaign_id, exam_id, domain_id, options)
    Route->>MW: Check authentication & permission
    MW-->>Route: OK
    Route->>C: assignExam(Request)
    C->>CM: find(campaign_id)
    CM-->>C: Campaign
    C->>E: find(exam_id)
    E-->>C: Exam (slug, exam_url)
    C->>CE: updateOrCreate([...]) // set exam_id, exam_final, grading_type, show_result
    CE-->>C: CampaignExam
    C-->>User: JSON success (AJAX) or reload view exam-mapping.index
```

## 2.4 Luồng: Xem chi tiết lịch sử bài thi (Student Exam History Detail)

```mermaid
sequenceDiagram
    participant User
    participant Route as Route (/student-exam-history/{id}/detail)
    participant MW as Middleware (auth + check.permission)
    participant C as StudentExamHistoryController
    participant H as StudentExamHistory
    participant SE as StudentExam
    participant SED as StudentExamDetail
    participant EMS as CommonEms/ApiEms
    participant V as View (student-exam-history/detail)

    User->>Route: GET /student-exam-history/{id}/detail
    Route->>MW: Check authentication & permission
    MW-->>Route: OK
    Route->>C: detail($id)
    C->>H: findOrFail($id)
    H-->>C: StudentExamHistory
    C->>SE: where(student_exam_history_id = id)
    SE-->>C: StudentExam
    C->>SED: where(student_exam_id in ...)
    SED-->>C: Collection<StudentExamDetail>
    C->>EMS: get history/contest detail (if needed)
    EMS-->>C: raw contest data
    C: build view model (per skill/part, scores, status)
    C->>V: render('student-exam-history.detail', data)
    V-->>User: HTML detail page
```

## 2.5 Luồng: API chấm lại (rescore) Student Exam Detail

```mermaid
sequenceDiagram
    participant FE as Frontend
    participant Route1 as Route (GET /api/student-exam-detail/data-rescored/{idHistory})
    participant Route2 as Route (POST /api/student-exam-detail/update-data-rescored)
    participant C1 as StudentExamDetailController
    participant C2 as StudentExamDetailController
    participant H as StudentExamHistory
    participant SE as StudentExam
    participant SED as StudentExamDetail

    FE->>Route1: GET /student-exam-detail/data-rescored/{idHistory}
    Route1->>C1: getDataRescored($idHistory)
    C1->>H: findOrFail($idHistory)
    H-->>C1: StudentExamHistory
    C1->>SE: where(student_exam_history_id = idHistory)
    SE-->>C1: StudentExam
    C1->>SED: where(student_exam_id in ...)
    SED-->>C1: Collection (with data_rescored/data_ems)
    C1-->>FE: JSON data for UI

    FE->>Route2: POST /student-exam-detail/update-data-rescored (payload)
    Route2->>C2: updateDataRescored(Request)
    C2->>SED: find(ids) & update data_rescored, status
    SED-->>C2: updated rows
    C2->>SE: recalc aggregated score (data_ems_after_submit)
    SE-->>C2: updated StudentExam
    C2-->>FE: JSON success
```

## 2.6 Luồng: Xem báo cáo Tracking

```mermaid
sequenceDiagram
    participant User
    participant Route as Route (/tracking)
    participant MW as Middleware (auth + check.permission)
    participant C as TrackingController
    participant M as StudentTracking
    participant V as View (tracking/index)

    User->>Route: GET /tracking?filters...
    Route->>MW: Check authentication & permission
    MW-->>Route: OK
    Route->>C: index(Request)
    C->>M: query() with filters (date_from, date_to, utm_campaign, phone, ...)
    M-->>C: paginated results
    C->>V: render('tracking.index', data)
    V-->>User: HTML table (UTM tracking)
```

---

# 3. Sơ đồ kiến trúc MVC (Mermaid Class Diagram)

```mermaid
classDiagram
    %% Controllers
    class CampaignController {
        +index()
        +create()
        +store()
        +edit(id)
        +update(id)
        +destroy(id)
    }

    class ExamController {
        +index()
        +create()
        +store()
        +show(id)
        +edit(id)
        +update(id)
        +destroy(id)
        +getEmsExams()
    }

    class ExamMappingController {
        +index()
        +assignExam()
        +removeExam()
        +updateShowResult()
        +updateGradeType()
    }

    class ExamConfigController {
        +index()
        +create()
        +store()
        +show(id)
        +edit(id)
        +update(id)
        +destroy(id)
        +showExamConfigs(examId)
        +getExamCampaignConfigs()
        +storeExamCampaignConfig()
        +updateExamCampaignConfig()
        +deleteExamCampaignConfig()
        +updateOrder()
    }

    class StudentExamHistoryController {
        +index()
        +myAssessment()
        +detail(id)
        +edit(id)
        +exportExcel()
        +getPartDetail(idHistory)
    }

    class StudentExamController {
        +assignTeacher()
    }

    class StudentExamDetailController {
        +getDataRescored(idHistory)
        +updateDataRescored()
    }

    class TrackingController {
        +index()
        +exportExcel()
    }

    class ApiEmsController {
        +getDataMocktest()
        +listAllContestType()
        +getDataContentCourse()
        +startExam()
        +saveExam()
        +submitExam()
        +calculateExamScore()
        +resultWritingTask1()
        +resultWritingTask2()
        %% ... các API khác với EMS
    }

    %% Models
    class Campaign {
        +id
        +name
        +code
        +start_at
        +end_at
        +hasMany(CampaignExam)
        +belongsToMany(Exam)
    }

    class Exam {
        +id
        +name
        +slug
        +ems_exam_id
        +hasMany(CampaignExam)
        +belongsToMany(Campaign)
    }

    class CampaignExam {
        +id
        +campaign_id
        +exam_id
        +exam_final
        +grading_type
        +show_result
        +belongsTo(Campaign)
        +belongsTo(Exam)
    }

    class ExamConfig {
        +id
        +exam_id
        +campaign_id
        +config_json
        +belongsTo(Exam)
        +belongsTo(Campaign)
    }

    class StudentExamHistory {
        +id
        +student_id
        +campaign_id
        +exam_id
        +utm_campaign
        +utm_source
        +hasMany(StudentExam)
    }

    class StudentExam {
        +id
        +student_exam_history_id
        +student_id
        +teacher_id
        +data_ems
        +data_ems_after_submit
        +hasMany(StudentExamDetail)
        +belongsTo(StudentExamHistory)
    }

    class StudentExamDetail {
        +id
        +student_exam_id
        +skill
        +data_ems
        +data_rescored
        +teacher_id
        +status
        +belongsTo(StudentExam)
    }

    class StudentTracking {
        +id
        +name
        +email
        +phone
        +utm_campaign
        +utm_source
        +utm_medium
        +utm_term
        +information_data
    }

    class CommonEms {
        +getExamList()
        +getExamHistory()
        %% ... helper EMS methods
    }

    class FeService {
        +callEmsApi()
        +startExam()
        +submitExam()
        +calculateScore()
    }

    %% Relationships Controller -> Model/Service
    CampaignController --> Campaign
    ExamController --> Exam
    ExamController --> CommonEms
    ExamMappingController --> Campaign
    ExamMappingController --> Exam
    ExamMappingController --> CampaignExam
    ExamConfigController --> Exam
    ExamConfigController --> Campaign
    ExamConfigController --> ExamConfig

    StudentExamHistoryController --> StudentExamHistory
    StudentExamHistoryController --> StudentExam
    StudentExamHistoryController --> StudentExamDetail
    StudentExamHistoryController --> Exam
    StudentExamHistoryController --> Campaign
    StudentExamHistoryController --> CampaignExam
    StudentExamHistoryController --> CommonEms

    StudentExamController --> StudentExam
    StudentExamController --> StudentExamDetail

    StudentExamDetailController --> StudentExamDetail
    StudentExamDetailController --> StudentExam

    TrackingController --> StudentTracking

    ApiEmsController --> CommonEms
    ApiEmsController --> FeService
```

---

# 4. Sơ đồ database (Mermaid ERD)

```mermaid
erDiagram
    CAMPAIGNS {
        bigint id PK
        string name
        string code
        datetime start_at
        datetime end_at
        timestamps
        softDeletes
    }

    EXAMS {
        bigint id PK
        string name
        string slug
        bigint ems_exam_id
        timestamps
        softDeletes
    }

    CAMPAIGN_EXAM {
        bigint id PK
        bigint campaign_id FK
        bigint exam_id FK
        string exam_final
        string grading_type
        boolean show_result
        timestamps
    }

    EXAM_CONFIGS {
        bigint id PK
        bigint exam_id FK
        bigint campaign_id FK
        json config_json
        integer sort_order
        timestamps
    }

    STUDENT_EXAM_HISTORIES {
        bigint id PK
        bigint student_id FK
        bigint campaign_id FK
        bigint exam_id FK
        string campaign_code
        string utm_campaign
        string utm_source
        string utm_medium
        string utm_term
        timestamps
    }

    STUDENT_EXAMS {
        bigint id PK
        bigint student_exam_history_id FK
        bigint student_id FK
        bigint teacher_id FK
        string campaign_code
        json data_ems
        json data_ems_after_submit
        timestamps
    }

    STUDENT_EXAM_DETAILS {
        bigint id PK
        bigint student_exam_id FK
        string skill
        json data_ems
        json data_exam
        json data_rescored
        bigint teacher_id FK
        string status
        timestamps
    }

    STUDENT_TRACKING {
        bigint id PK
        string name
        string email
        string phone
        string utm_campaign
        string utm_source
        string utm_medium
        string utm_term
        json information_data
        timestamps
    }

    STUDENTS {
        bigint id PK
        string name
        string email
        string phone
        timestamps
    }

    TEACHERS {
        bigint id PK
        string name
        string email
        timestamps
    }

    %% Relationships
    CAMPAIGNS ||--o{ CAMPAIGN_EXAM : hasMany
    EXAMS ||--o{ CAMPAIGN_EXAM : hasMany
    CAMPAIGNS ||--o{ EXAM_CONFIGS : hasMany
    EXAMS ||--o{ EXAM_CONFIGS : hasMany

    CAMPAIGNS ||--o{ STUDENT_EXAM_HISTORIES : hasMany
    EXAMS ||--o{ STUDENT_EXAM_HISTORIES : hasMany
    STUDENTS ||--o{ STUDENT_EXAM_HISTORIES : hasMany

    STUDENT_EXAM_HISTORIES ||--o{ STUDENT_EXAMS : hasMany
    STUDENTS ||--o{ STUDENT_EXAMS : hasMany
    TEACHERS ||--o{ STUDENT_EXAMS : hasMany

    STUDENT_EXAMS ||--o{ STUDENT_EXAM_DETAILS : hasMany
    TEACHERS ||--o{ STUDENT_EXAM_DETAILS : hasMany
```

---

**Ghi chú**:
- Các mối quan hệ và tên cột được suy luận từ controllers/models đã quét (đặc biệt là `StudentExamHistoryController`, `ExamController`, `ExamMappingController`, `TrackingController`, `ApiEmsController`). Khi cần chi tiết chính xác, có thể đối chiếu lại với migrations trong thư mục `database/migrations`.
- Các sơ đồ Mermaid có thể được copy trực tiếp vào tài liệu hoặc công cụ hỗ trợ Mermaid để render biểu đồ.

