# Phase 12: Production Data Client Integration - Context

**Gathered:** 2026-03-20
**Status:** Ready for planning

<domain>
## Phase Boundary

Connect the app binary to a real DashboardDataClient implementation so the dashboard displays live GitHub/Shopify data instead of seed data. Replace NoopClient + seed_cards() with a production client backed by the service crate's Repository and sync infrastructure.

</domain>

<decisions>
## Implementation Decisions

### Client implementation
- Production client wraps the service crate's Repository **directly** — no intermediate API layer
- Lives in its own module: `crates/app/src/live_client.rs` — keeps main.rs clean, testable separately
- NoopClient stays for tests
- Production client **owns the sync scheduler** — starts 5-minute auto-poll internally. Main.rs just creates the client and uses it
- Service-layer types (RecipientSnapshot, etc.) mapped to app-layer types (RecipientCardSnapshot) inside the client

### Startup flow
- **Offline-first design** — app always reads from local persistent store. Syncs when service is reachable. Queues mutations when disconnected, commits when reconnected
- First-ever launch with no prior data: shows empty state
- Subsequent launches: shows locally cached data immediately, syncs in background
- **Background bootstrap** — UI renders immediately with local data. Service connection and first sync happen on a background thread. Cards populate when sync completes
- **Subtle status indicator** — small icon/text in header showing connection state (connected/disconnected). Non-intrusive, always visible

### GitHub API access
- **All GitHub API access uses the `gh` CLI command** — already authenticated on the machine, no GitHub token management needed in the app
- The app shells out to `gh` for GitHub Project data fetching (e.g., `gh api graphql` for project queries)
- No GitHub token in config file or Windows Credential Manager — `gh` handles auth entirely
- This simplifies config: only Shopify credentials need to be managed by the app

### Config & credentials
- Config file at `%APPDATA%/WITwhat/config.toml` — standard Windows user app data location, not in project directory
- Config file holds non-secret settings (store slug, GitHub project URL) plus Shopify `secret_ref` keys (e.g., `wincred:shopify/token`) resolved by CredentialLoader at runtime
- GitHub auth is handled by `gh` CLI — not stored in config or credential manager
- Shopify secrets stored in Windows Credential Manager via existing WindowsCredentialManagerStore
- **In-app config setup** — if config is missing or incomplete on first run, app starts empty and provides UI to set up Shopify credentials and settings. A settings button resurfaces this setup. No placeholder files
- `SHOPIFY_STORE_SLUG` in config (non-secret), passed to projection layer per Phase 11 decision

### Claude's Discretion
- Exact config.toml schema and field names
- How the sync scheduler timer is implemented (std::thread sleep loop vs tokio vs other)
- Connection state indicator placement and styling
- How mutation queue persistence works (in-memory vs file-based)
- Settings UI layout and flow

</decisions>

<canonical_refs>
## Canonical References

**Downstream agents MUST read these before planning or implementing.**

### Client trait and types
- `crates/app/src/service_client.rs` — DashboardDataClient trait, RecipientCardSnapshot, all method signatures
- `crates/app/src/bootstrap.rs` — bootstrap_client(), connect_with_retry, BootstrapResult, ClientMode

### Service layer
- `crates/service/src/db/repository.rs` — Repository struct with all CRUD methods
- `crates/service/src/api/recipients.rs` — RecipientSnapshot, get_recipient_snapshot
- `crates/service/src/api/items.rs` — Item CRUD functions (add, remove, rename, save_note, search_catalog)
- `crates/service/src/runtime/startup.rs` — ServiceRuntime
- `crates/service/src/sync/merge.rs` — merge_recipient, merge pipeline

### Credentials
- `crates/service/src/security/windows_credential_manager.rs` — WindowsCredentialManagerStore
- `crates/service/src/bootstrap/credential_loader.rs` — CredentialLoader, secret_ref resolution

### Current app wiring
- `crates/app/src/main.rs` — NoopClient (line ~1681), seed_cards() (line ~134), client usage (line ~684)
- `crates/app/src/dashboard/projection.rs` — project_snapshot with store_slug parameter (Phase 11)
- `crates/app/src/dashboard/mod.rs` — from_snapshots with store_slug parameter

</canonical_refs>

<code_context>
## Existing Code Insights

### Reusable Assets
- `DashboardDataClient` trait: fully defined with 9 methods and default no-op implementations
- `bootstrap_client()`: health check + retry + auto-start + degraded mode detection
- `connect_with_retry()`: configurable max attempts with Live/Degraded result
- `CredentialLoader` + `WindowsCredentialManagerStore`: secret resolution from Windows Credential Manager
- `Repository`: in-memory storage with all CRUD operations
- `ServiceRuntime`: service lifecycle management
- Sync scheduler with backoff/jitter already in service crate

### Established Patterns
- `Rc<C>` where `C: DashboardDataClient` — client shared via Rc in main.rs callbacks
- `RefreshDispatcher<C>` / `EditDispatcher<C>` — generic over client type
- `project_snapshot(snapshot, now, store_slug)` — projection accepts store_slug
- PendingEditQueue for optimistic updates with pending-edit-count indicator

### Integration Points
- `main.rs:684` — `let client = Rc::new(NoopClient)` → replace with production client
- `main.rs:599` — `let all_cards = seed_cards()` → replace with client.fetch_card_snapshots() → project_snapshot
- `main.rs` — store_slug hardcoded in seed data → read from config
- Archive store path already wired in main.rs

</code_context>

<specifics>
## Specific Ideas

- User wants offline-first: "The app should always have a local copy of all data it displays"
- User wants in-app setup: "The user is given the opportunity to set up the config via UI in the client app. Never placeholder values, just starts empty"
- Settings button should resurface the in-app config setup at any time

</specifics>

<deferred>
## Deferred Ideas

- Setup wizard with step-by-step credential entry — could be a future UX enhancement beyond basic settings UI
- Mutation queue sync-on-reconnect — full offline mutation queue may need its own phase if complex
- Auto-update mechanism for the app binary

</deferred>

---

*Phase: 12-production-data-client*
*Context gathered: 2026-03-20*
