Tài liệu Thiết kế Cơ sở Dữ liệu

Module Quản lý Tệp tin
FILE
Phiên bản1.0
Hệ thốngHệ thống Cổng Thông tin Tuyển dụng
ModuleFILE - Quản lý Tệp tin
Cơ sở dữ liệufile_db
ORMDrizzle ORM
Ngày2026-08-17
Tác giảNam Nguyen
SRS liên quanSRS Quản lý Tệp tin

Mục lục

1. Tổng quan

1.1 Mục đích

Tài liệu này định nghĩa thiết kế cơ sở dữ liệu cho module Quản lý Tệp tin (cơ sở dữ liệu: file_db).

1.2 Yêu cầu được Giải quyết

Yêu cầu SRSGiải pháp Cơ sở dữ liệu
FR-001 Tải lên Tệp tinBảng sys_files (lưu trữ metadata)
FR-002 Tải xuống Tệp tinBảng sys_files (tra cứu file_path)
FR-003 Liệt kê Tệp tinBảng sys_files (truy vấn với chỉ mục)
FR-004 Xóa Tệp tinBảng sys_files (xóa mềm qua status/deleted_at)
FR-008 Tạo Thư mụcBảng sys_files (type=FOLDER, parent_folder_id)
FR-014 Quản lý QuyềnBảng sys_file_permissions
FR-016 Theo dõi Sử dụng Lưu trữBảng sys_storage_usage
FR-017 Quản lý Hạn ngạchBảng sys_storage_quotas
FR-018 Chính sách Lưu trữBảng sys_storage_policies

1.3 Sơ đồ ERD

Sơ đồ ERD
Hình 1: ERD Quản lý Tệp tin

2. Thiết kế Schema

2.1 Chiến lược Cơ sở dữ liệu

Khía cạnhQuyết định
Cơ sở dữ liệufile_db
Đặt tên bảngsys_<table_name>
Khóa chínhUUID (qua gen_random_uuid())
Thời giancreated_at, updated_at với mặc định NOW()
Xóa mềmCột deleted_at (NULL = đang hoạt động)
Backend Lưu trữLocal Filesystem (Multer + fs)

2.2 Metadata Tệp tin & Thư mục

CộtLoạiCho phép NULLMặc địnhMô tả
iduuidKHÔNGgen_random_uuid()Khóa chính
employer_iduuidNULLFK đến sys_employers(id), SET NULL khi xóa
user_iduuidKHÔNG-FK đến auth_users(id), CASCADE khi xóa
parent_folder_iduuidNULLFK đến sys_files(id), thư mục cha (NULL = gốc)
typevarchar(10)KHÔNG'FILE'Loại bản ghi: FILE hoặc FOLDER
original_namevarchar(500)KHÔNG-Tên tệp tin gốc hoặc tên thư mục
file_pathvarchar(1000)NULLĐường dẫn tệp tin trên local filesystem (NULL cho thư mục)
mime_typevarchar(100)NULLLoại MIME (NULL cho thư mục)
file_sizebigint0Kích thước tệp tin bằng byte (0 cho thư mục)
categoryvarchar(50)KHÔNG'OTHER'Phân loại danh mục tệp tin
is_publicbooleanKHÔNGFALSETệp tin có được truy cập công khai không
statusvarchar(20)KHÔNG'ACTIVE'Vòng đời trạng thái tệp tin
search_vectortsvectorNULLVector tìm kiếm toàn văn (chỉ tệp tin/thư mục)
created_attimestampKHÔNGNOW()Thời gian tạo
updated_attimestampKHÔNGNOW()Thời gian cập nhật lần cuối
deleted_attimestampNULLThời gian xóa mềm (NULL = đang hoạt động)
CREATE TABLE sys_files (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  employer_id     UUID REFERENCES sys_employers(id) ON DELETE SET NULL,
  user_id         UUID NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
  parent_folder_id UUID REFERENCES sys_files(id) ON DELETE SET NULL,
  type            VARCHAR(10) NOT NULL DEFAULT 'FILE',
  original_name   VARCHAR(500) NOT NULL,
  file_path       VARCHAR(1000),
  mime_type       VARCHAR(100),
  file_size       BIGINT DEFAULT 0,
  category        VARCHAR(50) NOT NULL DEFAULT 'OTHER',
  is_public       BOOLEAN NOT NULL DEFAULT FALSE,
  status          VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
  search_vector   TSVECTOR,
  created_at      TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at      TIMESTAMP NOT NULL DEFAULT NOW(),
  deleted_at      TIMESTAMP,
  CONSTRAINT sys_files_type_check CHECK (type IN ('FILE', 'FOLDER')),
  CONSTRAINT sys_files_category_check CHECK (category IN ('RESUME', 'AVATAR', 'COMPANY_DOC', 'JOB_ATTACHMENT', 'OTHER')),
  CONSTRAINT sys_files_status_check CHECK (status IN ('TEMP', 'ACTIVE', 'DELETED', 'REPLACED'))
);

