---
phase: 09-item-note-crud-wiring
plan: 06
subsystem: ui
tags: [slint, rust, item-squares, per-item-removal, data-model]

# Dependency graph
requires:
  - phase: 09-item-note-crud-wiring
    provides: item_summary pipe-separated string, apply_optimistic_item_remove, on_lookup_item_selected, on_lookup_create_confirmed
provides:
  - ItemSquareData struct in dashboard.slint with item-id, display-name, initials, bg-color-index, has-image, image-url
  - item-squares field ([ItemSquareData]) on CardData for per-item UI rendering
  - card-remove-single-item(int, string) callback on DashboardWindow
  - rebuild_item_squares() Rust helper syncing item_squares from item_summary on all mutation paths
  - item_square_color_index() deterministic palette index 0-7 from name hash
  - on_card_remove_single_item wired callback for per-item removal with EditCommand dispatch
  - Seed cards initialize item_squares on startup
affects: [09-07-item-squares-ui, plan-07-card-ui-redesign]

# Tech tracking
tech-stack:
  added: []
  patterns:
    - rebuild_item_squares called at every item mutation point (item-selected, create-confirmed, optimistic-remove, per-item-remove, seed-init)
    - Deterministic color from name hash avoids storing palette index in persistence layer
    - item-id uses display-name as fallback since no separate item UUID in pipe-separated format

key-files:
  created: []
  modified:
    - crates/app/ui/dashboard.slint
    - crates/app/src/main.rs

key-decisions:
  - "item-id uses display-name as the identifier since pipe-separated item_summary has no separate UUID field; per-item removal filters by trimmed name match"
  - "Last item in pipe list receives image_hint (has-image=true, image-url set); earlier items get no image"
  - "item_squares initialized with slint::ModelRc::default() in seed_cards() and overwritten immediately after all_cards_ref creation via rebuild_item_squares loop"

patterns-established:
  - "rebuild_item_squares: called after every item_summary mutation to keep item_squares in sync"
  - "item_square_color_index: deterministic 0-7 index from byte-sum hash of item name for palette coloring"

requirements-completed: [ITEM-01]

# Metrics
duration: 8min
completed: 2026-03-20
---

# Phase 09 Plan 06: Per-Item Data Model Summary

**ItemSquareData struct and rebuild_item_squares helper added to CardData, enabling per-item removal and UI squares with deterministic palette coloring**

## Performance

- **Duration:** ~8 min
- **Started:** 2026-03-20T12:07:00Z
- **Completed:** 2026-03-20T12:10:36Z
- **Tasks:** 2
- **Files modified:** 2

## Accomplishments
- Defined `ItemSquareData` struct in `dashboard.slint` with all fields needed for item square rendering (item-id, display-name, initials, bg-color-index, has-image, image-url)
- Added `item-squares: [ItemSquareData]` field to `CardData` struct — parallel to `item_summary` for UI rendering
- Implemented `rebuild_item_squares()` Rust helper that parses pipe-separated `item_summary` into typed array entries, assigning the last item any available `image_hint`
- Implemented `item_square_color_index()` for deterministic 0-7 palette index from name byte-sum hash
- Wired `on_card_remove_single_item` callback: removes single item by display-name match from pipe string, rebuilds squares, dispatches `EditCommand::RemoveItem`
- Called `rebuild_item_squares` at all five mutation points: `apply_optimistic_item_remove`, `on_lookup_item_selected`, `on_lookup_create_confirmed` (both paths), and seed initialization

## Task Commits

Each task was committed atomically:

1. **Task 1: Add ItemSquareData struct and item-squares field to CardData** - `50c2191` (feat)
2. **Task 2: Implement rebuild_item_squares helper and per-item removal in Rust** - `b1d9049` (feat)

## Files Created/Modified
- `crates/app/ui/dashboard.slint` - Added `ItemSquareData` struct before `CardData`; added `item-squares` field to `CardData`; added `card-remove-single-item(int, string)` callback to `DashboardWindow`
- `crates/app/src/main.rs` - Added `item_square_color_index()` and `rebuild_item_squares()` helpers; added `item_squares: slint::ModelRc::default()` to all seed card constructors; called `rebuild_item_squares` at all item mutation sites; wired `on_card_remove_single_item` callback block; added post-seed initialization loop

## Decisions Made
- `item-id` uses `display-name` as identifier since the pipe-separated `item_summary` format carries no separate UUID per item; per-item removal filters by trimmed name match
- Last item in pipe list receives the `image_hint` URL; earlier items get `has-image: false` and empty `image-url`
- Seed `item_squares` initialized to `slint::ModelRc::default()` in `seed_cards()` and immediately rebuilt after `all_cards_ref` is created, ensuring correct state before any callback is wired

## Deviations from Plan

### Auto-fixed Issues

**1. [Rule 1 - Bug] Added item_squares field to seed_cards() constructors**
- **Found during:** Task 1 (Slint struct change immediately broke compilation)
- **Issue:** Adding `item-squares` to `CardData` in Slint caused three `E0063: missing field item_squares` errors in the Rust seed card constructors
- **Fix:** Added `item_squares: slint::ModelRc::default()` to all three `CardData` literals in `seed_cards()`; the post-init loop then calls `rebuild_item_squares` to populate them correctly
- **Files modified:** `crates/app/src/main.rs`
- **Verification:** `cargo build -p app` compiled cleanly after fix
- **Committed in:** `50c2191` (Task 1 commit)

---

**Total deviations:** 1 auto-fixed (Rule 1 - struct field required by Rust exhaustive field matching)
**Impact on plan:** Required fix, no scope creep.

## Issues Encountered
None beyond the auto-fixed compilation error above.

## Next Phase Readiness
- Data layer for item squares is complete; Plan 07 can now render `item-squares` in the card UI redesign
- `card-remove-single-item(int, string)` callback is wired and ready for the card component to call
- `bg-color-index` (0-7 integer) is available for Slint conditional color expressions in the item square tiles

## Self-Check: PASSED

All files confirmed present and both task commits verified in git history.

---
*Phase: 09-item-note-crud-wiring*
*Completed: 2026-03-20*
