Skip to content

Feature/workmanager background sync - #13

Closed
Prajwal-4121998 wants to merge 28 commits into
mainfrom
feature/workmanager-background-sync
Closed

Prajwal-4121998 wants to merge 28 commits into
mainfrom
feature/workmanager-background-sync

Conversation

@Prajwal-4121998

Copy link
Copy Markdown
Owner

No description provided.

Only declare modules that exist with real code. Modules will be added
to settings.gradle.kts as they are created during development.
…radle caching

- Three-job structure: lint-and-test -> build -> deploy (placeholder)
- Added feature/**, hotfix/**, workflow_dispatch triggers
- Fine-grained Gradle cache key from libs.versions.toml + wrapper
- GRADLE_OPTS for CI performance
- Updated .gitignore to match production pattern
- Deploy job placeholder ready for Module 6
ci: complete Module 1 - proper three-job pipeline, branch triggers, g…
…eline

- Added dev/staging/prod product flavors with applicationIdSuffix
- versionCode auto-increments from GITHUB_RUN_NUMBER (1 locally)
- signingConfigs reads from keystore.properties locally, env vars on CI
- canSign guard prevents unsigned release build crashes when keystore absent
- CI: lintDevDebug + testDevDebugUnitTest in quality gate job
- CI: branch-conditional builds (feature->devDebug, develop->stagingDebug, main->prodRelease AAB)
- CI: keystore decoded from KEYSTORE_BASE64 secret on develop/main only
- CI: keystore cleaned up from runner after every build
…ariants

ci: Module 2+3 - product flavors, signing config, flavor-aware CI pip…
- Applied jacoco plugin to domain:product and core:common (was missing, caused 0% coverage)
- Fixed Hilt-generated package exclusion (hilt_aggregated_deps, dagger.hilt.internal)
- Recalibrated thresholds from guessed values to honest baseline: 35% overall, 65% domain
- Verified domain.product shows real coverage (GetProductsUseCaseTest exercising the use case)
- Decision: skip tests for core:common (Result/UiState are pure data classes, no logic to test)
- Decision: RetryInterceptor test deferred to next session, core:network indirect coverage via data:product repository tests
…-jacoco

ci: Module 4 - fix multi-module JaCoCo aggregation, calibrate thresholds
- Detekt 1.23.7 applied to app, domain:product, core:common, core:network
- Shared config/detekt/detekt.yml: complexity, style, naming, exceptions, potential-bugs rules
- Fixed deprecated ComplexMethod -> CyclomaticComplexMethod rule rename
- maxIssues: 0 - zero tolerance, any violation fails build
- All four modules pass with zero violations on first real run
- CI: detekt step added to quality gate job, report uploaded as artifact
ci: Module 5 - Detekt static analysis across all modules
…it tests

- ProductEntity with cachedAt timestamp for staleness detection
- ProductDao: Flow<List> for live updates, suspend funs for single ops
- CatalogDatabase with exportSchema=true for migration history
- ProductMapper: three-way mapping (DTO<->Entity<->Domain) as extension functions
- ProductRepositoryImpl: single source of truth pattern via onStart + Room Flow
  - 30-minute cache threshold before network refresh
  - ConnectivityChecker guards all network calls
  - Silent cache fallback on network failures
- DatabaseModule: Room singleton via Hilt @provides
- RepositoryModule: @BINDS ProductRepositoryImpl -> ProductRepository
  (domain layer never imports data layer - dependency inversion enforced)
- 6 unit tests covering all repository branching paths (fresh cache, stale+online,
  stale+offline, detail-cached, detail-network, detail-offline)
- JaCoCo updated to include data:product in aggregated coverage
…it tests

- ProductEntity with cachedAt timestamp for staleness detection
- ProductDao: Flow<List> for live updates, suspend funs for single ops
- CatalogDatabase with exportSchema=true for migration history
- ProductMapper: three-way mapping (DTO<->Entity<->Domain) as extension functions
- ProductRepositoryImpl: single source of truth pattern via onStart + Room Flow
  - 30-minute cache threshold before network refresh
  - ConnectivityChecker guards all network calls
  - Silent cache fallback on network failures
- DatabaseModule: Room singleton via Hilt @provides
- RepositoryModule: @BINDS ProductRepositoryImpl -> ProductRepository
  (domain layer never imports data layer - dependency inversion enforced)
- 6 unit tests covering all repository branching paths (fresh cache, stale+online,
  stale+offline, detail-cached, detail-network, detail-offline)
- JaCoCo updated to include data:product in aggregated coverage
- Add SocketTimeoutException silent fallback test
- Add HttpException silent fallback test
- Add null rating defensive mapping test
- Repository branch coverage: 63% -> 83%
- Exclude Room DAOs and generated classes from JaCoCo thresholds
- Exclude Kotlin synthetic lambda classes from threshold checks
- Recalibrate thresholds to honest achievable values:
  overall 0.55, domain 0.70, repository 0.70, mapper 0.85
…grade-fixes

Feature/jacoco production grade fixes
- Color.kt: complete light + dark color scheme from Stitch jewel-tone palette
  (Primary indigo #4F46E5, Secondary amber #FEA619, full surface token set)
- Type.kt: dual-font system via Google Fonts downloadable fonts
  (Hanken Grotesk for headlines, Inter for body/labels)
- Shape.kt: Stitch shape scale mapped to Material 3 Shapes
  (cards 16dp, buttons 24dp, chips 12dp)
- Spacing.kt: 8dp-base spacing system via CompositionLocal
- Theme.kt: CatalogTheme with light/dark/dynamic color support,
  CatalogTheme.spacing convenience accessor, dynamicColor=false default
  (preserves intentional brand palette on Android 12+)
- CatalogComponents.kt: shared loading/error/empty state composables
- MainActivity: CatalogTheme applied, HILT_TEST smoke test removed,
  edge-to-edge enabled
- Temporary core:network direct dependency removed from app module
feat: core:designsystem - Material 3 theme from Stitch design spec
…n + JaCoCo

feat: feature:catalog module
- CatalogContract: CatalogUiState data class, CatalogIntent + CatalogEffect sealed classes
- CatalogViewModel: MVI single processIntent() entry point, StateFlow, Channel effects
- CatalogScreen: stateless composition root delegating to components/ subfolder
- components/: CatalogTopBar, CatalogBottomBar, CatalogFab, CatalogBody, ProductGrid,
  ProductCard, CategoryChips, CategoryChip — each in own file (Detekt LongMethod fix)
- Stitch design: surface-container-lowest cards, tertiary-container active chips,
  secondary-container discount badge + FAB, amber rating row, 4:5 image aspect ratio,
  primary-container bottom nav active pill indicator
- Coil AsyncImage with crossfade for real product image loading
- 8 ViewModel unit tests: load, category filter, error, navigation effects,
  refresh, search navigation

feat: navigation
- CatalogNavHost with NavHost, Screen sealed class for route definitions
- CatalogScreen wired as start destination, detail placeholder ready
- MainActivity: CatalogTheme wrapping CatalogNavHost, enableEdgeToEdge

fix: Detekt violations
- Extracted named constants for magic numbers (aspect ratio, corner radius, icon sizes)
- Locale.getDefault() for String.format (ImplicitDefaultLocale)
- Split large composables into component files (LongMethod, TooManyFunctions)

ci: JaCoCo updated for feature:catalog
- jacoco plugin applied to feature:catalog build.gradle.kts
- catalogTree class files path added to both JaCoCo tasks
- exec file path: build/jacoco/testDebugUnitTest.exec
- CatalogViewModel-specific threshold: 0.75 minimum
- Compose UI composables excluded (instrumented tests concern, not JUnit)
- Overall verification passing

feat: core:designsystem
- surfaceContainerLow, surfaceContainerLowest, surfaceContainerHigh added to Theme.kt
- ConnectivityChecker minor fix

deps: libs.versions.toml
- hilt-navigation-compose, lifecycle-viewmodel-compose, coil added
- feature:catalog added to settings.gradle.kts
feat: feature:catalog - complete MVI catalog screen with Stitch desig…
…+ type-safe navigation

feat: type-safe Navigation 3
- Replaced string-based Screen sealed class with @serializable route classes
- CatalogRoute (object) and DetailRoute(productId: Int) as type-safe routes
- NavHost updated to composable<CatalogRoute> and composable<DetailRoute>
- toRoute<DetailRoute>() for extracting navigation arguments
- Compile-time route safety: wrong argument types fail at build, not runtime

feat: feature:detail module
- DetailContract: DetailUiState data class, DetailIntent + DetailEffect sealed classes
- DetailViewModel: MVI single processIntent() entry point, ProductRepository injection
  (direct repo injection — no use case needed for single pass-through call)
- DetailScreen: transparent overlay top bar (back + share + cart),
  hero image with gradient overlay, content card overlapping hero (-48dp offset),
  brand label in primary + uppercase, rating pill, in-stock emerald badge,
  price with strikethrough + discount %, features bento grid, expandable description,
  static reviews section with avatar initials, sticky bottom bar
- DetailBottomBar: outlined wishlist button (border-2 primary), secondary-container
  Add to Cart button with shopping bag icon (Stitch spec)
- 6 ViewModel unit tests: initial state, load success, load not found,
  toggle wishlist, toggle description, navigate back effect, add to cart effect

ci: JaCoCo updated for feature:detail
- jacoco plugin applied, exec file at build/jacoco/testDebugUnitTest.exec
- DetailViewModel threshold added to coverage verification

deps: kotlinx-serialization added for type-safe navigation
…igation

feat: feature:detail - complete MVI detail screen with Stitch design …
feat: implement feature:search with debounced local filtering, error …
…traction

refactor: extract SearchProductsUseCase from SearchViewModel for SRP …
…, dark theme fix, nav safety guards, bundled fonts
…sh-loading-ux

feat(designsystem): content-shaped skeletons, Coil crossfade pipeline…
- Added syncProducts() to ProductRepository interface, returns domain-owned SyncResult
- SyncResult/SyncError: sealed domain types, zero framework deps, replace exception-based
  failure signaling across the repository boundary
- ProductRepositoryImpl: sole translation boundary, catches real exceptions, maps to
  SyncError, never throws outward for expected failure cases
- ProductSyncWorker: @HiltWorker CoroutineWorker kept as thin glue only
- SyncResultMapper: pure function extracted for retry/fail decision logic,
  unit tested independently of WorkManager/Android runtime
- SyncScheduler: encapsulates WorkManager scheduling, UNMETERED (Wi-Fi only) +
  battery-not-low constraints, 6-hour interval, exponential backoff (15min base),
  ExistingPeriodicWorkPolicy.KEEP prevents timer reset on repeated schedule calls
- WorkManagerModule: @provides WorkManager singleton via Hilt
- CatalogApplication: implements Configuration.Provider with HiltWorkerFactory,
  removed default WorkManagerInitializer (required for Hilt worker injection to
  take effect), schedules sync in onCreate()
- Tests: SyncResultMapperTest covers all retry/fail branches including
  runAttemptCount boundary; ProductRepositoryImplTest covers syncProducts
  success and NoInternet error paths
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant