← Back to Main Documentation Core Systems Index

Object Status System

Overview

The Plings system supports multiple simultaneous statuses for ObjectInstance documents. This allows for nuanced tracking of an object’s condition and availability state. For example, an object can be both “for_sale” and “broken”, indicating that it’s available for purchase as a repair item.

Supported Status Types

Status Description Typical Use Cases Color
active Object is in normal use and under the owner’s physical control Daily operations, personal belongings Green
for_sale Available for purchase while still in custody Marketplace listings, spare parts Blue
reserved A buyer has a temporary reservation Click-&-collect, deposit taken Light Blue
under_auction Listed in an auction until bidding closes Online or physical auction house Light Blue
pending_transfer Sale agreed; paperwork or payment pending Waiting for payment or contract signing Light Blue
sold Ownership has permanently transferred Completed sale, invoice issued Gray-Green
donated Given away for free to another party Charity donations, giveaways Gray-Green
lent_out Temporarily loaned, ownership retained Lending to friends, internal department loan Yellow-Green
rented_out Temporarily leased for a fee, ownership retained Equipment rental, tool library Yellow-Green
consigned Held by a reseller on consignment Second-hand shop, art gallery Yellow-Green
on_display On exhibit at a partner venue/showroom Museum loan, showroom model Yellow-Green
in_storage Stored off-site or in long-term storage Warehouse, self-storage Yellow-Green
in_transit With a carrier / on the move Courier shipment, freight forwarding Orange
awaiting_pickup Packed and ready for carrier or customer Click-&-collect counter, loading dock Orange
returned_inbound Being returned back to the owner Product returns, failed delivery Orange
lost Misplaced; location unknown but no theft suspicion Lost & found workflow, insurance Yellow
stolen Confirmed or suspected theft Police report, insurance Red
broken Not functioning properly Repair requests, parts salvage Orange-Red
in_service Under routine maintenance / calibration Scheduled service, inspection Orange-Green
in_repair Under repair due to a fault Workshop, service center Orange-Red
under_warranty_service At manufacturer for warranty repair Manufacturer RMA Orange-Red
refurbished Completed repair/refit; QC pending Refurb workflow Green-Blue
quarantined Isolated due to contamination or defect suspicion Bio-hazard, recalls Purple
recycled Handed to recycler for material recovery E-waste recycling, scrap metal Gray
discarded Thrown away with no recycling process Landfill disposal Gray
dismantled Object has been disassembled into parts; original assembly no longer exists Part-out workflows, salvage operations Dark Gray
destructed Physically destroyed (shredded, burned, etc.) Secure data destruction, end-of-life Black

About active

active is the baseline status meaning the object is operational, present, and under control of the current owner. Certain negative or terminal conditions automatically disqualify active (see rules below).

Status Combinations

Mutually Exclusive Status Rules

The backend validator will reject combinations that break real-world logic. Key rules:

  1. active cannot coexist with any of: lost, stolen, broken, destructed, dismantled, sold, donated, recycled, discarded, in_repair, under_warranty_service, quarantined.
  2. destructed, recycled, discarded, or dismantled are terminal – they cannot be combined with any other status.
  3. sold / donated are mutually exclusive with for_sale, reserved, under_auction, and pending_transfer.
  4. lost and stolen can coexist during investigation but cannot be combined with any custody-related statuses (in_transit, in_storage, etc.).
  5. Only one external-custody status from the set {lent_out, rented_out, consigned, on_display, in_service, in_repair, under_warranty_service} may be present at a time.
  6. in_service, in_repair, and under_warranty_service are mutually exclusive with broken (the repair process replaces the “broken” flag).

These rules are enforced in the service layer. The UI presents invalid combinations as disabled choices, and the API returns 409 Conflict if violated.

Common Multi-Status Scenarios

  1. ["for_sale", "broken"]: Selling broken items for parts or repair
  2. ["lost", "stolen"]: Unclear if item is lost or stolen (investigation phase)
  3. ["active", "for_sale"]: Selling functional items while still using them
  4. ["broken", "for_sale", "dismantled"]: Parent object has been disassembled; parts are being sold (note: dismantled is on parent only, not on parts)

Data Storage

Neo4j Graph Database

In Neo4j, statuses are stored as a list of strings in the statuses property on an :ObjectInstance node.

MATCH (o:ObjectInstance {id: 'example-123'})
SET o.statuses = ["for_sale", "broken"]
RETURN o

Supabase Storage

