# Dependency Injection Migration Plan

## Overview

This document outlines the migration approach for converting legacy exported singleton services to the dependency injection pattern, following the successful authentication architecture refactoring.

## Legacy Pattern vs New Pattern

### ❌ Legacy Pattern (To Be Replaced)
```typescript
// Service definition with exported singleton
export class SomeService {
  // service implementation
}
export const someService = new SomeService()

// Consumer code
import { someService } from '@/services/someService'
someService.doSomething()
```

### ✅ New Dependency Injection Pattern
```typescript
// Service definition (no exported singleton)
export class SomeService extends BaseService {
  // service implementation
}

// Service registration in module
container.provide(SERVICE_TOKENS.SOME_SERVICE, someService)

// Consumer code
const someService = injectService(SERVICE_TOKENS.SOME_SERVICE) as SomeService
someService.doSomething()
```

## Services to Migrate

### Priority 1: High Impact Services

#### 1. InvoiceService
- **File**: `src/core/services/invoiceService.ts`
- **Current**: `export const invoiceService = new InvoiceService()`
- **Token**: Need to add `INVOICE_SERVICE: Symbol('invoiceService')`
- **Usage**: Market store and components for payment processing
- **Impact**: Core business logic, high usage
- **Dependencies**: Likely uses LnbitsAPI and other services

#### 2. NostrmarketService
- **File**: `src/modules/market/services/nostrmarketService.ts`
- **Current**: `export const nostrmarketService = new NostrmarketService()`
- **Token**: Need to add `NOSTRMARKET_SERVICE: Symbol('nostrmarketService')`
- **Usage**: Market module composables and components
- **Impact**: Key module service, should follow DI pattern
- **Dependencies**: Likely uses RelayHub and other Nostr services

### Priority 2: Medium Impact Services

#### 3. PaymentMonitorService
- **File**: `src/modules/market/services/paymentMonitor.ts`
- **Current**: `export const paymentMonitor = new PaymentMonitorService()`
- **Token**: `SERVICE_TOKENS.PAYMENT_MONITOR` (already exists)
- **Status**: Partially migrated - token exists but service not properly registered
- **Usage**: Market store
- **Impact**: Background service, less direct component usage

#### 4. LnbitsAPI
- **File**: `src/lib/api/lnbits.ts`
- **Current**: `export const lnbitsAPI = new LnbitsAPI()`
- **Token**: Need to add `LNBITS_API: Symbol('lnbitsAPI')`
- **Usage**: AuthService and other core services
- **Impact**: API layer foundation, widely used but lower-level

## Migration Steps

### Step 1: Add SERVICE_TOKENS

Update `src/core/di-container.ts` to add missing tokens:

```typescript
export const SERVICE_TOKENS = {
  // ... existing tokens ...
  
  // New service tokens
  INVOICE_SERVICE: Symbol('invoiceService'),
  NOSTRMARKET_SERVICE: Symbol('nostrmarketService'),
  LNBITS_API: Symbol('lnbitsAPI'),
  
  // PAYMENT_MONITOR already exists
} as const
```

### Step 2: Register Services in Modules

#### Base Module Registration
For core services like InvoiceService and LnbitsAPI:

```typescript
// src/modules/base/index.ts
import { InvoiceService } from '@/core/services/invoiceService'
import { LnbitsAPI } from '@/lib/api/lnbits'

const invoiceService = new InvoiceService()
const lnbitsAPI = new LnbitsAPI()

container.provide(SERVICE_TOKENS.INVOICE_SERVICE, invoiceService)
container.provide(SERVICE_TOKENS.LNBITS_API, lnbitsAPI)
```

#### Market Module Registration
For market-specific services:

```typescript
// src/modules/market/index.ts
import { NostrmarketService } from './services/nostrmarketService'
import { PaymentMonitorService } from './services/paymentMonitor'

const nostrmarketService = new NostrmarketService()
const paymentMonitor = new PaymentMonitorService()

container.provide(SERVICE_TOKENS.NOSTRMARKET_SERVICE, nostrmarketService)
container.provide(SERVICE_TOKENS.PAYMENT_MONITOR, paymentMonitor)
```

### Step 3: Update Service Classes

Convert services to extend BaseService for dependency injection:

```typescript
// Before
export class SomeService {
  constructor() {
    // direct imports/dependencies
  }
}

// After
export class SomeService extends BaseService {
  protected readonly metadata = {
    name: 'SomeService',
    dependencies: ['AuthService', 'RelayHub'] // declare dependencies
  }
  
  // Access dependencies through DI
  private get authService(): AuthService {
    return this.dependencies.get('AuthService') as AuthService
  }
}
```

### Step 4: Update Consumer Code

Replace direct imports with dependency injection:

```typescript
// Before
import { invoiceService } from '@/core/services/invoiceService'

// After
import { injectService, SERVICE_TOKENS } from '@/core/di-container'

const invoiceService = injectService(SERVICE_TOKENS.INVOICE_SERVICE) as InvoiceService
```

### Step 5: Remove Exported Singletons

After migration, remove the exported singleton from service files:

```typescript
// Remove this line
export const someService = new SomeService()
```

## Migration Order

1. **LnbitsAPI** - Foundation API layer, needed by other services
2. **InvoiceService** - High impact business logic
3. **PaymentMonitorService** - Complete partial migration
4. **NostrmarketService** - Module-specific service

## Validation Steps

For each migrated service:

1. ✅ Service registered in appropriate module
2. ✅ SERVICE_TOKEN added to di-container.ts
3. ✅ All consumers updated to use injectService()
4. ✅ Exported singleton removed from service file
5. ✅ Service extends BaseService if applicable
6. ✅ Dependencies declared in metadata
7. ✅ No build errors or TypeScript warnings
8. ✅ Functionality testing - service works as expected

## Benefits of Migration

### Architecture Benefits
- **Single Source of Truth**: Services managed by DI container
- **Loose Coupling**: Components depend on interfaces, not concrete classes
- **Testability**: Easy to inject mock services for testing
- **Module Boundaries**: Clear service ownership and lifecycle

### Maintainability Benefits
- **Centralized Registration**: All services registered in module definitions
- **Consistent Patterns**: Same DI pattern across all services
- **Service Lifecycle**: Container manages service instantiation and disposal
- **Dependency Visibility**: Service dependencies clearly declared

### Performance Benefits
- **No Duplicate Instances**: Container ensures singleton behavior
- **Lazy Loading**: Services only created when needed
- **Efficient Memory Usage**: Single instances shared across modules

## Testing Strategy

Each migrated service should include:

1. **Unit Tests**: Test service logic with mocked dependencies
2. **Integration Tests**: Test service with real dependencies via DI
3. **Mock Service Creation**: For testing consumers

Example mock setup:
```typescript
// Test setup
const mockInvoiceService = {
  createInvoice: vi.fn(),
  checkPayment: vi.fn()
}

container.provide(SERVICE_TOKENS.INVOICE_SERVICE, mockInvoiceService)
```

## Risk Mitigation

- **Incremental Migration**: One service at a time
- **Backward Compatibility**: Keep old imports temporarily during migration
- **Comprehensive Testing**: Validate each service after migration
- **Rollback Plan**: Git commits allow easy rollback if issues arise

## Migration Status

### ✅ Completed Migrations

#### 1. InvoiceService (Completed)
- **Status**: ✅ Successfully migrated
- **Token**: `SERVICE_TOKENS.INVOICE_SERVICE`
- **Registration**: Base module (`src/modules/base/index.ts`)
- **Usage**: Market store (`src/modules/market/stores/market.ts`)

**Before:**
```typescript
// ❌ Legacy singleton pattern
import { invoiceService } from '@/core/services/invoiceService'
const invoice = await invoiceService.createInvoice(order, adminKey)
```

**After:**
```typescript
// ✅ Dependency injection pattern
const invoiceService = injectService(SERVICE_TOKENS.INVOICE_SERVICE) as InvoiceService
const invoice = await invoiceService.createInvoice(order, adminKey)
```

