Chuyển tới nội dung chính

Cơ sở dữ liệu

Thiết kế Multi-Schema

SmartCK Hub sử dụng PostgreSQL multi-schema để phân tách dữ liệu theo miền nghiệp vụ. Prisma hỗ trợ tính năng này qua preview feature multiSchema.

apps/backend/prisma/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
schemas = ["accounting", "auth", "operations", "organization", "public"]
}
SchemaMô tảSố models
authXác thực, phiên đăng nhập, token~7
organizationPhòng ban, chức vụ, nhân viên, POD~8
operationsDự án, sprint, task, post, shooting~12
accountingTài chính POD, ngân sách media~4
publicChung: settings, audit, permissions, menus~12

Tổng quan Models

Hệ thống có 43 models phân bổ qua 5 schemas. Các model chính:

Auth & Users

ModelSchemaMô tả
UserauthTài khoản người dùng
ProfileauthThông tin cá nhân chi tiết
UserSessionauthPhiên đăng nhập (JWT tracking)
PasswordResetTokenauthToken reset mật khẩu
LoginAttemptauthLịch sử đăng nhập (brute-force)

Organization

ModelSchemaMô tả
DepartmentorganizationPhòng ban (hỗ trợ hierarchy)
PositionorganizationChức vụ (gắn phòng ban + level)
PodorganizationNhóm Agile POD
PodMemberorganizationThành viên POD (role trong POD)
UserDepartmentorganizationLiên kết user-department (N:N)

Operations

ModelSchemaMô tả
ProjectoperationsDự án
SprintoperationsSprint trong dự án
TaskoperationsCông việc (gắn sprint, assign)
PostoperationsBài đăng (content calendar)
ShootingSessionoperationsPhiên chụp/quay
ContractoperationsHợp đồng
Customer / CustomerBrandoperationsKhách hàng + brand
SupportTicketoperationsPhiếu hỗ trợ
NonBillableDeliverableRequestoperationsYêu cầu ngoài hợp đồng

Accounting

ModelSchemaMô tả
PodFinancialReportaccountingBáo cáo tài chính POD
PodExpenseaccountingChi phí POD
MediaBudgetCategoryaccountingDanh mục ngân sách media
MediaBudgetItemaccountingChi tiết ngân sách media

Quan hệ chính

User ──┬── Profile (1:1)
├── UserDepartment ── Department (N:N)
├── UserRole ── Role ── RolePermission ── Permission
├── PodMember ── Pod
└── Task (assigned)

Contract ── Customer
── Project ── Sprint ── Task
── Post
── DeliverableService

Department ── Position (1:N)
── Department (self-ref hierarchy)

Lệnh quản lý Database

# Generate Prisma Client (chạy sau khi sửa schema)
pnpm db:generate

# Đẩy schema thay đổi lên DB (dev - không tạo migration)
pnpm db:push

# Tạo migration file (khi cần track thay đổi)
pnpm db:migrate

# Reset toàn bộ database + chạy lại seed
pnpm db:reset

# Mở Prisma Studio (GUI browser)
pnpm db:studio

# Seed dữ liệu mẫu
pnpm db:seed
db:push vs db:migrate
  • db:push: Nhanh, dùng khi phát triển. Không tạo migration file.
  • db:migrate: Dùng khi cần lưu lịch sử thay đổi schema (staging/production).

Seed Data

Hệ thống có 22 seed files tại apps/backend/prisma/seeds/, chạy theo thứ tự:

permissions → roles → role-permissions → settings → menus
→ departments → positions → users → customers → customer-brands
→ service-packages → contracts → projects → sprints → task-types
→ tasks → posts → pods → shooting-sessions → support-tickets
→ media-budget-categories

Indexing Strategy

Prisma schema định nghĩa index tại từng model. Chiến lược indexing:

model Position {
// ...
@@index([departmentId]) // FK lookup
@@index([level]) // Filter theo cấp bậc
@@index([sortOrder], map: "idx_positions_sort") // Sắp xếp
@@index([level, departmentId]) // Composite index
@@index([status]) // Filter theo trạng thái
}

Nguyên tắc:

  • Index trên mọi foreign key (FK lookup)
  • Composite index cho các query filter phổ biến
  • Index trên cột status, createdAt cho filtering/sorting
  • Sử dụng @@map để đặt tên index có ý nghĩa

Audit Trail

Model Audit ghi lại mọi thay đổi quan trọng:

model Audit {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
tableName String @map("table_name")
recordId String @map("record_id")
action String // CREATE, UPDATE, DELETE
oldData Json? @map("old_data")
newData Json? @map("new_data")
userId String? @map("user_id") @db.Uuid
createdAt DateTime @default(now())
}

Service AuditService tại src/shared/common/services/audit.service.ts tự động ghi log khi có thay đổi dữ liệu quan trọng.