| Phiên bản | 1.0.0 |
| Base URL | http://localhost:3001/api/files |
| Hệ thống | Hệ thống Cổng Thông tin Tuyển dụng |
| Module | FILE - Quản lý Tệp tin |
| Ngày | 2026-08-17 |
| Tác giả | Nam Nguyen |
| SRS liên quan | SRS Quản lý Tệp tin |
| Yêu cầu SRS | Endpoint API |
|---|---|
| FR-001 Tải lên Tệp tin | POST /files/upload (multipart) |
| FR-002 Tải xuống Tệp tin | GET /files/:id/download |
| FR-003 Liệt kê Tệp tin | GET /files |
| FR-004 Xóa Tệp tin | DELETE /files/:id |
| FR-005 Kiểm soát Truy cập Tệp tin | Tất cả endpoint (middleware) |
| FR-008 Tạo Thư mục | POST /files/folders |
| FR-009 Tìm kiếm Tệp tin | GET /files/search |
| FR-010 Đổi tên Tệp tin | PATCH /files/:id |
| FR-011 Tải lên Hàng loạt | POST /files/batch |
| FR-012 Sao chép Tệp tin | POST /files/:id/copy |
| FR-013 Di chuyển Tệp tin | POST /files/:id/move |
| FR-014 Quản lý Quyền | GET /files/:id/permissions, PUT /files/:id/permissions |
| FR-016 Theo dõi Sử dụng Lưu trữ | GET /files/storage-usage |
| FR-017 Quản lý Hạn ngạch | GET /files/quotas, PUT /files/quotas |
| FR-018 Chính sách Lưu trữ | GET /files/policies, PUT /files/policies |
Tất cả endpoint yêu cầu xác thực qua:
Authorization: Bearer <token>apiKeyCookieNgoài ra, quyền truy cập tệp tin được kiểm tra theo quyền sở hữu hoặc thành viên tổ chức (RBAC).
| Phương thức | Đường dẫn | Mô tả | Cần Xác thực |
|---|---|---|---|
| POST | /files/upload | Tải lên tệp tin (multipart/form-data) | Có |
| POST | /files/batch | Tải lên hàng loạt (nhiều tệp tin) | Có |
| GET | /files/:id/download | Tải xuống tệp tin (file stream) | Có |
| GET | /files | Liệt kê tệp tin với lọc và phân trang | Có |
| GET | /files/search | Tìm kiếm toàn văn tệp tin/thư mục | Có |
| POST | /files/folders | Tạo thư mục mới | Có |
| PATCH | /files/:id | Đổi tên tệp tin hoặc thư mục | Có |
| POST | /files/:id/copy | Sao chép tệp tin đến thư mục đích | Có |
| POST | /files/:id/move | Di chuyển tệp tin đến thư mục đích | Có |
| DELETE | /files/:id | Xóa mềm tệp tin hoặc thư mục | Có |
| GET | /files/:id/permissions | Lấy quyền tệp tin/thư mục | Có |
| PUT | /files/:id/permissions | Quản lý quyền tệp tin/thư mục | Có (Admin) |
| GET | /files/storage-usage | Lấy thống kê sử dụng lưu trữ | Có |
| GET | /files/quotas | Lấy cấu hình hạn ngạch lưu trữ | Có (Admin) |
| PUT | /files/quotas | Cập nhật giới hạn hạn ngạch lưu trữ | Có (Admin) |
| GET | /files/policies | Lấy chính sách lưu trữ | Có (Admin) |
| PUT | /files/policies | Cập nhật chính sách lưu trữ | Có (Admin) |
{
"success": true,
"data": { ... },
"message": "Thao tác hoàn tất thành công"
}
{
"success": true,
"data": {
"files": [ ... ],
"total": 42,
"page": 1,
"limit": 20
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Loại tệp tin không hợp lệ cho danh mục RESUME"
}
}
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
| id | string (UUID) | Có | Định danh tệp tin duy nhất |
| employerId | string (UUID) | Không | Mã nhà tuyển dụng liên kết (null cho tệp tin cá nhân) |
| userId | string (UUID) | Có | Mã người dùng chủ sở hữu |
| originalName | string | Có | Tên tệp tin gốc khi tải lên |
| filePath | string | Có | Đường dẫn tệp tin trên local filesystem |
| mimeType | string | Có | Loại MIME (ví dụ: application/pdf) |
| fileSize | number (bigint) | Có | Kích thước tệp tin bằng byte |
| category | string (enum) | Có | RESUME, AVATAR, COMPANY_DOC, JOB_ATTACHMENT, OTHER |
| isPublic | boolean | Có | Tệp tin có được truy cập công khai không |
| status | string (enum) | Có | TEMP, ACTIVE, DELETED, REPLACED |
| createdAt | datetime | Có | Thời gian tạo |
| updatedAt | datetime | Có | Thời gian cập nhật lần cuối |
| Trường | Loại | Mô tả |
|---|---|---|
| id | string (UUID) | Mã bản ghi tệp tin |
| originalName | string | Tên tệp tin gốc |
| filePath | string | Đường dẫn tệp tin trên filesystem |
Tải lên tệp tin qua multipart/form-data. Server lưu tệp tin vào local filesystem và tạo bản ghi metadata.
Yêu cầu: Content-Type: multipart/form-data
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
| file | file | Có | Tệp tin cần tải lên |
| category | string (enum) | Có | RESUME, AVATAR, COMPANY_DOC, JOB_ATTACHMENT, OTHER |
| employer_id | string (UUID) | Không | Mã nhà tuyển dụng cho tệp tin theo phạm vi tổ chức |
Quy tắc Xác thực:
| Danh mục | Các loại MIME được phép | Kích thước Tối đa |
|---|---|---|
| RESUME | application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document | 10 MB |
| AVATAR | image/jpeg, image/png, image/webp | 5 MB |
| COMPANY_DOC | image/*, application/pdf | 10 MB |
| JOB_ATTACHMENT | application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, image/* | 10 MB |
| OTHER | * | 10 MB |
Phản hồi 200:
{
"success": true,
"data": {
"id": "file-uuid-123",
"original_name": "my-resume.pdf",
"file_path": "user-123/RESUME/a1b2c3d4-resume.pdf",
"mime_type": "application/pdf",
"file_size": 524288,
"category": "RESUME",
"status": "ACTIVE"
}
}
Tải lên nhiều tệp tin trong một yêu cầu duy nhất (multipart/form-data).
Yêu cầu: Content-Type: multipart/form-data
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
| files | file[] | Có | Mảng các tệp tin cần tải lên |
| category | string (enum) | Có | RESUME, AVATAR, COMPANY_DOC, JOB_ATTACHMENT, OTHER |
| employer_id | string (UUID) | Không | Mã nhà tuyển dụng |
Phản hồi 200:
{
"success": true,
"data": {
"uploads": [
{ "id": "uuid-1", "original_name": "resume.pdf", "file_path": "..." },
{ "id": "uuid-2", "original_name": "avatar.jpg", "file_path": "..." }
],
"errors": []
}
}
Tải xuống tệp tin từ local filesystem. Kiểm tra quyền truy cập trước khi trả về nội dung.
Tham số Đường dẫn:
| Tham số | Loại | Mô tả |
|---|---|---|
| id | string (UUID) | Mã tệp tin |
Phản hồi 200: File stream (Content-Type: application/octet-stream)
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="my-resume.pdf"
Content-Length: 524288
<binary file data>
Lỗi 403 — Từ chối truy cập:
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "Bạn không có quyền truy cập tệp tin này"
}
}
Lỗi 404 — Không tìm thấy tệp tin:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Không tìm thấy tệp tin"
}
}
Liệt kê tệp tin với lọc tùy chọn theo người dùng, nhà tuyển dụng và danh mục. Hỗ trợ phân trang.
Tham số Truy vấn:
| Tham số | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
| user_id | string (UUID) | Không | Lọc theo mã người dùng (mặc định là người dùng hiện tại) |
| employer_id | string (UUID) | Không | Lọc theo mã nhà tuyển dụng |
| category | string (enum) | Không | Lọc theo danh mục (RESUME, AVATAR, COMPANY_DOC, JOB_ATTACHMENT, OTHER) |
| page | integer | Không | Số trang (mặc định: 1) |
| limit | integer | Không | Số mục mỗi trang (mặc định: 20, tối đa: 100) |
Ví dụ Yêu cầu:
GET /files?category=RESUME&page=1&limit=10
Phản hồi 200:
{
"success": true,
"data": {
"files": [
{
"id": "file-uuid-123",
"employer_id": "acme-corp-uuid",
"user_id": "user-uuid-456",
"original_name": "my-resume.pdf",
"file_path": "user-123/RESUME/a1b2c3d4-resume.pdf",
"file_path": "user-123/RESUME/a1b2c3d4-resume.pdf",
"mime_type": "application/pdf",
"file_size": 524288,
"category": "RESUME",
"is_public": false,
"status": "ACTIVE",
"created_at": "2026-08-17T10:45:00Z",
"updated_at": "2026-08-17T10:45:00Z"
}
],
"total": 42,
"page": 1,
"limit": 10
}
}
Tìm kiếm toàn văn trên tên và metadata tệp tin/thư mục.
Tham số Truy vấn:
| Tham số | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
| q | string | Có | Truy vấn tìm kiếm |
| category | string | Không | Lọc theo danh mục |
| mime_type | string | Không | Lọc theo loại MIME |
| page | integer | Không | Số trang (mặc định: 1) |
| limit | integer | Không | Số mục mỗi trang (mặc định: 20) |
Phản hồi 200:
{
"success": true,
"data": {
"files": [ ... ],
"total": 15,
"page": 1,
"limit": 20
}
}
Tạo thư mục mới trong cấu trúc thư mục được ủy quyền.
Yêu cầu:
{
"name": "My Documents",
"parent_folder_id": "folder-uuid-123"
}
Phản hồi 200:
{
"success": true,
"data": {
"id": "folder-uuid-456",
"name": "My Documents",
"parent_folder_id": "folder-uuid-123",
"type": "FOLDER",
"created_at": "2026-08-17T10:45:00Z"
}
}
Đổi tên tệp tin hoặc thư mục. Xử lý tên trùng lặp bằng cách thêm hậu tố số.
Yêu cầu:
{
"name": "New Document Name"
}
Phản hồi 200:
{
"success": true,
"data": {
"id": "file-uuid-123",
"original_name": "New Document Name",
"updated_at": "2026-08-17T10:50:00Z"
}
}
Sao chép tệp tin đến thư mục đích. Tạo bản ghi mới với cùng file vật lý.
Yêu cầu:
{
"destination_folder_id": "folder-uuid-789"
}
Phản hồi 200:
{
"success": true,
"data": {
"id": "file-uuid-new",
"original_name": "document.pdf",
"parent_folder_id": "folder-uuid-789",
"file_path": "same-as-original",
"created_at": "2026-08-17T10:55:00Z"
}
}
Di chuyển tệp tin đến thư mục đích. Cập nhật parent_folder_id.
Yêu cầu:
{
"destination_folder_id": "folder-uuid-789"
}
Phản hồi 200:
{
"success": true,
"data": {
"id": "file-uuid-123",
"original_name": "document.pdf",
"parent_folder_id": "folder-uuid-789",
"updated_at": "2026-08-17T11:00:00Z"
}
}
Xóa mềm tệp tin hoặc thư mục. Đối với thư mục, đánh dấu đệ quy tất cả các mục con là DELETED.
Phản hồi 200:
{
"success": true,
"message": "Tệp tin/thư mục đã được xóa thành công"
}
Lấy tất cả quyền cho tệp tin hoặc thư mục.
Phản hồi 200:
{
"success": true,
"data": {
"permissions": [
{ "id": "perm-uuid-1", "user_id": "user-uuid-1", "permission": "VIEW" },
{ "id": "perm-uuid-2", "role": "HR", "permission": "DOWNLOAD" },
{ "id": "perm-uuid-3", "org_id": "org-uuid-1", "permission": "EDIT" }
]
}
}
Cập nhật quyền cho tệp tin hoặc thư mục (chỉ admin).
Yêu cầu:
{
"permissions": [
{ "user_id": "user-uuid-1", "permission": "VIEW" },
{ "role": "HR", "permission": "DOWNLOAD" },
{ "org_id": "org-uuid-1", "permission": "EDIT" }
]
}
Phản hồi 200:
{
"success": true,
"message": "Quyền đã được cập nhật thành công"
}
Lấy thống kê sử dụng lưu trữ cho người dùng hoặc tổ chức hiện tại.
Phản hồi 200:
{
"success": true,
"data": {
"user": { "total_size": 52428800, "file_count": 25 },
"organization": { "total_size": 524288000, "file_count": 250 }
}
}
Lấy cấu hình hạn ngạch lưu trữ (chỉ admin).
Phản hồi 200:
{
"success": true,
"data": {
"quotas": [
{ "user_id": "user-uuid-1", "max_total_size": 104857600, "max_file_count": 100 },
{ "org_id": "org-uuid-1", "max_total_size": 1073741824, "max_file_count": 1000 }
]
}
}
Cập nhật giới hạn hạn ngạch lưu trữ (chỉ admin).
Yêu cầu:
{
"user_id": "user-uuid-1",
"max_total_size": 209715200,
"max_file_count": 200
}
Lấy chính sách lưu trữ theo danh mục (chỉ admin).
Phản hồi 200:
{
"success": true,
"data": {
"policies": [
{
"category": "RESUME",
"allowed_mime_types": ["application/pdf", "application/msword"],
"max_file_size": 10485760,
"retention_days": null,
"encryption_enabled": false
}
]
}
}
Cập nhật chính sách lưu trữ (chỉ admin).
Yêu cầu:
{
"category": "RESUME",
"allowed_mime_types": ["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
"max_file_size": 10485760,
"retention_days": 365,
"encryption_enabled": true
}
| HTTP Status | Mã Lỗi | Mô tả |
|---|---|---|
| 400 | VALIDATION_ERROR | Xác thực yêu cầu thất bại (thiếu/trường không hợp lệ, loại tệp tin không hợp lệ) |
| 400 | INVALID_NAME | Tên tệp tin/thư mục chứa ký tự đặc biệt |
| 400 | INVALID_FOLDER | Không thể di chuyển thư mục vào chính nó |
| 401 | UNAUTHORIZED | Thiếu hoặc xác thực không hợp lệ |
| 403 | FORBIDDEN | Không đủ quyền (không phải chủ sở hữu tệp tin, không phải admin tổ chức) |
| 404 | NOT_FOUND | Không tìm thấy tệp tin/thư mục hoặc đã bị xóa |
| 409 | NAME_CONFLICT | Tệp tin/thư mục với tên tương tự đã tồn tại tại vị trí đích |
| 413 | PAYLOAD_TOO_LARGE | Tệp tin vượt quá kích thước tối đa cho danh mục |
| 413 | QUOTA_EXCEEDED | Vượt quá hạn ngạch lưu trữ cho người dùng hoặc tổ chức |
| 415 | UNSUPPORTED_MEDIA_TYPE | Loại MIME tệp tin không được phép cho danh mục |
| 429 | RATE_LIMITED | Quá nhiều yêu cầu |
| 500 | INTERNAL_ERROR | Lỗi server (filesystem không khả dụng) |