Use Case: Assign Status to an Object

Overview

Objects support multiple simultaneous statuses (e.g., active, for_sale, broken). This use-case covers adding or removing statuses via the UI and enforcing business rules using the comprehensive GraphQL Status API that has been implemented in the backend.

Implementation with Status API ✅ BACKEND COMPLETE

The backend now provides a complete status management system with 17 defined statuses, validation rules, and comprehensive GraphQL mutations.

1. Load Status Definitions

On app initialization, load all available status definitions:

const GET_STATUS_DEFINITIONS = gql`
  query GetStatusDefinitions {
    statusDefinitions {
      key
      name
      description
      color
      category
      isTerminal
      conflictsWith
      requiresActiveFalse
    }
  }
`;

const { statusDefinitions, statusesByCategory } = useStatusDefinitions();

2. Render Status Selection UI

Create a categorized, multi-select interface using the backend API:

// Status selection component with real-time validation
const StatusSelector = ({ currentStatuses, onChange }) => {
  const { statusesByCategory, statusByKey } = useStatusDefinitions();
  const { validationState, validate } = useStatusValidation();
  
  const handleStatusChange = (newStatuses) => {
    // Validate combination before allowing selection
    validate(newStatuses);
    if (validationState.result?.valid) {
      onChange(newStatuses);
    }
  };

  return (
    <div className="space-y-4">
      {Object.entries(statusesByCategory).map(([category, statuses]) => (
        <div key={category}>
          <h3 className="font-medium text-lg capitalize">{category} Statuses</h3>
          <div className="grid grid-cols-2 gap-2 mt-2">
            {statuses.map(status => (
              <StatusCheckbox
                key={status.key}
                status={status}
                checked={currentStatuses.includes(status.key)}
                disabled={wouldConflict(status.key, currentStatuses, statusByKey)}
                onChange={(checked) => handleStatusToggle(status.key, checked)}
              />
            ))}
          </div>
        </div>
      ))}
      
      {/* Real-time validation feedback */}
      {validationState.result?.errors?.map(error => (
        <div key={error} className="text-red-500 text-sm">{error}</div>
      ))}
      {validationState.result?.warnings?.map(warning => (
        <div key={warning} className="text-yellow-500 text-sm">{warning}</div>
      ))}
    </div>
  );
};

3. Real-time Validation

Use the validation API to provide instant feedback:

const VALIDATE_STATUS_COMBINATION = gql`
  query ValidateStatusCombination($statusKeys: [String!]!) {
    validateStatusCombination(statusKeys: $statusKeys) {
      valid
      errors
      warnings
    }
  }
`;

// Check conflicts before allowing selection
const wouldConflict = (statusKey, currentStatuses, statusByKey) => {
  const status = statusByKey[statusKey];
  if (!status) return false;
  
  // Check direct conflicts
  return status.conflictsWith.some(conflict => 
    currentStatuses.includes(conflict)
  );
};

// Real-time validation hook
const useStatusValidation = () => {
  const [validationState, setValidationState] = useState({
    isValidating: false,
    result: null,
    error: null
  });

  const [validateStatusCombination] = useLazyQuery(VALIDATE_STATUS_COMBINATION, {
    onCompleted: (data) => {
      setValidationState({
        isValidating: false,
        result: data.validateStatusCombination,
        error: null
      });
    },
    onError: (error) => {
      setValidationState({
        isValidating: false,
        result: null,
        error
      });
    }
  });

  const validate = useCallback(
    debounce((statusKeys: string[]) => {
      setValidationState(prev => ({ ...prev, isValidating: true }));
      validateStatusCombination({ variables: { statusKeys } });
    }, 300),
    [validateStatusCombination]
  );

  return { validationState, validate };
};

4. Status Update Mutation ✅ IMPLEMENTED

Update object statuses with optimistic UI using the exact backend mutation:

const UPDATE_OBJECT_STATUSES = gql`
  mutation UpdateObjectStatuses($objectId: ID!, $statusKeys: [String!]!) {
    updateObjectStatuses(objectId: $objectId, statusKeys: $statusKeys) {
      id
      name
      statuses
      owner
      location
      description
      imageUrls
      mainImageUrl
    }
  }
`;

const [updateObjectStatuses] = useMutation(UPDATE_OBJECT_STATUSES, {
  optimisticResponse: ({ objectId, statusKeys }) => ({
    updateObjectStatuses: {
      __typename: 'ObjectInstance',
      id: objectId,
      statuses: statusKeys,
      // Keep other fields unchanged for optimistic update
    }
  }),
  update(cache, { data: { updateObjectStatuses } }) {
    // Update any cached object queries
    cache.modify({
      id: cache.identify(updateObjectStatuses),
      fields: {
        statuses() {
          return updateObjectStatuses.statuses;
        }
      }
    });
  }
});

