Use Case: User Creates a New Object
Use Case: User Creates a New Object
Overview
This document describes the complete workflow when a user creates a new physical object in the Plings system, from frontend interaction through backend processing to data storage across multiple databases.
User Story
As a user, I want to create a digital record of my physical objects so that I can track, organize, and manage my items across different organizations.
Workflow Steps
Step 1: User Initiates Object Creation
- Location: Objects Dashboard (
/objects) - Action: User clicks “Create Object” button
- UI Response: Modal opens with creation form
Step 2: User Uploads Images (Optional)
- Action: User clicks image upload area or drags files
- Frontend Processing:
- Validates file types (image/*)
- Shows image previews
- Marks first image as “Main”
- Allows image removal
- Technical: Images stored in browser memory until submission
Step 3: User Fills Object Details
- Required Fields:
- Object Name: User-friendly identifier (e.g., “My ski helmet”)
- Optional Fields:
- Description: Additional context or notes
- Auto-filled:
- Statuses: Defaults to [“active”] (multiple statuses supported)
Step 4: User Selects Organization (Save As)
- Frontend: Displays buttons for each organization user belongs to
- Options: “Save as [Organization Name]” for each accessible org
- Validation: User must be member of selected organization
Step 5: Form Submission and Processing
The system uses a single GraphQL mutation to create new objects. If images are included, they are handled as part of the same operation using the GraphQL multipart request specification.
Frontend Processing
The frontend client constructs a createObject mutation. If files are present, they are mapped to variables in the GraphQL operation.
// Simplified conceptual example using Apollo Client
import { useMutation, gql } from '@apollo/client';
const CREATE_OBJECT = gql`
mutation createObject($name: String!, $description: String, $ownerOrgId: ID!, $statuses: [String!], $photos: [Upload!]) {
createObject(name: $name, description: $description, ownerOrgId: $ownerOrgId, statuses: $statuses, photos: $photos) {
id
name
main_image_url
}
}
`;
const [createObject] = useMutation(CREATE_OBJECT);
// When the user submits the form:
createObject({
variables: {
name: objectName,
description,
ownerOrgId: selectedOrgId,
statuses: ['active'],
photos: files, // Array of File objects
},
});
Backend Processing Flow
- Receive GraphQL Request: The server receives the multipart request containing the GraphQL mutation and the uploaded files.
- Authentication & Authorization: The user session and organization membership are validated from the GraphQL context.
- Process Mutation: The
createObjectresolver is executed. - Image Upload (if files exist): The files are streamed from the request and uploaded to Supabase Storage.
- Neo4j Node Creation: A new
:ObjectInstancenode is created in the graph. - Supabase Record Creation: Tracking records are created in the
object_instancesandobject_imagestables. - Response: The newly created object is returned in the GraphQL response.
Data Flow Architecture
Frontend → Backend
- Protocol: HTTP POST with
multipart/form-data, conforming to the GraphQL multipart request specification. - Authentication: Bearer token from Supabase session, passed in the
Authorizationheader. - Payload: A single request contains the GraphQL mutation string, variables (including metadata), and the file data.
Backend → Supabase Storage
- Bucket:
object-images(public bucket) - Path Structure:
objects/{instance_id}/image_{index}_{uuid}.{ext} - Response: Public URLs for uploaded images
Backend → Neo4j
- Node Type:
:ObjectInstance - Relationships: Creates an
:INSTANCE_OFrelationship if an object class is provided. - Transaction: Single commit with node creation message.
Backend → Supabase Database
- Tables:
object_instances,object_images - Purpose: Ownership tracking, audit trail, image metadata
- RLS: Enforced based on organization membership
Database Schema Impact
Neo4j (Graph Database)
A new :ObjectInstance node is created.
{
"name": "My ski helmet",
"description": "Blue helmet from last skiing trip",
"statuses": ["active"],
"owner": "{organization_id}"
}
An -[:INSTANCE_OF]-> relationship to an :ObjectClass node may also be created.
Supabase PostgreSQL
-- object_instances table
INSERT INTO object_instances (
neo4j_id,
name,
description,
owner_organization_id,
created_by,
statuses,
main_image_url
) VALUES (...);
-- object_images table (if images uploaded)
INSERT INTO object_images (
object_instance_id,
storage_path,
public_url,
is_main,
uploaded_by
) VALUES (...);
Security and Access Control
Row Level Security (RLS) Policies
- Object Creation: User must be member of target organization
- Object Viewing: User can see objects from their organizations
- Image Access: Images inherit object access permissions
File Upload Security
- Content Type Validation: Server validates actual file types
- File Size Limits: Enforced at both frontend and storage level
- Public Access: Images are public (required for marketplace/lost item scenarios)
Error Handling
Validation Errors
- Missing Name: “Object name is required”
- Invalid Organization: “User not member of organization”
- File Upload Failures: Specific error messages from storage layer
Transaction Failures
- Neo4j Failure: Rollback Supabase records.
- Storage Failure: Continue without images, log error
- Partial Success: Report what succeeded, what failed
Future Enhancements
Planned Features
- AI Classification: Automatic object class suggestion based on images/name
- Plings Identifiers: Generate and assign QR codes during creation
- Component Detection: AI identification of sub-components
- Spatial Relationships: Immediate location assignment during creation
Technical Improvements
- Image Processing: Thumbnail generation, compression
- Offline Support: Cache and sync when connection restored
- Bulk Upload: Create multiple objects from photo gallery
- Voice Input: Speech-to-text for object names and descriptions
Performance Considerations
Optimization Strategies
- Lazy Loading: Objects loaded per organization, paginated
- Image Compression: Reduce file sizes before upload
- Caching: Organization list cached in frontend
- Batch Operations: Group database operations where possible
Scaling Factors
- Storage Growth: Images will be primary storage consumer
- Database Load: Balanced between Neo4j (graph) and Supabase (relational)
- CDN Integration: Consider CloudFront for global image delivery
Success Metrics
- Creation Time: < 30 seconds for object with 3 images
- Success Rate: > 99% successful object creation
- User Adoption: Increase in objects created per user over time
- Data Quality: High percentage of objects with descriptions and images