#### 2. NostrmarketService (Completed)
- **Status**: ✅ Successfully migrated
- **Token**: `SERVICE_TOKENS.NOSTRMARKET_SERVICE`
- **Registration**: Market module (`src/modules/market/index.ts`)
- **Usage**: Market module composables and stores

**Before:**
```typescript
// ❌ Legacy singleton pattern
import { nostrmarketService } from '@/modules/market/services/nostrmarketService'
await nostrmarketService.publishOrder(orderData)
```

**After:**
```typescript
// ✅ Dependency injection pattern
const nostrmarketService = injectService(SERVICE_TOKENS.NOSTRMARKET_SERVICE) as NostrmarketService
await nostrmarketService.publishOrder(orderData)
```

#### 3. PaymentMonitorService (Completed)
- **Status**: ✅ Successfully migrated
- **Token**: `SERVICE_TOKENS.PAYMENT_MONITOR`
- **Registration**: Market module (`src/modules/market/index.ts`)
- **Usage**: Market store for payment status monitoring

#### 4. LnbitsAPI (Completed)
- **Status**: ✅ Successfully migrated
- **Token**: `SERVICE_TOKENS.LNBITS_API`
- **Registration**: Base module (`src/modules/base/index.ts`)
- **Usage**: AuthService and events API integration

## Practical Example: Market Module Using InvoiceService

Here's a real-world example of how the Market module now uses the migrated InvoiceService through dependency injection:

### Market Store Implementation

```typescript
// src/modules/market/stores/market.ts
import { defineStore } from 'pinia'
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import type { InvoiceService } from '@/core/services/invoiceService'

export const useMarketStore = defineStore('market', () => {
  // Inject InvoiceService via dependency injection
  const invoiceService = injectService(SERVICE_TOKENS.INVOICE_SERVICE) as InvoiceService
  
  const createOrderInvoice = async (order: Order, adminKey: string) => {
    try {
      // Use injected service to create Lightning invoice
      const invoice = await invoiceService.createInvoice(order, adminKey, {
        tag: "nostrmarket",
        order_id: order.id,
        merchant_pubkey: order.sellerPubkey,
        expiry: 3600
      })
      
      console.log('Invoice created:', {
        paymentHash: invoice.payment_hash,
        bolt11: invoice.bolt11,
        amount: invoice.amount
      })
      
      return invoice
    } catch (error) {
      console.error('Failed to create order invoice:', error)
      throw error
    }
  }
  
  return {
    createOrderInvoice,
    // ... other store methods
  }
})
```

### Benefits Demonstrated

1. **Service Injection**: `injectService(SERVICE_TOKENS.INVOICE_SERVICE)` provides the service
2. **Type Safety**: TypeScript knows the exact service type with `as InvoiceService`
3. **Testability**: Easy to mock `INVOICE_SERVICE` for testing
4. **Modularity**: Market module depends on base module's InvoiceService
5. **Single Source**: One InvoiceService instance shared across the app

### Service Registration (Base Module)

```typescript
// src/modules/base/index.ts
import { InvoiceService } from '@/core/services/invoiceService'

const invoiceService = new InvoiceService()

export const baseModule: ModulePlugin = {
  async install(_app: App) {
    // Register InvoiceService in DI container
    container.provide(SERVICE_TOKENS.INVOICE_SERVICE, invoiceService)
    
    // Other service registrations...
  }
}
```

## Success Metrics

### Completed Services
- ✅ **InvoiceService**: Successfully migrated to DI pattern
- ✅ **AuthService**: Previously migrated to DI pattern

### Remaining Tasks
- 🔄 **NostrmarketService**: Needs migration
- 🔄 **PaymentMonitorService**: Complete partial migration  
- 🔄 **LnbitsAPI**: Needs migration

### Overall Progress
- ✅ 2/5 services migrated to dependency injection
- ✅ Zero build errors
- ✅ Consistent DI patterns established
- ✅ Documentation updated with examples