zenith-backend / MIGRATION_GUIDE.md
teoat's picture
Upload folder using huggingface_hub
4ae946d verified

Developer Migration Guide - From database_service to Domain Services

Effective Date: 2026-01-15
Breaking Changes: None (backward compatible)
Recommended Action: Update code to use domain services


πŸ“‹ Quick Start

Before (❌ Old Way)

from app.services.infrastructure.storage.database_service import db_service

# Getting cases
cases = db_service.get_cases_paginated(page=1, per_page=20)

# Creating a case  
case = db_service.create_case(case_data, creator_id="user123")

# Getting analytics
stats = db_service.get_case_analytics(date_from, date_to)

After (βœ… New Way)

from app.modules.cases.service import case_service
from app.modules.analytics.service import analytics_service
from core.database import get_db

db = next(get_db())

# Getting cases
cases = case_service.get_cases_paginated(db, page=1, per_page=20, filters={})

# Creating a case
case = case_service.create_case(db, case_data, creator_id="user123")

# Getting analytics
stats = analytics_service.get_case_analytics(db, date_from, date_to)

πŸ“Š Complete Migration Map

Cases β†’ case_service

Old Method New Method Import
db_service.get_cases() case_service.get_cases_paginated() from app.modules.cases.service import case_service
db_service.get_cases_paginated() case_service.get_cases_paginated() Same
db_service.get_case() case_service.get_case() Same
db_service.create_case() case_service.create_case() Same
db_service.update_case() case_service.update_case() Same
db_service.delete_case() case_service.delete_case() Same
db_service.get_case_stats() case_service.get_case_stats() Same
db_service.add_case_note() case_service.add_note() Same
db_service.get_case_notes() case_service.get_notes() Same

Users β†’ user_service

Old Method New Method Import
db_service.get_users_paginated() user_service.get_paginated() from app.modules.users.service import user_service
db_service.get_user() user_service.get_user() Same
db_service.update_user() user_service.update_user() Same
db_service.delete_user() user_service.delete_user() Same

Transactions β†’ transaction_service ⭐ NEW

Old Method New Method Import
db_service.get_transactions_by_case() transaction_service.get_transactions_by_case() from app.modules.transactions.service import transaction_service
db_service.create_transaction() transaction_service.create_transaction() Same
db_service.update_transaction_status() transaction_service.update_transaction_status() Same

Analytics β†’ analytics_service

Old Method New Method Import
db_service.get_case_analytics() analytics_service.get_case_analytics() from app.modules.analytics.service import analytics_service
db_service.get_transaction_aggregates() analytics_service.get_transaction_aggregates() Same

Evidence β†’ evidence_service

Old Method New Method Import
db_service.get_evidence_by_case() evidence_service.get_evidence_paginated() from app.modules.evidence.service import evidence_service
db_service.create_evidence() evidence_service.process_file() Same

πŸ”§ Infrastructure Methods (Still in database_service)

These methods remain in database_service - they are infrastructure, not business logic:

from app.services.infrastructure.storage.database_service import db_service

# βœ… These are CORRECT uses of db_service:
db = db_service.get_db()  # Get database session
health = db_service.health_check()  # Check DB health
stats = db_service.get_database_stats()  # DB metrics
cache_stats = db_service.get_cache_stats()  # Cache info
db_service.clear_all_cache()  # Clear cache

πŸ› οΈ Step-by-Step Migration

1. Identify Usage

Search your codebase:

grep -r "db_service\." backend/app/ --include="*.py"

2. For Each File

Example file: app/modules/reports/service.py

Before

from app.services.infrastructure.storage.database_service import db_service

class ReportService:
    def generate_case_report(self, case_id):
        case = db_service.get_case(case_id)  # ❌ Business logic in infrastructure
        transactions = db_service.get_transactions_by_case(case_id)  # ❌
        return self._format_report(case, transactions)

After

from app.modules.cases.service import case_service
from app.modules.transactions.service import transaction_service
from core.database import get_db
from fastapi import Depends
from sqlalchemy.orm import Session

class ReportService:
    def generate_case_report(self, case_id: str, db: Session):
        case = case_service.get_case(db, case_id)  # βœ… Domain service
        transactions = transaction_service.get_transactions_by_case(db, case_id)  # βœ…
        return self._format_report(case, transactions)

3. Update FastAPI Routes

Before

@router.get("/cases/{case_id}")
async def get_case(case_id: str):
    from app.services.infrastructure.storage.database_service import db_service
    case = db_service.get_case(case_id)  # ❌
    return case

After

@router.get("/cases/{case_id}")
async def get_case(
    case_id: str,
    db: Session = Depends(get_db)
):
    from app.modules.cases.service import case_service
    case = case_service.get_case(db, case_id)  # βœ…
    return case

⚠️ Common Pitfalls

1. Forgetting to Pass db Session

❌ Wrong:

case_service.get_case(case_id)  # Missing db parameter!

βœ… Correct:

case_service.get_case(db, case_id)

2. Using database_service for Business Logic

❌ Wrong:

# In a new feature
from app.services.infrastructure.storage.database_service import db_service
cases = db_service.get_cases()  # Don't add new business logic here!

βœ… Correct:

# Use domain service
from app.modules.cases.service import case_service
cases = case_service.get_cases_paginated(db, ...)

3. Not Importing Domain Services

❌ Wrong:

from app.services.infrastructure.storage.database_service import case_service  # Doesn't exist!

βœ… Correct:

from app.modules.cases.service import case_service  # In modules/

πŸ§ͺ Testing After Migration

1. Unit Tests

def test_get_case(db_session):
    from app.modules.cases.service import case_service
    
    # Create test data
    case = case_service.create_case(db_session, {...})
    
    # Test retrieval
    retrieved = case_service.get_case(db_session, case.id)
    assert retrieved.id == case.id

2. Integration Tests

def test_case_endpoint(test_client):
    response = test_client.get("/api/v1/cases?page=1&per_page=20")
    assert response.status_code == 200
    assert "cases" in response.json()

πŸ“ˆ Rollout Strategy

Phase 1: Non-Breaking (Current)

  • βœ… All domain services created
  • βœ… database_service still works (infrastructure only)
  • βœ… Both old and new code work

Phase 2: Migration (This Week)

  • Update routers to use domain services
  • Update internal services
  • Update tests

Phase 3: Cleanup (Next Week)

  • Remove deprecated db_service methods (if any remain)
  • Final testing
  • Documentation update

πŸ†˜ Need Help?

Decision Tree

Q: Should I use database_service?

  • Is it for getting a database session? β†’ βœ… Yes, use db_service.get_db()
  • Is it for health checks/monitoring? β†’ βœ… Yes, use db_service.health_check()
  • Is it for business data (cases, users, etc.)? β†’ ❌ No, use domain service

Q: Which domain service should I use?

  • Cases/investigations? β†’ case_service
  • Users/authentication? β†’ user_service
  • Transactions? β†’ transaction_service
  • Analytics/reports? β†’ analytics_service
  • Evidence/files? β†’ evidence_service

Reference Documentation


βœ… Checklist

Before marking migration complete:

  • All db_service calls for business logic replaced
  • Only infrastructure methods use db_service
  • All imports updated
  • Tests passing
  • No lint errors
  • Documentation updated

Status: Active Migration
Contact: Backend Team
Last Updated: 2026-01-15