Tổng quan Mô-đun Lưu trữ Tệp

Mô tả Tổng quan

Mô-đun Lưu trữ Tệp cung cấp chức năng quản lý upload tệp lên Google Cloud Storage (GCS) và theo dõi lịch sử upload. Bao gồm tạo Signed URL để upload trực tiếp, lưu metadata, truy xuất lịch sử và quản lý báo cáo lỗi. Hỗ trợ upload CSV với theo dõi lỗi xác thực và cung cấp cả API lẫn tải về CSV.

(Các sơ đồ hoạt động, endpoint và lược đồ CSDL giữ nguyên như bản EN để đồng bộ tài liệu.)

Activity Diagram

---
config:
  theme: base
  layout: dagre
  flowchart:
    curve: linear
    htmlLabels: true
  themeVariables:
    edgeLabelBackground: "transparent"
---
flowchart TD
    Client[Ứng dụng Client]
    API[UploadGcsController]
    GCSService[GcsService]
    ImportService[ImportReviewService]
    ExportService[ExportService]
    Repository[ReviewUploadHistoryRepository]
    Database[(Cơ sở dữ liệu)]
    GCS[(Google Cloud Storage)]
    
    Client --- Step1[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>1</span>
            <p style='margin-top: 8px'>Yêu cầu URL có chữ ký</p>
        </div>
    ]
    Step1 --> API

    API --- Step2[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>2</span>
            <p style='margin-top: 8px'>Tạo URL có chữ ký</p>
        </div>
    ]
    Step2 --> ImportService

    ImportService --- Step3[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3</span>
            <p style='margin-top: 8px'>Yêu cầu URL từ GCS</p>
        </div>
    ]
    Step3 --> GCSService

    GCSService --- Step4[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4</span>
            <p style='margin-top: 8px'>Trả về URL có chữ ký</p>
        </div>
    ]
    Step4 --> GCS

    GCS --- Step5[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>5</span>
            <p style='margin-top: 8px'>Trả về URL cho client</p>
        </div>
    ]
    Step5 --> GCSService
    GCSService --> ImportService
    ImportService --> API
    API --> Client

    Client --- Step6[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6</span>
            <p style='margin-top: 8px'>Tải lên tệp trực tiếp</p>
        </div>
    ]
    Step6 --> GCS

    Client --- Step7[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>7</span>
            <p style='margin-top: 8px'>Lưu lịch sử tải lên</p>
        </div>
    ]
    Step7 --> API

    API --- Step8[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>8</span>
            <p style='margin-top: 8px'>Lưu vào cơ sở dữ liệu</p>
        </div>
    ]
    Step8 --> Repository

    Repository --- Step9[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>9</span>
            <p style='margin-top: 8px'>Lưu bản ghi lịch sử</p>
        </div>
    ]
    Step9 --> Database

    Client --- Step10[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc66cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>10</span>
            <p style='margin-top: 8px'>Yêu cầu danh sách lịch sử</p>
        </div>
    ]
    Step10 --> API

    API --- Step11[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc66cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>11</span>
            <p style='margin-top: 8px'>Truy vấn cơ sở dữ liệu</p>
        </div>
    ]
    Step11 --> Repository

    Repository --- Step12[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #cc66cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>12</span>
            <p style='margin-top: 8px'>Trả về dữ liệu lịch sử</p>
        </div>
    ]
    Step12 --> Database

    Client --- Step13[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #ff9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>13</span>
            <p style='margin-top: 8px'>Tải xuống CSV lỗi</p>
        </div>
    ]
    Step13 --> API

    API --- Step14[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #ff9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>14</span>
            <p style='margin-top: 8px'>Tạo tệp CSV</p>
        </div>
    ]
    Step14 --> ExportService

    ExportService --- Step15[
        <div style='text-align: center'>
            <span style='display: inline-block; background-color: #ff9966 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>15</span>
            <p style='margin-top: 8px'>Trả về tải xuống CSV</p>
        </div>
    ]
    Step15 --> API
    API --> Client
    
    style Client fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
    style API fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
    style GCSService fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style ImportService fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style ExportService fill:#f0f8e6,stroke:#339933,stroke-width:2px
    style Repository fill:#fff0f5,stroke:#cc6699,stroke-width:2px
    style Database fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
    style GCS fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
    style Step1 fill:transparent,stroke:transparent,stroke-width:1px
    style Step2 fill:transparent,stroke:transparent,stroke-width:1px
    style Step3 fill:transparent,stroke:transparent,stroke-width:1px
    style Step4 fill:transparent,stroke:transparent,stroke-width:1px
    style Step5 fill:transparent,stroke:transparent,stroke-width:1px
    style Step6 fill:transparent,stroke:transparent,stroke-width:1px
    style Step7 fill:transparent,stroke:transparent,stroke-width:1px
    style Step8 fill:transparent,stroke:transparent,stroke-width:1px
    style Step9 fill:transparent,stroke:transparent,stroke-width:1px
    style Step10 fill:transparent,stroke:transparent,stroke-width:1px
    style Step11 fill:transparent,stroke:transparent,stroke-width:1px
    style Step12 fill:transparent,stroke:transparent,stroke-width:1px
    style Step13 fill:transparent,stroke:transparent,stroke-width:1px
    style Step14 fill:transparent,stroke:transparent,stroke-width:1px
    style Step15 fill:transparent,stroke:transparent,stroke-width:1px

