---
phase: 16.2-bugsweeper
plan: 02
subsystem: testing
tags: [rust, slint, serde, json, http, bugsweeper, debugging]

# Dependency graph
requires:
  - phase: 16.2-01
    provides: BugsweeperBackend trait, query_ui/mutate_ui bridge, router with stub endpoints
provides:
  - CardDataJson and ItemSquareJson serializable mirror structs for Slint types
  - get_cards endpoint: full Slint card model as JSON array
  - get_property endpoint: reads 16 named DashboardWindow properties
  - set_property endpoint: writes 8 writable in-out properties with type validation
  - invoke_callback endpoint: dispatches all 31 DashboardWindow callbacks with argument parsing
  - card_data_to_card_json conversion helper in bugsweeper_impl
  - router PUT/POST body parsing via read_to_string
affects: [16.2-03, any phase that uses bugsweeper HTTP endpoints for UAT]

# Tech tracking
tech-stack:
  added: []
  patterns:
    - "query_ui closure pattern: capture window_weak.clone() before move into closure, upgrade inside, return Result<Value, String>"
    - "CardDataJson mirror struct pattern: bugsweeper crate owns JSON types, app crate owns conversion (since Slint types only visible in app)"
    - "router body parsing: read_json_body reads via as_reader().read_to_string(), accepts bare JSON or {value: ...} wrapper for PUT"

key-files:
  created:
    - crates/bugsweeper/src/card_json.rs
  modified:
    - crates/bugsweeper/src/lib.rs
    - crates/bugsweeper/src/router.rs
    - crates/bugsweeper/src/server.rs
    - crates/app/src/main.rs

key-decisions:
  - "ItemSquareJson mirrors full ItemSquareData (item_id, display_name, initials, bg_color_index, has_image, image_url) — not the condensed 3-field version in the plan, since actual Slint struct has 6 fields"
  - "router PUT handler accepts both bare JSON value and {value: ...} wrapper for ergonomic curl usage"
  - "avatar_image omitted from CardDataJson — Slint Image is an opaque handle with no serializable representation"
  - "purpose_color serialized as hex string (#rrggbb) via Color.red()/.green()/.blue() in app crate conversion"

patterns-established:
  - "Slint model iteration: (0..model.row_count()).filter_map(|i| model.row_data(i)).map(...).collect()"
  - "query_ui double-Result flattening: closure returns Result<Value, String>, query_ui returns Result<Result<...>, String> — flatten with ? on outer"

requirements-completed: []

# Metrics
duration: 25min
completed: 2026-03-24
---

# Phase 16.2 Plan 02: UI Endpoint Implementation Summary

**CardDataJson serialization layer and full /api/ui/* endpoint implementations that let agents dump the Slint card model as JSON, read/write 16 properties, and invoke all 31 DashboardWindow callbacks**

## Performance

- **Duration:** 25 min
- **Started:** 2026-03-24T11:00:00Z
- **Completed:** 2026-03-24T11:25:00Z
- **Tasks:** 2
- **Files modified:** 5

## Accomplishments
- Created `CardDataJson` and `ItemSquareJson` mirror structs in bugsweeper crate with `serde::Serialize` — decouples serialization from Slint's non-serializable types
- Implemented `get_cards` that iterates the full Slint `ModelRc<CardData>` via `query_ui` and returns a JSON array
- Implemented `get_property` with 16 named match arms covering all readable DashboardWindow properties plus virtual `card-count`
- Implemented `set_property` with 8 writable in-out properties and type validation (string/bool/int)
- Implemented `invoke_callback` dispatching all 31 DashboardWindow callbacks with argument parsing
- Fixed router.rs PUT/POST handlers to parse request body using `read_to_string`

## Task Commits

Each task was committed atomically:

1. **Task 1: CardDataJson serialization module** - `d644c06` (feat)
2. **Task 2: get_cards, get_property, set_property, invoke_callback + router body parsing** - `824a1ce` (feat)

**Plan metadata:** (docs commit follows)

## Files Created/Modified
- `crates/bugsweeper/src/card_json.rs` - CardDataJson and ItemSquareJson structs with serde::Serialize
- `crates/bugsweeper/src/lib.rs` - Added `pub mod card_json`
- `crates/bugsweeper/src/router.rs` - Added read_json_body helper; fixed PUT/POST to parse body; route_request takes &mut Request
- `crates/bugsweeper/src/server.rs` - Pass `mut request` to route_request (already fixed by Plan 03 as Rule 1 deviation)
- `crates/app/src/main.rs` - card_data_to_card_json helper + full implementations of get_cards, get_property, set_property, invoke_callback

## Decisions Made
- `ItemSquareJson` was defined with all 6 fields from the actual `ItemSquareData` Slint struct (`item_id`, `display_name`, `initials`, `bg_color_index`, `has_image`, `image_url`), not the 3-field condensed version in the plan — actual struct has more fields so the full set was preserved
- PUT handler accepts both `{"value": X}` wrapper and bare JSON value for curl ergonomics
- `avatar_image` omitted from CardDataJson as specified — Slint Image is opaque

## Deviations from Plan

### Auto-fixed Issues

**1. [Rule 3 - Blocking] Fixed router PUT/POST to parse request body**
- **Found during:** Task 2 (implementing set_property/invoke_callback)
- **Issue:** router.rs PUT handler used a hardcoded stub value; POST handler passed empty name and args — both endpoints would never work regardless of backend implementation
- **Fix:** Added `read_json_body(request: &mut Request)` helper using `as_reader().read_to_string()`; updated PUT to accept `{"value": X}` or bare value; updated POST to parse `{"name": "...", "args": [...]}` body; changed `route_request` signature to `&mut Request`; updated server.rs to pass `mut request`
- **Files modified:** crates/bugsweeper/src/router.rs, crates/bugsweeper/src/server.rs
- **Verification:** cargo build --features bugsweeper exits 0
- **Committed in:** `824a1ce` (Task 2 commit)

**Note on execution order:** Plan 03 was executed before Plan 02 in this session. Plan 03's commits (`b9de866`, `694af3f`) appeared in history before Plan 02 commits. The Rule 1 fix for `server.rs` (route_request &mut) was independently applied by both Plan 03 and Plan 02 — Plan 03's commit captured it first. All required behavior is in the correct final state.

---

**Total deviations:** 1 auto-fixed (1 blocking)
**Impact on plan:** Essential fix — PUT and POST endpoints would silently pass wrong data to backend without body parsing. No scope creep.

## Issues Encountered
- Plan 03 had been executed before Plan 02, meaning some files (server.rs, main.rs app_config field) were already modified. Plan 02's edits were layered on top correctly with no conflicts.

## User Setup Required
None - no external service configuration required.

## Next Phase Readiness
- All /api/ui/* endpoints are now functional
- Agents can use curl to dump card state, read/write properties, and fire callbacks
- Plan 03 (data/state endpoints) was already implemented — the full bugsweeper server is ready for UAT

---
*Phase: 16.2-bugsweeper*
*Completed: 2026-03-24*
