Skip to content
sysout.dev

Feature Spec: The Digital Twin (Doc 06)

Product and implementation specification for Homey's flexible location hierarchy, items, optional grids, and inventory workflows.

Version 2.0 Update: This spec has been updated to reflect the implemented Location/Item + Optional Grid architecture, which replaces the original rigid Zone→Unit→Cell (2x2) design. The new approach provides more flexibility for real-world home organization.

Version 2.1 Update: Added domain extensibility notes. While MVP 1.0 focuses on Kitchen/Grocery items, the Location and Item architecture supports multiple domains (Wardrobe, Toolbox, etc.) in future phases.

Domain Extensibility

The Digital Twin architecture is domain-agnostic:

  • Locations can represent any physical space (Kitchen, Bedroom, Garage)

  • Items use a sealed class hierarchy supporting domain-specific extensions:

    • GroceryItem (MVP 1.0) - expiry dates, categories, quantities

    • ClothingItem (Future) - size, color, material

    • ToolItem (Future) - brand, condition

Locations are not restricted to a single domain. A "Garage" location can contain both ToolItem (tools) and GroceryItem (overflow pantry storage).

1. User Goal

To provide a spatial and categorical view of household items, allowing users to: * Quickly locate items using search or filters * Optionally map items spatially using flexible grid layouts * Group items by category regardless of physical location * Track expiry dates and consumption patterns

2. Architecture Overview

Flexible Hierarchy (Updated Design)

Concept: Locations form a flexible tree structure with optional spatial organization.

Structure: * Location (e.g., Kitchen → Pantry → Top Shelf) - Hierarchical: Can have parent and children - Flexible depth: As many levels as needed - Optional grid: Each location can enable grid view independently

  • Items (e.g., Organic Walnuts, Blue Rice Container)

    • Belong to one location

    • May have grid position (row, column) or be unassigned

    • Categorized for list view grouping

Key Change from v1.0: * ❌ Removed rigid Zone→Unit→Cell (2x2) structure * ✅ Added flexible Location hierarchy with optional variable grids (2x2 to 6x6)

Rationale for Change

Real homes don’t fit rigid structures: * Shelves vary in size (some 2x3, some 4x2) * Not every location needs a grid (drawers, baskets) * Users need both spatial AND categorical views * Hierarchy depth varies by household

3. Data Model (Implemented)

Location Entity

Location {
  id: UUID
  name: String
  parentId: UUID? (null for root locations)
  gridConfig: GridConfig? (null if grid disabled)
  createdAt: Date
}

GridConfig {
  rows: Int (2-6)
  columns: Int (2-6)
  enabled: Boolean
}

Examples: * Kitchen (parent=null, grid=null) → Pantry (parent=Kitchen, grid={3x3, enabled}) → Top Shelf (parent=Pantry, grid={2x4, enabled}) → Fridge (parent=Kitchen, grid={4x3, enabled}) * Garage (parent=null, grid=null) → Tool Rack (parent=Garage, grid={2x5, enabled})

Item Entity

Item {
  id: UUID
  name: String
  locationId: UUID
  gridPosition: GridPosition? (null if unassigned)
  sortOrder: Int
  photoUri: String?
  createdAt: Date
}

GridPosition {
  row: Int
  column: Int
}

GroceryItem extends Item {
  brand: String?
  category: ItemCategory
  expiryDate: Date?
}

ItemCategory enum {
  DAIRY, PRODUCE, MEAT, FROZEN,
  BEVERAGES, SNACKS, PANTRY, GENERAL
}

Key Properties: * Nullable gridPosition → Items exist without spatial assignment * Hierarchy lives in Location, not Item * GroceryItem extends Item (joined-table inheritance)

4. User Interface & Workflows

4.1 Location Navigation (Accordion View)

Screen: LocationScreen

Visual: Vertical scrollable list with expandable location headers.

Interaction: 1. User sees root locations collapsed: [ > Kitchen ] [ > Garage ] 2. Tapping "Kitchen" expands to show children: Pantry, Fridge, Freezer 3. Tapping "Pantry" navigates to ItemScreen for that location

