← Back to Main Documentation Core Systems Index

Set Object Scanning Workflows

This document defines the scanning workflows for managing Set Objects through component scanning, addressing the fundamental constraint that sets cannot have physical identifiers.

Core Constraint: No Direct Set Scanning

Set objects cannot have PlingsIdentifiers because they are logical groupings, not physical objects. Only individual components can have QR codes, NFC tags, or other physical identifiers.

Implication: All set operations must be accessed through component scanning workflows.

Scanning Workflow Patterns

1. Component Scan Detection

When a component with a PlingsIdentifier is scanned:

// Component scan detection
MATCH (identifier:PlingsIdentifier {key: $scannedKey})-[:IDENTIFIES]->(component:ObjectInstance)
OPTIONAL MATCH (component)-[:PART_OF]->(setObject:ObjectInstance)
RETURN {
  component: component,
  parentSet: setObject,
  hasSet: setObject IS NOT NULL,
  availableActions: CASE
    WHEN setObject IS NOT NULL THEN ["WORK_WITH_COMPONENT", "WORK_WITH_SET"]
    ELSE ["WORK_WITH_COMPONENT"]
  END
}

2. User Choice Prompt

If component is part of a set:

┌─────────────────────────────────────────────┐
│ Scanned: Left Ski Glove                    │
│ Part of: My Ski Gloves                     │
│                                             │
│ Choose operation scope:                     │
│ ○ Work with Left Ski Glove only           │
│ ● Work with entire My Ski Gloves set      │
│                                             │
│ [Continue]  [Cancel]                       │
└─────────────────────────────────────────────┘

If component is not part of a set:

┌─────────────────────────────────────────────┐
│ Scanned: Standalone Wrench                 │
│                                             │
│ Proceeding with individual object...        │
└─────────────────────────────────────────────┘

3. Operation Execution

3a. Component-Only Operations

Move Component Only:

// Update only the scanned component
MATCH (component:ObjectInstance {id: $componentId})
MATCH (newLocation:ObjectInstance {id: $newLocationId})

// Remove old spatial relationship
OPTIONAL MATCH (component)-[old:CURRENT_IN|CURRENT_ON|CURRENT_ATTACHED_TO]-()
DELETE old

// Create new spatial relationship
CREATE (component)-[:CURRENT_IN]->(newLocation)

RETURN component, newLocation

3b. Set-Level Operations

Move Entire Set:

// Update all components in the set
MATCH (setObject:ObjectInstance {id: $setId})<-[:PART_OF]-(component:ObjectInstance)
MATCH (newLocation:ObjectInstance {id: $newLocationId})

// Remove old spatial relationships for all components
OPTIONAL MATCH (component)-[old:CURRENT_IN|CURRENT_ON|CURRENT_ATTACHED_TO]-()
DELETE old

// Create new spatial relationships for all components
CREATE (component)-[:CURRENT_IN]->(newLocation)

RETURN COUNT(component) as movedComponents

Detailed Workflow Examples

Example 1: Moving Ski Gloves

Step 1: Scan Component

User scans QR code on left ski glove
System identifies: "Left Ski Glove" (part of "My Ski Gloves" set)

Step 2: Choose Scope

UI presents choice:
- Work with "Left Ski Glove" only
- Work with entire "My Ski Gloves" set

User selects: "Work with entire set"

Step 3: Scan Target Location

UI prompts: "Scan location where My Ski Gloves should be moved"
User scans: Gear bag QR code
System identifies: "Main Gear Bag"

Step 4: Confirm and Execute

UI shows confirmation:
"Move My Ski Gloves (2 items) to Main Gear Bag?"
- Left Ski Glove → Main Gear Bag
- Right Ski Glove → Main Gear Bag

User confirms: Yes

System executes:
- Updates both gloves' CURRENT_IN relationships to gear bag
- Records movement timestamp
- Updates spatial hierarchy for both components

Step 5: Result

// After move operation
(:LeftSkiGlove)-[:CURRENT_IN]->(:MainGearBag)
(:RightSkiGlove)-[:CURRENT_IN]->(:MainGearBag)

// Set maintains logical relationship
(:MySkiGloves)<-[:PART_OF]-(:LeftSkiGlove)
(:MySkiGloves)<-[:PART_OF]-(:RightSkiGlove)

Example 2: Individual Component Operation

Scenario: Taking one glove for repair while leaving other in set location

Step 1: Scan Component

User scans right ski glove
System identifies: "Right Ski Glove" (part of "My Ski Gloves" set)

Step 2: Choose Scope

User selects: "Work with Right Ski Glove only"

Step 3: Scan Target Location

User scans: Repair shop location
System identifies: "Equipment Repair Station"

Step 4: Execute Individual Move