Statuses are stored as JSON strings in the PostgreSQL status column:

UPDATE object_instances
SET status = '["for_sale", "broken"]'
WHERE neo4j_id = 'example-123';

Frontend Implementation

Status Data Loading

The frontend should load status definitions on application startup:

// Load status definitions once on app init
const { data: statusDefinitions } = useQuery(GET_STATUS_DEFINITIONS);

// Create lookup maps for efficient access
const statusByKey = useMemo(() => 
  statusDefinitions?.statusDefinitions.reduce((acc, status) => {
    acc[status.key] = status;
    return acc;
  }, {}) || {}, [statusDefinitions]
);

Status Selection UI

  • Edit Form: Multi-select checkboxes for status selection
  • Validation: Use GraphQL validation query before submission
  • Visual: Each status displays as a colored badge using backend-provided colors
  • Categories: Group statuses by category for better UX
  • Disabled States: Use conflictsWith data to disable incompatible options

Status Display

  • Object Cards: Multiple status badges with appropriate colors from backend
  • Badge Format: Use name field from status definitions (properly formatted)
  • Layout: Badges wrap to multiple lines if needed
  • Tooltips: Show description from status definitions on hover

Status Validation

Implement client-side validation using the GraphQL endpoint:

const validateStatuses = async (statusKeys) => {
  const { data } = await validateStatusCombination({ 
    variables: { statusKeys } 
  });
  return data.validateStatusCombination;
};

API Interface

GraphQL Status Queries

The backend provides comprehensive GraphQL queries for status management:

Get All Status Definitions

query GetStatusDefinitions {
  statusDefinitions {
    key
    name
    description
    color
    category
    isTerminal
    conflictsWith
    requiresActiveFalse
  }
}

Get Status Categories

query GetStatusCategories {
  statusCategories
}

Get Statuses by Category

query GetCommerceStatuses {
  statusesByCategory(category: "commerce") {
    key
    name
    description
    color
  }
}

Validate Status Combination

query ValidateStatusCombination {
  validateStatusCombination(statusKeys: ["for_sale", "broken"]) {
    valid
    errors
    warnings
  }
}

Update Object Statuses

mutation UpdateObjectStatuses($objectId: ID!, $statusKeys: [String!]!) {
  updateObjectStatuses(objectId: $objectId, statusKeys: $statusKeys) {
    id
    name
    statuses
    owner
    location
    description
  }
}

Create Object

const formData = new FormData();
formData.append('name', 'My Object');
formData.append('statuses', JSON.stringify(['active', 'for_sale']));

Update Object

const formData = new FormData();
formData.append('statuses', JSON.stringify(['broken', 'for_sale']));

Response Format

{
  "id": "ObjectInstance/abc123",
  "name": "My Object",
  "statuses": ["broken", "for_sale"],
  "message": "Object updated successfully"
}

Backend Implementation

Status Definitions Storage

Status definitions are centrally managed in app/statuses.py with comprehensive metadata:

@dataclass
class StatusDefinition:
    key: str                    # Status identifier (e.g., "for_sale")
    name: str                   # Display name (e.g., "For Sale")
    description: str            # Human-readable description
    color: str                  # UI color identifier
    category: str               # Grouping category
    is_terminal: bool = False   # Whether this is an end-of-life status
    conflicts_with: List[str] = None        # Mutually exclusive statuses
    requires_active_false: bool = False     # Cannot coexist with "active"

Status Categories

Statuses are organized into logical categories:

  • operational - Normal operational states
  • commerce - Sale, auction, transfer states
  • custody - External custody situations
  • transit - Movement and shipping states
  • problem - Lost, stolen, broken states
  • service - Maintenance and repair states
  • end-of-life - Terminal disposal states

Validation Logic

The backend provides validation for status combinations:

def validate_status_combination(status_keys: List[str]) -> Dict[str, Any]:
    """Validate a combination of status keys and return validation result"""
    # Check conflicts with "active" status
    # Check direct conflicts between statuses
    # Check for multiple terminal statuses
    # Return validation result with errors and warnings

GraphQL Resolvers

Status-related queries and mutations are handled by dedicated resolvers in app/status_resolvers.py:

  • resolve_status_definitions() - Returns all available statuses
  • resolve_status_categories() - Returns category list
  • resolve_statuses_by_category() - Filters by category
  • resolve_validate_status_combination() - Validates combinations
  • resolve_update_object_statuses() - Updates object statuses (mutation)

Status Update Operations