Features: * Grid badge indicator: Shows 📊 icon if location has grid enabled * Smooth expand/collapse animations * Persistent expansion state (preserved across app restarts) * FAB (+) button to add new locations

4.2 Item View (Dual-Mode Display)

Screen: ItemScreen

Two View Modes:

A. Grid View (When grid enabled)

Trigger: Location has grid configuration enabled

Visual: NxM grid based on location’s grid config (e.g., 3x3, 4x4)

Interaction: * Empty cells show "+" icon (tap to quick-assign) * Filled cells show item count badge if multiple items * Tapping cell opens item list for that position * Tapping specific item shows item details

Layout:

+-------+-------+-------+
|   🥛  |  ☕×3 |   +   |  Row 1
+-------+-------+-------+
|  🍞   |   +   | 🧀×2  |  Row 2
+-------+-------+-------+
|   +   |  🥜   |   +   |  Row 3
+-------+-------+-------+
  Col 1   Col 2   Col 3

B. List View (Default or when grid disabled)

Visual: Category-grouped list with section headers

Grouping: Items grouped by ItemCategory * Section header shows category icon + name * Items within category sorted by expiry date (urgent first) * Empty categories hidden

Layout:

📦 DAIRY (3 items)
  🥛 Milk - Expires in 2 days
  🧀 Cheddar Cheese - Jan 20
  🧈 Butter - Jan 25

🥬 PRODUCE (1 item)
  🥕 Carrots - Expires today

☕ BEVERAGES (2 items)
  ...

4.3 View Mode Toggle

Location: Top app bar (right side)

Behavior: * Only visible when location has grid enabled * Icon: 📋 (List) or 📊 (Grid) * Tapping toggles between Grid and List view * View preference saved per-location

4.4 Search & Filter

Location: Below top app bar

Components: 1. Search Field: Text input with clear button 2. Category Chips: Horizontal scrollable row - All categories shown as chips - Tappable to filter by category - Multi-select supported

Behavior: * Search filters by item name (real-time) * Category filters are additive (OR logic) * Filters apply to both Grid and List views * In Grid view, filtered items remain in their grid positions (non-matching cells fade)

4.5 Unassigned Items Bar

Location: Bottom of screen (always visible if items exist)

Purpose: Surface items without grid positions

Visual: * Floating card with secondary color * Horizontal scrollable chip list * Badge shows total count

Interaction: * Tap item chip → Quick assign dialog (select grid cell) * Long-press chip → Starts drag-to-assign mode (future)

Layout:

┌─────────────────────────────────────┐
│ Unassigned Items                 [3]│
│ ┌─────┐ ┌────────┐ ┌──────┐        │
│ │Flour│ │Walnuts │ │Coffee│  ···   │
│ └─────┘ └────────┘ └──────┘        │
└─────────────────────────────────────┘

4.6 Grid Configuration

Access: Settings icon in ItemScreen top bar

Dialog Fields: 1. Enable Grid Layout (toggle switch) 2. Rows (slider: 2-6, only if enabled) 3. Columns (slider: 2-6, only if enabled) 4. Preview (live grid preview showing selected dimensions)

Behavior: * Turning off grid → Items keep gridPosition (not deleted) * View switches to List mode automatically * Turning on grid → Items with positions appear in grid * Changing dimensions → Items outside new bounds become unassigned

5. Logic Rules & Edge Cases

Scenario Behavior

Adding new item

Appears in Unassigned Items Bar (gridPosition = null)

Assigning to grid cell

Quick assign dialog shows grid, tap cell to assign

Cell with multiple items

Grid cell shows item count badge (e.g., "×3")

Moving item

Long-press item → Select new cell from grid overlay

Deleting location

All child locations and items CASCADE delete (user warned)

Grid disabled

Items retain gridPosition but view shows List mode only

Search while in Grid

Grid cells fade if no matching items in that position

Empty location

Shows empty state with "Add Item" CTA

Expiry warnings

Item cards show red background if expiring within 7 days

6. Component Architecture (Implemented)

Reusable UI Components

