# Project Research Summary

**Project:** WITwhat v1.1 — Data Architecture and Product Catalog milestone
**Domain:** Rust/Slint Windows desktop app — prototype device logistics and recipient tracking
**Researched:** 2026-03-22
**Confidence:** HIGH

## Executive Summary

WITwhat v1.1 is a focused data-architecture migration for an existing Rust/Slint desktop app. The v1.0 app already has a working card grid, Shopify sync pipeline, GitHub Project integration, search, archive, and item CRUD. The v1.1 milestone closes four critical gaps: replacing the in-memory Repository with SQLite as the single read source (RULE-03), making GitHub Issues the cloud of record for cards and products (RULE-05), adding a product catalog and per-unit serial instance lifecycle (Layers 3 and 4 of DATA-FLOW.md), and removing accumulated data-model debt (RULES 01, 02, 07, 08). The research is entirely grounded in the project's own DATA-FLOW.md specification and direct codebase inspection — not aspirational patterns from external domains.

The recommended approach is a strict dependency-ordered build sequence: SQLite foundation first (it unblocks everything), then new GH Project column ingestion, then GH Issues client and product catalog, then GH Issues write-back with notes, then serial instance tracking, then offline mode hardening, then the Lists feature. This order is non-negotiable because of hard FK and data-source dependencies: products must exist in SQLite before serial instances can reference them; GH Issues write-back requires the GH Issues client from the product catalog phase; offline flush requires the pending_edits SQLite table from the foundation phase. Skipping or reordering phases requires double-implementation.

The primary risk is the SQLite cut-over itself: the existing in-memory Repository is wired throughout the service and app crates, and it is possible to add SQLite writes without removing Repository reads, leaving RULE-03 violated in a way that appears to work until process restart. The second major risk is GH Issue body format fragility — if the first implementation does not include a `schema_version` key and a stable JSON schema, every subsequent phase that extends the format will require a retroactive migration against live production issues. Both risks have clear structural mitigations documented in the research.

## Key Findings

### Recommended Stack

The existing stack (Rust, Slint, tokio, serde/serde_json, ureq v2, keyring, fuzzy-matcher, toml, uuid) requires four additions and one version upgrade for v1.1. No ORM or external job-queue library is needed — the schema is small enough for direct rusqlite access, and the offline queue is a simple drain table.

**Core additions/changes:**
- `rusqlite 0.39` (features: `bundled`, `chrono`, `uuid`): SQLite local mirror cache — `bundled` eliminates the Windows system SQLite requirement by compiling SQLite 3.51.3 from C source via the `cc` crate; no MSVC link headache
- `rusqlite_migration 2.5`: Schema migrations at startup using SQLite's built-in `user_version` integer — no CLI, no migration files, just ordered SQL strings defined in Rust at compile time
- `chrono 0.4` (feature: `serde`): `DateTime<Utc>` for timestamps in domain types and SQLite TEXT columns; required by `NoteEntry.date`, `assigned_at`, `last_synced_at`; the `serde` feature covers both JSON and SQLite round-trips
- `ureq 3.3` (upgrade from v2): GH Issues REST calls — v2 is no longer maintained; v3 has stricter TLS defaults and changed error types; existing `match` arms on `ureq::Error` in `crates/integrations/` must be audited during the upgrade

**What does not change:** tokio, serde/serde_json, keyring, uuid, slint — no new primitives are needed for any v1.1 feature. The `dirs` crate (already in `app`) provides the DB file path via `data_local_dir()`.

See `.planning/research/STACK.md` for full Cargo.toml change specifications per crate.

### Expected Features

All v1.1 features are P1 or P2. There are no speculative or aspirational items — every feature traces back to a specific DATA-FLOW.md RULE or operational need.

**Must have (P1 — table stakes):**
- SQLite full-mirror cache — replaces in-memory Repository; RULE-03 satisfied; prerequisite for everything else
- GH Issues round-trip for `ww-card` and `ww-product` — RULE-05 satisfied; cloud-of-record requirement
- Product catalog (Layer 3) — standalone product entities browsable in app; prerequisite for serial tracking and `product_refs`
- Serial instance tracking (Layer 4) — 7-state lifecycle machine (Created → Assigned → InTransit → Delivered → ReturnInTransit → Returned → Available); single-active-assignment invariant enforced
- Deprecated field cleanup — RULES 01, 02, 07, 08; remove `github_profile_url`, shipment fields on Recipient, `item_summary`, `latest_note`, `first_item_image_hint`
- New GH Project columns ingest — Purpose, Vision Rx OD/OS, Discord fields, product parallel-arrays
- Offline mode with pending edit flush-on-reconnect — queue persisted in SQLite, automatic flush on reconnect, explicit UI state

**Should have (P2 — differentiators):**
- Start Return feature — serial state transition (Delivered → ReturnInTransit) + GH Issue write; closes the return loop without leaving the app
- Lists feature — named card groupings, SQLite-backed, new discovery mode; no hard blockers beyond SQLite
- Vision Rx and Purpose ring display — low-cost UI wins once GH Project columns are ingested

**Defer (v1.x or v2+):**
- Shopify return label generation — Shopify Returns API is complex; trigger return intent in GH Issue only for v1.1; label generation is v2
- Bulk product assignment, list cloud sync — add after validating usage patterns
- Per-user authentication, Shopify write actions (timeline comments, order tags) — v2+

See `.planning/research/FEATURES.md` for dependency graph and UX pattern notes.

### Architecture Approach

The v1.1 architecture is a layered cut-over: integrations clients feed a SQLite mirror, and the UI reads exclusively from SQLite. The sync pipeline writes to SQLite; user edits write to SQLite immediately (optimistic) and queue a GH Issues write in `pending_edits`. A `PendingEditFlusher` background task drains the queue in FIFO order on reconnect, always before the next sync cycle runs. The `DashboardDataClient` trait in `service_client.rs` is the seam — replacing `fetch_card_snapshots()` to read from SQLite instead of the in-memory Repository is the central cut-over operation.

**Major components:**
1. `SqliteStore` (`service/db/sqlite_store.rs`, NEW) — production read/write store replacing `Arc<Mutex<Repository>>`; tables: recipients, cards, card_products, notes, products, serial_instances, archive_records, pending_edits, sync_audit_log
2. `GhIssuesClient` (`integrations/github/issues_client.rs`, NEW) — REST client for ww-card and ww-product issue create/update/read; distinct from existing GH Project GraphQL client so each can be mocked independently
3. `ProductCatalog` (`service/product_catalog.rs`, NEW) — CRUD for Product entities and SerialInstance lifecycle; transition guard enforces state machine; does not belong in sync pipeline or UI layer
4. `PendingEditFlusher` (`app/src/dashboard/edit_queue.rs`, extend) — drains `pending_edits` table on reconnect; must complete before any sync cycle starts; `Flushing` status field prevents re-sends on retry
5. `LiveClient` (modify) — replace Repository wiring with SqliteStore; add reconnect detection and PendingEditFlusher trigger
6. `ListsState` (`app/src/dashboard/lists.rs`, NEW) — list membership in SQLite; added to DashboardRuntime alongside DiscoveryState

See `.planning/research/ARCHITECTURE.md` for full data flow diagrams, component responsibility table, and anti-patterns.

### Critical Pitfalls

1. **Reading in-memory Repository after SQLite exists** — compile-gate all `Repository` reads behind `#[cfg(test)]` atomically during the SQLite cut-over; do not add SQLite writes alongside existing Repository reads and leave both alive. Recovery cost is HIGH.
2. **GH Issue body format lock-in** — define a JSON schema with a top-level `schema_version` key before writing any production issues; test round-trip parse/emit on all fields; every subsequent phase that extends the format depends on this decision.
3. **Offline queue racing with sync** — flush `pending_edits` completely (Pending → Flushing → Done) before starting any sync cycle on reconnect; use an `AtomicBool` gate; never run flush and sync concurrently.
4. **Serial instance double-assignment** — enforce the single-active-assignment invariant at the SQLite schema level with a UNIQUE constraint on `serial_instances.assigned_card_id`, not just in application code; application-layer validation is bypassed by the sync ingest path.
5. **SQLite connection deadlock** — decide connection management strategy (single `Arc<Mutex<Connection>>` + WAL mode vs. `r2d2-sqlite` pool) before writing any SQLite code; never hold a connection lock across a GH API call or across `slint::invoke_from_event_loop`.
6. **Deprecated field pipeline break** — remove each deprecated field as a complete vertical slice bottom-up (Slint UI → ViewModel → app DTO → service DTO → domain model) in one PR per field; dummy default values are not acceptable as placeholders.
7. **Slint z-order blocking product item squares** — declare full-card TouchArea elements before child interactive elements in `.slint` files; this already caused a bug in this project (documented in MEMORY.md).

See `.planning/research/PITFALLS.md` for full "looks done but isn't" checklists and recovery strategies per pitfall.

## Implications for Roadmap

Based on research, the feature dependency graph mandates a 7-phase build sequence. All phases are additive within existing crate boundaries — no crate restructuring is required.

### Phase 1: SQLite Foundation and Deprecated Field Cleanup

**Rationale:** SQLite is the hard prerequisite for every other v1.1 feature. Deprecated field removal must happen before new features build on the same transformation pipeline — doing it later requires two full-pipeline refactors. Bundling both into Phase 1 minimizes the total number of pipeline-wide changes.

**Delivers:** Production SqliteStore replacing in-memory Repository; `pending_edits` and `archive_records` migrated from JSON files to SQLite tables; complete cut-over so all production reads go through SQLite; transformation pipeline clean of all RULE-01/02/07/08 debt.

**Addresses:** SQLite full-mirror cache (P1), Deprecated field cleanup (P1).

**Avoids:** Pitfall 1 (in-memory reads after SQLite — Repository compile-gated to test-only), Pitfall 5 (deprecated field pipeline break — bottom-up vertical slice per field), Pitfall 8 (SQLite deadlock — connection strategy decided at schema design time).

**Research flag:** Needs phase research. Connection management decision (single Arc<Mutex<Connection>> + WAL mode vs. r2d2-sqlite pool) and the exact Repository cut-over sequence need explicit design before coding begins.

### Phase 2: New GH Project Columns Ingestion

**Rationale:** Low implementation cost; unblocks the Purpose ring and Vision Rx UI features; produces product parallel-array stubs that Phase 3 resolves against real product IDs. Depends only on Phase 1 (recipients SQLite table must exist).

**Delivers:** Purpose, Vision Rx OD/OS, discord_username, discord_user_id, and product parallel-arrays flowing from GH Project → `project_mapping.rs` → recipients table → RecipientCardSnapshot → UI.

**Addresses:** New GH Project columns ingest (P1), Vision Rx display (P2), Purpose ring (P2).

**Avoids:** Anti-pattern 4 (adding fields without DATA-FLOW.md documentation — all new columns are already documented in DATA-FLOW.md).

**Research flag:** Standard patterns. `project_mapping.rs` already handles GH Project column ingestion; this is additive field mapping. Skip phase research.

### Phase 3: GH Issues Client and Product Catalog (Layer 3)

**Rationale:** The `GhIssuesClient` is a shared dependency for both product catalog reads and card write-back (Phase 4) — build it once here. The `products` SQLite table is the FK parent for `serial_instances` (Phase 5); the table must exist before serial tracking begins. The GH Issue body schema established here locks in every subsequent phase — it is the most consequential design decision in v1.1.

**Delivers:** `GhIssuesClient` REST client with rate limit backoff and pagination; `products` and `card_products` SQLite tables; `ProductCatalog` service; product parallel-array refs from Phase 2 resolved against real product IDs; product catalog browsable in app.

**Addresses:** Product catalog / Layer 3 (P1), GH Issues read for ww-product.

**Avoids:** Pitfall 2 (GH Issue body format lock-in — `schema_version` established here), Pitfall 6 (GH API rate limits — idempotent issue creation with rate limit backoff and pagination implemented here), Anti-pattern 3 (building product catalog before SQLite exists).

**Research flag:** Needs phase research. Open questions OQ-01 (serial instance storage: ww-product issue body block vs. structured comments) and OQ-03 (issue body encoding format: JSON fenced block vs. YAML vs. custom delimiter) from DATA-FLOW.md must be resolved before implementation. The body schema established here cannot be changed without migrating all production issues.

### Phase 4: GH Issues Write-Back, Notes, and Card Cloud Storage (RULE-05)

**Rationale:** `GhIssuesClient` now exists (Phase 3). This phase closes RULE-05 for cards, creates the `PendingEditFlusher` that Phases 5 and 6 depend on, and completes the `Vec<NoteEntry>` migration that was started in the deprecated field cleanup.

**Delivers:** `ww-card` issue create/update; `notes` SQLite table; `Vec<NoteEntry>` replacing `latest_note` scalar in snapshots and view model; `PendingEditFlusher` with flush-before-sync sequencing and `Flushing` status gate; `CreateNote` EditCommand variant.

**Addresses:** GH Issues round-trip for ww-card (P1), Notes as Vec<NoteEntry> (RULE-08 completion).

