Tài liệu Thiết kế Cơ sở dữ liệu
Module Xác thực
AUTH
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 Xác thực (cơ sở dữ liệu: auth_db).
1.2 Yêu cầu được đề cập
| Yêu cầu SRS | Giải pháp Cơ sở dữ liệu |
| FR-001 Đăng ký | auth_users, auth_accounts |
| FR-002 Đăng nhập | auth_users, auth_sessions |
| FR-008/FR-009 Xác minh | auth_verification |
| FR-011 Vai trò | auth_roles, auth_user_roles |
1.3 Sơ đồ ERD
Hình 1: ERD Module Xác thực
2. Thiết kế Schema
2.1 Chiến lược Cơ sở dữ liệu
| Khía cạnh | Quyết định |
| Cơ sở dữ liệu | auth_db |
| Quy tắc đặt tên bảng | auth_<table_name> |
| Khóa chính | UUID (via gen_random_uuid()) |
| Dấu thời gian | created_at, updated_at with NOW() default |
2.2 Bảng: auth_users
| Tên Cột | Kiểu Dữ liệu | Nullable | Mặc định | Mô tả |
| id | uuid | NO | gen_random_uuid() | Khóa chính |
| email | varchar(255) | YES | NULL | Email duy nhất |
| phone | varchar(20) | YES | NULL | Số điện thoại duy nhất |
| name | varchar(100) | NO | - | Tên hiển thị |
| password_hash | varchar(255) | YES | NULL | bcrypt hash |
| email_verified | boolean | NO | false | Cờ xác minh email |
| phone_verified | boolean | NO | false | Cờ xác minh số điện thoại |
| status | varchar(20) | NO | active | active, inactive, banned |
| created_at | timestamp | NO | NOW() | Thời gian tạo |
| updated_at | timestamp | NO | NOW() | Thời gian cập nhật cuối |
CREATE TABLE auth_users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE,
phone VARCHAR(20) UNIQUE,
name VARCHAR(100) NOT NULL,
password_hash VARCHAR(255),
email_verified BOOLEAN NOT NULL DEFAULT false,
phone_verified BOOLEAN NOT NULL DEFAULT false,
status VARCHAR(20) NOT NULL DEFAULT 'active'
CHECK (status IN ('active', 'inactive', 'banned')),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT auth_users_email_or_phone CHECK (email IS NOT NULL OR phone IS NOT NULL)
);
2.3 Bảng: auth_sessions
CREATE TABLE auth_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
token VARCHAR(500) NOT NULL,
refresh_token VARCHAR(500),
ip_address VARCHAR(45),
user_agent TEXT,
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
2.4 Bảng: auth_accounts
CREATE TABLE auth_accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
provider VARCHAR(50) NOT NULL,
provider_id VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT auth_accounts_provider_unique UNIQUE (provider, provider_id)
);
2.5 Bảng: auth_verification
CREATE TABLE auth_verification (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
code VARCHAR(10) NOT NULL,
type VARCHAR(20) NOT NULL
CHECK (type IN ('email', 'phone', 'password_reset')),
expires_at TIMESTAMP NOT NULL,
used BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
2.6 Bảng: auth_roles
CREATE TABLE auth_roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(50) NOT NULL UNIQUE,
description TEXT,
permissions JSONB DEFAULT '[]',
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
Vai trò Hệ thống Mặc định
| Vai trò | Mô tả | Đăng ký Tự động | Quyền hạn |
user | Tài khoản người dùng thông thường (mặc định). Có thể tạo tổ chức và nhận vai trò cấp tổ chức. | Có (mặc định) | Quyền hạn trong phạm vi tổ chức |
super_admin | Quản trị viên hệ thống có toàn quyền truy cập tất cả người dùng, vai trò và tổ chức. | Không (chỉ tạo bởi admin qua POST /admin/create-user) | Truy cập toàn bộ hệ thống |
Lưu ý: Tài khoản super_admin chỉ có thể được tạo bởi admin hiện tại qua POST /admin/create-user. Endpoint đăng ký (POST /sign-up/email) chỉ gán vai trò user.
2.7 Bảng: auth_user_roles
CREATE TABLE auth_user_roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
role_id UUID NOT NULL REFERENCES auth_roles(id) ON DELETE CASCADE,
assigned_at TIMESTAMP NOT NULL DEFAULT NOW(),
assigned_by UUID REFERENCES auth_users(id),
CONSTRAINT auth_user_roles_unique UNIQUE (user_id, role_id)
);
2.8 Bảng: auth_organizations
CREATE TABLE auth_organizations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100) NOT NULL,
slug VARCHAR(100) NOT NULL UNIQUE,
logo VARCHAR(500),
metadata JSONB,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
2.9 Bảng: auth_members
CREATE TABLE auth_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES auth_organizations(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
role VARCHAR(50) NOT NULL DEFAULT 'member',
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT auth_members_unique UNIQUE (organization_id, user_id)
);
2.10 Bảng: auth_teams
CREATE TABLE auth_teams (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100) NOT NULL,
organization_id UUID NOT NULL REFERENCES auth_organizations(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
2.11 Bảng: auth_team_members
CREATE TABLE auth_team_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
team_id UUID NOT NULL REFERENCES auth_teams(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT auth_team_members_unique UNIQUE (team_id, user_id)
);
2.12 Bảng: auth_invitations
CREATE TABLE auth_invitations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES auth_organizations(id) ON DELETE CASCADE,
email VARCHAR(255) NOT NULL,
token_hash VARCHAR(64) UNIQUE,
role VARCHAR(50) DEFAULT 'member',
team_id UUID REFERENCES auth_teams(id) ON DELETE SET NULL,
employer_id UUID,
status VARCHAR(20) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'accepted', 'rejected', 'canceled', 'expired', 'revoked')),
expires_at TIMESTAMP NOT NULL,
accepted_at TIMESTAMP,
inviter_id UUID NOT NULL REFERENCES auth_users(id),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
Định nghĩa Cột (cột mới):
| Tên Cột | Kiểu Dữ liệu | Mô tả |
| token_hash | varchar(64) | SHA-256 hash của token mời gốc. Chỉ lưu hash; token gốc được gửi qua URL email. Ràng buộc UNIQUE đảm bảo không có token trùng lặp. |
| employer_id | uuid | Tham chiếu tùy chọn đến tổ chức nhà tuyển dụng. Được sử dụng cho các lời mời vai trò cụ thể (ví dụ: vai trò HR cần ngữ cảnh nhà tuyển dụng). |
| accepted_at | timestamp | Dấu thời gian khi lời mời được chấp nhận. NULL cho đến khi được chấp nhận. |
| updated_at | timestamp | Dấu thời gian sửa đổi cuối. Cập nhật khi gửi lại, thu hồi hoặc thay đổi trạng thái. |
Giá trị Trạng thái:
| Trạng thái | Mô tả |
pending | Lời mời đã gửi, đang chờ phản hồi |
accepted | Lời mời đã được chấp nhận (trạng thái cuối) |
rejected | Lời mời bị từ chối bởi người được mời |
canceled | Đã hủy bởi người gửi lời mời (cũ) |
expired | Token đã hết hạn (tự động đặt khi xác minh) |
revoked | Đã thu hồi bởi người gửi lời mời (chỉ chủ sở hữu) |
2.13 Bảng: auth_organization_roles
CREATE TABLE auth_organization_roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES auth_organizations(id) ON DELETE CASCADE,
role VARCHAR(50) NOT NULL,
description VARCHAR(500),
permission VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT auth_org_roles_unique UNIQUE (organization_id, role)
);
Định nghĩa Cột:
| Tên Cột | Mô tả |
| organization_id | FK tham chiếu auth_organizations, CASCADE khi xóa |
| role | Tên vai trò, duy nhất trong tổ chức (2-50 ký tự, chữ cái số + gạch dưới) |
| description | Mô tả tùy chọn về mục đích vai trò |
| permission | Các quyền hạn phân tách bằng dấu phẩy theo định dạng resource:action (tối đa 255 ký tự) |
Định dạng Quyền hạn: resource:action (ví dụ: job:read, member:update)
Vai trò Tổ chức Mặc định
Mỗi tổ chức có thể định nghĩa vai trò riêng. Dưới đây là các vai trò tổ chức tiêu chuẩn thường được sử dụng:
| Vai trò | Mô tả | Quyền hạn Thường gặp |
Employer | Chủ sở hữu/quản trị viên tổ chức quản lý hồ sơ công ty và đăng tin tuyển dụng. Được gán tự động khi người dùng tạo tổ chức. | job:create, job:update, job:delete, application:read, member:read, settings:read, settings:update |
HR | Thành viên đội ngũ tuyển dụng nội bộ quản lý quy trình tuyển dụng. | job:read, job:create, job:update, application:read, application:update, interview:create, interview:update, member:read |
Candidate | Ứng viên tìm việc nộp đơn vào các vị trí trong tổ chức. | job:read, application:create, application:read (chỉ của bản thân) |
Lưu ý: Vai trò tổ chức độc lập với vai trò cấp hệ thống (user, super_admin). Người dùng có vai trò hệ thống user có thể có các vai trò tổ chức khác nhau trong các tổ chức khác nhau.
3. Chỉ mục
-- auth_users
CREATE INDEX idx_auth_users_email ON auth_users(email);
CREATE INDEX idx_auth_users_phone ON auth_users(phone);
CREATE INDEX idx_auth_users_status ON auth_users(status);
-- auth_sessions
CREATE INDEX idx_auth_sessions_user_id ON auth_sessions(user_id);
CREATE INDEX idx_auth_sessions_token ON auth_sessions(token);
CREATE INDEX idx_auth_sessions_expires ON auth_sessions(expires_at);
-- auth_verification
CREATE INDEX idx_auth_verification_user_id ON auth_verification(user_id);
CREATE INDEX idx_auth_verification_code ON auth_verification(code);
CREATE INDEX idx_auth_verification_type ON auth_verification(type);
-- auth_user_roles
CREATE INDEX idx_auth_user_roles_user_id ON auth_user_roles(user_id);
CREATE INDEX idx_auth_user_roles_role_id ON auth_user_roles(role_id);
-- auth_organizations
CREATE INDEX idx_auth_organizations_slug ON auth_organizations(slug);
-- auth_members
CREATE INDEX idx_auth_members_org_id ON auth_members(organization_id);
CREATE INDEX idx_auth_members_user_id ON auth_members(user_id);
-- auth_teams
CREATE INDEX idx_auth_teams_org_id ON auth_teams(organization_id);
-- auth_team_members
CREATE INDEX idx_auth_team_members_team_id ON auth_team_members(team_id);
CREATE INDEX idx_auth_team_members_user_id ON auth_team_members(user_id);
-- auth_invitations
CREATE UNIQUE INDEX idx_auth_invitations_token_hash ON auth_invitations(token_hash);
CREATE INDEX idx_auth_invitations_org_id ON auth_invitations(organization_id);
CREATE INDEX idx_auth_invitations_email ON auth_invitations(email);
CREATE INDEX idx_auth_invitations_status ON auth_invitations(status);
CREATE INDEX idx_auth_invitations_inviter_id ON auth_invitations(inviter_id);
CREATE INDEX idx_auth_invitations_employer_id ON auth_invitations(employer_id);
-- auth_organization_roles
CREATE INDEX idx_auth_org_roles_org_id ON auth_organization_roles(organization_id);
4. Di chuyển dữ liệu
4.1 Chiến lược Di chuyển dữ liệu
| Khía cạnh | Quyết định |
| Công cụ | Drizzle ORM (drizzle-kit) |
| Cơ sở dữ liệu | auth_db |
| Hoàn tác | Bắt buộc cho mỗi lần di chuyển dữ liệu |
4.2 Thứ tự Di chuyển dữ liệu
| Thứ tự | Di chuyển dữ liệu | Mô tả |
| 1 | 001_create_users | Tạo bảng auth_users |
| 2 | 002_create_sessions | Tạo bảng auth_sessions |
| 3 | 003_create_accounts | Tạo bảng auth_accounts |
| 4 | 004_create_verification | Tạo bảng auth_verification |
| 5 | 005_create_roles | Tạo bảng auth_roles |
| 6 | 006_create_user_roles | Tạo bảng auth_user_roles |
| 7 | 007_create_organizations | Tạo bảng auth_organizations |
| 8 | 008_create_members | Tạo bảng auth_members |
| 9 | 009_create_teams | Tạo bảng auth_teams |
| 10 | 010_create_team_members | Tạo bảng auth_team_members |
| 11 | 011_create_invitations | Tạo bảng auth_invitations |
| 12 | 012_create_org_roles | Tạo bảng auth_organization_roles |
| 13 | 013_create_indexes | Tạo tất cả chỉ mục |
5. Từ điển Dữ liệu
| Bảng | Mô tả | Giải quyết | S dòng Đánh giá (Năm 1) |
| auth_users | Tài khoản người dùng | FR-001, FR-002 | 10,000 |
| auth_sessions | Phiên đăng nhập và token của người dùng | FR-002, FR-003, FR-004 | 50,000 |
| auth_accounts | Tài khoản OAuth provider | FR-001 | 10,000 |
| auth_verification | Mã xác minh email/số điện thoại | FR-005, FR-006, FR-008, FR-009 | 20,000 |
| auth_roles | Vai trò người dùng | FR-011 | 10 |
| auth_user_roles | Phân công vai trò người dùng | FR-011 | 15,000 |
| auth_organizations | Tổ chức | FR-015 | 100 |
| auth_members | Thành viên tổ chức | FR-015 | 500 |
| auth_teams | Đội nhóm trong tổ chức | FR-016 | 300 |
| auth_team_members | Thành viên đội nhóm | FR-016 | 1,000 |
| auth_invitations | Lời mời tổ chức với xác minh dựa trên token | FR-017, FR-018, FR-019, FR-020 | 5,000 |
| auth_organization_roles | Vai trò tổ chức tùy chỉnh | FR-015 | 50 |