Object Creation Backend API Specification
Object Creation Backend API Specification
Overview
This document provides technical API specifications for backend developers implementing object creation functionality. For project coordination and user stories, see API Requirements. For UI/UX requirements, see Frontend Requirements.
1. GraphQL Schema Definitions
A. CREATE_OBJECT - Single Object Creation
mutation CreateObject($input: CreateObjectInput!) {
createObject(input: $input) {
id
name
shortCode
isSet
status
organization {
id
name
}
spatialParent {
id
name
spatialPath
}
tagData {
instanceKey
classKey
path
shortCode
isManufacturerTag
}
images {
id
url
isMain
thumbnailUrl
}
createdAt
updatedAt
}
}
input CreateObjectInput {
name: String!
description: String
organizationId: ID!
spatialParentId: ID
tagInstanceKey: String
tagClassKey: String
tagPath: String
isSet: Boolean = false
status: String = "active"
batchId: String
objectType: String
}
B. BATCH_CREATE_OBJECTS - Mobile Batch Creation
mutation BatchCreateObjects($input: BatchCreateInput!) {
batchCreateObjects(input: $input) {
success
batchId
totalRequested
totalCreated
objects {
tempId
id
name
shortCode
status
tagConflict {
hasConflict
conflictType
existingObjectId
message
}
}
failed {
tempId
error
code
retryable
}
}
}
input BatchCreateInput {
sessionId: String!
organizationId: ID!
spatialParentId: ID
objects: [BatchObjectInput!]!
}
input BatchObjectInput {
tempId: String!
name: String!
description: String
objectType: String
tagInstanceKey: String
tagClassKey: String
tagPath: String
}
C. Set Object Mutations
mutation ConvertToSet($objectId: ID!, $setName: String) {
convertToSet(objectId: $objectId, setName: $setName) {
id
name
isSet
originalName
children {
id
name
shortCode
}
tagData {
instanceKey
shortCode
}
}
}
mutation CreateSetChild($setId: ID!, $input: SetChildInput!) {
createSetChild(setId: $setId, input: $input) {
id
name
shortCode
setParent {
id
name
isSet
}
tagData {
instanceKey
shortCode
}
tagMigrated
tagConflict {
hasConflict
message
existingObject {
id
name
}
}
}
}
input SetChildInput {
name: String!
description: String
tagInstanceKey: String
suggestedName: String
}
mutation CompleteSet($setId: ID!) {
completeSet(setId: $setId) {
id
name
isComplete
children {
id
name
shortCode
}
totalChildren
completedAt
}
}
D. Tag Management Mutations
mutation ResolveTagIdentifier($input: TagResolverInput!) {
resolveTagIdentifier(input: $input) {
tagData {
instanceKey
classKey
path
shortCode
isManufacturerTag
isGenericTag
}
existingObject {
id
name
owner {
id
name
}
canEdit
isSet
setParent {
id
name
}
}
conflict {
hasConflict
conflictType
message
resolutionOptions
}
cryptographicValid
}
}
input TagResolverInput {
instanceKey: String!
classKey: String
path: String
tagType: String!
}
mutation AssignTagToObject($objectId: ID!, $tagInput: TagAssignmentInput!) {
assignTagToObject(objectId: $objectId, tagInput: $tagInput) {
success
object {
id
name
tagData {
instanceKey
shortCode
}
}
tagMigrated
previousObject {
id
name
}
auditLog {
action
timestamp
userId
}
}
}
input TagAssignmentInput {
instanceKey: String!
classKey: String
path: String
forceReassign: Boolean = false
}
E. Auto-naming Support
query GenerateObjectName($input: GenerateNameInput!) {
generateObjectName(input: $input) {
suggestedName
isAvailable
conflictCount
alternatives {
name
isAvailable
}
}
}
input GenerateNameInput {
organizationId: ID!
baseName: String # User input or "Object" if empty
tagShortCode: String # First 4 chars of tag if present
preferredPattern: String # "base", "base (tag)", etc.
}
query CheckNameAvailability($organizationId: ID!, $name: String!) {
checkNameAvailability(organizationId: $organizationId, name: $name) {
isAvailable
conflictCount
suggestedAlternatives
}
}
Backend Implementation Requirements:
- Name Generation Logic: ```typescript function generateObjectName(input: GenerateNameInput): string { const { organizationId, baseName, tagShortCode } = input;
// Determine base name const base = baseName?.trim() || “Object”;
// Add tag if present
const nameWithTag = tagShortCode ? ${base} (${tagShortCode}) : base;
// Check availability and auto-increment return findAvailableName(organizationId, nameWithTag); }
function findAvailableName(orgId: string, baseName: string): string { const existingNames = getObjectNamesInOrganization(orgId);
if (!existingNames.includes(baseName)) { return baseName; }
// Find next available number
for (let i = 2; i <= 1000; i++) {
const candidate = ${baseName} ${i};
if (!existingNames.includes(candidate)) {
return candidate;
}
}
// Fallback with timestamp if too many conflicts
return ${baseName} ${Date.now()};
}
2. **Performance Requirements:**
- **Response Time**: <100ms for name generation
- **Caching**: Cache organization name lists for 5 minutes
- **Batch Support**: Support bulk name generation for batch creation
- **Case Sensitivity**: Case-insensitive duplicate detection
3. **Database Query Optimization:**
```sql
-- Efficient name lookup within organization
SELECT name FROM object_instances
WHERE organization_id = $1
AND LOWER(name) LIKE LOWER($2 || '%')
ORDER BY name;
-- Index for fast name lookups
CREATE INDEX idx_object_names_org_lower
ON object_instances(organization_id, LOWER(name));
F. Object Class Queries
query SearchObjectClasses($query: String!, $organizationId: ID, $limit: Int = 10) {
searchObjectClasses(query: $query, organizationId: $organizationId, limit: $limit) {
id
name
description
manufacturer
isGeneric
parentClass {
id
name
}
usageCount
recentlyUsed
matchScore
}
}
query GetRecentObjectTypes($organizationId: ID!, $limit: Int = 4) {
getRecentObjectTypes(organizationId: $organizationId, limit: $limit) {
className
displayName
usageCount
lastUsed
iconUrl
}
}
query GetContainerContext($containerId: ID!) {
getContainerContext(containerId: $containerId) {
id
name
spatialPath
breadcrumb {
id
name
}
permissions {
canCreateObjects
canCreateSets
}
recentObjectTypes
organization {
id
name
}
}
}
F. Batch Session Management
query GetBatchSession($sessionId: String!) {
getBatchSession(sessionId: $sessionId) {
id
status
organizationId
spatialParentId
createdBy
createdAt
objects {
tempId
id
name
status
hasErrors
}
totalObjects
completedObjects
failedObjects
}
}
mutation ResumeBatchSession($sessionId: String!) {
resumeBatchSession(sessionId: $sessionId) {
session {
id
status
canResume
}
pendingObjects {
tempId
name
status
retryable
}
}
}
mutation CompleteBatchSession($sessionId: String!) {
completeBatchSession(sessionId: $sessionId) {
success
session {
id
completedAt
summary {
totalRequested
totalCreated
totalFailed
duration
}
}
}
}
G. Advanced Object Class Operations
query GetObjectClassHierarchy($classId: ID!) {
getObjectClassHierarchy(classId: $classId) {
id
name
path
parentClass {
id
name
}
childClasses {
id
name
objectCount
}
properties {
name
type
required
defaultValue
validation
}
}
}
mutation CreateObjectClass($input: CreateObjectClassInput!) {
createObjectClass(input: $input) {
id
name
description
parentClassId
properties {
name
type
required
}
permissions {
canEdit
canDelete
canCreateInstances
}
}
}
input CreateObjectClassInput {
name: String!
description: String
parentClassId: ID
organizationId: ID!
properties: [ObjectClassPropertyInput!]
}
input ObjectClassPropertyInput {
name: String!
type: PropertyType!
required: Boolean = false
defaultValue: String
validation: PropertyValidationInput
}
enum PropertyType {
TEXT
NUMBER
DATE
BOOLEAN
SELECT
MULTI_SELECT
URL
EMAIL
}
H. Advanced Tag Operations
query GetTagHistory($tagInstanceKey: String!) {
getTagHistory(tagInstanceKey: $tagInstanceKey) {
assignments {
objectId
objectName
assignedAt
assignedBy
removedAt
removedBy
}
scans {
scannedAt
scannedBy
location
deviceInfo
}
conflicts {
occurredAt
conflictType
resolutionAction
resolvedBy
}
}
}
mutation TransferTag($input: TagTransferInput!) {
transferTag(input: $input) {
success
fromObject {
id
name
tagData {
instanceKey
shortCode
}
}
toObject {
id
name
tagData {
instanceKey
shortCode
}
}
auditLog {
action
timestamp
userId
reason
}
}
}
input TagTransferInput {
tagInstanceKey: String!
fromObjectId: ID!
toObjectId: ID!
reason: String
forceTransfer: Boolean = false
}
I. Analytics and Usage Tracking
query GetCreationAnalytics($organizationId: ID!, $timeRange: TimeRange!) {
getCreationAnalytics(organizationId: $organizationId, timeRange: $timeRange) {
totalObjects
dailyCreationCounts {
date
count
}
topObjectTypes {
typeName
count
percentage
}
creationMethods {
method
count
percentage
}
averageCreationTime
taggedObjectsPercentage
setObjectsCount
}
}
mutation TrackCreationEvent($input: CreationEventInput!) {
trackCreationEvent(input: $input) {
success
eventId
}
}
input CreationEventInput {
objectId: ID!
eventType: CreationEventType!
creationMethod: CreationMethod!
duration: Int
deviceInfo: String
metadata: JSON
}
enum CreationEventType {
OBJECT_CREATED
BATCH_SESSION_STARTED
BATCH_SESSION_COMPLETED
SET_CREATED
TAG_SCANNED
IMAGE_UPLOADED
}
enum CreationMethod {
SINGLE_DESKTOP
SINGLE_MOBILE
BATCH_MOBILE
BULK_IMPORT
API_DIRECT
}
J. Real-time Subscriptions
subscription ObjectCreated($organizationId: ID!, $spatialParentId: ID) {
objectCreated(organizationId: $organizationId, spatialParentId: $spatialParentId) {
id
name
shortCode
status
createdBy {
id
name
}
spatialParent {
id
name
}
isSet
batchId
createdAt
}
}
subscription BatchProgress($batchId: String!) {
batchProgress(batchId: $batchId) {
batchId
totalObjects
completedObjects
failedObjects
currentStatus
estimatedCompletion
lastObjectCreated {
id
name
}
}
}
2. Error Handling
Error Code Enumeration
enum ObjectCreationErrorCode {
# Tag-related errors
INVALID_TAG_FORMAT
TAG_ALREADY_ASSIGNED
TAG_CONFLICT_DIFFERENT_SET
TAG_CRYPTOGRAPHIC_INVALID
# Permission errors
INVALID_ORGANIZATION_ACCESS
INSUFFICIENT_PERMISSIONS
INVALID_SPATIAL_PARENT
# Validation errors
DUPLICATE_OBJECT_NAME
INVALID_OBJECT_TYPE
REQUIRED_FIELD_MISSING
# Set operation errors
SET_CONVERSION_FAILED
SET_ALREADY_COMPLETE
INVALID_SET_PARENT
# Batch operation errors
BATCH_CREATION_FAILED
BATCH_PARTIAL_FAILURE
BATCH_SESSION_EXPIRED
# System errors
IMAGE_REGISTRATION_FAILED
DATABASE_TRANSACTION_FAILED
EXTERNAL_SERVICE_UNAVAILABLE
}
Error Response Format
type Error {
code: ObjectCreationErrorCode!
message: String!
field: String
retryable: Boolean!
details: ErrorDetails
}
type ErrorDetails {
conflictingObject: ObjectInfo
suggestedActions: [String!]
retryAfter: Int
}
3. Database Schema Changes
Table Modifications
-- Object instances table updates
ALTER TABLE object_instances ADD COLUMN short_code VARCHAR(4);
ALTER TABLE object_instances ADD COLUMN is_set BOOLEAN DEFAULT FALSE;
ALTER TABLE object_instances ADD COLUMN batch_id VARCHAR(50);
ALTER TABLE object_instances ADD COLUMN status VARCHAR(20) DEFAULT 'active';
-- Set relationships table
CREATE TABLE set_relationships (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
parent_set_id UUID REFERENCES object_instances(id),
child_object_id UUID REFERENCES object_instances(id),
created_at TIMESTAMP DEFAULT NOW()
);
-- Tag assignments table
CREATE TABLE tag_assignments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
instance_key VARCHAR(100) UNIQUE NOT NULL,
class_key VARCHAR(100),
path VARCHAR(200),
object_id UUID REFERENCES object_instances(id),
assigned_at TIMESTAMP DEFAULT NOW(),
assigned_by UUID REFERENCES auth.users(id)
);
-- Batch sessions table
CREATE TABLE batch_sessions (
id VARCHAR(50) PRIMARY KEY,
organization_id UUID REFERENCES organizations(id),
spatial_parent_id UUID REFERENCES object_instances(id),
created_by UUID REFERENCES auth.users(id),
created_at TIMESTAMP DEFAULT NOW(),
completed_at TIMESTAMP,
status VARCHAR(20) DEFAULT 'active'
);
-- Object types usage tracking
CREATE TABLE object_type_usage (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID REFERENCES organizations(id),
object_type VARCHAR(100),
usage_count INTEGER DEFAULT 1,
last_used TIMESTAMP DEFAULT NOW()
);
-- Object class definitions
CREATE TABLE object_classes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(200) NOT NULL,
description TEXT,
path VARCHAR(500), -- Hierarchical path: "electronics.computers.laptops"
parent_class_id UUID REFERENCES object_classes(id),
organization_id UUID REFERENCES organizations(id), -- NULL for global classes
is_manufacturer_class BOOLEAN DEFAULT FALSE,
manufacturer_key VARCHAR(100), -- For cryptographic verification
created_at TIMESTAMP DEFAULT NOW(),
created_by UUID REFERENCES auth.users(id),
is_active BOOLEAN DEFAULT TRUE
);
-- Object class properties
CREATE TABLE object_class_properties (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
class_id UUID REFERENCES object_classes(id),
name VARCHAR(100) NOT NULL,
property_type VARCHAR(50) NOT NULL, -- TEXT, NUMBER, DATE, BOOLEAN, SELECT, etc.
is_required BOOLEAN DEFAULT FALSE,
default_value TEXT,
validation_rules JSONB, -- JSON validation rules
display_order INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW()
);
-- Tag scan history and audit trail
CREATE TABLE tag_scan_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
instance_key VARCHAR(100) NOT NULL,
scanned_by UUID REFERENCES auth.users(id),
scanned_at TIMESTAMP DEFAULT NOW(),
scan_location JSONB, -- GPS coordinates, spatial context
device_info JSONB, -- Device type, app version, etc.
scan_result VARCHAR(50), -- SUCCESS, CONFLICT, INVALID, etc.
object_id UUID REFERENCES object_instances(id), -- NULL if conflict/invalid
ip_address INET,
user_agent TEXT
);
-- Tag conflict resolution log
CREATE TABLE tag_conflicts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
instance_key VARCHAR(100) NOT NULL,
conflict_type VARCHAR(50), -- ALREADY_ASSIGNED, DIFFERENT_SET, etc.
existing_object_id UUID REFERENCES object_instances(id),
attempted_object_id UUID REFERENCES object_instances(id),
occurred_at TIMESTAMP DEFAULT NOW(),
resolved_at TIMESTAMP,
resolution_action VARCHAR(50), -- REASSIGN, CANCEL, FORCE, etc.
resolved_by UUID REFERENCES auth.users(id),
resolution_reason TEXT
);
-- Creation analytics and metrics
CREATE TABLE creation_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
object_id UUID REFERENCES object_instances(id),
event_type VARCHAR(50) NOT NULL, -- OBJECT_CREATED, BATCH_STARTED, etc.
creation_method VARCHAR(50) NOT NULL, -- SINGLE_DESKTOP, BATCH_MOBILE, etc.
organization_id UUID REFERENCES organizations(id),
created_by UUID REFERENCES auth.users(id),
occurred_at TIMESTAMP DEFAULT NOW(),
duration_ms INTEGER, -- Time taken for creation
device_info JSONB,
metadata JSONB -- Additional event-specific data
);
-- Batch session detailed tracking
ALTER TABLE batch_sessions ADD COLUMN spatial_parent_name VARCHAR(200);
ALTER TABLE batch_sessions ADD COLUMN device_info JSONB;
ALTER TABLE batch_sessions ADD COLUMN session_metadata JSONB;
-- Enhanced object instances for full feature support
ALTER TABLE object_instances ADD COLUMN class_id UUID REFERENCES object_classes(id);
ALTER TABLE object_instances ADD COLUMN class_properties JSONB; -- Dynamic properties
ALTER TABLE object_instances ADD COLUMN creation_method VARCHAR(50);
ALTER TABLE object_instances ADD COLUMN creation_duration_ms INTEGER;
Performance Indices
-- Short code lookups
CREATE INDEX idx_object_instances_short_code ON object_instances(short_code);
-- Tag assignments
CREATE INDEX idx_tag_assignments_instance_key ON tag_assignments(instance_key);
CREATE INDEX idx_tag_assignments_object_id ON tag_assignments(object_id);
-- Batch operations
CREATE INDEX idx_object_instances_batch_id ON object_instances(batch_id);
CREATE INDEX idx_batch_sessions_organization ON batch_sessions(organization_id);
-- Set relationships
CREATE INDEX idx_set_relationships_parent ON set_relationships(parent_set_id);
CREATE INDEX idx_set_relationships_child ON set_relationships(child_object_id);
-- Usage tracking
CREATE INDEX idx_object_type_usage_org ON object_type_usage(organization_id, last_used DESC);
-- Object class indices
CREATE INDEX idx_object_classes_org ON object_classes(organization_id);
CREATE INDEX idx_object_classes_parent ON object_classes(parent_class_id);
CREATE INDEX idx_object_classes_path ON object_classes(path);
CREATE INDEX idx_object_classes_manufacturer ON object_classes(manufacturer_key);
CREATE UNIQUE INDEX idx_object_classes_name_org ON object_classes(name, organization_id);
-- Object class properties
CREATE INDEX idx_class_properties_class ON object_class_properties(class_id);
CREATE INDEX idx_class_properties_order ON object_class_properties(class_id, display_order);
-- Tag scanning and conflict tracking
CREATE INDEX idx_tag_scan_events_key ON tag_scan_events(instance_key);
CREATE INDEX idx_tag_scan_events_user ON tag_scan_events(scanned_by, scanned_at DESC);
CREATE INDEX idx_tag_scan_events_time ON tag_scan_events(scanned_at DESC);
CREATE INDEX idx_tag_conflicts_key ON tag_conflicts(instance_key);
CREATE INDEX idx_tag_conflicts_time ON tag_conflicts(occurred_at DESC);
-- Creation analytics
CREATE INDEX idx_creation_events_object ON creation_events(object_id);
CREATE INDEX idx_creation_events_org_time ON creation_events(organization_id, occurred_at DESC);
CREATE INDEX idx_creation_events_method ON creation_events(creation_method, occurred_at DESC);
CREATE INDEX idx_creation_events_type ON creation_events(event_type, occurred_at DESC);
-- Enhanced object instances
CREATE INDEX idx_object_instances_class ON object_instances(class_id);
CREATE INDEX idx_object_instances_creation_method ON object_instances(creation_method);
4. Implementation Requirements
A. Short Code Generation Logic
function generateShortCode(tagInstanceKey?: string, organizationId: string): string {
if (tagInstanceKey) {
// Extract first 4 characters of Base58-encoded key
return tagInstanceKey.substring(0, 4);
} else {
// Generate sequential number within organization
const count = getObjectCountInOrganization(organizationId);
return (count + 1).toString();
}
}
B. Tag Validation Logic
function validateTag(tagData: TagResolverInput): TagValidationResult {
// 1. Validate Base58 encoding format
if (!isValidBase58(tagData.instanceKey)) {
throw new Error('INVALID_TAG_FORMAT');
}
// 2. For manufacturer tags: verify classKey authenticity
if (tagData.classKey) {
if (!verifyCryptographicSignature(tagData.classKey, tagData.instanceKey)) {
throw new Error('TAG_CRYPTOGRAPHIC_INVALID');
}
}
// 3. Check for existing assignments
const existingAssignment = findTagAssignment(tagData.instanceKey);
if (existingAssignment) {
return { hasConflict: true, existingObjectId: existingAssignment.objectId };
}
return { hasConflict: false };
}
C. Set Tag Migration Logic
function migrateTagFromSetToChild(setId: string, childId: string, tagInstanceKey: string): void {
// Check if tag currently points to set
const currentAssignment = findTagAssignment(tagInstanceKey);
if (currentAssignment?.objectId === setId) {
// Migrate tag from set to child
updateTagAssignment(tagInstanceKey, childId);
logTagMigration(setId, childId, tagInstanceKey);
} else if (currentAssignment && currentAssignment.objectId !== setId) {
// Tag points to different object - conflict
throw new Error('TAG_ALREADY_ASSIGNED');
}
// If no current assignment, proceed with normal assignment
}
D. Batch Transaction Safety
async function batchCreateObjects(input: BatchCreateInput): Promise<BatchCreateResult> {
const transaction = await db.transaction();
try {
const results = [];
for (const objectInput of input.objects) {
try {
const object = await createSingleObject(objectInput, transaction);
results.push({ success: true, tempId: objectInput.tempId, object });
} catch (error) {
results.push({
success: false,
tempId: objectInput.tempId,
error: error.message,
retryable: isRetryableError(error)
});
}
}
await transaction.commit();
return { success: true, results };
} catch (error) {
await transaction.rollback();
throw error;
}
}
5. Performance Requirements
Response Time Targets
- Single Object Creation: < 1 second
- Batch Operations: < 5 seconds for 100 objects
- Tag Resolution: < 200ms
- Search Queries: < 500ms
Scalability Targets
- Concurrent Users: 100+ simultaneous object creation
- Batch Size: Up to 1000 objects per batch
- Database Load: < 80% CPU during peak usage
- Memory Usage: < 2GB per backend instance
6. Security Implementation
Authentication Requirements
- JWT Validation: All mutations require valid JWT token
- Organization Membership: Verify user belongs to target organization
- Permission Checking: Validate create_objects permission
Authorization Logic
function validateObjectCreationPermissions(userId: string, organizationId: string): void {
const membership = getUserOrganizationMembership(userId, organizationId);
if (!membership) {
throw new Error('INVALID_ORGANIZATION_ACCESS');
}
if (!membership.permissions.includes('create_objects')) {
throw new Error('INSUFFICIENT_PERMISSIONS');
}
}
Data Validation
- Input Sanitization: All string inputs sanitized for XSS
- File Validation: Image files validated for type and size
- SQL Injection Prevention: Parameterized queries only
- Rate Limiting: Max 100 requests per minute per user
7. REST Endpoint: Image Registration
POST /register-image/{objectId}
interface ImageRegistrationRequest {
public_url: string;
storage_path: string;
is_main?: boolean;
metadata?: {
width: number;
height: number;
size: number;
format: string;
device_info?: string;
};
}
interface ImageRegistrationResponse {
success: boolean;
image: {
id: string;
url: string;
thumbnailUrl: string;
isMain: boolean;
};
object: {
id: string;
imageUrls: string[];
mainImageUrl: string | null;
};
}
📚 Related Documentation
- API Requirements & Coordination: Development tracking and team coordination
- Frontend Object Creation Requirements: UI/UX specifications
- API Endpoints Reference: Working examples and integration patterns
Technical Specification Last Updated: 2025-07-02