-- Thư mục: file_path, mime_type là NULL
-- Tệp tin: file_path, mime_type không NULL

2.3 Chiến lược Đường dẫn Lưu trữ

Các tệp tin được tổ chức trên local filesystem bằng cấu trúc thư mục phân cấp hỗ trợ đa tenancy và kiểm soát truy cập:

Ngữ cảnhMẫuVí dụ
Theo phạm vi Tổ chứcuploads/{user_id}/{category}/{uuid_filename}uploads/user-123/RESUME/a1b2c3d4-resume.pdf
Người dùng cá nhânuploads/{user_id}/{category}/{uuid_filename}uploads/user-456/AVATAR/e5f6g7h8-photo.jpg

Các Thành phần Đường dẫn:

2.4 Giá trị Enum Danh mục

Danh mụcMô tảCác loại MIME Thông thườngKích thước Tối đa
RESUMETệp tin hồ sơ/CV của người dùngapplication/pdf, application/msword10 MB
AVATARẢnh hồ sơ người dùngimage/jpeg, image/png, image/webp5 MB
COMPANY_DOCTài liệu công ty (logo, chứng nhận)image/*, application/pdf10 MB
JOB_ATTACHMENTĐính kèm bài tuyển dụngapplication/pdf, application/msword, image/*10 MB
OTHERTệp tin chung/khác*10 MB

2.5 Vòng đời Trạng thái

Trạng tháiMô tảChuyển đổi
TEMPMultipartFile đã nhận, lưu vào filesystemTEMP → ACTIVE (khi xác nhận), TEMP → DELETED (khi hết hạn/dọn dẹp)
ACTIVEĐã xác nhận tải lên, tệp tin sẵn sàng sử dụngACTIVE → DELETED (khi người dùng/hệ thống xóa), ACTIVE → REPLACED (tải lên CV)
DELETEDĐã xóa mềm, đã xóa vật lý trên filesystemDELETED → (trạng thái kết thúc, dọn dẹp vật lý bởi worker)
REPLACEDĐã thay thế bởi phiên bản mới hơn (tải lên CV)REPLACED → (trạng thái kết thúc, dọn dẹp vật lý bởi worker)

2.6 Quyền truy cập Tệp tin

CộtLoạiCho phép NULLMặc địnhMô tả
iduuidKHÔNGgen_random_uuid()Khóa chính
file_iduuidKHÔNG-FK đến sys_files(id), CASCADE khi xóa
user_iduuidNULLFK đến auth_users(id), quyền cấp người dùng
rolevarchar(50)NULLQuyền dựa trên vai trò (ADMIN, HR, MEMBER)
org_iduuidNULLQuyền trên toàn tổ chức
permissionvarchar(20)KHÔNG-Loại quyền: VIEW, DOWNLOAD, EDIT, DELETE
created_attimestampKHÔNGNOW()Thời gian tạo
updated_attimestampKHÔNGNOW()Thời gian cập nhật lần cuối
CREATE TABLE sys_file_permissions (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  file_id         UUID NOT NULL REFERENCES sys_files(id) ON DELETE CASCADE,
  user_id         UUID REFERENCES auth_users(id) ON DELETE CASCADE,
  role            VARCHAR(50),
  org_id          UUID,
  permission      VARCHAR(20) NOT NULL,
  created_at      TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at      TIMESTAMP NOT NULL DEFAULT NOW(),
  CONSTRAINT sys_file_permissions_permission_check CHECK (permission IN ('VIEW', 'DOWNLOAD', 'EDIT', 'DELETE')),
  CONSTRAINT sys_file_permissions_target_check CHECK (
    (user_id IS NOT NULL AND role IS NULL AND org_id IS NULL) OR
    (user_id IS NULL AND role IS NOT NULL AND org_id IS NULL) OR
    (user_id IS NULL AND role IS NULL AND org_id IS NOT NULL)
  )
);

-- Một trong ba: user_id, role, hoặc org_id phải được đặt (không phải nhiều)

2.7 Thống kê Sử dụng Lưu trữ

CộtLoạiCho phép NULLMặc địnhMô tả
iduuidKHÔNGgen_random_uuid()Khóa chính
user_iduuidNULLFK đến auth_users(id), sử dụng cấp người dùng
org_iduuidNULLSử dụng cấp tổ chức
total_sizebigintKHÔNG0Tổng dung lượng lưu trữ đã sử dụng bằng byte
file_countintegerKHÔNG0Số lượng tệp tin
last_calculated_attimestampKHÔNGNOW()Thời gian tính toán lần cuối
CREATE TABLE sys_storage_usage (
  id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id             UUID REFERENCES auth_users(id) ON DELETE CASCADE,
  org_id              UUID,
  total_size          BIGINT NOT NULL DEFAULT 0,
  file_count          INTEGER NOT NULL DEFAULT 0,
  last_calculated_at  TIMESTAMP NOT NULL DEFAULT NOW(),
  CONSTRAINT sys_storage_usage_scope_check CHECK (
    (user_id IS NOT NULL AND org_id IS NULL) OR
    (user_id IS NULL AND org_id IS NOT NULL)
  )
);

CREATE UNIQUE INDEX sys_storage_usage_user_idx ON sys_storage_usage(user_id) WHERE user_id IS NOT NULL;
CREATE UNIQUE INDEX sys_storage_usage_org_idx ON sys_storage_usage(org_id) WHERE org_id IS NOT NULL;

2.8 Hạn ngạch Lưu trữ

CộtLoạiCho phép NULLMặc địnhMô tả
iduuidKHÔNGgen_random_uuid()Khóa chính
user_iduuidNULLFK đến auth_users(id), hạn ngạch cấp người dùng
org_iduuidNULLHạn ngạch cấp tổ chức
max_total_sizebigintKHÔNG-Tổng dung lượng tối đa bằng byte
max_file_countintegerKHÔNG-Số lượng tệp tin tối đa
created_attimestampKHÔNGNOW()Thời gian tạo
updated_attimestampKHÔNGNOW()Thời gian cập nhật lần cuối
CREATE TABLE sys_storage_quotas (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id         UUID REFERENCES auth_users(id) ON DELETE CASCADE,
  org_id          UUID,
  max_total_size  BIGINT NOT NULL,
  max_file_count  INTEGER NOT NULL,
  created_at      TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at      TIMESTAMP NOT NULL DEFAULT NOW(),
  CONSTRAINT sys_storage_quotas_scope_check CHECK (
    (user_id IS NOT NULL AND org_id IS NULL) OR
    (user_id IS NULL AND org_id IS NOT NULL)
  )
);

CREATE UNIQUE INDEX sys_storage_quotas_user_idx ON sys_storage_quotas(user_id) WHERE user_id IS NOT NULL;
CREATE UNIQUE INDEX sys_storage_quotas_org_idx ON sys_storage_quotas(org_id) WHERE org_id IS NOT NULL;

2.9 Chính sách Lưu trữ

CộtLoạiCho phép NULLMặc địnhMô tả
iduuidKHÔNGgen_random_uuid()Khóa chính
categoryvarchar(50)KHÔNG-Danh mục tệp tin (duy nhất)
allowed_mime_typesjsonbKHÔNG-Mảng các loại MIME được phép
max_file_sizebigintKHÔNG-Kích thước tệp tin tối đa bằng byte
retention_daysintegerNULLThời gian lưu trữ bằng ngày (NULL = vĩnh viễn)
encryption_enabledbooleanKHÔNGFALSEBật mã hóa phía server
created_attimestampKHÔNGNOW()Thời gian tạo
updated_attimestampKHÔNGNOW()Thời gian cập nhật lần cuối
CREATE TABLE sys_storage_policies (
  id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  category            VARCHAR(50) NOT NULL UNIQUE,
  allowed_mime_types  JSONB NOT NULL,
  max_file_size       BIGINT NOT NULL,
  retention_days      INTEGER,
  encryption_enabled  BOOLEAN NOT NULL DEFAULT FALSE,
  created_at          TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at          TIMESTAMP NOT NULL DEFAULT NOW()
);

-- Chính sách mặc định
INSERT INTO sys_storage_policies (category, allowed_mime_types, max_file_size) VALUES
  ('RESUME', '["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"]', 10485760),
  ('AVATAR', '["image/jpeg", "image/png", "image/webp"]', 5242880),
  ('COMPANY_DOC', '["image/*", "application/pdf"]', 10485760),
  ('JOB_ATTACHMENT', '["application/pdf", "application/msword", "image/*"]', 10485760),
  ('OTHER', '["*/*"]', 10485760);

