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

  1. Receive GraphQL Request: The server receives the multipart request containing the GraphQL mutation and the uploaded files.
  2. Authentication & Authorization: The user session and organization membership are validated from the GraphQL context.
  3. Process Mutation: The createObject resolver is executed.
  4. Image Upload (if files exist): The files are streamed from the request and uploaded to Supabase Storage.
  5. Neo4j Node Creation: A new :ObjectInstance node is created in the graph.
  6. Supabase Record Creation: Tracking records are created in the object_instances and object_images tables.
  7. 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 Authorization header.
  • 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_OF relationship 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

  1. AI Classification: Automatic object class suggestion based on images/name
  2. Plings Identifiers: Generate and assign QR codes during creation
  3. Component Detection: AI identification of sub-components
  4. Spatial Relationships: Immediate location assignment during creation

Technical Improvements

  1. Image Processing: Thumbnail generation, compression
  2. Offline Support: Cache and sync when connection restored
  3. Bulk Upload: Create multiple objects from photo gallery
  4. 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