// Only right glove moves
(:RightSkiGlove)-[:CURRENT_IN]->(:RepairStation)

// Left glove remains in original location
(:LeftSkiGlove)-[:CURRENT_IN]->(:MainGearBag)

// Set relationship unchanged
(:MySkiGloves)<-[:PART_OF]-(:LeftSkiGlove)
(:MySkiGloves)<-[:PART_OF]-(:RightSkiGlove)

Example 3: Distributed Set Status

Scenario: Checking location of distributed set components

Query Set Status:

MATCH (set:ObjectInstance {name: "My Ski Gloves"})<-[:PART_OF]-(component:ObjectInstance)
OPTIONAL MATCH (component)-[:CURRENT_IN|CURRENT_ON]->(location:ObjectInstance)
RETURN {
  setName: set.name,
  components: COLLECT({
    componentName: component.name,
    currentLocation: location.name,
    locationId: location.id
  }),
  isUnified: COUNT(DISTINCT location.id) = 1,
  locationCount: COUNT(DISTINCT location.id)
}

Example Result:

{
  "setName": "My Ski Gloves",
  "components": [
    {
      "componentName": "Left Ski Glove", 
      "currentLocation": "Main Gear Bag",
      "locationId": "gear-bag-1"
    },
    {
      "componentName": "Right Ski Glove",
      "currentLocation": "Equipment Repair Station", 
      "locationId": "repair-station-1"
    }
  ],
  "isUnified": false,
  "locationCount": 2
}

GraphQL API Integration

Scan Result Type

type ScanResult {
  component: ObjectInstance!
  parentSet: ObjectInstance
  hasSet: Boolean!
  availableActions: [ScanAction!]!
}

enum ScanAction {
  WORK_WITH_COMPONENT
  WORK_WITH_SET
}

Movement Mutations

type Mutation {
  # Scan identifier and get context
  scanIdentifier(identifierKey: String!): ScanResult!
  
  # Move individual component
  moveComponent(
    componentId: ID!
    newLocationId: ID!
    relationshipType: SpatialRelationshipType = CURRENT_IN
  ): ComponentMoveResult!
  
  # Move entire set via component scan
  moveSet(
    setId: ID!
    newLocationId: ID!
    relationshipType: SpatialRelationshipType = CURRENT_IN
  ): SetMoveResult!
}

type ComponentMoveResult {
  component: ObjectInstance!
  newLocation: ObjectInstance!
  updatedAt: DateTime!
}

type SetMoveResult {
  set: ObjectInstance!
  components: [ObjectInstance!]!
  newLocation: ObjectInstance!
  movedCount: Int!
  updatedAt: DateTime!
}

Query Set Status

type ObjectInstance {
  # ... existing fields
  
  # Set-specific fields
  isSet: Boolean!
  componentLocations: [ComponentLocation!]
  isLocationUnified: Boolean
  locationSummary: String
}

type ComponentLocation {
  component: ObjectInstance!
  currentLocation: ObjectInstance
  spatialHierarchy: [SpatialReference!]
}

UI Implementation Guidelines

1. Scan Flow Components

ScanResultModal Component:

  • Shows scanned component details
  • Displays parent set information if applicable
  • Provides action selection (component vs set)

SetActionSelector Component:

  • Radio button selection for operation scope
  • Clear labeling of what will be affected
  • Preview of components that will be moved

2. Confirmation Workflows

MoveConfirmationDialog:

  • Lists all objects that will be affected
  • Shows source and target locations
  • Provides clear “Cancel” option before execution

3. Status Displays

SetStatusCard:

  • Shows unified vs distributed status
  • Lists component locations when distributed
  • Provides quick actions for reunifying set

4. Error Handling

Common Error Scenarios:

  • Component not found
  • Set has missing components
  • Location not accessible
  • Permission denied for set operations

Performance Considerations

1. Query Optimization

  • Index on PART_OF relationships for fast set membership checks
  • Cache set component lists for frequently accessed sets
  • Batch location updates for set operations

2. UI Responsiveness

  • Progressive loading for large sets
  • Optimistic UI updates with rollback on failure
  • Background status updates for distributed sets

3. Scanning Performance

  • Fast identifier lookup with proper indexing
  • Minimal query complexity for scan detection
  • Efficient component counting for large sets

Implementation Checklist

Backend Requirements

  • Scan detection query with set membership
  • Component vs set operation mutations
  • Set status aggregation queries
  • Validation for set operation permissions

Frontend Requirements

  • Scan result modal with action selection
  • Set vs component choice UI
  • Move confirmation with affected items list
  • Set status display components

Database Requirements

  • Proper indexing on PART_OF relationships
  • Performance testing with large sets
  • Transaction handling for set operations