Database Workflow
Apply this skill any time work involves database schema, queries, repositories, or migrations.
Environment Assumptions
- Assume MySQL 8+ in all target environments.
- Assume Aurora MySQL in staging/production.
- Assume Docker MySQL locally.
Schema Change Rules
- Implement schema changes through TypeORM entities in
src/entities(sometimes documented assrc/entitites). - Keep entity file naming pattern:
- File name prefixed with
I, example:IMyThing.ts - Class name without
Iand suffixed withEntity, example:MyThingEntity
- File name prefixed with
- Treat edits to existing entities as high risk and check for possible data loss before changing types or columns.
- Never use foreign keys.
- Prefer UUID primary keys unless sequential IDs are strictly required.
- Prefer
bigintUnix epoch milliseconds for time fields over SQLdatetime/date. - For every new
@Entity(TABLE_NAME), add/use a table constant insrc/constants/db-tables.ts(example:MY_THINGS_TABLE). - Keep entity class/file names singular; keep table names plural (example table:
my_things).
Query and Repository Rules
- Isolate DB access inside repository-style classes (usually
*Repository, sometimes*Db). - Use caller-level transactions only when work must span multiple repositories:
await sqlExecutor.executeNativeQueriesInTransaction(async (connection) => {
// do all the transactional stuff here by passing the connection with context
});
- Make
ctx: RequestContextthe last argument of repository functions. - Time every repository function with this pattern:
try {
ctx.timer?.start(`${this.constructor.name}->nameOfTheCalledRepositoryFunction`);
// do whatever you need to do here
} finally {
ctx.timer?.stop(`${this.constructor.name}->nameOfTheCalledRepositoryFunction`);
}
- Use
ctx.connectionwhen present, so operations participate in caller-provided transactions. - Never use generated
Api*classes in repositories. - Allow callers (services/routes/etc.) to use entity classes and repository-defined types.
- Use constants from
src/constants/db-tables.tsinstead of hardcoded table names whenever possible. - Prefer typed queries via
execute<T>()andoneOrNull<T>().
Data Migration Rules
- Use db-migrate only for data migration.
- Never use db-migrate for schema changes.
- Create migrations with:
npm run migrate:new migration-name
- Edit files created under
migrations/. - Delete the
downmigration path; do not implement revert logic.
Practical Checklist
- Kept schema changes in entity classes (not SQL migrations).
- Preserved entity naming convention (
I*.tsfile,*Entityclass). - Checked entity edits for data-loss risk.
- Avoided foreign keys.
- Used UUID PK unless sequential ID was required.
- Used epoch-millis
bigintfor time where applicable. - Added/used table name constants in
src/constants/db-tables.ts. - Kept table names plural and entity names singular.
- Kept DB logic in repository/
*Dbclasses. - Used transaction wrapper only when spanning repositories.
- Passed
ctx: RequestContextas last parameter. - Added timer start/stop in repository methods.
- Used
ctx.connectionwhen available. - Avoided generated
Api*models in repositories. - Used typed query methods and table constants in SQL.
- Used db-migrate only for data migration and removed down path.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.