Files
lcbp3/specs/06-tasks/TASK-BE-001-database-migrations.md
admin 047e1b88ce
Some checks failed
Spec Validation / validate-markdown (push) Has been cancelled
Spec Validation / validate-diagrams (push) Has been cancelled
Spec Validation / check-todos (push) Has been cancelled
Main: revise specs to 1.5.0 (completed)
2025-12-01 01:28:32 +07:00

6.7 KiB

Task: Database Setup & Migrations

Status: Not Started Priority: P0 (Critical - Foundation) Estimated Effort: 2-3 days Dependencies: None Owner: Backend Team


📋 Overview

ตั้งค่า Database schema สำหรับ LCBP3-DMS โดยใช้ TypeORM Migrations และ Seeding data


🎯 Objectives

  • สร้าง Initial Database Schema
  • Setup TypeORM Configuration
  • Create Migration System
  • Setup Seed Data
  • Verify Database Structure

📝 Acceptance Criteria

  1. Database Schema:

    • ทุกตารางถูกสร้างตาม Data Dictionary v1.4.5
    • Foreign Keys ถูกต้องครบถ้วน
    • Indexes ครบตาม Specification
    • Virtual Columns สำหรับ JSON fields
  2. Migrations:

    • Migration files เรียงลำดับถูกต้อง
    • สามารถ migrate:up และ migrate:down ได้
    • ไม่มี Data loss เมื่อ rollback
  3. Seed Data:

    • Master data (Organizations, Project, Roles, Permissions)
    • Test users สำหรับแต่ละ Role
    • Sample data สำหรับ Development

🛠️ Implementation Steps

1. TypeORM Configuration

// File: backend/src/config/database.config.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';

export const databaseConfig: TypeOrmModuleOptions = {
  type: 'mysql',
  host: process.env.DB_HOST || 'localhost',
  port: parseInt(process.env.DB_PORT) || 3306,
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_DATABASE,
  entities: [__dirname + '/../**/*.entity{.ts,.js}'],
  migrations: [__dirname + '/../database/migrations/*{.ts,.js}'],
  migrationsRun: false, // Manual migration
  synchronize: false, // ห้ามใช้ใน Production
  logging: process.env.NODE_ENV === 'development',
};

2. Create Entity Classes

Core Entities:

  • Organization (organizations)
  • Project (projects)
  • Contract (contracts)
  • User (users)
  • Role (roles)
  • Permission (permissions)
  • UserAssignment (user_assignments)

Document Entities:

  • Correspondence (correspondences)
  • CorrespondenceRevision (correspondence_revisions)
  • Rfa (rfas)
  • RfaRevision (rfa_revisions)
  • ShopDrawing (shop_drawings)
  • ShopDrawingRevision (shop_drawing_revisions)

Supporting Entities:

  • WorkflowDefinition (workflow_definitions)
  • WorkflowInstance (workflow_instances)
  • WorkflowHistory (workflow_history)
  • DocumentNumberFormat (document_number_formats)
  • DocumentNumberCounter (document_number_counters)
  • Attachment (attachments)
  • AuditLog (audit_logs)

3. Create Initial Migration

npm run migration:generate -- -n InitialSchema

Migration File Structure:

// File: backend/src/database/migrations/1701234567890-InitialSchema.ts
import { MigrationInterface, QueryRunner } from 'typeorm';

export class InitialSchema1701234567890 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    // Create organizations table
    await queryRunner.query(`
      CREATE TABLE organizations (
        id INT PRIMARY KEY AUTO_INCREMENT,
        organization_code VARCHAR(20) NOT NULL UNIQUE,
        organization_name VARCHAR(200) NOT NULL,
        is_active BOOLEAN DEFAULT TRUE,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        deleted_at TIMESTAMP NULL,
        INDEX idx_org_code (organization_code),
        INDEX idx_org_active (is_active, deleted_at)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    `);

    // Continue with other tables...
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP TABLE IF EXISTS organizations;`);
    // Rollback other tables...
  }
}

4. Create Seed Script

// File: backend/src/database/seeds/run-seed.ts
import { DataSource } from 'typeorm';
import { seedOrganizations } from './organization.seed';
import { seedRoles } from './role.seed';
import { seedUsers } from './user.seed';

async function runSeeds() {
  const dataSource = new DataSource(databaseConfig);
  await dataSource.initialize();

  try {
    console.log('🌱 Seeding database...');

    await seedOrganizations(dataSource);
    await seedRoles(dataSource);
    await seedUsers(dataSource);

    console.log('✅ Seeding completed!');
  } catch (error) {
    console.error('❌ Seeding failed:', error);
  } finally {
    await dataSource.destroy();
  }
}

runSeeds();

Testing & Verification

1. Migration Testing

# Run migrations
npm run migration:run

# Verify tables created
mysql -u root -p lcbp3_dev -e "SHOW TABLES;"

# Rollback one migration
npm run migration:revert

# Re-run migrations
npm run migration:run

2. Seed Data Verification

# Run seed
npm run seed

# Verify data
mysql -u root -p lcbp3_dev -e "SELECT * FROM organizations;"
mysql -u root -p lcbp3_dev -e "SELECT * FROM roles;"
mysql -u root -p lcbp3_dev -e "SELECT * FROM users;"

3. Schema Validation

-- Check Foreign Keys
SELECT
  TABLE_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME
FROM
  INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE
  TABLE_SCHEMA = 'lcbp3_dev'
  AND REFERENCED_TABLE_NAME IS NOT NULL;

-- Check Indexes
SELECT
  TABLE_NAME, INDEX_NAME, COLUMN_NAME
FROM
  INFORMATION_SCHEMA.STATISTICS
WHERE
  TABLE_SCHEMA = 'lcbp3_dev'
ORDER BY
  TABLE_NAME, INDEX_NAME;


📦 Deliverables

  • TypeORM configuration file
  • Entity classes (50+ entities)
  • Initial migration file
  • Seed scripts (organizations, roles, users)
  • Migration test script
  • Documentation: How to run migrations

🚨 Risks & Mitigation

Risk Impact Mitigation
Migration errors High Test on dev DB first, backup before migrate
Missing indexes Medium Review Data Dictionary carefully
Seed data conflicts Low Use INSERT IGNORE or check existing

📌 Notes

  • ใช้ utf8mb4_unicode_ci สำหรับ Thai language support
  • ตรวจสอบ Virtual Columns สำหรับ JSON indexing
  • ใช้ @VersionColumn() สำหรับ Optimistic Locking tables