Files
lcbp3/.agents/skills/nestjs-best-practices/rules/db-use-migrations.md
T
admin 740c116b95
CI / CD Pipeline / build (push) Successful in 6m25s
CI / CD Pipeline / deploy (push) Failing after 39s
690326:2212 Fixing Refactor ADR-019 Naming convention uuid #08
2026-03-26 22:12:55 +07:00

4.0 KiB

title, impact, impactDescription, tags
title impact impactDescription tags
No TypeORM Migrations (ADR-009) HIGH Use direct SQL schema files instead of TypeORM migrations per project ADR database, schema, typeorm, migrations, adr-009

No TypeORM Migrations (ADR-009)

This project follows ADR-009: Direct SQL Schema Management

Unlike standard NestJS/TypeORM practices, this project does NOT use TypeORM migrations. Instead, we manage database schema through direct SQL files.

Why No Migrations?

  • ADR-009 Decision: Explicit schema control over auto-generated migrations
  • MariaDB-specific features: Native UUID type, virtual columns, custom indexing
  • Team workflow: Schema changes reviewed as SQL, not TypeORM migration classes
  • Audit trail: Single source of truth in specs/03-Data-and-Storage/

Schema File Locations

specs/03-Data-and-Storage/
├── lcbp3-v1.8.0-schema-01-drop.sql      # Drop statements (dev only)
├── lcbp3-v1.8.0-schema-02-tables.sql   # CREATE TABLE statements
├── lcbp3-v1.8.0-schema-03-views-indexes.sql  # Views, indexes, constraints
└── deltas/                              # Incremental changes
    ├── 01-add-reference-date.sql
    ├── 02-add-rbac-bulk-permission.sql
    └── 03-fix-numbering-enums.sql

Correct: Using SQL Schema Files

// TypeORM configuration - NO migrationsRun
TypeOrmModule.forRootAsync({
  inject: [ConfigService],
  useFactory: (config: ConfigService) => ({
    type: 'mariadb',
    host: config.get('DB_HOST'),
    port: config.get('DB_PORT'),
    username: config.get('DB_USERNAME'),
    password: config.get('DB_PASSWORD'),
    database: config.get('DB_NAME'),
    entities: ['dist/**/*.entity.js'],
    synchronize: false, // NEVER true, even in development
    migrationsRun: false, // Disabled per ADR-009
    // Migrations are managed via SQL files, not TypeORM
  }),
});

Schema Change Process (ADR-009)

  1. Modify SQL file directly:

    -- specs/03-Data-and-Storage/lcbp3-v1.8.0-schema-02-tables.sql
    ALTER TABLE correspondences
    ADD COLUMN priority VARCHAR(20) DEFAULT 'normal';
    
  2. Create delta for existing databases:

    -- specs/03-Data-and-Storage/deltas/04-add-priority-column.sql
    ALTER TABLE correspondences
    ADD COLUMN priority VARCHAR(20) DEFAULT 'normal';
    
  3. Apply to database manually or via deployment script:

    mysql -u root -p lcbp3 < specs/03-Data-and-Storage/deltas/04-add-priority-column.sql
    

Entity Definition (No Migration Needed)

@Entity('correspondences')
export class Correspondence {
  @PrimaryGeneratedColumn()
  id: number; // Internal INT PK

  @Column({ type: 'uuid' })
  uuid: string; // Public UUID

  @Column({ name: 'priority', default: 'normal' })
  priority: string;

  // No migration class needed - schema managed via SQL
}

Anti-Pattern: TypeORM Migrations (Do NOT Use)

// ❌ WRONG - Do not create migration files
// migrations/1705312800000-AddUserAge.ts
export class AddUserAge1705312800000 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`ALTER TABLE "users" ADD "age" integer`);
  }
}

// ❌ WRONG - Do not enable migrationsRun
TypeOrmModule.forRoot({
  migrationsRun: true, // Disabled per ADR-009
  migrations: ['dist/migrations/*.js'],
});

When You Need Schema Changes

  1. Check specs/03-Data-and-Storage/lcbp3-v1.8.0-schema-02-tables.sql
  2. Add your DDL to the appropriate SQL file
  3. Create delta file in deltas/ directory
  4. Apply SQL to your database
  5. Update corresponding Entity class

Reference

Warning

: Attempting to use TypeORM migrations in this project violates ADR-009 and will be rejected in code review.