Skip to content

fix(alembic): merge migration heads and make enum upgrades idempotent

Lakshy Yarlagadda requested to merge fix/migration_files into develop
## Overview

This MR fixes local startup failures during `docker compose up -d` by resolving Alembic migration issues in the database initialization flow.

### What problem does it solve?
`db-init` runs `alembic upgrade head` during startup. That was failing for two reasons:
- Alembic had multiple heads after the `role_requests` migration was added, so `head` was ambiguous.
- On existing local Postgres volumes, enum migrations for `medicinetypeenum` could fail with duplicate label errors because values like `ointment` had already been added previously.

### What does this MR do and why?
This MR makes the migration chain safe and deterministic for local startup and rebuilds.
- It adds a merge migration so Alembic has a single head again.
- It makes the medicine enum migrations idempotent by using `ADD VALUE IF NOT EXISTS`.

### Motivation
The main motivation was to unblock local development and Docker-based setup. Without this fix, `db-init` exited with code `1`, which prevented the `api` service from starting.

### Approach Taken
- Added a no-op Alembic merge revision instead of rewriting existing migration history.
- Updated enum migrations to tolerate partially initialized local databases and repeated startup attempts.

### Trade-offs
Using `IF NOT EXISTS` is more resilient for local/dev environments, but it can hide some out-of-band schema drift for enum values. In this case, that trade-off is acceptable because the goal is reliable initialization without breaking existing local volumes.

## Changes Made

### Files added / modified / removed
- Added: `alembic/versions/c9d4e5f6a7b8_merge_role_requests_and_medicine_enum_heads.py`
- Modified: `alembic/versions/add_ointment_powder_to_medicine_type_enum.py`
- Modified: `alembic/versions/add_drops_to_medicine_type_enum.py`

### New models, services, or utilities introduced
- Added a new Alembic merge revision to unify migration history.
- No new application models, services, or utilities were introduced.

### API endpoint changes
- No API contract changes.
- No request/response schema changes.

### Configuration changes
- No application configuration changes.
- No new environment variables added.

## Technical Details

### Root Cause
- The migration graph had two heads:
  - `8f6c2a4d1b30`
  - `add_drops_to_medicine_type_enum`
- `db-init` executes `alembic upgrade head`, which fails when multiple heads exist.
- After resolving that, startup still failed on some existing databases because enum migrations attempted to add values that were already present.

### How the fix addresses it
- The merge migration creates a single Alembic head without changing existing schema behavior.
- The enum migrations now use `ALTER TYPE ... ADD VALUE IF NOT EXISTS`, which allows reruns against existing local databases without crashing.

### Architecture / Data Flow Notes
- No service-layer or endpoint architecture changes.
- No new database tables or columns were introduced by this MR.
- This is primarily a migration-history and startup reliability fix.

## Type of Change

- [x] 🐛 Bug fix (non-breaking change that fixes an issue)
- [ ] ✨ New feature (non-breaking change that adds functionality)
- [ ] 💥 Breaking change
- [ ] 📝 Documentation update
- [ ] ♻️ Refactor
- [ ] ⚡ Performance improvement
- [ ] 🧪 Test update
- [ ] 🔧 Configuration change
- [ ] 🚨 Security fix
- [ ] 🗑️ Deprecation

## Related Issues / References

- Closes #<issue-id-if-applicable>

## Screenshots or Screen Recordings

Backend/migration-only change. No UI screenshots.
Recommended attachments for review:
- `docker compose up -d --build` success output
- `docker compose ps -a`
- `docker compose logs db-init --tail 80`

## How to Validate Locally

### Previous behavior
- `docker compose up -d` failed because `db-init` exited with code `1`.
- Alembic reported multiple heads, or enum migrations failed with duplicate enum label errors.

### Steps to validate
1. Pull this branch.
2. Run `docker compose up -d --build`.
3. Run `docker compose ps -a`.
4. Confirm `db-init` exited with status `0`.
5. Confirm `api` is running on port `8000`.
6. Run `docker compose logs db-init --no-color --tail 80`.
7. Confirm logs show `Database migrations completed successfully!`
8. Optionally run `uv run alembic heads` and confirm only one head is present.

### New behavior
- `db-init` completes successfully.
- The migration graph resolves to a single head.
- Existing local DB volumes no longer fail on repeated enum-value additions.
- `api` starts normally after database initialization.

## Testing Done

### Manual verification performed
- Verified `uv run alembic heads` returns a single head.
- Verified `docker compose up -d --build` completes successfully.
- Verified `docker compose ps -a` shows:
  - `db-init` exited with `0`
  - `api` is `Up`
- Verified `docker compose logs db-init --no-color --tail 80` contains successful migration completion.
- Verified `docker compose logs api --no-color --tail 40` shows application startup completed.

### Automated tests
- No unit or API tests were added/updated in this MR.
- Full test suite was not run as part of this change.

### Test Commands Run
```bash
uv run alembic heads
docker compose up -d --build
docker compose ps -a
docker compose logs db-init --no-color --tail 80
docker compose logs api --no-color --tail 40

Code Quality Checklist

  • Change follows existing Alembic migration patterns
  • No API behavior changes introduced
  • No destructive migration history rewrite performed
  • Ruff checks run
  • Mypy checks run
  • Bandit scan run
  • Automated test suite run

Known Limitations / Technical Debt

  • IF NOT EXISTS improves resilience but may mask enum drift if values are added manually outside migrations.
  • A non-blocking LogBull startup warning still exists because LOGBULL_PROJECT_ID is not a UUID. This MR does not address that.

Additional Notes

  • The fix intentionally preserves migration history by merging heads rather than editing old revisions in place.
  • This change is low-risk for runtime behavior because it does not alter API logic or service flow.
  • Main impact is improving startup reliability for Docker/local development.

MR Acceptance Checklist

  • Code works as intended and solves the stated problem
  • Existing functionality remains intact
  • Migration chain is now valid and deterministic
  • Change is maintainable and easy to review
  • Reviewed by at least 1 teammate
  • Reviewed by product owner
Edited by Lakshy Yarlagadda

Merge request reports

Loading