---
phase: 17-gh-issues-client-and-product-catalog
plan: 02
subsystem: integrations, database, ui
tags: [github-issues, product-catalog, orphan-branch, sqlite, sync]

# Dependency graph
requires:
  - phase: 17-01
    provides: "GhIssuesClient, SQLite product/unit tables, body parsers"
provides:
  - "ProductImagesBranchClient for product image uploads to orphan branch"
  - "sync_products() pipeline: ww-product issues + subissue units to SQLite"
  - "build_product_option_grid() for catalog-backed product tiles with recipient counts"
affects: [17-03, 17-04, 17-05]

# Tech tracking
tech-stack:
  added: []
  patterns: ["orphan branch file storage (product-images)", "non-fatal sync step pattern"]

key-files:
  created:
    - "crates/integrations/src/github/product_images_branch_client.rs"
  modified:
    - "crates/integrations/src/github/mod.rs"
    - "crates/app/src/live_client.rs"
    - "crates/app/src/dashboard/discovery.rs"

key-decisions:
  - "sync_products is non-fatal: errors logged but do not fail the overall sync cycle"
  - "GhIssuesClient constructed on background thread (not stored on LiveClient for sync)"
  - "build_product_option_grid matches products to cards by name (case-insensitive) during transition period"

patterns-established:
  - "Non-fatal sync step: additional sync operations log errors to stderr but never fail run_sync_cycle"
  - "Product image storage: product-images orphan branch with images/{product_id}.jpg path pattern"

requirements-completed: [PROD-01]

# Metrics
duration: 9min
completed: 2026-03-25
---

# Phase 17 Plan 02: Product Sync Pipeline and Catalog-backed Grid Summary

**Product sync via ww-product GH Issues + subissue units to SQLite, ProductImagesBranchClient for orphan branch image storage, and catalog-backed product option grid with recipient counts**

## Performance

- **Duration:** 9 min
- **Started:** 2026-03-25T08:35:44Z
- **Completed:** 2026-03-25T08:44:33Z
- **Tasks:** 2
- **Files modified:** 4

## Accomplishments
- ProductImagesBranchClient created for uploading/downloading product images on the `product-images` orphan branch
- sync_products() wired into run_sync_cycle: fetches ww-product issues, lists subissues for units, upserts both to SQLite
- build_product_option_grid() provides catalog-backed product tiles sorted alphabetically with recipient counts and Shopify link status
- 4 unit tests for the catalog grid function (sorting, recipient count, empty catalog, Shopify linked)

## Task Commits

Each task was committed atomically:

1. **Task 1: ProductImagesBranchClient and product sync in LiveClient** - `55170b2` (feat)
2. **Task 2: Catalog-backed product option grid replacing card-derived tiles** - `c342b4d` (feat, included in concurrent 17-03 commit)

## Files Created/Modified
- `crates/integrations/src/github/product_images_branch_client.rs` - Orphan branch client for product image upload/download/ensure
- `crates/integrations/src/github/mod.rs` - Added product_images_branch_client module export
- `crates/app/src/live_client.rs` - Added sync_products() and wired into run_sync_cycle with GhIssuesClient
- `crates/app/src/dashboard/discovery.rs` - Added ProductTile struct, build_product_option_grid(), and 4 tests

## Decisions Made
- sync_products is non-fatal: errors are logged to stderr but do not fail the overall run_sync_cycle, preserving existing recipient/card sync reliability
- GhIssuesClient constructed on background sync thread alongside other clients (not stored on LiveClient struct for now)
- build_product_option_grid matches products to cards by name (case-insensitive) as a transition strategy until product_refs are fully populated
- Preserved existing extract_product_tiles() as fallback for when catalog is empty

## Deviations from Plan

### Auto-fixed Issues

**1. [Rule 3 - Blocking] Added gh_issues_client parameter to run_sync_cycle**
- **Found during:** Task 1 (product sync wiring)
- **Issue:** run_sync_cycle is a free function without access to GhIssuesClient; plan specified calling sync_products from within it
- **Fix:** Added optional `gh_issues_client: Option<&GhIssuesClient>` parameter to run_sync_cycle signature and updated both call sites
- **Files modified:** crates/app/src/live_client.rs
- **Verification:** cargo build -p app exits 0
- **Committed in:** 55170b2 (Task 1 commit)

---

**Total deviations:** 1 auto-fixed (1 blocking)
**Impact on plan:** Necessary to wire sync_products into run_sync_cycle. No scope creep.

## Issues Encountered
- Task 2 changes to discovery.rs were committed by a concurrent 17-03 agent execution (c342b4d) that picked up the in-flight edits. No data loss; all changes verified present.

## Known Stubs
None - all functions are fully implemented with real data sources.

## User Setup Required
None - no external service configuration required.

## Next Phase Readiness
- Product sync pipeline ready for end-to-end testing with real ww-product GH Issues
- build_product_option_grid ready for Slint UI integration in Plan 03/04
- ProductImagesBranchClient ready for image upload workflows

---
*Phase: 17-gh-issues-client-and-product-catalog*
*Completed: 2026-03-25*
