Overview
Divvy uses the Repository Pattern to abstract data access logic from the UI and business logic layers. All repositories follow a consistent interface-based design with Supabase implementations.Architecture
Interface-Based Abstractions
Each repository is defined as a Kotlin interface that declares the contract for data operations:Supabase Implementations
Each interface has a corresponding Supabase implementation:GroupRepository→SupabaseGroupRepositoryExpensesRepository→SupabaseExpensesRepositoryAuthRepository→SupabaseAuthRepositoryProfilesRepository→SupabaseProfilesRepository
@Singleton and injected via Hilt:
DataResult Wrapper
Divvy uses aDataResult sealed class to handle loading states, success, and errors uniformly across the app.
Definition
Source:backend/DataResult.kt:3
Usage Pattern
Repositories returnDataResult for operations that may fail:
Error Handling
Try-Catch Pattern
Repository implementations wrap Supabase calls in try-catch blocks:Error States
Repositories maintain internalMutableStateFlow with DataResult states:
Dependency Injection with Hilt
Repository Binding
Repositories are injected as singletons:ViewModel Injection
ViewModels receive repository instances via constructor injection:Reactive Data with Flow
Observing Data Changes
Repositories exposeFlow<DataResult<T>> for reactive UI updates:
Data Refresh
Repositories provide explicit refresh methods:Suspend Functions
All data mutations use Kotlin coroutines withsuspend functions:
Repository List
GroupRepository
Manage groups, members, and group metadata
ExpensesRepository
Create, update, and track expenses with splits
AuthRepository
Handle user authentication and sessions
ProfilesRepository
Manage user profiles and preferences
Best Practices
1. Always Use Interfaces
Depend on interfaces, not concrete implementations:2. Handle All DataResult States
Always handleLoading, Success, and Error states: