# Architecture Research

**Domain:** Rust/Slint Windows desktop app — v1.1 data architecture integration
**Researched:** 2026-03-22
**Confidence:** HIGH (derived entirely from authoritative source files: DATA-FLOW.md, codebase inspection)

---

## Standard Architecture

### System Overview: Current vs. Target

#### Current (v1.0 transitional state)

```
+---------------------------------------------------------------------+
|                        EXTERNAL SOURCES                             |
|   GitHub Project (GH CLI graphql)   Shopify Admin (HTTP)            |
+---------------------------+---------------------------+-------------+
                            |                           |
+---------------------------v---------------------------v-------------+
|                     crates/app  (background thread)                 |
|   LiveClient  -->  run_sync_cycle()                                  |
|                         |                                            |
|          Arc<Mutex<Repository>>  (in-memory HashMap)                 |
|          Arc<Mutex<unassigned_cards>>                                |
|          Arc<Mutex<recipient_list>>                                  |
+---------------------------+-----------------------------------------+
                            |  slint::invoke_from_event_loop
+---------------------------v-----------------------------------------+
|                     crates/app  (UI thread)                          |
|   RecipientCardSnapshot --> DashboardCardViewModel --> CardData       |
|   DashboardRuntime  (archive, discovery, card UI state)              |
|   PendingEditQueue  (JSON file)   ArchiveStore (JSON file)           |
+----------------------------------------------------------------------+
```

#### Target (v1.1 state)

```
+----------------------------------------------------------------------+
|                         EXTERNAL SOURCES                              |
|  GH Project (GH CLI)     GH Issues/beyond-outgoing    Shopify Admin   |
|  (recipients, read-only) (ww-card, ww-product, r/w)   (orders, read)  |
+---+---------------------------+---------------------+----------------+
    | GH CLI graphql            | GH REST API         | HTTP
    v                           v                     v
+----------------------------------------------------------------------+
|              crates/integrations (background thread)                  |
|   GhCliProjectClient      GhIssuesClient (NEW)      HttpShopifyClient |
|   (project_client.rs)     (issues_client.rs)        (http_client.rs)  |
+---+---------------------------+---------------------+----------------+
    |                           |                     |
    +---------------------------+---------------------+
                                |
                                v  run_sync_cycle() in live_client.rs
+----------------------------------------------------------------------+
|               SQLite Cache  (%APPDATA%\WITwhat\witwhat.db)            |
|   recipients  cards  card_products  notes  products  serial_instances  |
|   archive_records  pending_edits  sync_audit_log                      |
+------------------------------+---------------------------------------+
                               |  all reads go through SQLite (RULE-03)
                               v
+----------------------------------------------------------------------+
|                    crates/app  (UI thread)                            |
|   SqliteReadClient (replaces Repository)                              |
|   RecipientCardSnapshot --> DashboardCardViewModel --> CardData        |
|   DashboardRuntime  (archive, discovery, card UI state)               |
|   PendingEditQueue (migrated to SQLite pending_edits table)           |
+----------------------------------------------------------------------+
```

### Component Responsibilities

| Component | Responsibility | Location | Status |
|-----------|----------------|----------|--------|
| `GhCliProjectClient` | Reads GH Project rows via GH CLI graphql | `integrations/github/project_client.rs` | Exists |
| `GhIssuesClient` | Reads/writes ww-card and ww-product GH Issues via REST API | `integrations/github/issues_client.rs` | NEW |
| `HttpShopifyClient` | Reads Shopify orders, fulfillments, tracking | `integrations/shopify/http_client.rs` | Exists |
| `SqliteStore` | Full-mirror SQLite cache; all reads/writes; replaces in-memory Repository | `service/db/sqlite_store.rs` | NEW |
| `LiveClient` | Background sync thread; calls run_sync_cycle(); dispatches to SQLite | `app/src/live_client.rs` | Modify |
| `run_sync_cycle()` | Shopify-first pipeline; writes all entities to SQLite | `app/src/live_client.rs` | Modify |
| `PendingEditFlusher` | On reconnect: drain pending_edits, send to GH Issues, mark done | `app/src/dashboard/edit_queue.rs` (extend) | NEW |
| `DashboardRuntime` | UI-thread state: discovery, archive, card UI states | `app/src/dashboard/mod.rs` | Modify (remove JSON file persistence) |
| `RecipientCardSnapshot` | App DTO: merged card shape passed to projection pipeline | `app/src/service_client.rs` | Modify (add product_refs, notes, remove deprecated fields) |
| `DashboardCardViewModel` | View model: UI-ready; computes pills, badges, archive state | `app/dashboard/view_model.rs` | Modify |
| `EditDispatcher` | Routes edit commands through DashboardDataClient trait | `app/dashboard/actions.rs` | Modify (add new commands for product assign, return init) |
| `ProductCatalog` | CRUD for Product entities; serial instance lifecycle | `service/product_catalog.rs` | NEW |

---

## Recommended Project Structure

The workspace crate boundaries are sound. Changes are additive within existing crates.

```
crates/
+-- core/                         # Domain models, traits (no change to crate boundary)
|   +-- src/domain/
|       +-- recipient.rs          # MODIFY: remove deprecated fields (RULES 01, 02)
|       +-- card.rs               # NEW: explicit Card domain model
|       +-- product.rs            # NEW: Product + SerialInstance domain models
|       +-- item.rs               # REMOVE or repurpose (replaced by product_refs)
|
+-- integrations/                 # External API clients
|   +-- src/
|       +-- github/
|       |   +-- project_client.rs # EXISTS: GH Project reads
|       |   +-- issues_client.rs  # NEW: ww-card / ww-product GH Issues R/W
|       |   +-- project_mapping.rs# MODIFY: add Purpose, Vision Rx, product parallel-arrays
|       +-- shopify/
|           +-- http_client.rs    # EXISTS: may add return initiation if in scope
|
+-- service/                      # Storage layer
|   +-- src/
|       +-- db/
|       |   +-- sqlite_store.rs   # NEW: replaces repository.rs as production store
|       |   +-- schema.rs         # NEW: CREATE TABLE statements, migrations
|       |   +-- repository.rs     # KEEP (test/transitional only, per RULE-03)
|       |   +-- models.rs         # MODIFY: add Product, SerialInstance, NoteEntry aggregates
|       +-- product_catalog.rs    # NEW: product + serial instance logic
|
+-- app/                          # Slint UI + runtime
    +-- src/
        +-- live_client.rs        # MODIFY: write to SQLite; add PendingEditFlusher trigger
        +-- service_client.rs     # MODIFY: update RecipientCardSnapshot
        +-- dashboard/
            +-- actions.rs        # MODIFY: add StartReturn, AssignProduct commands
            +-- edit_queue.rs     # MODIFY: pending edits now target SQLite table
            +-- projection.rs     # MODIFY: project product_refs + notes from snapshot
            +-- view_model.rs     # MODIFY: rm item_summary/latest_note, add product_tiles/notes
            +-- lists.rs          # NEW: Lists feature state and projection
```

### Structure Rationale

- **`core/domain/card.rs` (new):** Card is a first-class domain entity once SQLite introduces a UUID PK for cards. Separating it from Recipient eliminates the shipment-on-recipient debt (RULE-02).
- **`core/domain/product.rs` (new):** Product and SerialInstance are not representable in the current domain. They need new structs before any catalog or serial tracking phases begin.
- **`integrations/github/issues_client.rs` (new):** GH Issues read/write is a distinct capability from GH Project column reads. It should be a separate client so it can be mocked independently in tests.
- **`service/db/sqlite_store.rs` (new):** The production SQLite store implementing the same interface as Repository. Keeping `repository.rs` for tests avoids a large test breakage surface.
- **`service/product_catalog.rs` (new):** Product CRUD and serial lifecycle logic are domain operations that do not belong in the sync pipeline or UI layer.

---

## Architectural Patterns

### Pattern 1: SQLite-as-Single-Read-Source (RULE-03)

**What:** Once SQLite is implemented, all production reads come from SQLite. The sync pipeline writes to SQLite; the UI reads from SQLite. There is no path from integration clients directly to the UI.

**When to use:** Every production data access after SQLite phase is complete.

**Trade-offs:** Requires a write-through sync design. The benefit is that UI reads are always fast (local disk) and offline-safe. The cost is that the sync pipeline must be complete before UI data is fresh.

**Implementation note:** The `DashboardDataClient` trait in `service_client.rs` is the seam. The `LiveClient` already implements this trait. Replace its `fetch_card_snapshots()` to query SQLite rather than the in-memory Repository.

```rust
// live_client.rs (simplified target shape)
impl DashboardDataClient for LiveClient {
    fn fetch_card_snapshots(&self) -> Vec<RecipientCardSnapshot> {
        // reads from SQLite, not Arc<Mutex<Repository>>
        self.sqlite_store.lock().unwrap().load_all_card_snapshots()
    }
}
```

### Pattern 2: Shopify-First Sync Pipeline (RULE-04)

**What:** Cards only exist from Shopify orders tagged "wit-what". The sync pipeline starts by fetching Shopify orders, then looks up GH recipients by customer ID — not the reverse.

**When to use:** Every sync cycle. Never generate a card from a GH-only recipient.

**Trade-offs:** Shopify is required for any card to appear. GH recipients without matching Shopify orders produce no card. This is correct by design.

**Integration point:** `run_sync_cycle()` currently writes to in-memory Repository. With SQLite it must write all layers: recipients table, then cards table (FK dependency), then card_products/notes. Sync order within a cycle is constrained by FK dependencies.

### Pattern 3: GH Issues as Cloud of Record (RULE-05)

**What:** `ww-card` and `ww-product` GH Issues in `BigscreenVR/beyond-outgoing` are the authoritative remote store. SQLite is a local mirror. Writes go to GH Issues first; SQLite reflects GH state after sync.

**When to use:** All card and product mutations (notes, product assignment, serial state transitions).

**Trade-offs:** Writes are asynchronous (write to GH, sync re-fetches, SQLite updated). The UI sees a brief stale state after a mutation until the next sync cycle. Acceptable for this use case.

**Offline implication:** When offline, mutations queue in `pending_edits` table. On reconnect, `PendingEditFlusher` sends them to GH Issues in order, then triggers a sync cycle.

### Pattern 4: PendingEdit Queue with Flush-on-Reconnect

**What:** Any write that requires GH Issues (notes, product assign, serial state) is written to the local `pending_edits` SQLite table when offline. On reconnect, a flusher drains the queue in FIFO order.

**When to use:** All GH Issue write-back operations.

**Trade-offs:** Requires idempotency checking on flush — if an edit was partially applied before disconnect, re-flushing must not create duplicates. GH Issue comment creation is not idempotent by default; a local `status` field (`Pending -> Flushing -> Done/Failed`) prevents re-sending completed edits.

**Existing infrastructure:** `PendingEditQueue` already exists in `edit_queue.rs` as a JSON file. The SQLite migration replaces the file with the `pending_edits` table, preserving the same `PendingEdit` enum variants (plus new ones for product/serial operations).

### Pattern 5: Deprecated Field Removal as a Precondition

**What:** Several fields exist only as migration debt and must be removed before building new features that overlap their scope: `github_profile_url` (RULE-01), `shipment_status`/`tracking_state` on `Recipient` (RULE-02), `item_summary` (RULE-07), `latest_note` (RULE-08), `first_item_image_hint`.

**When to use:** Before any phase that adds `product_refs`, `notes`, or Card-level shipment fields.

**Trade-offs:** Removing them breaks existing tests and consumers. Must be done in a dedicated cleanup phase with coordinated test updates, not scattered across feature phases.

---

## Data Flow

### Sync Cycle Write Path (target)

```
External sources (GH Project + GH Issues + Shopify)
    |
    v  run_sync_cycle() in live_client.rs
    |
    +-- write recipients table (upsert by recipient_key)
    +-- write cards table (upsert by shopify_order_id)
    +-- write card_products table (from ww-card issue body: product_refs)
    +-- write notes table (from ww-card issue comments: Vec<NoteEntry>)
    +-- write products table (from ww-product issues)
    +-- write serial_instances table (from ww-product issue body/comments)
    +-- write sync_audit_log (changed fields, old/new values)
    |
    v  slint::invoke_from_event_loop
    |
UI refresh: fetch_card_snapshots() reads SQLite
```

### UI Edit Write Path (target)

```
User action (note save, product assign, serial state change)
    |
    v  EditDispatcher.dispatch(EditCommand)
    |
    +-- Is online?
    |   YES: write to GH Issue API (ww-card comment or ww-product body update)
    |        write to SQLite (immediate local mirror)
    |   NO:  insert into pending_edits table (status=Pending)
    |        write to SQLite optimistically (for immediate UI update)
    |
    v  on reconnect: PendingEditFlusher
    |   drain pending_edits (Pending -> Flushing)
    |   POST to GH Issues API
    |   mark Done or Failed
    |
    v  sync cycle runs --> refreshes SQLite from canonical GH state
```

### New GH Project Fields Ingestion (Layer 1 additions)

```
GH Project column "Purpose"           --> project_mapping.rs map_rows()
GH Project column "Vision Rx - OD"    --> map_rows()
GH Project column "Vision Rx - OS"    --> map_rows()
GH Project column "discord_username"  --> map_rows()
GH Project column "discord_user_id"   --> map_rows()
GH Project product parallel columns   --> map_rows() --> Vec<ProductRef>
    |
    v  all land on GithubMappedRecipient
    v  written to SQLite recipients table during sync
    v  surfaced in RecipientCardSnapshot via SQLite read
```

### Serial Instance State Transitions

```
SerialInstanceState machine (in product_catalog.rs):
    Created
        | assign_to_card(card_id)
        v
    Assigned
        | shipped (Shopify fulfillment event)
        v
    InTransit
        | delivered (Shopify tracking event)
        v
    Delivered
        | start_return()  -- new EditCommand
        v
    ReturnInTransit
        | returned (Shopify tracking or manual confirmation)
        v
    Returned
        | process_return()  -- marks unit available
        v
    Available  --> ready for next assignment (back to Created lifecycle)
```

Each transition writes to the `serial_instances` SQLite table and queues a `pending_edit` for GH Issue update.

---

## Integration Points

### New Components and Where They Plug In

| New Component | Plugs Into | Interface |
|---------------|-----------|-----------|
| `SqliteStore` | Replaces `Arc<Mutex<Repository>>` in `LiveClient` | Same `DashboardDataClient` trait surface; extend with product/serial queries |
| `GhIssuesClient` | Called in `run_sync_cycle()` alongside existing `GhCliProjectClient` | New `GhIssuesClient` trait in `integrations/github/` |
| `ProductCatalog` | Called from `run_sync_cycle()` (sync writes) and `EditDispatcher` (user writes) | `ProductCatalogStore` trait operating on `SqliteStore` |
| `PendingEditFlusher` | Called in `LiveClient` background loop when reconnect detected | Receives `GhIssuesClient` ref; reads/writes `pending_edits` in `SqliteStore` |
| `ListsState` | Added to `DashboardRuntime` alongside `DiscoveryState` | `ListsState` struct tracking active list, membership changes |
| New `EditCommand` variants | `EditDispatcher` match arm additions | `StartReturn { card_id }`, `AssignProduct { card_id, product_id, serial_id? }`, `CreateNote { card_id, content }` |

### Modified Components (existing, not new)

| Component | What Changes | Why |
|-----------|-------------|-----|
| `LiveClient` | Replace `Arc<Mutex<Repository>>` with `SqliteStore`; add `PendingEditFlusher` trigger on reconnect | SQLite migration (RULE-03) |
| `run_sync_cycle()` | Add: GH Issues fetch (ww-card, ww-product), SQLite writes for all new tables | GH Issues cloud storage, product catalog |
| `RecipientCardSnapshot` | Remove: `github_profile_url`, `item_summary`, `latest_note`, `first_item_image_hint`. Add: `product_refs: Vec<ProductRef>`, `notes: Vec<NoteEntry>`, `purpose`, `vision_rx_od/os` | Deprecated field cleanup + new fields |
| `DashboardCardViewModel` | Remove same deprecated fields. Add: `product_tiles: Vec<ProductTile>`, `note_preview` (from `notes[0]`), `purpose_ring_color`, `vision_rx` | Downstream of RecipientCardSnapshot changes |
| `project_mapping.rs` | Add `Purpose`, `Vision Rx OD/OS`, `discord_username/id`, product parallel-array columns | New GH Project columns |
| `DashboardRuntime` | Remove JSON file-backed `archive_store`/`pending_edits`; both migrate to SQLite tables | SQLite migration |
| `Recipient` domain model | Remove `github_profile_url`, `shipment_status`, `tracking_state`, `shopify_order_id`, `email` | Deprecated field cleanup (RULES 01, 02) |

### External Service Integration Points

| Service | New Capability | Integration Module |
|---------|---------------|-------------------|
| GitHub Issues API | Read ww-card/ww-product issues; write comments; create/update issue bodies | `integrations/github/issues_client.rs` (NEW) |
| GitHub Project API | Add 5+ new column reads (Purpose, Vision Rx, Discord fields, product arrays) | `integrations/github/project_mapping.rs` (MODIFY) |
| Shopify Admin API | Start Return (if in v1.1 scope) | `integrations/shopify/` (scope TBD per DATA-FLOW.md) |

---

## Suggested Build Order

Features have strict dependency ordering. The following sequence minimizes rework and avoids building on a foundation that changes underneath later phases.

### Phase 1: Foundation — SQLite + Deprecated Field Removal

Must come first. All downstream feature phases read from/write to SQLite. Removing deprecated fields before adding new ones avoids double-migration.

1. Implement `SqliteStore` with schema for existing entities (recipients, cards, archive_records, pending_edits)
2. Migrate `run_sync_cycle()` writes to SQLite
3. Migrate `fetch_card_snapshots()` reads to SQLite (RULE-03 compliance)
4. Migrate `archive_store.json` and `pending_edits.json` to SQLite tables
5. Remove deprecated fields from `Recipient`, `RecipientCardSnapshot`, `DashboardCardViewModel`

Dependency: Nothing depends on this yet; it unblocks everything else.

### Phase 2: New GH Project Columns + Recipient Fields

Depends on: Phase 1 SQLite schema (recipients table must exist with new columns).

1. Add `Purpose`, `Vision Rx OD/OS`, `discord_username`, `discord_user_id` to `project_mapping.rs`
2. Extend SQLite `recipients` table schema with new columns
3. Propagate to `RecipientCardSnapshot` and `DashboardCardViewModel`
4. Add product parallel-array columns to `project_mapping.rs` (produces `Vec<ProductRef>` stub for Phase 3)

Dependency: Phase 1 SQLite exists. Phase 3 products table must exist before product refs resolve to real product IDs.

### Phase 3: GH Issues Client + Product Catalog (Layer 3)

Depends on: Phase 1 SQLite (products table), Phase 2 (product names from GH Project).

1. Implement `GhIssuesClient` for ww-product and ww-card reads
2. Add `products` and `card_products` tables to SQLite schema
3. Implement `ProductCatalog` (CRUD, no serial tracking yet)
4. Wire `run_sync_cycle()` to fetch ww-product issues and populate SQLite products table
5. Resolve product parallel-array refs from Phase 2 against products table

`GhIssuesClient` is required by both product catalog (Phase 3) and GH card cloud storage (Phase 4). Build the client once here.

### Phase 4: GH Issues Write-Back + Notes (Layer 2 cloud, RULE-05)

Depends on: Phase 3 (`GhIssuesClient` exists), Phase 1 (pending_edits in SQLite).

1. Add `notes` table to SQLite schema
2. Implement ww-card issue creation/update via `GhIssuesClient`
3. Sync ww-card issue comments to `notes` table
4. Replace `latest_note` scalar with `notes: Vec<NoteEntry>` in snapshot/viewmodel
5. Implement `PendingEditFlusher` — flushes queued notes to GH Issues on reconnect

Dependency: `pending_edits` SQLite table (Phase 1). `GhIssuesClient` (Phase 3).

### Phase 5: Serial Instance Tracking (Layer 4)

Depends on: Phase 3 (products table, ProductCatalog), Phase 4 (GH Issues write-back pattern established).

1. Add `serial_instances` table to SQLite schema
2. Implement `SerialInstanceState` machine in `product_catalog.rs`
3. Sync serial instances from ww-product GH Issue (body block or comments — resolves OQ-01)
4. Add `AssignProduct` and `StartReturn` `EditCommand` variants
5. Wire serial state transitions to GH Issue updates via `PendingEditFlusher`

### Phase 6: Offline Mode Hardening

Depends on: Phase 1 (pending_edits table), Phase 4 (PendingEditFlusher exists).

1. Reconnect detection in `LiveClient` background loop
2. Full flush-and-sync sequence on reconnect
3. UI indicator for offline state
4. `Failed` edit retry / discard UX

### Phase 7: Lists Feature

Depends on: Phase 1 (SQLite exists), Phase 3 (product catalog for product-based list views).

1. `lists` table in SQLite (list name, card memberships)
2. `ListsState` added to `DashboardRuntime`
3. Lists viewing mode in `DiscoveryState`
4. Card management (add/remove from list) as new `EditCommand` variants

---

## Anti-Patterns

### Anti-Pattern 1: Reading from in-memory Repository in production after SQLite exists

**What people do:** After SQLite is implemented, keep reading from `Arc<Mutex<Repository>>` for convenience or because a code path was missed.

**Why it's wrong:** Violates RULE-03. Repository is no longer the single read source. Data diverges between SQLite and the in-memory store, causing stale reads and hard-to-reproduce bugs.

**Do this instead:** After SQLite phase completes, remove all production reads from Repository. Repository is test-only.

### Anti-Pattern 2: Adding new fields to Recipient domain model

**What people do:** New data (shipment info, email) added to `Recipient` because it's easy to find.

**Why it's wrong:** Recipients are people. RULE-02 prohibits shipment fields on Recipient. Email lives on Shopify orders (card-level). Adding fields here perpetuates the data-model confusion that required RULES 01 and 02.

**Do this instead:** If data is card-level, add it to `RecipientCardSnapshot` and the `cards` SQLite table. If it's a new GH Project column, document it in DATA-FLOW.md first (RULE-06).

### Anti-Pattern 3: Building product catalog before SQLite exists

**What people do:** Implement `ww-product` GH Issues parsing and store results in in-memory Repository since SQLite is not done yet.

**Why it's wrong:** SQLite schema must include `products` and `serial_instances` tables for FK enforcement (`card_products.product_id` references `products.id`). Building products in-memory first means a double implementation with a risky schema migration later.

**Do this instead:** Complete Phase 1 (SQLite foundation) before Phase 3 (products). The schema is the contract.

### Anti-Pattern 4: Skipping DATA-FLOW.md before adding new fields

**What people do:** Add a field directly to a struct because it seems obvious, without documenting the source.

**Why it's wrong:** RULE-06 is binding. Undocumented fields become RULE-01/07/08-style debt within a few iterations. DATA-FLOW.md is the contract that prevents ghost columns.

**Do this instead:** Name the source (GH Project column name, Shopify API field, GH Issue body field) in DATA-FLOW.md before writing code.

### Anti-Pattern 5: Writing to GH Issues synchronously on the UI thread

**What people do:** When a user saves a note, call GH Issues API immediately in the Slint callback.

**Why it's wrong:** GH API calls are slow (100-300ms+) and can fail. Blocking the Slint UI thread causes visible freezes. Failures have no retry path.

**Do this instead:** UI thread writes to `pending_edits` SQLite table immediately (fast), triggers background flush, shows optimistic local state. Background thread handles the GH API call and reports result via `slint::invoke_from_event_loop`.

---

## Scaling Considerations

This is a single-user Windows desktop app. Scaling in the traditional sense does not apply. The relevant operational concerns are:

| Concern | Mitigation |
|---------|-----------|
| SQLite write contention (UI thread + background sync thread both writing) | Use `Arc<Mutex<rusqlite::Connection>>` or a single-writer channel pattern. SQLite WAL mode enables concurrent reads during sync writes. |
| GH API rate limits (sync cycle + pending edits flush both calling GH) | Throttle flush to stay under 60 req/min. Sync cycle already runs every 5 min. Risk is low for typical use. |
| GH Issue body size (serial instances stored in issue body) | For typical use (10-50 serials per product), issue body stays well under GH's 65535 char limit. OQ-01 resolution (body block vs comments) affects this. |

---

## Open Questions (from DATA-FLOW.md — do not resolve without explicit direction)

| Question | Impact | Ref |
|----------|--------|-----|
| Serial instance storage in GH Issue: body block vs structured comments | Affects `GhIssuesClient` read/write design and SQLite sync logic | OQ-01 |
| GH Issue body encoding format: JSON front-matter, YAML, or custom delimiter | Affects `GhIssuesClient` parser and `ww-card`/`ww-product` writer | OQ-03 |
| `recipient_key` vs `recipient_id` naming consolidation once UUID PK exists | Affects all FK references across SQLite schema and struct fields | OQ-02 |

---

## Sources

- `.planning/DATA-FLOW.md` — authoritative architecture reference (HIGH confidence; prescriptive, not aspirational)
- `crates/app/src/live_client.rs` — sync pipeline implementation; background thread structure
- `crates/app/src/service_client.rs` — `DashboardDataClient` trait; `RecipientCardSnapshot` shape
- `crates/app/src/dashboard/` — `DashboardRuntime`, `EditDispatcher`, `PendingEditQueue`, `ArchiveStore`
- `crates/service/src/db/repository.rs` — in-memory Repository (replacement target)
- `Cargo.toml` — workspace structure confirming four crates: core, integrations, service, app

---
*Architecture research for: WITwhat v1.1 — Rust/Slint desktop app data architecture integration*
*Researched: 2026-03-22*
