Migration Cơ sở dữ liệu
BANA sử dụng hai hệ thống migration bổ sung cho nhau:
- Drizzle Kit CLI -- Tạo và áp dụng SQL migration DDL từ định nghĩa schema (quản lý trong
@nx/core) - Framework Seed Migration -- Chạy các quy trình dữ liệu mẫu thông qua
bootstrapMigration()(sử dụng bởi mỗi gói dịch vụ)
Nguồn: packages/core/src/migrations/
Ngăn xếp Công nghệ
| Công cụ | Phiên bản | Mục đích |
|---|---|---|
| Drizzle ORM | ^0.45.1 | Trình tạo truy vấn an toàn kiểu và định nghĩa schema |
| Drizzle Kit | ^0.31.8 | Công cụ CLI migration (tạo SQL, áp dụng vào cơ sở dữ liệu) |
| PostgreSQL | Mới nhất | Công cụ cơ sở dữ liệu |
| Bun | >=1.3.8 | Runtime cho script CLI |
Cấu trúc Thư mục
packages/core/
├── src/
│ ├── models/
│ │ └── schemas/
│ │ ├── common.ts # Shared pgSchema objects, column generators
│ │ ├── public/ # Public schema models (30)
│ │ ├── pricing/ # Pricing schema models (7)
│ │ ├── allocation/ # Allocation schema models (4)
│ │ ├── sale/ # Sale schema models (2)
│ │ ├── inventory/ # Inventory schema models (8)
│ │ ├── finance/ # Finance schema models (3)
│ │ └── payment/ # Payment schema models (1)
│ ├── migrations/
│ │ ├── migrators/
│ │ │ ├── cli.ts # Migration CLI entry point
│ │ │ ├── all.ts # Config: all schemas combined
│ │ │ ├── public.ts # Config: public schema only
│ │ │ ├── pricing.ts # Config: pricing schema only
│ │ │ ├── allocation.ts # Config: allocation schema only
│ │ │ ├── sale.ts # Config: sale schema only
│ │ │ ├── inventory.ts # Config: inventory schema only
│ │ │ ├── finance.ts # Config: finance schema only
│ │ │ ├── payment.ts # Config: payment schema only
│ │ │ ├── identity.ts # Config: identity schema only
│ │ │ ├── ledger.ts # Config: ledger schema only
│ │ │ └── outreach.ts # Config: outreach schema only
│ │ └── drizzle/ # Generated migration output
│ │ ├── public/ # Public schema SQL + meta/
│ │ ├── pricing/ # Pricing schema SQL + meta/
│ │ ├── allocation/ # Allocation schema SQL + meta/
│ │ ├── sale/ # Sale schema SQL + meta/
│ │ ├── inventory/ # Inventory schema SQL + meta/
│ │ ├── finance/ # Finance schema SQL + meta/
│ │ ├── payment/ # Payment schema SQL + meta/
│ │ ├── identity/ # Identity schema SQL + meta/
│ │ ├── ledger/ # Ledger schema SQL + meta/
│ │ └── outreach/ # Outreach schema SQL + meta/
│ └── helpers/
│ ├── bootstraps/
│ │ └── migration.ts # bootstrapMigration() helper
│ └── migration/
│ ├── helper.ts # MigrationHelper class
│ ├── process-loader.ts # createMigrationProcessLoader()
│ └── types.ts # TMigrationProcess, TMigrationHooks
└── package.json # db:generate, db:migrate scriptsDrizzle Kit CLI
Tổng quan
Công cụ CLI tại src/migrations/migrators/cli.ts bọc Drizzle Kit để hỗ trợ quản lý migration theo từng schema. Nó yêu cầu RUN_MODE=migrate như một biện pháp an toàn.
Sử dụng
bun run src/migrations/migrators/cli.ts <command> [schema] [options]Các Lệnh
| Lệnh | Mô tả |
|---|---|
generate | Tạo file SQL migration bằng cách so sánh định nghĩa schema với cơ sở dữ liệu |
migrate | Áp dụng các migration đang chờ vào cơ sở dữ liệu |
Tham số
| Tham số | Mô tả |
|---|---|
schema | Tên schema đích: public, pricing, allocation, sale, inventory, finance, payment, identity, ledger, outreach |
--all | Chạy lệnh cho tất cả 7 schema tuần tự |
Biện pháp An toàn: RUN_MODE
CLI yêu cầu biến môi trường RUN_MODE được đặt là migrate. Điều này ngăn việc thực thi migration vô tình:
# Without RUN_MODE -- will fail
bun run src/migrations/migrators/cli.ts generate public
# Error: RUN_MODE environment variable must be set to "migrate"
# With RUN_MODE -- will succeed
RUN_MODE=migrate bun run src/migrations/migrators/cli.ts generate publicVí dụ
# Generate migration SQL for a single schema
RUN_MODE=migrate bun run src/migrations/migrators/cli.ts generate public
RUN_MODE=migrate bun run src/migrations/migrators/cli.ts generate sale
# Apply migrations for a single schema
RUN_MODE=migrate bun run src/migrations/migrators/cli.ts migrate inventory
RUN_MODE=migrate bun run src/migrations/migrators/cli.ts migrate finance
# Generate migrations for ALL schemas
RUN_MODE=migrate bun run src/migrations/migrators/cli.ts generate --all
# Apply migrations for ALL schemas
RUN_MODE=migrate bun run src/migrations/migrators/cli.ts migrate --allScript Package.json
Gói @nx/core cung cấp các script viết tắt với RUN_MODE=migrate được cấu hình sẵn:
{
"db:generate": "RUN_MODE=migrate bun run src/migrations/migrators/cli.ts generate",
"db:migrate": "RUN_MODE=migrate bun run src/migrations/migrators/cli.ts migrate",
"db:generate:all": "RUN_MODE=migrate bun run src/migrations/migrators/cli.ts generate --all",
"db:migrate:all": "RUN_MODE=migrate bun run src/migrations/migrators/cli.ts migrate --all"
}Sử dụng với bun run:
cd packages/core
# Single schema
bun run db:generate public
bun run db:migrate sale
# All schemas
bun run db:generate:all
bun run db:migrate:allCấu hình Theo Schema
Mỗi schema có file cấu hình Drizzle Kit riêng trong src/migrations/migrators/. Các cấu hình tuân theo một mẫu nhất quán:
Mẫu Cấu hình
// src/migrations/migrators/{schema}.ts
import 'dotenv-flow/config';
import { applicationEnvironment, int, LoggerFactory } from '@venizia/ignis';
import { defineConfig } from 'drizzle-kit';
import { EnvironmentKeys, PostgresSchemas } from './../../common';
const migrate = () => {
const databaseConfigs = {
host: applicationEnvironment.get<string>(EnvironmentKeys.APP_ENV_POSTGRES_HOST),
port: int(applicationEnvironment.get<number>(EnvironmentKeys.APP_ENV_POSTGRES_PORT)),
database: applicationEnvironment.get<string>(EnvironmentKeys.APP_ENV_POSTGRES_DATABASE),
user: applicationEnvironment.get<string>(EnvironmentKeys.APP_ENV_POSTGRES_USERNAME),
password: applicationEnvironment.get<string>(EnvironmentKeys.APP_ENV_POSTGRES_PASSWORD),
ssl: false,
};
return defineConfig({
dialect: 'postgresql',
out: './src/migrations/drizzle/{schema}', // Output directory per schema
schema: ['./src/models/schemas/{schema}/**/schema.ts',
'./src/models/schemas/{schema}/common.ts'], // Schema source files
dbCredentials: databaseConfigs,
schemaFilter: [PostgresSchemas.{SCHEMA}], // Filter to this schema only
});
};
export default migrate();Tóm tắt Cấu hình
| File Cấu hình | Bộ lọc Schema | Thư mục Đầu ra | Nguồn Schema |
|---|---|---|---|
public.ts | public | drizzle/public/ | schemas/public/**/schema.ts |
pricing.ts | pricing | drizzle/pricing/ | schemas/pricing/**/schema.ts |
allocation.ts | allocation | drizzle/allocation/ | schemas/allocation/**/schema.ts |
sale.ts | sale | drizzle/sale/ | schemas/sale/**/schema.ts |
inventory.ts | inventory | drizzle/inventory/ | schemas/inventory/**/schema.ts |
finance.ts | finance | drizzle/finance/ | schemas/finance/**/schema.ts |
payment.ts | payment | drizzle/payment/ | schemas/payment/**/schema.ts |
identity.ts | identity | drizzle/identity/ | schemas/identity/**/schema.ts |
ledger.ts | ledger | drizzle/ledger/ | schemas/ledger/**/schema.ts |
outreach.ts | outreach | drizzle/outreach/ | schemas/outreach/**/schema.ts |
all.ts | Tất cả 10 schema | drizzle/ (gốc) | dist/models/schemas/*.js |
Lưu ý: Cấu hình all.ts khác với cấu hình schema đơn lẻ. Nó sử dụng file .js đã biên dịch từ dist/ và lọc tất cả 10 schema, xuất ra thư mục drizzle/ gốc.
Khác biệt Chính: Đơn lẻ vs Tất cả
| Khía cạnh | Cấu hình Schema Đơn lẻ | Cấu hình Tất cả (all.ts) |
|---|---|---|
| Nguồn schema | File TypeScript nguồn (./src/models/schemas/{schema}/**/schema.ts) | JavaScript đã biên dịch (./dist/models/schemas/*.js) |
| Thư mục đầu ra | Thư mục con theo schema (drizzle/{schema}/) | Thư mục drizzle gốc (drizzle/) |
| Bộ lọc schema | Một schema | Tất cả 7 schema |
| Cần build | Không (đọc .ts trực tiếp) | Có (đọc .js đã biên dịch) |
Quy trình Migration
Kết quả Migration
Mỗi thư mục schema chứa các file SQL đã tạo và journal để theo dõi:
src/migrations/drizzle/{schema}/
├── 0000_initial_migration.sql
├── 0001_add_new_column.sql
├── 0002_create_table.sql
└── meta/
└── _journal.jsonFile Journal
File meta/_journal.json theo dõi lịch sử migration:
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1705708800000,
"tag": "0000_initial_migration",
"breakpoints": true
}
]
}Biến Môi trường
Tất cả cấu hình migrator đọc thông tin xác thực cơ sở dữ liệu từ môi trường thông qua dotenv-flow:
| Biến | Bắt buộc | Mô tả |
|---|---|---|
RUN_MODE | Có | Phải là migrate (biện pháp an toàn) |
APP_ENV_POSTGRES_HOST | Có | Host PostgreSQL |
APP_ENV_POSTGRES_PORT | Có | Cổng PostgreSQL |
APP_ENV_POSTGRES_DATABASE | Có | Tên cơ sở dữ liệu |
APP_ENV_POSTGRES_USERNAME | Có | Tên người dùng cơ sở dữ liệu |
APP_ENV_POSTGRES_PASSWORD | Có | Mật khẩu cơ sở dữ liệu |
Các file môi trường được tải thông qua dotenv-flow/config ở đầu mỗi file cấu hình.
Seed Data Migration
Ngoài các thay đổi DDL schema, mỗi gói dịch vụ có thể định nghĩa quy trình dữ liệu mẫu để chèn hoặc cập nhật các bản ghi ban đầu (vai trò, cấu hình, danh mục mặc định, v.v.). Điều này được quản lý bởi framework MigrationHelper trong @nx/core.
bootstrapMigration()
Helper bootstrapMigration() khởi động ứng dụng, đăng ký MigrationRepository, và chạy tất cả quy trình seed:
// packages/{package}/src/migrate.ts
import { bootstrapMigration } from '@nx/core';
import { Application } from './application';
import { getMigrationProcesses } from './migrations/processes/migration-process';
bootstrapMigration({
ApplicationClass: Application,
getMigrationProcesses,
})
.then(() => {
process.exit(0);
})
.catch(err => {
console.error('Cannot migrate database schema', err);
process.exit(1);
});createMigrationProcessLoader()
Định nghĩa các quy trình seed cần tải thông qua import động:
// packages/{package}/src/migrations/processes/migration-process.ts
import { createMigrationProcessLoader } from '@nx/core';
export const getMigrationProcesses = createMigrationProcessLoader({
seedPaths: [
'identity-0001-seed-roles',
'identity-0002-seed-users',
'identity-0003-seed-table-configurations',
'identity-0004-seed-mail-configurations',
],
importFn: path => import(`../processes/${path}.js`),
});TMigrationProcess
Mỗi quy trình seed triển khai kiểu TMigrationProcess:
type TMigrationProcess = {
name: string; // Unique process name
migrateFn: (opts: { context: BaseApplication }) => ValueOrPromise<void>; // Migration logic
cleanFn?: (opts: { context: BaseApplication }) => ValueOrPromise<void>; // Optional cleanup
options?: {
alwaysRun?: boolean; // If true, runs even if previously completed
};
};Ví dụ Quy trình Seed
// packages/identity/src/migrations/processes/identity-0001-seed-roles.ts
import { INameI18n, TMigrationProcess } from '@nx/core';
import { RoleRepository } from '@/repositories';
const defaultRoles: Array<{ identifier: string; name: INameI18n; priority: number }> = [
{ identifier: '999-super-admin', name: { en: 'Super Admin', vi: 'Sieu Quan Tri Vien' }, priority: 999 },
{ identifier: '998-admin', name: { en: 'Admin', vi: 'Quan Tri Vien' }, priority: 998 },
// ...
];
const migrationProcess: TMigrationProcess = {
name: __filename.slice(__dirname.length + 1),
migrateFn: async ({ context: application }) => {
const roleRepository = application.get<RoleRepository>({
key: 'repositories.RoleRepository',
});
for (const role of defaultRoles) {
const existing = await roleRepository.findOne({
filter: { where: { identifier: role.identifier } },
});
if (!existing) {
await roleRepository.create({ data: role });
} else {
await roleRepository.updateById({ id: existing.id, data: role });
}
}
},
};
export default migrationProcess;MigrationHelper
Lớp MigrationHelper quản lý toàn bộ quy trình seed migration:
- Giai đoạn dọn dẹp -- Chạy
cleanFncho mỗi quy trình (tùy chọn) - Giai đoạn migration -- Chạy
migrateFncho mỗi quy trình, theo dõi trạng thái trong bảngMigration
Các hành vi chính:
| Hành vi | Mô tả |
|---|---|
| Thực thi idempotent | Mỗi quy trình được ghi nhận trong bảng public.Migration. Các quy trình đã hoàn thành sẽ bị bỏ qua |
Ghi đè alwaysRun | Các quy trình có options.alwaysRun = true chạy mỗi lần, ngay cả khi đã hoàn thành trước đó |
| Theo dõi trạng thái | Mỗi quy trình được ghi nhận là SUCCESS hoặc FAIL trong bảng Migration |
| Hook vòng đời | Hỗ trợ beforeCleanup, afterCleanup, beforeMigration, afterMigration, onMigrationSuccess, onMigrationError hook |
| Thực thi tuần tự | Các quy trình chạy theo thứ tự (vị trí mảng quyết định thứ tự thực thi) |
Các Gói Sử dụng Seed Migration
| Gói | Quy trình Seed |
|---|---|
@nx/identity | identity-0001-seed-roles, identity-0002-seed-users, identity-0003-seed-table-configurations, identity-0004-seed-mail-configurations, identity-0005-seed-permissions, identity-0006-seed-sms-configurations |
@nx/commerce | commerce-0001-seed-tax-types, commerce-0002-seed-permissions, commerce-0003-seed-typesense-embedding-configs |
@nx/finance | finance-0001-seed-categories, finance-0002-seed-permissions |
@nx/inventory | inventory-0001-seed-inventory-tracking-types, inventory-0002-seed-permissions |
@nx/payment | payment-0001-seed-vnpay-qr-mms-configuration, payment-0002-seed-vnpay-phone-pos-configuration, payment-0003-seed-permissions |
@nx/pricing | pricing-0001-seed-permissions |
@nx/sale | sale-0001-seed-permissions |
@nx/signal | signal-0001-seed-permissions |
@nx/ledger | ledger-0001-seed-permissions |
@nx/outreach | (chưa có seed) |
@nx/search | (chưa có seed) |
Chạy Seed Migration
Mỗi gói cung cấp script migrate:dev:
cd packages/identity
bun run migrate:dev # Runs with .env.developmentLệnh này thực thi src/migrate.ts gọi bootstrapMigration().
Quy trình Migration Hoàn chỉnh
Khi thiết lập môi trường mới hoặc thêm thay đổi schema, thực hiện theo trình tự sau:
Hướng dẫn Từng bước
- Sửa đổi định nghĩa schema trong
packages/core/src/models/schemas/{schema}/ - Tạo SQL migration từ
packages/core/:bashbun run db:generate public # or: bun run db:generate:all - Xem lại SQL đã tạo trong
src/migrations/drizzle/{schema}/ - Áp dụng DDL migration vào cơ sở dữ liệu:bash
bun run db:migrate public # or: bun run db:migrate:all - Chạy seed migration cho mỗi gói dịch vụ cần dữ liệu:bash
cd packages/identity && bun run migrate:dev cd packages/payment && bun run migrate:dev - Commit file schema, SQL đã tạo, và quy trình seed cùng nhau
Khắc phục Sự cố
Lỗi RUN_MODE
[cli] Error: RUN_MODE environment variable must be set to "migrate"CLI yêu cầu RUN_MODE=migrate. Sử dụng script package.json (bun run db:generate, bun run db:migrate) đã tự động thiết lập sẵn.
Schema Không tìm thấy
Error: Unknown schema "order"
Available schemas: public, pricing, allocation, sale, inventory, finance, paymentĐảm bảo bạn sử dụng tên schema hợp lệ từ PostgresSchemas.SCHEME_SET. Schema order đã được đổi tên thành sale.
Migration Không phát hiện Thay đổi
- File nguồn schema là TypeScript -- đảm bảo mẫu glob schema khớp với vị trí file của bạn
- Đối với cấu hình
all.ts, cần build trước (bun run rebuild) vì nó đọc từdist/ - Xác minh
schemaFilterđúng được đặt trong cấu hình
Lỗi Kết nối
Kiểm tra biến môi trường được đặt chính xác. Các cấu hình tải từ dotenv-flow, đọc .env.development (hoặc .env.local):
# Verify environment
cat .env.development | grep APP_ENV_POSTGRESTài liệu Liên quan
- Tổng quan Cơ sở dữ liệu -- Tóm tắt schema, cột chung, kiểu chia sẻ
- Public Schema -- 30 model trong public schema
- Pricing Schema -- 7 model định giá
- Allocation Schema -- 4 model phân bổ
- Sale Schema -- 2 model đơn hàng bán
- Inventory Schema -- 8 model tồn kho
- Finance Schema -- 3 model tài chính
- Payment Schema -- 1 model cấu hình webhook
- Outreach Schema -- 2 model outreach
- Sơ đồ Quan hệ Thực thể -- ERD toàn diện cho tất cả các model