Skip to main content

Database Migration Workflow

Liquibase manages schema changes in the application server. Follow this workflow to keep the database and ERD docs in sync.

Quick start

  1. Modify JPA entities with the desired changes.

  2. Generate a draft changelog:

    pnpm run db:draft-changelog
  3. Review changelog_new.xml carefully – check for destructive operations.

  4. Rename and move the file to server/application-server/src/main/resources/db/changelog/{id}_changelog.xml.

  5. Regenerate docs:

    pnpm run db:generate-erd-docs
  6. Commit the migration and documentation (docs/contributor/erd/schema.mmd).

:::danger Always validate Generated migrations can drop or rename columns unexpectedly. Double-check each changeset before committing. :::

Validation checklist

  • Replace the autogenerated user (generated) author with your GitHub username.
  • Prefer renameColumn over drop/add sequences when renaming fields to avoid data loss.
  • Ensure new sequences start at 1 unless you have a data migration plan.
  • Confirm destructive statements (dropTable, dropColumn) are intentional and safe.
  • Run pnpm run db:generate-erd-docs and inspect the diff before committing.

Safe rename example

<!-- ❌ Avoid drop + add when renaming -->
<dropColumn tableName="user" columnName="first_name"/>
<addColumn tableName="user">
<column name="firstName" type="VARCHAR(255)"/>
</addColumn>

<!-- ✅ Use renameColumn to preserve data -->
<renameColumn tableName="user" oldColumnName="first_name" newColumnName="firstName"/>

CI validation

Two GitHub Actions guard against drift:

  1. Database schema validation – Applies migrations to a fresh DB and compares it with current entities. Failure produces a new changelog_new.xml.
  2. Database documentation validation – Generates an ERD from migrations and compares it with the committed diagram.

Entity change tips

  • Prefer renameColumn over drop/add pairs to avoid data loss.
  • Replace user (generated) in Liquibase files with your GitHub username.
  • Sequences should start at 1 unless explicitly required otherwise.

Example

@Entity
public class User {
@NonNull
private String email; // Newly added field
}

Generates:

<changeSet author="yourusername" id="1749286026779-1">
<addColumn tableName="user">
<column name="email" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>

CI flow

Resources