All components built with Jetpack Compose + Material 3:

  1. LocationAccordion (location/components/LocationAccordion.kt)

    • Recursive expandable location hierarchy

    • Grid badge indicator

    • Animated expand/collapse

  2. FlexibleGrid (location/components/FlexibleGrid.kt)

    • Dynamic rows × columns layout

    • Empty cell "+" indicators

    • Multi-item cell support

    • Cell and item click handlers

  3. ItemCard (item/components/ItemCard.kt)

    • Compact mode (grid cells)

    • Expanded mode (list view)

    • Expiry warning colors

    • Brand, category, position display

  4. CategoryGroupList (item/components/CategoryGroupList.kt)

    • Category section headers

    • Sorted by expiry within category

    • Lazy loading for performance

  5. UnassignedItemsBar (item/components/UnassignedItemsBar.kt)

    • Horizontal scrollable chips

    • Item count badge

    • Tap/long-press handlers

  6. ItemSearchBar (item/components/ItemSearchBar.kt)

    • Text search with clear button

    • Category filter chips

    • Multi-select support

Screen Integration

  • LocationScreen → Uses LocationAccordion

  • ItemScreen → Orchestrates all components:

    • ItemSearchBar (top)

    • FlexibleGrid OR CategoryGroupList (center, based on mode)

    • UnassignedItemsBar (bottom)

    • Grid configuration dialog

7. Future Enhancements

7.1 Drag-and-Drop Assignment

  • Long-press unassigned item chip

  • Drag over grid cells

  • Drop to assign position

  • Visual feedback during drag

7.2 3D Shelf View

  • Support for multiple shelf levels within same unit

  • Swipe gesture to "flip" between shelves

  • Maintains same grid dimensions across shelves

7.3 Bulk Operations

  • Multi-select mode (long-press to activate)

  • Batch move items

  • Batch delete

  • Bulk category assignment

7.4 Templates

  • Save grid configurations as templates

  • Apply template to new locations

  • Common templates: "Fridge 3x4", "Pantry 5x3"

7.5 Photo Grid View

  • Camera-captured photos of physical spaces

  • Overlay grid on photo

  • Tap grid cells to see what’s stored

  • Requires photo storage and processing

8. Technical Considerations

Performance

  • Large item counts: Use LazyColumn/LazyRow for virtualization

  • Grid rendering: Compose efficiently handles up to 6×6 (36 cells)

  • Search filtering: Debounced search (300ms) to reduce recompositions

  • Image loading: Coil library for efficient photo loading (future)

Database Queries

  • Spatial queries: Indexed on (locationId, gridRow, gridColumn)

  • Unassigned items: WHERE gridRow IS NULL AND gridColumn IS NULL

  • Items at position: WHERE locationId=? AND gridRow=? AND gridColumn=?

  • Category grouping: In-memory groupBy after Room query

State Management

  • ViewModel StateFlows: Reactive updates on data changes

  • Room Flow queries: Automatic UI refresh on DB changes

  • Compose remember: Grid expansion, view mode persisted

  • Hilt DI: ViewModel injection in Composables

9. Migration from v1.0 Spec

For teams referencing the original spec:

Old Concept New Concept Notes

Zone

Location (root)

Top-level locations (Kitchen, Garage)

Unit

Location (child)

Nested locations (Pantry, Fridge)

Cell (2x2 fixed)

GridPosition (flexible)

Variable grid sizes, optional

Rigid hierarchy

Flexible tree

Any depth, any branching

Always spatial

Dual-mode view

Grid OR List based on preference

N/A

Unassigned items

Items without grid position

N/A

Category grouping

List view groups by ItemCategory

10. Spec Status

Database schema: Implemented (Room v2) ✅ Domain models: Implemented (Location, Item, GroceryItem) ✅ UI components: Implemented (6 components) ✅ Screens: Implemented (LocationScreen, ItemScreen) ⬜ Item details dialog: TODO ⬜ Drag-and-drop: TODO ⬜ Quick assign dialog: TODO ⬜ Location editing: TODO


Last updated: 2026-01-14 Implemented by: Development Team Original concept: Project Lead Architecture update: Development Team (Jan 2026)