3. Chỉ mục

-- sys_files
CREATE INDEX sys_files_user_id_idx ON sys_files(user_id);
CREATE INDEX sys_files_employer_id_idx ON sys_files(employer_id);
CREATE INDEX sys_files_category_idx ON sys_files(category);
CREATE INDEX sys_files_status_idx ON sys_files(status);
CREATE INDEX sys_files_created_at_idx ON sys_files(created_at);
CREATE INDEX sys_files_type_idx ON sys_files(type);
CREATE INDEX sys_files_parent_folder_id_idx ON sys_files(parent_folder_id);

-- Chỉ mục tổng hợp cho mẫu truy vấn phổ biến (liệt kê tệp tin đang hoạt động theo người dùng và danh mục)
CREATE INDEX sys_files_user_category_status_idx ON sys_files(user_id, category, status);

-- Chỉ mục tổng hợp cho truy vấn theo phạm vi nhà tuyển dụng
CREATE INDEX sys_files_employer_category_status_idx ON sys_files(employer_id, category, status);

-- Chỉ mục tổng hợp cho liệt kê thư mục (các mục con của một thư mục)
CREATE INDEX sys_files_parent_folder_type_idx ON sys_files(parent_folder_id, type, status);

-- Chỉ mục tìm kiếm toàn văn
CREATE INDEX sys_files_search_idx ON sys_files USING gin(search_vector);

