| # | Quyết định | Lý do | Giải quyết |
| 1 | Tải lên qua Multer (multipart/form-data) |
Đơn giản; server kiểm soát trực tiếp; không phụ thuộc service bên ngoài |
FR-001, NFR-004 |
| 2 | Xóa mềm với xóa vật lý trên filesystem |
Cho phép hoàn nguyên metadata; xóa vật lý ngay khi xóa mềm; kiểm toán |
FR-004 |
| 3 | Cơ sở dữ liệu file_db riêng biệt |
Mở rộng độc lập; biệt lập miền lỗi; phân tách rõ ràng trách nhiệm |
NFR-003 |
| 4 | Cấu trúc thư mục local phân cấp |
Hỗ trợ đa tenancy; đơn giản hóa kiểm soát truy cập; cách ly file theo user |
FR-005 |
| 5 | Trạng thái TEMP cho tải lên đang thực hiện |
Ngăn chặn tệp tin ảo; cho phép dọn dẹp tự động các tải lên bị bỏ rơi |
FR-006 |
| 6 | Xác thực dựa trên danh mục |
Bắt buộc quy tắc loại/kích thước tệp tin theo từng trường hợp sử dụng; ngăn chặn lạm dụng |
FR-001, NFR-005 |
| 7 | Thư mục là bản ghi sys_files (type=FOLDER) |
Bảng thống nhất cho tệp tin và thư mục; đơn giản hóa truy vấn; hỗ trợ điều hướng phân cấp |
FR-008 |
| 8 | Bảng quyền riêng biệt (sys_file_permissions) |
Kiểm soát truy cập chi tiết; hỗ trợ quyền ở cấp người dùng/vai trò/tổ chức; có thể kế thừa |
FR-014 |
| 9 | Tìm kiếm toàn văn qua PostgreSQL tsvector |
Tìm kiếm PostgreSQL gốc; không phụ thuộc bên ngoài; hỗ trợ nội dung Thái/Anh |
FR-009, NFR-007 |
| 10 | Ghi nhật ký truy cập dựa trên sự kiện (RabbitMQ → LOG → OpenSearch) |
Kiểm toán tách biệt; ghi nhật ký bất đồng bộ; quản lý nhật ký tập trung |
FR-015, NFR-010 |
| 11 | Sao chép = bản ghi mới với cùng file_path (không sao chép vật lý) |
Lưu trữ hiệu quả; không trùng lặp file vật lý; dọn dẹp theo số tham chiếu |
FR-012 |
| 12 | Di chuyển = cập nhật parent_folder_id |
Thao tác chỉ trên metadata; nhanh; không cần di chuyển file vật lý |
FR-013 |
| 13 | Hạn ngạch lưu trữ với theo dõi bất đồng bộ |
Ngăn chặn lạm dụng; kiểm tra hạn ngạch khi tải lên; theo dõi sử dụng qua tác vụ cron |
FR-016, FR-017 |
| 14 | Chính sách lưu trữ theo danh mục |
Các quy tắc có thể cấu hình; quản trị viên quản lý; chỉ ảnh hưởng tải lên mới |
FR-018 |
| Thành phần | Trách nhiệm | Giải quyết |
| FileController | Endpoint HTTP cho tải lên, tải xuống, liệt kê, xóa, sao chép, di chuyển, hàng loạt | FR-001 - FR-004, FR-007, FR-011, FR-012, FR-013 |
| FileService | Logic nghiệp vụ: xác thực, CRUD metadata, phối hợp filesystem | FR-001 - FR-005 |
| FileGuard | Kiểm soát truy cập: xác thực quyền sở hữu và RBAC | FR-005 |
| PermissionGuard | Kiểm tra quyền chi tiết (xem/sửa/xóa) theo người dùng/vai trò/tổ chức | FR-014 |
| PermissionService | Quản lý quyền tệp tin/thư mục (CRUD trên sys_file_permissions) | FR-014 |
| FolderService | CRUD thư mục, quản lý cấu trúc thư mục | FR-008, FR-015 |
| SearchService | Tìm kiếm toàn văn trên tên và metadata tệp tin/thư mục | FR-009 |
| StorageService | Theo dõi sử dụng lưu trữ, quản lý hạn ngạch, áp dụng chính sách | FR-016, FR-017, FR-018 |
| AuditService | Ghi nhật ký lịch sử truy cập (phát đến RabbitMQ cho module LOG) | FR-015 |
| FileWorker | Bộ tiêu thụ xóa file vật lý bất đồng bộ (xóa đối tượng vật lý) | FR-004 |
| MulterUtil | Cấu hình Multer cho upload multipart (disk storage, file filter) | FR-001 |
| FileUtil | Thao tác filesystem: đọc, xóa, copy tệp tin (fs.readFile, fs.unlink, fs.copyFile) | FR-001, FR-002, FR-004 |
| NameResolverUtil | Xử lý tên tệp tin/thư mục trùng lặp (thêm hậu tố số) | FR-010, FR-012, FR-013 |
| TempCleanupJob | Tác vụ cron xóa các tệp tin TEMP cũ hơn 24h | FR-006 |
| StorageUsageJob | Tác vụ cron tính toán và cập nhật thống kê sử dụng lưu trữ | FR-016 |
| Phương thức | Chữ ký | Mô tả |
| POST | uploadFile(dto: CreateFileDto) | Tải lên tệp tin (multipart) |
| POST | confirmUpload(dto: ConfirmFileDto) | Xác nhận tải lên, đặt trạng thái ACTIVE |
| POST | batchUpload(dto: BatchUploadDto) | Tải lên nhiều tệp tin |
| GET | downloadFile(id: string) | Tải xuống tệp tin (file stream) |
| GET | listFiles(query: ListFilesDto) | Liệt kê tệp tin với bộ lọc và phân trang |
| GET | searchFiles(query: SearchFilesDto) | Tìm kiếm toàn văn trên tệp tin/thư mục |
| POST | createFolder(dto: CreateFolderDto) | Tạo thư mục mới |
| PATCH | renameFile(id: string, dto: RenameFileDto) | Đổi tên tệp tin hoặc thư mục |
| POST | copyFile(id: string, dto: CopyFileDto) | Sao chép tệp tin đến thư mục đích |
| POST | moveFile(id: string, dto: MoveFileDto) | Di chuyển tệp tin đến thư mục đích |
| DELETE | deleteFile(id: string) | Xóa mềm tệp tin/thư mục, phát sự kiện dọn dẹp |
| GET | getPermissions(id: string) | Lấy quyền tệp tin/thư mục |
| PUT | managePermissions(id: string, dto: ManagePermissionsDto) | Cập nhật quyền cho tệp tin/thư mục |
| GET | getStorageUsage() | Lấy thống kê sử dụng lưu trữ |
| GET | getStorageQuotas() | Lấy cấu hình hạn ngạch lưu trữ |
| PUT | manageStorageQuotas(dto: StorageQuotaDto) | Cập nhật giới hạn hạn ngạch lưu trữ |
| GET | getStoragePolicies() | Lấy chính sách lưu trữ |
| PUT | manageStoragePolicies(dto: StoragePolicyDto) | Cập nhật chính sách lưu trữ |
| Phương thức | Chữ ký | Mô tả |
| createFileMetadata | (dto, userId, employerId?) | Chèn bản ghi sys_files với trạng thái TEMP |
| confirmUpload | (fileId, userId) | Xác minh quyền sở hữu, cập nhật trạng thái thành ACTIVE |
| generateDownloadUrl | (fileId, userId) | Xác thực truy cập, đọc file từ disk |
| listFiles | (filters, pagination) | Truy vấn tệp tin với kiểm soát truy cập |
| searchFiles | (query, filters, pagination) | Tìm kiếm toàn văn với kiểm soát truy cập |
| softDelete | (fileId, userId) | Đặt trạng thái DELETED, phát sự kiện file.deleted |
| cleanupTempFiles | () | Xóa các tệp tin TEMP cũ hơn 24h (cron) |
| Yêu cầu SRS | Giải pháp Thiết kế | Bảng CSDL |
| FR-001 Tải lên Tệp tin | Lưu tệp tin vào filesystem, tạo metadata | sys_files |
| FR-002 Tải xuống Tệp tin | Tra cứu file_path, đọc file từ disk | sys_files |
| FR-003 Liệt kê Tệp tin | Truy vấn với bộ lọc (người dùng, nhà tuyển dụng, danh mục) + phân trang | sys_files |
| FR-004 Xóa Tệp tin | Xóa mềm (status=DELETED), phát sự kiện để xóa file vật lý | sys_files |
| FR-005 Kiểm soát Truy cập | Middleware FileGuard xác thực quyền sở hữu hoặc thành viên tổ chức | sys_files + auth_users + auth_members |
| FR-006 Dọn dẹp Tạm | Tác vụ cron xóa các bản ghi TEMP > 24h, phát sự kiện dọn dẹp | sys_files |
| FR-007 Tải lên CV/Hồ sơ | Danh mục RESUME, thay thế CV hiện có | sys_files |
| FR-008 Tạo Thư mục | Tạo bản ghi với type=FOLDER, parent_folder_id | sys_files |
| FR-009 Tìm kiếm Tệp tin | Tìm kiếm toàn văn qua tsvector, lọc theo kiểm soát truy cập | sys_files |
| FR-010 Đổi tên Tệp tin | Cập nhật original_name, xử lý trùng lặp | sys_files |
| FR-011 Tải lên Hàng loạt | Nhiều tệp tin multipart, báo cáo thành công một phần | sys_files |
| FR-012 Sao chép Tệp tin | Bản ghi mới với cùng file_path, xử lý trùng lặp | sys_files |
| FR-013 Di chuyển Tệp tin | Cập nhật parent_folder_id, xử lý trùng lặp | sys_files |
| FR-014 Quản lý Quyền | CRUD trên sys_file_permissions, có thể kế thừa | sys_file_permissions |
| FR-015 Ghi nhật ký Truy cập | Sự kiện đến RabbitMQ → module LOG → OpenSearch | OpenSearch (qua LOG) |
| FR-016 Theo dõi Sử dụng | Tác vụ cron tính toán sử dụng theo người dùng/tổ chức | sys_storage_usage |
| FR-017 Quản lý Hạn ngạch | CRUD trên sys_storage_quotas, kiểm tra khi tải lên | sys_storage_quotas |
| FR-018 Chính sách Lưu trữ | CRUD trên sys_storage_policies, theo danh mục | sys_storage_policies |
| Phương thức | Đường dẫn | Mô tả | Giải quyết |
| POST | /files/upload | Tải lên tệp tin (multipart/form-data) | FR-001 |
| POST | /files/batch | Tải lên hàng loạt (nhiều tệp tin) | FR-011 |
| GET | /files/:id/download | Tải xuống tệp tin (file stream) | FR-002 |
| GET | /files | Liệt kê tệp tin với bộ lọc | FR-003 |
| GET | /files/search | Tìm kiếm toàn văn tệp tin/thư mục | FR-009 |
| POST | /files/folders | Tạo thư mục | FR-008 |
| PATCH | /files/:id | Đổi tên tệp tin/thư mục | FR-010 |
| POST | /files/:id/copy | Sao chép tệp tin đến thư mục | FR-012 |
| POST | /files/:id/move | Di chuyển tệp tin đến thư mục | FR-013 |
| DELETE | /files/:id | Xóa mềm tệp tin/thư mục | FR-004 |
| GET | /files/:id/permissions | Lấy quyền tệp tin | FR-014 |
| PUT | /files/:id/permissions | Quản lý quyền tệp tin | FR-014 |
| GET | /files/storage-usage | Lấy thống kê sử dụng lưu trữ | FR-016 |
| GET | /files/quotas | Lấy hạn ngạch lưu trữ | FR-017 |
| PUT | /files/quotas | Cập nhật hạn ngạch lưu trữ | FR-017 |
| GET | /files/policies | Lấy chính sách lưu trữ | FR-018 |
| PUT | /files/policies | Cập nhật chính sách lưu trữ | FR-018 |
| Yêu cầu SRS | Giải pháp Thiết kế | Triển khai |
| FR-005 Kiểm soát Truy cập Tệp tin |
Middleware FileGuard với kiểm tra quyền sở hữu + RBAC |
Kiểm tra khớp user_id hoặc thành viên tổ chức với vai trò admin/HR |
| NFR-002 Giới hạn Kích thước |
Kiểm tra kích thước tệp tin theo danh mục |
RESUME/COMPANY_DOC/JOB_ATTACHMENT: 10MB, AVATAR: 5MB |
| NFR-005 Giới hạn Kích thước Tệp tin |
Xác thực dựa trên danh mục |
RESUME/COMPANY_DOC/JOB_ATTACHMENT: 10MB, AVATAR: 5MB |
| Mã Yêu cầu SRS | Yêu cầu | Phần TDS | Quyết định Thiết kế |
| FR-001 | Tải lên Tệp tin | 3.2, 5.1, 6.1 | FileController + POST /files/upload (multipart) + Multer + FileUtil |
| FR-002 | Tải xuống Tệp tin | 3.2, 5.1, 6.2 | FileController + GET /files/:id/download + FileUtil (file stream) |
| FR-003 | Liệt kê Tệp tin | 3.2, 5.1 | FileController + GET /files với bộ lọc và phân trang |
| FR-004 | Xóa Tệp tin | 3.2, 5.1, 6.3 | FileController + DELETE /files/:id + sự kiện file.deleted + FileWorker |
| FR-005 | Kiểm soát Truy cập Tệp tin | 3.2, 7 | Middleware FileGuard với quyền sở hữu + xác thực RBAC |
| FR-006 | Dọn dẹp Tệp tin Tạm | 3.2, 6.4 | TempCleanupJob (cron) + sự kiện file.temp_cleanup + FileWorker |
| FR-007 | Tải lên CV/Hồ sơ | 3.2, 5.1 | FileController + danh mục RESUME + logic thay thế CV hiện có |
| FR-008 | Tạo Thư mục | 3.2, 5.1 | FolderService + POST /files/folders + bản ghi type=FOLDER |
| FR-009 | Tìm kiếm Tệp tin | 3.2, 5.1 | SearchService + GET /files/search + tìm kiếm toàn văn tsvector |
| FR-010 | Đổi tên Tệp tin | 3.2, 5.1 | FileController + PATCH /files/:id + NameResolverUtil |
| FR-011 | Tải lên Hàng loạt | 3.2, 5.1 | FileController + POST /files/batch + báo cáo thành công một phần |
| FR-012 | Sao chép Tệp tin | 3.2, 5.1 | FileController + POST /files/:id/copy + cùng file_path |
| FR-013 | Di chuyển Tệp tin | 3.2, 5.1 | FileController + POST /files/:id/move + cập nhật parent_folder_id |
| FR-014 | Quản lý Quyền | 3.2, 5.1, 7 | PermissionService + PUT /files/:id/permissions + có thể kế thừa |
| FR-015 | Ghi nhật ký Truy cập | 3.2 | AuditService → RabbitMQ → module LOG → OpenSearch |
| FR-016 | Theo dõi Sử dụng | 3.2, 5.1 | StorageService + GET /files/storage-usage + tác vụ cron |
| FR-017 | Quản lý Hạn ngạch | 3.2, 5.1 | StorageService + PUT /files/quotas + kiểm tra khi tải lên |
| FR-018 | Chính sách Lưu trữ | 3.2, 5.1 | StorageService + PUT /files/policies + cấu hình theo danh mục |
| NFR-001 | Hiệu suất | 2.1 | Local filesystem, server xử lý trực tiếp |
| NFR-002 | Bảo mật - Thời hạn URL | 7.3 | Giới hạn kích thước tệp tin theo danh mục |
| NFR-003 | Khả dụng | 2.1 | file_db độc lập; filesystem local trên server |
| NFR-004 | Khả năng mở rộng | 2.2 | Tải lên phía client; không bộ đệm tệp tin trên server |
| NFR-005 | Giới hạn Kích thước Tệp tin | 3.2, 7 | Xác thực dựa trên danh mục trong FileService |
| NFR-006 | Dọn dẹp Tạm | 6.4 | Tác vụ cron hàng giờ qua NestJS Scheduler |
| NFR-007 | Hiệu suất Tìm kiếm | 2.1, 3.2 | Chỉ mục PostgreSQL tsvector; < 1000ms p95 |
| NFR-008 | Tải lên Hàng loạt | 2.1, 3.2 | Xử lý upload song song; < 2000ms cho 20 tệp tin |
| NFR-009 | Độ trễ Kiểm soát Truy cập | 7 | PermissionGuard với tra cứu vai trò được đệm; < 100ms p95 |
| NFR-010 | Thời gian Lưu trữ Nhật ký | 3.2 | Chính sách vòng đời chỉ mục OpenSearch; 90 ngày mặc định |
| NFR-011 | Độ chính xác Lưu trữ | 3.2 | Tác vụ cron bất đồng bộ với dung sai +-1% |