Use Case: Assign Status to an Object
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
- Open Status Panel – Object Detail → Lifecycle tab
- Load Status Definitions – Categories and rules loaded from GraphQL API ✅ Available
- Select Statuses – Multi-select interface grouped by category with real-time validation ✅ API Ready
- Validate Combination – Use
validateStatusCombinationquery for client-side feedback ✅ Implemented - Update Object – Submit
updateObjectStatusesmutation with optimistic UI updates ✅ Implemented - 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.