# Dependency Injection System This directory contains the new dependency injection system for the GridPilot website, built with InversifyJS. ## Overview The DI system provides: - **Centralized dependency management** - All services are registered in modules - **Type-safe injection** - Compile-time validation of dependencies - **Easy testing** - Simple mocking via container overrides - **React integration** - Hooks for component-level injection - **NestJS-like patterns** - Familiar structure for API developers ## Architecture ``` lib/di/ ├── index.ts # Main exports ├── container.ts # Container factory & lifecycle ├── tokens.ts # Symbol-based tokens ├── providers/ # React Context integration │ └── ContainerProvider.tsx ├── hooks/ # Injection hooks │ └── useInject.ts └── modules/ # Domain modules ├── core.module.ts # Logger, error reporter, config ├── api.module.ts # API clients ├── league.module.ts # League services ├── driver.module.ts # Driver services └── team.module.ts # Team services ``` ## Usage ### 1. Setup Root Provider ```tsx // app/layout.tsx import { ContainerProvider } from '@/lib/di/providers/ContainerProvider'; export default function RootLayout({ children }) { return ( {children} ); } ``` ### 2. Inject Services in Hooks ```typescript // hooks/useLeagueService.ts import { useInject } from '@/lib/di/hooks/useInject'; import { LEAGUE_SERVICE_TOKEN } from '@/lib/di/tokens'; import { useQuery } from '@tanstack/react-query'; export function useAllLeagues() { const leagueService = useInject(LEAGUE_SERVICE_TOKEN); return useQuery({ queryKey: ['allLeagues'], queryFn: () => leagueService.getAllLeagues(), }); } ``` ### 3. Inject in Components ```typescript // components/MyComponent.tsx 'use client'; import { useInject } from '@/lib/di/hooks/useInject'; import { LEAGUE_SERVICE_TOKEN } from '@/lib/di/tokens'; export function MyComponent() { const leagueService = useInject(LEAGUE_SERVICE_TOKEN); // Use leagueService... } ``` ### 4. Server Components ```typescript // app/leagues/[id]/page.tsx import { createContainer } from '@/lib/di/container'; import { LEAGUE_SERVICE_TOKEN } from '@/lib/di/tokens'; export default async function LeaguePage({ params }) { const container = createContainer(); const leagueService = container.get(LEAGUE_SERVICE_TOKEN); const league = await leagueService.getLeague(params.id); return ; } ``` ### 5. Testing ```typescript import { createTestContainer } from '@/lib/di/container'; import { ContainerProvider } from '@/lib/di/providers/ContainerProvider'; import { LEAGUE_SERVICE_TOKEN } from '@/lib/di/tokens'; test('component works', () => { const mockService = { getData: jest.fn() }; const overrides = new Map([ [LEAGUE_SERVICE_TOKEN, mockService] ]); const container = createTestContainer(overrides); render( ); }); ``` ## Token Naming Convention ```typescript // Format: DOMAIN_SERVICE_TYPE_TOKEN export const LEAGUE_SERVICE_TOKEN = Symbol.for('Service.League'); export const LEAGUE_API_CLIENT_TOKEN = Symbol.for('Api.LeagueClient'); export const LOGGER_TOKEN = Symbol.for('Core.Logger'); ``` ## Module Pattern ```typescript import { ContainerModule } from 'inversify'; import { Service } from './Service'; import { SERVICE_TOKEN } from '../tokens'; export const DomainModule = new ContainerModule((options) => { const bind = options.bind; bind(SERVICE_TOKEN) .to(Service) .inSingletonScope(); }); ``` ## Migration from Old System ### Before ```typescript const { leagueService } = useServices(); ``` ### After ```typescript const leagueService = useInject(LEAGUE_SERVICE_TOKEN); ``` ## Benefits ✅ **Testability** - Easy mocking via container overrides ✅ **Maintainability** - Clear dependency graphs ✅ **Type Safety** - Compile-time validation ✅ **Consistency** - Same patterns as NestJS API ✅ **Performance** - Singleton scope by default ## Next Steps 1. Complete module implementations for all domains 2. Migrate all React-Query hooks to use `useInject()` 3. Update tests to use test containers 4. Remove old `ServiceProvider` and `ServiceFactory`