Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/ARCHITECTURE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,10 @@ The project adopts an explicit, manual Dependency Injection (DI) pattern for all

### How It Works
- **Dependencies are always passed as arguments** to orchestration functions (e.g., logic, use cases), never imported or instantiated directly inside them.
- **Repositories and fetchers** are created at the application layer and injected into logic functions.
- **No direct infrastructure imports** in logic modules: all dependencies must be provided from the outside.
- **Concrete repositories and repository-backed local/localStorage adapters** are created only in the app container or in tests.
- **Application factories accept ready collaborators** such as repositories, CRUD services, or resource fetchers; they do not construct infrastructure defaults internally.
- **UI components consume container-owned modules** through `useContainer()` instead of creating use-cases at module scope.
- **No direct infrastructure imports** in logic modules: all infrastructure-facing dependencies must be provided from the outside.

### Example: Search Module

Expand Down Expand Up @@ -593,4 +595,4 @@ export const templates = createResource(
- **Decoupling:** Application logic is not tied to infrastructure details.
- **Clarity:** Function signatures make dependencies explicit.

---
---
104 changes: 96 additions & 8 deletions src/di/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,15 @@ import {
createCopyDayOperations,
} from '~/modules/diet/day-diet/application/usecases/useCopyDayOperations'
import { createDayDietRepository } from '~/modules/diet/day-diet/infrastructure/dayDietRepository'
import { createFoodCrud } from '~/modules/diet/food/application/usecases/foodCrud'
import {
createFoodCrud,
type FoodCrud,
} from '~/modules/diet/food/application/usecases/foodCrud'
import { createSupabaseFoodRepository } from '~/modules/diet/food/infrastructure/api/infrastructure/supabase/supabaseFoodRepository'
import {
createRecipeItemUseCases,
type RecipeItemUseCases,
} from '~/modules/diet/item/application/recipeItemUseCases'
import { createMacroProfileCrudService } from '~/modules/diet/macro-profile/application/service/macroProfileCrudService'
import { createMacroProfileCacheStore } from '~/modules/diet/macro-profile/application/store/macroProfileCacheStore'
import {
Expand All @@ -46,6 +53,10 @@ import {
createMealUseCases,
type MealUseCases,
} from '~/modules/diet/meal/application/meal'
import {
createRecentFoodUseCases,
type RecentFoodUseCases,
} from '~/modules/diet/recent-food/application/usecases/recentFoodUseCases'
import {
createRecipeCrud,
type RecipeCrud,
Expand All @@ -61,6 +72,7 @@ import {
type MeasureState,
} from '~/modules/measure/application/usecases/measureState'
import { type BodyMeasure } from '~/modules/measure/domain/measure'
import { createMeasureRepository } from '~/modules/measure/infrastructure/measureRepository'
import {
createTelemetry,
type TelemetryModule,
Expand All @@ -71,6 +83,12 @@ import {
type ProfileModule,
} from '~/modules/profile/application/profile'
import { createRecentFoodCrud } from '~/modules/recent-food/application/usecases/recentFoodCrud'
import { createRecentFoodRepository } from '~/modules/recent-food/infrastructure/recentFoodRepository'
import {
type CachedSearchCrud,
createCachedSearchCrud,
} from '~/modules/search/application/usecases/cachedSearchCrud'
import { createCachedSearchRepository } from '~/modules/search/infrastructure/cachedSearchRepository'
import {
createTemplateSearchState,
type TemplateSearchState,
Expand All @@ -83,6 +101,10 @@ import { type NewUser } from '~/modules/user/domain/user'
import { type UserRepository } from '~/modules/user/domain/userRepository'
import { createGuestUserRepository } from '~/modules/user/infrastructure/guest/guestUserRepository'
import { createSupabaseUserRepository } from '~/modules/user/infrastructure/supabase/supabaseUserRepository'
import {
createWeightChartSettings,
type WeightChartSettings,
} from '~/modules/weight/application/chart/weightChartSettings'
import {
createWeightChartUseCases,
type WeightChartUseCases,
Expand All @@ -91,6 +113,9 @@ import {
createWeightUseCases,
type WeightUseCases,
} from '~/modules/weight/application/weight/usecases/weightUseCases'
import { createLocalStorageWeightChartPreferenceRepository } from '~/modules/weight/infrastructure/chart/localStorage/localStorageWeightChartPreferenceRepository'
import { createLocalStorageWeightCacheRepository } from '~/modules/weight/infrastructure/weight/localStorage/localStorageWeightCacheRepository'
import { createWeightRepository } from '~/modules/weight/infrastructure/weight/supabase/supabaseWeightRepository'
import { GUEST_USER_ID } from '~/shared/guest/guestConstants'
import {
createGuestUseCases,
Expand All @@ -102,6 +127,7 @@ type ContainerInstances = {
clipboardUseCases: ClipboardUseCases
copyDayOperations: CopyDayOperations
dayUseCases: DayUseCases
foodCrud: FoodCrud
guestUseCases: GuestUseCases
macroProfileState: MacroProfileState
macroProfileUseCases: MacroProfileUseCases
Expand All @@ -110,10 +136,13 @@ type ContainerInstances = {
measureCrud: MeasureCrud
measureState: MeasureState
profileUseCases: ProfileModule
recentFoodUseCases: RecentFoodUseCases
recipeCrud: RecipeCrud
recipeItemUseCases: RecipeItemUseCases
templateSearchState: TemplateSearchState
telemetryUseCases: TelemetryModule
userUseCases: UserUseCases
weightChartSettings: WeightChartSettings
weightChartUseCases: WeightChartUseCases
weightUseCases: WeightUseCases
}
Expand All @@ -123,6 +152,7 @@ export type Container = {
clipboardUseCases: () => ClipboardUseCases
copyDayOperations: () => CopyDayOperations
dayUseCases: () => DayUseCases
foodCrud: () => FoodCrud
guestUseCases: () => GuestUseCases
macroProfileState: () => MacroProfileState
macroProfileUseCases: () => MacroProfileUseCases
Expand All @@ -131,10 +161,13 @@ export type Container = {
measureCrud: () => MeasureCrud
measureState: () => MeasureState
profileUseCases: () => ProfileModule
recentFoodUseCases: () => RecentFoodUseCases
recipeCrud: () => RecipeCrud
recipeItemUseCases: () => RecipeItemUseCases
templateSearchState: () => TemplateSearchState
telemetryUseCases: () => TelemetryModule
userUseCases: () => UserUseCases
weightChartSettings: () => WeightChartSettings
weightChartUseCases: () => WeightChartUseCases
weightUseCases: () => WeightUseCases
initialize: () => void
Expand Down Expand Up @@ -203,23 +236,35 @@ export function createContainer(
})
guestUseCasesRef = guestUseCases

const recipeRepository = createRecipeRepository()
const cachedSearchRepository = createCachedSearchRepository()
const foodRepository = createSupabaseFoodRepository()
const recentFoodRepository = createRecentFoodRepository()
const measureRepository = createMeasureRepository()
const weightCacheRepository = createLocalStorageWeightCacheRepository()
const weightRepository = createWeightRepository({
isGuestMode: () => guestUseCases.isGuestMode(),
})
const weightChartPreferenceRepository =
createLocalStorageWeightChartPreferenceRepository()

const recipeCrud =
overrides.recipeCrud ??
createRecipeCrud({
repository: () => createRecipeRepository(),
repository: () => recipeRepository,
})

const macroProfileCache = createMacroProfileCacheStore()
const macroProfileRepository = createMacroProfileRepository({
isGuestMode: () => guestUseCases.isGuestMode(),
})
const macroProfileCrudService = createMacroProfileCrudService({
repository: () => macroProfileRepository,
repository: macroProfileRepository,
})
const macroProfileUseCases =
overrides.macroProfileUseCases ??
createMacroProfileUseCases({
crudService: () => macroProfileCrudService,
crudService: macroProfileCrudService,
cache: macroProfileCache,
})
const macroProfileState =
Expand Down Expand Up @@ -257,6 +302,14 @@ export function createContainer(
authUseCases.currentUserIdOrGuestId(),
isGuestMode: () => guestUseCases.isGuestMode(),
},
weightCacheRepository,
weightRepository,
})

const weightChartSettings =
overrides.weightChartSettings ??
createWeightChartSettings({
repository: weightChartPreferenceRepository,
})

const weightChartUseCases =
Expand Down Expand Up @@ -286,7 +339,11 @@ export function createContainer(
dayUseCases: () => dayUseCases,
})

const measureCrud = overrides.measureCrud ?? createMeasureCrud()
const measureCrud =
overrides.measureCrud ??
createMeasureCrud({
measureRepository,
})
const measureState =
overrides.measureState ??
createMeasureState({
Expand All @@ -295,10 +352,29 @@ export function createContainer(
measureCrud.fetchUserBodyMeasures(userId),
})

const recentFoodCrud = createRecentFoodCrud()
const foodCrud = createFoodCrud({
repository: () => createSupabaseFoodRepository(),
const recentFoodCrud = createRecentFoodCrud({
recentFoodRepository,
})
const recentFoodUseCases =
overrides.recentFoodUseCases ??
createRecentFoodUseCases({
getCurrentUserIdOrGuestId: () => authUseCases.currentUserIdOrGuestId(),
recentFoodCrud,
})
const cachedSearchCrud: CachedSearchCrud = createCachedSearchCrud({
repository: cachedSearchRepository,
})
const foodCrud =
overrides.foodCrud ??
createFoodCrud({
repository: foodRepository,
cachedSearchCrud,
})
const recipeItemUseCases =
overrides.recipeItemUseCases ??
createRecipeItemUseCases({
fetchRecipeById: (recipeId) => recipeCrud.fetchRecipeById(recipeId),
})
const templateSearchState =
overrides.templateSearchState ??
createTemplateSearchState({
Expand All @@ -316,11 +392,14 @@ export function createContainer(
userUseCases: () => userUseCases,
guestUseCases: () => guestUseCases,
dayUseCases: () => dayUseCases,
foodCrud: () => foodCrud,
clipboardUseCases: () => clipboardUseCases,
profileUseCases: () => profileUseCases,
weightUseCases: () => weightUseCases,
weightChartSettings: () => weightChartSettings,
weightChartUseCases: () => weightChartUseCases,
recipeCrud: () => recipeCrud,
recipeItemUseCases: () => recipeItemUseCases,
macroProfileUseCases: () => macroProfileUseCases,
macroProfileState: () => macroProfileState,
macroTargetUseCases: () => macroTargetUseCases,
Expand All @@ -329,6 +408,7 @@ export function createContainer(
templateSearchState: () => templateSearchState,
measureCrud: () => measureCrud,
measureState: () => measureState,
recentFoodUseCases: () => recentFoodUseCases,
initialize: () => {
guestUseCases.initializeGuestMode()
authUseCases.initializeAuth()
Expand Down Expand Up @@ -447,6 +527,13 @@ export function createTestContainer(
refetchBodyMeasures: () => undefined,
}

const weightChartSettings: WeightChartSettings = {
weightChartType: () => 'all',
setWeightChartType: () => {
/* no-op */
},
}

const templateSearchState: TemplateSearchState = {
templateSearch: () => '',
setTemplateSearch: () => {
Expand All @@ -467,6 +554,7 @@ export function createTestContainer(
guestUseCases,
measureState,
templateSearchState,
weightChartSettings,
...overrides,
})
}
108 changes: 0 additions & 108 deletions src/di/useCases.ts

This file was deleted.

Loading
Loading