**Avoids:** Pitfall 3 (offline queue racing with sync — flush-before-sync gate with AtomicBool implemented here), Pitfall 5 (writing to GH Issues synchronously on UI thread — pending_edits + background flush pattern enforced).

**Research flag:** Standard patterns. Flush-before-sync sequencing is fully specified in PITFALLS.md and ARCHITECTURE.md. Skip phase research.

### Phase 5: Serial Instance Tracking (Layer 4)

**Rationale:** Requires the products SQLite table (Phase 3) and the GH Issues write-back pattern including PendingEditFlusher (Phase 4). Serial instances are sub-entities of products; state machine transitions write to both SQLite and GH Issues via the flusher.

**Delivers:** `serial_instances` SQLite table with UNIQUE constraint on `assigned_card_id`; `SerialInstanceState` machine in `product_catalog.rs`; sync of serial instances from ww-product GH Issue; `AssignProduct` and `StartReturn` EditCommand variants; serial state displayed on item squares in card UI.

**Addresses:** Serial instance tracking / Layer 4 (P1), Start Return feature (P2).

**Avoids:** Pitfall 4 (serial double-assignment — UNIQUE constraint in schema, not just application code), Pitfall 7 (Slint z-order blocking product item squares — full-card TouchArea declared before item squares).

**Research flag:** Needs phase research. OQ-01 resolution (serial storage: ww-product body block vs. comments) must be confirmed before implementation — it drives the GhIssuesClient read/write design and the SQLite sync logic. This is a dependency from Phase 3 planning.

### Phase 6: Offline Mode Hardening

**Rationale:** `pending_edits` SQLite table exists (Phase 1); `PendingEditFlusher` exists (Phase 4). This phase adds the user-visible reliability features: reconnect detection, explicit UI state, and failed-edit UX. The underlying infrastructure is already in place.

**Delivers:** Reconnect detection in LiveClient background loop; distinct offline vs. syncing UI states (separate icons/colors); pending edit count indicator; Failed edit retry/discard UX; confirmed that queue survives app restart (already true via SQLite from Phase 1).

**Addresses:** Offline mode with pending edit flush-on-reconnect (P1).

**Avoids:** Pitfall 3 (flush/sync race — AtomicBool gate confirmed correct here), UX pitfall (no visual distinction between syncing and offline states — verified in UI testing).

**Research flag:** Standard patterns. tokio reconnect detection and AtomicBool gate are well-established. Skip phase research.

### Phase 7: Lists Feature

**Rationale:** Lists have no hard blockers beyond SQLite (Phase 1). Building Lists last allows the discovery mode patterns established in earlier phases to inform the Lists UX, and avoids designing a Lists view before the card grid has its final v1.1 shape (product tiles, notes, serial state badges).

**Delivers:** `lists` and `list_memberships` SQLite tables; `ListsState` added to DashboardRuntime; Lists as a new discovery mode tab; add/remove card from list EditCommand variants; a card can belong to multiple lists simultaneously.

**Addresses:** Lists feature (P2).

**Avoids:** UX pitfall (Lists view must have visually distinct treatment from main dashboard to prevent confusion with shipment status).

**Research flag:** Standard patterns. VecModel list state follows the same Slint pattern as existing discovery modes. Skip phase research.

### Phase Ordering Rationale

- **SQLite first is non-negotiable.** Five of the seven phases have SQLite as a hard FK or read-source prerequisite. Building any feature against the in-memory Repository and migrating later means double-implementation and a risky schema migration.
- **GH Issues client is built once in Phase 3.** Both product catalog (Phase 3) and card write-back (Phase 4) need it; building it in Phase 3 avoids splitting a cross-cutting concern across phases.
- **Deprecated field cleanup is bundled with Phase 1** because the same 7-layer transformation pipeline that SQLite reads restructure also carries the deprecated fields. Doing them in separate phases means two full-pipeline refactors.
- **Serial tracking (Phase 5) after write-back (Phase 4)** because AssignProduct and StartReturn use the PendingEditFlusher established in Phase 4. Building Phase 5 first would require placeholder flush logic to be replaced.
- **Lists last** because it is the only v1.1 feature with no dependencies on Phases 2-6 beyond SQLite, and it has lower operational urgency than serial tracking and offline hardening.

### Research Flags