const handleSave = async (objectId, newStatuses) => {
  // Final validation before submission
  const validation = await validateStatuses(newStatuses);
  if (!validation.valid) {
    showErrors(validation.errors);
    return;
  }
  
  try {
    // Submit with exact parameter names expected by backend
    await updateObjectStatuses({
      variables: { 
        objectId,      // camelCase to match GraphQL schema
        statusKeys: newStatuses  // camelCase to match GraphQL schema
      }
    });
    
    toast.success('Status updated successfully');
  } catch (error) {
    console.error('Status update failed:', error);
    toast.error('Failed to update status');
  }
};

Workflow Steps

  1. Open Status Panel – Object Detail → Lifecycle tab
  2. Load Status Definitions – Categories and rules loaded from GraphQL API ✅ Available
  3. Select Statuses – Multi-select interface grouped by category with real-time validation ✅ API Ready
  4. Validate Combination – Use validateStatusCombination query for client-side feedback ✅ Implemented
  5. Update Object – Submit updateObjectStatuses mutation with optimistic UI updates ✅ Implemented
  6. Real-time Updates – Other users see changes via GraphQL subscriptions ✅ Backend Ready

Business Rules Enforcement ✅ BACKEND COMPLETE

Backend Validation

All status combination rules are enforced in the backend with 17 comprehensive status definitions:

// Example status definitions from backend
const statusExamples = {
  active: {
    key: "active",
    name: "Active",
    description: "Object is in normal use",
    color: "green",
    category: "operational",
    conflictsWith: ["broken", "lost", "stolen", "destructed"],
    requiresActiveFalse: false
  },
  for_sale: {
    key: "for_sale",
    name: "For Sale",
    description: "Object is available for purchase",
    color: "blue", 
    category: "commerce",
    conflictsWith: ["sold", "destructed"],
    requiresActiveFalse: false
  },
  broken: {
    key: "broken",
    name: "Broken",
    description: "Object is damaged and non-functional",
    color: "red",
    category: "problem",
    conflictsWith: ["active"],
    requiresActiveFalse: true
  }
};

Frontend UI Logic

  • Disabled States: Conflicting options are disabled in the UI
  • Real-time Feedback: Validation runs as user selects options
  • Error Display: Clear error messages for invalid combinations
  • Smart Defaults: Common combinations suggested based on context
  • Category Organization: Statuses grouped by operational, commerce, custody, transit, problem, service, and end-of-life

Status Categories ✅ IMPLEMENTED

The API organizes statuses into logical categories:

  • operational - Normal operational states (active, inactive)
  • commerce - Sale, auction, transfer states (for_sale, reserved, sold)
  • custody - External custody situations (donated, loaned, borrowed)
  • transit - Movement and shipping states (in_transit, shipped)
  • problem - Lost, stolen, broken states (lost, stolen, broken)
  • service - Maintenance and repair states (in_repair)
  • end-of-life - Terminal disposal states (destructed, recycled)

API Benefits ✅ PRODUCTION READY

  • Dynamic UI: Frontend automatically adapts to new status definitions
  • Centralized Rules: All validation logic managed in backend
  • Type Safety: GraphQL provides strongly-typed status operations
  • Real-time Sync: Status changes propagate immediately to all users
  • Comprehensive Validation: 17 status definitions with conflict detection
  • Database Consistency: Updates synchronized between Neo4j and Supabase
  • Error Handling: Graceful degradation and rollback on failures

Query Examples for Category Filtering

// Get statuses by specific category
const GET_COMMERCE_STATUSES = gql`
  query GetCommerceStatuses {
    statusesByCategory(category: "commerce") {
      key
      name
      description
      color
    }
  }
`;

// Get all categories
const GET_STATUS_CATEGORIES = gql`
  query GetStatusCategories {
    statusCategories
  }
`;

Implementation Status ✅ BACKEND COMPLETE

The backend provides a production-ready status management system with:

  • ✅ 17 comprehensive status definitions with metadata
  • ✅ Real-time validation API with conflict detection
  • ✅ Category-based organization and filtering
  • ✅ updateObjectStatuses mutation with dual database updates
  • ✅ Business rule enforcement (terminal statuses, active conflicts)
  • ✅ Comprehensive error handling and rollback support
  • ✅ GraphQL subscriptions for real-time updates

The frontend can now implement rich status management workflows using the complete GraphQL API. Full rule matrix and status definitions are available via the statusDefinitions query.