refactor(queue): replace manual status validation with pytransitions
Merge Request
Overview
This MR replaces the manual, dictionary-based status transition validation for the consultation queue with a robust, centralized finite state machine using the transitions library. It eliminates scattered imperative checks and replaces them with an automated, scalable state enforcement mechanism.
What does this MR do and why?
Queue status transitions in app/services/consultation_queue_service.py were previously governed by a hardcoded VALID_TRANSITIONS dictionary (~120 LOC) alongside manual validation logic. This approach was error-prone, fragile, and difficult to maintain when adding or modifying states.
By integrating the actively maintained transitions library, we have:
- Centralized the state definitions (
MACHINE_STATES) and transition rules (MACHINE_TRANSITIONS). - Delegated the responsibility of strict transition validation entirely to the state machine.
- Maintained exact backward compatibility with how errors (
ValueError) are bubbled up to the API layer when invalid transitions are attempted.
Changes Made
-
Added Dependencies: Added
transitions>=0.9.0to pyproject.toml and updated uv.lock. - Modified Service: Refactored app/services/consultation_queue_service.py.
-
Removed Code: Deleted the static
VALID_STATUS_TRANSITIONSdictionary entirely. -
Added Logic: Created a dynamic StateWrapper inside update_queue_status that initializes the
Machineon the fly to process the requested status change trigger (advance_to_<status>).
Technical Details
- Architecture decisions made: Instead of attaching the state machine directly to the SQLAlchemy model (which can cause caching/initialization headaches in FastAPI request lifecycles), we dynamically instantiate a lightweight StateWrapper inside the service function exactly when an update is requested. This ensures total thread safety and predictable validation without polluting the database model.
-
Error Handling:
transitions.MachineErroris natively caught and translated into the exactValueErrorthe original code threw, meaning all existing API integrations and frontend clients remain completely unaffected.
Type of Change
-
🐛 Bug fix (non-breaking change that fixes an issue) -
✨ New feature (non-breaking change that adds functionality) -
💥 Breaking change (fix or feature that would cause existing functionality to change) -
📝 Documentation update -
♻ ️ Refactor (no functional changes) -
⚡ Performance improvement -
🧪 Test update -
🔧 Configuration change -
🚨 Security fix -
🗑 ️ Deprecation (removing deprecated code)
Related Issues / References
- Resolves #79
- Reference: pytransitions/transitions
Screenshots or Screen Recordings
(Not applicable as these are internal service layer logic changes only. No API contracts or UI layouts were modified).
How to Validate Locally
- Pull the branch locally and rebuild the Docker container to ensure the new
transitionsdependency is installed:docker compose up -d --build api - Start the application and log in as a coordinator or doctor.
- Valid transition check: Register a patient and assign them to a doctor (moves them to vitals queue). Progress them normally through the frontend UI (e.g. vitals -> know_your_patient -> waiting).
-
Invalid transition check: Attempt to skip a mandatory state (e.g., trying to force a patient from vitals directly to in_consultation via swagger UI or curl). Verify the API rejects the request with a 400 Bad Request / 500 error containing the
ValueErrormatching the old behavior.
Testing Done
-
Unit tests added/updated -
API endpoint tests passing
Test Cases Covered:
| Scenario | Expected Result | Status |
|---|---|---|
| Valid state transition (vitals -> know_your_patient) | Transition success, state updated | |
| Invalid state transition jump (vitals -> in_consultation) | Raises ValueError, aborts update | |
| Attempting to transition to current state | Ignored/handled gracefully |
Test Commands Run:
Run consultation queue specific tests
uv run pytest tests/test_services/test_consultation_queue_service.py -v
Run queue-related tests (recommended for this MR)
uv run pytest -k queue -v
Run all tests
uv run pytest
Example: Run with coverage
uv run pytest --cov=app
Code Quality Checklist
Code Standards
-
Code follows project conventions (naming, structure, formatting) -
No debug statements or commented-out code left (unless necessary and intended) -
No unused imports, variables, or functions -
No duplicate code (DRY principle followed) -
Type hints are properly defined (no Anyunless justified and no mypy type check errors) -
Ruff checks pass: ruff check . ruff format . --check
Python & FastAPI Best Practices
-
Functions follow single-responsibility principle -
Async/await used correctly (no blocking calls in async functions) -
Dependency injection used appropriately -
Pydantic models used for request/response validation -
SQLAlchemy queries are optimized (no N+1 queries) -
Error handling is comprehensive (try/except with proper logging)
API Design
-
RESTful conventions followed -
Proper HTTP status codes returned -
Input validation implemented -
Authentication/authorization enforced -
Role Base access control used for user restriction -
API documentation (docstrings) updated
Database & Migrations
-
Database migrations created (if schema changed) -
Database migrations version is pointing to the latest version (and version name follows project conventions) -
Migrations are reversible (migrations contain downgrade scripts) -
Indexes added for frequently queried fields -
No raw SQL queries (using SQLAlchemy ORM) -
Data integrity constraints maintained
Security
-
No sensitive data logged (passwords, tokens, PII) -
SQL injection prevention verified (ORM used) -
Input sanitization implemented -
Authentication tokens handled securely -
CORS settings appropriate -
Security scan passes: bandit -r app/
Error Handling
-
Errors are caught and handled gracefully -
User-friendly error messages returned -
Errors are logged appropriately -
HTTP error responses follow API standards
Documentation
-
README.md updated (if setup steps changed) -
.env.exampleupdated (if new env vars added) -
API documentation updated (docstrings, OpenAPI specs) -
CHANGELOG.md will be updated (if applicable) -
Code comments explain complex logic (not what, but why)
Known Limitations / Technical Debt
Additional Notes
MR Acceptance Checklist
Quality & Correctness
-
Code works as intended and solves the stated problem -
No bugs introduced (existing functionality not broken) -
Edge cases handled appropriately
Maintainability
-
Code is readable and well-organized -
Code is testable and well-tested -
Follows project patterns and conventions
Acceptance Review
-
Reviewed by at least 1 teammate -
Reviewed by product owner