Phases needing deeper research during planning:
- **Phase 1 (SQLite Foundation):** Connection management strategy (single `Arc<Mutex<Connection>>` + WAL mode vs. `r2d2-sqlite` pool) needs an explicit design decision before coding. The deadlock risk is concrete, not theoretical, based on the existing Repository mutex pattern.
- **Phase 3 (GH Issues Client + Product Catalog):** Open questions OQ-01 and OQ-03 from DATA-FLOW.md must be resolved. The body schema decided here locks in Phases 4 and 5.
- **Phase 5 (Serial Instance Tracking):** OQ-01 resolution from Phase 3 is a prerequisite input. Cannot plan the SQLite sync logic or GhIssuesClient read design without it.

Phases with standard patterns (skip phase research):
- **Phase 2 (GH Project Columns):** Additive change to existing `project_mapping.rs`.
- **Phase 4 (GH Issues Write-Back):** Flush-before-sync pattern fully specified in research.
- **Phase 6 (Offline Mode):** tokio reconnect detection and AtomicBool gate are standard.
- **Phase 7 (Lists):** Follows established Slint VecModel + DashboardRuntime pattern.

## Confidence Assessment

| Area | Confidence | Notes |
|------|------------|-------|
| Stack | HIGH | All versions verified against docs.rs/crates.io at research time (2026-03-22). ureq v3 error type changes are the only migration hazard; existing match arms must be audited during upgrade. |
| Features | HIGH | Derived entirely from DATA-FLOW.md authoritative spec and existing codebase. No aspirational features — every item has a documented RULE or operational source. |
| Architecture | HIGH | Based on direct codebase inspection of all four crates plus DATA-FLOW.md. Component boundaries and data flow are fully mapped. |
| Pitfalls | HIGH | Pitfalls 1, 4, 5, 7 verified against actual code patterns in the codebase. Pitfalls 3, 6, 8 based on well-established Rust/SQLite/GH API patterns with multiple corroborating sources. |

**Overall confidence:** HIGH

### Gaps to Address

- **OQ-01 (serial instance storage location):** DATA-FLOW.md leaves open whether serial instances are stored in the ww-product issue body as a JSON block or as structured comments. Affects GhIssuesClient design, SQLite sync logic, and GH Issue body size limits. Must be resolved before Phase 3 planning begins.
- **OQ-03 (GH Issue body encoding format):** JSON fenced block vs. YAML vs. custom delimiter. The format must be locked before any ww-card or ww-product issues are written to production. Research recommendation: JSON with `schema_version` key — needs explicit sign-off.
- **OQ-02 (recipient_key vs. recipient_id naming):** Low-urgency FK naming question once UUID PK exists. Can be deferred to Phase 1 design without blocking roadmap planning.
- **ureq v3 migration audit:** The existing codebase uses ureq v2. All `ureq::Error` match arms in `crates/integrations/` need an audit pass during Phase 3. Not a planning blocker, but a concrete implementation task to flag in the Phase 3 work breakdown.

## Sources

### Primary (HIGH confidence)
- `.planning/DATA-FLOW.md` — authoritative field definitions, layer architecture, RULES 01–08, open questions OQ-01/02/03
- `crates/app/src/live_client.rs` — sync pipeline; background thread structure; Repository wiring
- `crates/app/src/service_client.rs` — DashboardDataClient trait; RecipientCardSnapshot shape
- `crates/service/src/db/repository.rs` — in-memory Repository (replacement target)
- `crates/app/src/dashboard/` — DashboardRuntime, EditDispatcher, PendingEditQueue, ArchiveStore
- `Cargo.toml` — workspace structure confirming four crates: core, integrations, service, app
- [rusqlite docs.rs](https://docs.rs/rusqlite/latest/rusqlite/) — version 0.39.0 confirmed; `bundled` compiles SQLite 3.51.3
- [rusqlite_migration docs.rs](https://docs.rs/crate/rusqlite_migration/latest) — version 2.5.0 confirmed (released 2026-03-21)
- [ureq docs.rs](https://docs.rs/crate/ureq/latest) — version 3.3.0 confirmed; v3 API changes documented
- [chrono crates.io](https://crates.io/crates/chrono) — version 0.4.42 confirmed; `serde` feature verified
- [GitHub REST API — Issues](https://docs.github.com/en/rest/reference/issues) — create/update/comment endpoints; rate limits (5,000/hr); pagination (30/page default)

### Secondary (MEDIUM confidence)
- Established desktop app patterns for SQLite caching, offline queuing, and lifecycle state machines — verify implementation details during phase execution
- MEMORY.md project memory — Slint z-order/TouchArea precedence, TextInput arrow key capture, CardData archive_state sync requirements

---
*Research completed: 2026-03-22*
*Ready for roadmap: yes*