Danh sách module

Tên Liên kết tổng quan Mô tả
Tạo URL có chữ ký Tải lên GCS Tạo URL có chữ ký cho tải lên trực tiếp tệp lên Google Cloud Storage
Lưu lịch sử tải lên Lưu lịch sử Lưu metadata tải lên tệp bao gồm trạng thái và thông tin lỗi
Lịch sử tải lên Lịch sử tải lên Lấy danh sách có phân trang các bản ghi lịch sử tải lên với bộ lọc
Danh sách lịch sử Danh sách lịch sử Lấy danh sách lịch sử được định dạng bằng chuyển đổi API Resource
Lấy lịch sử theo ID Lấy theo ID Lấy thông tin chi tiết của một lịch sử tải lên cụ thể
Lấy lỗi import Lỗi import Lấy lỗi xác thực của một lịch sử tải lên cụ thể
Tải xuống CSV lỗi Tải xuống CSV Tải xuống tệp CSV chứa thông tin lỗi chi tiết

API Endpoints

Phương thức Endpoint Mô tả
GET /api/v1/general/upload-file/gcs/get-signed-url Tạo URL có chữ ký cho tải lên trực tiếp tệp
POST /api/v1/general/upload-file/gcs/upload-history Lưu metadata lịch sử tải lên
GET /api/v1/general/upload-file/gcs/histories/list Lấy danh sách có phân trang lịch sử tải lên
GET /api/v1/general/upload-file/gcs/histories/{id} Lấy lịch sử tải lên cụ thể theo ID
GET /api/v1/general/upload-file/gcs/histories/{id}/import-errors Lấy lỗi import của lịch sử cụ thể
GET /api/v1/general/upload-file/gcs/histories/{id}/download-errors Tải xuống tệp CSV lỗi

Schema cơ sở dữ liệu

erDiagram
    review_upload_histories {
        bigint id PK
        bigint user_id FK "Tham chiếu đến bảng users"
        bigint group_id FK "Tham chiếu đến bảng groups"
        string file_name "Tên tệp đã tải lên"
        string gcs_path "Đường dẫn tệp được lưu trong Google Cloud Storage"
        tinyInteger status "Trạng thái tải lên: 0=Chưa xử lý, 1=Đang xử lý, 2=Thành công, 3=Thất bại"
        string error_reason "Thông báo lỗi khi tải lên thất bại (có thể null)"
        timestamp validated_at "Thời điểm tệp được xác thực (có thể null)"
        timestamp created_at
        timestamp updated_at
    }
    review_upload_errors {
        bigint id PK
        bigint review_upload_history_id FK "Tham chiếu đến bảng review_upload_histories"
        string header "Tiêu đề trường gây lỗi (có thể null)"
        string value "Giá trị dữ liệu có vấn đề (có thể null)"
        integer error_line "Số dòng xảy ra lỗi (có thể null)"
        json error_messages "Mảng thông báo lỗi của trường"
        timestamp created_at
        timestamp updated_at
    }
    users {
        bigint id PK
        string name "Họ tên đầy đủ của người dùng"
        string email "Địa chỉ email của người dùng"
    }
    groups {
        bigint id PK
        string name "Tên nhóm"
    }

    review_upload_histories ||--o{ users : Thuộc về
    review_upload_histories ||--o{ groups : Thuộc về
    review_upload_histories ||--o{ review_upload_errors : Có nhiều

Tính năng chính

  • Hỗ trợ tải lên trực tiếp: Tạo URL có chữ ký cho tải lên trực tiếp từ client đến GCS
  • Theo dõi tải lên: Theo dõi lịch sử toàn diện với trạng thái và thông tin lỗi
  • Quản lý lỗi: Theo dõi lỗi chi tiết bao gồm lỗi xác thực cấp trường
  • Xuất CSV: Tải xuống báo cáo lỗi dưới dạng CSV để sửa dữ liệu
  • Phân trang: Hỗ trợ tập dữ liệu lớn với phân trang có thể cấu hình
  • Truy cập dựa trên nhóm: Tự động lọc theo nhóm của người dùng để bảo mật dữ liệu
  • Chuyển đổi Resource: Phản hồi API nhất quán sử dụng Laravel Resources
  • Cấu trúc đường dẫn dựa trên nhóm: Tạo đường dẫn tự động dựa trên nhóm và ngày của người dùng

Cân nhắc bảo mật

  • Phân tách nhóm: Người dùng chỉ có thể truy cập lịch sử tải lên của nhóm mình
  • Thời hạn URL có chữ ký: URL được tạo sẽ hết hạn sau 15 phút
  • Xác thực đầu vào: Tất cả endpoint đều có xác thực đầu vào toàn diện
  • Ghi log lỗi: Các thao tác thất bại được ghi log để giám sát và debug
  • Bảo mật đường dẫn tệp: Tệp được lưu trong thư mục riêng biệt cho nhóm với tổ chức dựa trên ngày