The updateObjectStatuses mutation handles all status modifications:

  1. Authentication: Verifies user permissions for the target object
  2. Validation: Uses validate_status_combination() to check business rules
  3. Dual Updates: Updates both Neo4j (o.statuses) and Supabase (status column)
  4. Error Handling: Provides detailed error messages for invalid operations
  5. Ownership Check: Ensures user owns object or belongs to owning organization

Mutation Behavior

  • Atomic Operation: Status updates are validated before any database changes
  • Permission-Based: Only object owners/organization members can modify statuses
  • Graceful Degradation: If Supabase update fails, Neo4j update still succeeds (with warning)
  • Real-time Response: Returns updated object data immediately after successful update

Backend Processing

Status Parsing

The backend handles both old single-status and new multi-status formats:

# Parse statuses from JSON string
try:
    statuses_list = json.loads(statuses)
    if not statuses_list:
        statuses_list = ["active"]  # Default fallback
except (json.JSONDecodeError, TypeError):
    statuses_list = ["active"]  # Default fallback

Database Updates

  • Neo4j: Stores as a native list property on the :ObjectInstance node.
  • Supabase: Stores as a JSON string in the status column.

Migration Strategy

Backward Compatibility

The system gracefully handles existing objects with single-status format:

// Old format support
if (obj.status && !obj.statuses) {
    statuses = [obj.status];
} else if (obj.statuses && Array.isArray(obj.statuses)) {
    statuses = obj.statuses;
} else {
    statuses = ['active']; // Fallback
}

Migration Process

  1. No Data Migration Required: Existing single-status objects work automatically
  2. Gradual Adoption: Users can update objects to multi-status through the edit interface
  3. Legacy Support: Old single-status format continues to work indefinitely

Use Cases

1. Marketplace for Broken Items

Scenario: User wants to sell a broken laptop for parts

  • Statuses: ["broken", "for_sale"]
  • Search: Buyers can filter for broken items specifically
  • Display: Clear indication that item is broken but available

2. Theft Investigation

Scenario: Unclear if bike is lost or stolen

  • Initial: ["lost"]
  • Update: ["lost", "stolen"] during investigation
  • Final: ["stolen"] after police confirmation

3. Functional Items for Sale

Scenario: Selling working items while still using them

  • Statuses: ["active", "for_sale"]
  • Transition: Remove "active" when sold and ownership transfers

4. End-of-Life Tracking

Scenario: Item is recycled or disposed of

  • Statuses: ["destructed"]
  • Effect: Cannot be marked for_sale (future business logic)
  • Purpose: Environmental tracking, warranty void confirmation

Future Enhancements

Business Logic Rules

  1. Status Validation: Implement mutually exclusive status combinations
  2. Automatic Transitions: Auto-remove incompatible statuses
  3. Workflow Triggers: Status changes trigger notifications/actions

Analytics and Reporting

  1. Status Distribution: Track status combinations across object types
  2. Lifecycle Analysis: Monitor status transition patterns
  3. Marketplace Metrics: Analyze for_sale status effectiveness

Enhanced UI Features

  1. Bulk Status Updates: Change status for multiple objects
  2. Status History: Track status changes over time
  3. Smart Suggestions: Recommend status combinations based on context

Implementation Notes

Performance Considerations

  • Database Indexing: Consider GIN indexes on JSON status fields for PostgreSQL
  • API Efficiency: Batch status updates for bulk operations
  • Caching: Cache status color mappings for UI performance

Security Considerations

  • Ownership Validation: Only owners can change object statuses
  • Audit Trail: Log all status changes for security/compliance
  • Fraud Prevention: Monitor suspicious status change patterns

API Benefits

The new GraphQL status API provides several key advantages:

Centralized Status Management

  • Single Source of Truth: All status definitions managed in backend code
  • Consistent Metadata: Colors, descriptions, and categories defined once
  • Easy Updates: Adding new statuses requires only backend changes

Enhanced Frontend Experience

  • Dynamic UI: Frontend automatically adapts to new status definitions
  • Smart Validation: Real-time validation prevents invalid status combinations
  • Rich Metadata: Colors, descriptions, and categories improve UX

Developer Experience

  • Type Safety: GraphQL provides strongly-typed status operations
  • Self-Documenting: Status definitions include comprehensive metadata
  • Easy Integration: Simple queries provide all necessary frontend data

This multi-status system provides the foundation for a sophisticated object lifecycle management system while maintaining simplicity for basic use cases.