-- Ràng buộc duy nhất trên file_path để ngăn trùng lặp (chỉ cho tệp tin)
CREATE UNIQUE INDEX sys_files_file_path_unique ON sys_files(file_path) WHERE file_path IS NOT NULL;

-- sys_file_permissions
CREATE INDEX sys_file_permissions_file_id_idx ON sys_file_permissions(file_id);
CREATE INDEX sys_file_permissions_user_id_idx ON sys_file_permissions(user_id);
CREATE INDEX sys_file_permissions_role_idx ON sys_file_permissions(role);
CREATE INDEX sys_file_permissions_org_id_idx ON sys_file_permissions(org_id);

-- sys_storage_usage
CREATE INDEX sys_storage_usage_user_id_idx ON sys_storage_usage(user_id);
CREATE INDEX sys_storage_usage_org_id_idx ON sys_storage_usage(org_id);

-- sys_storage_quotas
CREATE INDEX sys_storage_quotas_user_id_idx ON sys_storage_quotas(user_id);
CREATE INDEX sys_storage_quotas_org_id_idx ON sys_storage_quotas(org_id);

Mẫu Sử dụng Chỉ mục

Mẫu Truy vấnChỉ mục Sử dụng dòng Ước tính
Liệt kê CV của người dùngsys_files_user_category_status_idx5-20
Liệt kê tài liệu nhà tuyển dụngsys_files_employer_category_status_idx10-50
Tìm tệp tin theo IDKhóa chính (id)1
Dọn dẹp các tệp tin TEMP cũsys_files_status_idx + sys_files_created_at_idx0-100
Liệt kê các tải lên gần đâysys_files_created_at_idxthay đổi

4. Di chuyển Dữ liệu

4.1 Chiến lược Di chuyển

Khía cạnhQuyết định
Công cụDrizzle ORM (drizzle-kit)
Cơ sở dữ liệufile_db
Hoàn nguyênBắt buộc cho mỗi bản di chuyển

4.2 Thứ tự Di chuyển

Thứ tựDi chuyểnMô tả
1001_create_sys_filesTạo bảng sys_files với ràng buộc
2002_create_indexesTạo tất cả chỉ mục
3003_add_folder_supportThêm các cột parent_folder_id, type, search_vector vào sys_files
4004_create_sys_file_permissionsTạo bảng sys_file_permissions
5005_create_sys_storage_usageTạo bảng sys_storage_usage
6006_create_sys_storage_quotasTạo bảng sys_storage_quotas
7007_create_sys_storage_policiesTạo bảng sys_storage_policies với dữ liệu mặc định

5. Từ điển Dữ liệu

BảngMô tảGiải quyết dòng Ước tính (Năm 1)
sys_filesMetadata tệp tin và thư mục, tham chiếu lưu trữFR-001 - FR-013150,000
sys_file_permissionsQuyền truy cập chi tiết cho mỗi tệp tin/thư mụcFR-01450,000
sys_storage_usageThống kê sử dụng lưu trữ theo người dùng/tổ chứcFR-01610,000
sys_storage_quotasCấu hình hạn ngạch lưu trữ theo người dùng/tổ chứcFR-0175,000
sys_storage_policiesChính sách lưu trữ theo danh mục tệp tinFR-0185

Ước tính Tăng trưởng Dòng

Danh mục Tệp tinKích thước Trung bình (byte)Ước tính Dòng/Năm 1Lưu trữ (GB)
RESUME500 KB20,00010
AVATAR200 KB15,0003
COMPANY_DOC1 MB5,0005
JOB_ATTACHMENT800 KB10,0008
OTHER500 KB5,0002.5
Tổng cộng-55,00028.5