Database & migrations

Merinaa's DatabaseModule wraps Deepkit ORM with a migration runner that picks up files from each module's migrations/ folder.

Where migrations live

modules/bank/
├── entities/
│   └── bank-account.entity.ts
└── migrations/
    ├── 0001-create-bank-accounts.ts
    └── 0002-add-pin-column.ts

Migration file shape

// modules/bank/migrations/0001-create-bank-accounts.ts
import { Migration } from '@merinaa/server';

export default class extends Migration {
    up = async () => {
        await this.sql.exec(`
            CREATE TABLE bank_accounts (
                id INT AUTO_INCREMENT PRIMARY KEY,
                owner_id VARCHAR(36) NOT NULL,
                balance DECIMAL(12,2) NOT NULL DEFAULT 0
            );
        `);
    };

    down = async () => {
        await this.sql.exec(`DROP TABLE bank_accounts;`);
    };
}

Running migrations

pnpm run db:migrate              # apply pending migrations
pnpm run db:migrate:create add-xyz   # scaffold a new migration file

Migrations run automatically on server start when autoMigrate: true is set (default in DatabaseModule.forRoot). For production, consider running them from CI before deploying a new build.

Naming convention

NNNN-kebab-case-description.ts where NNNN is a zero-padded sequence. The migration runner picks them up in lexicographic order across every module, so the prefix disambiguates order across modules.

Rollback

pnpm run db:migrate down         # undo the last applied migration

Schema generation

Entities decorated with @entity + @PrimaryKey / @AutoIncrement can also be used with Deepkit's schema generator — but for anything beyond "scaffold the table", hand-written migrations give you control over column order, indexes and foreign keys.