Work orders
Lists and gets work orders for the current tenant; create, transition status, complete, log time; list attachments and update attachment metadata. Set tenant context before calling these methods.
End-user CMMS flows: request portal (submit and track my requests), SLA rules, acknowledgment, and breach views are covered in Request portal and SLA. Asset downtime (availability events) is under Asset downtime.
List work orders
List all work orders for the current tenant (from v_work_orders).
client.workOrders.list()
await client.setTenant(tenantId)
// Refresh session so JWT carries tenant_id, then:
const workOrders = await client.workOrders.list()
// Returns WorkOrderRow[]
Get by ID
Fetch a single work order by ID.
client.workOrders.getById(id)
const workOrder = await client.workOrders.getById('uuid-of-work-order')
// Returns WorkOrderRow | null
Create work order
Create a new work order. Returns the new work order UUID.
client.workOrders.create(params)
const workOrderId = await client.workOrders.create({
tenantId: 'uuid-of-tenant',
title: 'Repair HVAC unit',
description: 'Inspect and repair unit 3B',
priority: 'medium',
maintenanceType: 'corrective',
assignedTo: 'uuid-of-user',
locationId: 'uuid-of-location',
assetId: 'uuid-of-asset',
dueDate: '2025-03-01',
pmScheduleId: null,
projectId: null, // optional, for cost roll-up by project
})
// Returns string (UUID)
- Name
tenantId- Description
Required. Tenant UUID.
- Name
title- Description
Required. Work order title.
- Name
description- Description
Optional. Description.
- Name
priority- Description
Optional. Default
medium. Priority key.
- Name
maintenanceType- Description
Optional. Maintenance type key.
- Name
assignedTo- Description
Optional. Assignee user UUID.
- Name
locationId- Description
Optional. Location UUID.
- Name
assetId- Description
Optional. Asset UUID.
- Name
dueDate- Description
Optional. ISO date string.
- Name
pmScheduleId- Description
Optional. PM schedule UUID.
- Name
projectId- Description
Optional. Project UUID for cost roll-up by project. See Projects and Costs & lifecycle.
Transition status
Move a work order to a new status (e.g. from open to in_progress).
client.workOrders.transitionStatus(params)
await client.workOrders.transitionStatus({
tenantId: 'uuid-of-tenant',
workOrderId: 'uuid-of-work-order',
toStatusKey: 'in_progress',
})
Complete work order
Mark a work order as completed (transition to completed status). You can optionally record cause and resolution when completing.
client.workOrders.complete(params)
await client.workOrders.complete({
tenantId: 'uuid-of-tenant',
workOrderId: 'uuid-of-work-order',
cause: 'Worn bearing caused vibration',
resolution: 'Replaced bearing and realigned motor',
})
Log time
Log time spent on a work order. Returns the time entry UUID.
client.workOrders.logTime(params)
const timeEntryId = await client.workOrders.logTime({
tenantId: 'uuid-of-tenant',
workOrderId: 'uuid-of-work-order',
minutes: 60,
entryDate: '2025-02-03',
userId: null,
description: 'Replaced filter',
})
// Returns string (UUID)
- Name
tenantId- Description
Required. Tenant UUID.
- Name
workOrderId- Description
Required. Work order UUID.
- Name
minutes- Description
Required. Number of minutes.
- Name
entryDate- Description
Optional. ISO date string.
- Name
userId- Description
Optional. User UUID. Defaults to current user.
- Name
description- Description
Optional. Work description.
Attachments overview
Attachments use Supabase Storage and a database trigger: there is no RPC to “add” an attachment. You upload a file to the attachments bucket with path tenant_id/work_order/work_order_id/filename (three folder segments before the filename). A trigger creates app.files and app.entity_attachments. The SDK provides list attachments and update attachment metadata; use Storage for upload and signed URLs.
| Action | SDK / API |
|---|---|
| Create attachment | client.supabase.storage.from('attachments').upload(path, file, opts). Path: tenant_id/work_order/work_order_id/uuid_filename; trigger creates records. |
| List attachments | client.workOrders.listAttachments(workOrderId). Returns WorkOrderAttachmentRow[] with id, bucket_id, storage_path, filename, label, kind, etc. |
| Get file URL | client.supabase.storage.from(row.bucket_id).createSignedUrl(row.storage_path, expiresIn). |
| Update label/kind | client.workOrders.updateAttachmentMetadata({ attachmentId, label?, kind? }). |
Set tenant context with client.setTenant(tenantId) before listing or uploading.
Upload attachment
Upload the file to the attachments bucket. The path must be {tenantId}/work_order/{workOrderId}/{uuid}_{filename} (folder segments are tenant, entity type, entity id). Optional metadata (tenant_id, entity_type, entity_id, label, kind, document fields) may be passed if your Supabase version supports it; otherwise set label/kind later via rpc_update_entity_attachment_metadata.
Upload to attachments bucket
await client.setTenant(tenantId)
const path = `${tenantId}/work_order/${workOrderId}/${crypto.randomUUID()}_${file.name}`
const { data, error } = await client.supabase.storage
.from('attachments')
.upload(path, file, {
contentType: file.type ?? 'application/octet-stream',
upsert: false,
metadata: {
tenant_id: tenantId,
entity_type: 'work_order',
entity_id: workOrderId,
label: 'Before photo', // optional
kind: 'photo', // optional
},
})
if (error) throw error
// Trigger creates app.files + entity_attachments; no attachment UUID returned from upload.
// To get the new attachment id, list v_work_order_attachments for this work_order_id and take the latest.
The uploader must be a tenant member and either assigned to the work order or have workorder.edit permission; otherwise Storage RLS rejects the upload.
List attachments
List attachments for a work order. Returns rows with id, work_order_id, file_id, bucket_id, storage_path, filename, label, kind, created_by_name, created_at. Use bucket_id and storage_path with createSignedUrl (see next section).
client.workOrders.listAttachments(workOrderId)
await client.setTenant(tenantId)
const attachments = await client.workOrders.listAttachments(workOrderId)
// Returns WorkOrderAttachmentRow[] (ordered by created_at desc)
// Use row.bucket_id and row.storage_path for createSignedUrl.
Raw: query v_work_order_attachments
await client.setTenant(tenantId)
const { data: attachments, error } = await client.supabase
.from('v_work_order_attachments')
.select('id, work_order_id, file_id, bucket_id, storage_path, filename, label, kind, created_by_name, created_at')
.eq('work_order_id', workOrderId)
.order('created_at', { ascending: false })
if (error) throw error
Get signed URL
Attachments are stored in a private bucket. Do not store permanent URLs. For each row from listAttachments, call createSignedUrl with bucket_id and storage_path to get a short-lived URL (e.g. 1 hour). RLS on storage.objects is evaluated when creating the signed URL; only users who can read the linked work order receive a URL.
Create signed URL for an attachment row
// row is a WorkOrderAttachmentRow from client.workOrders.listAttachments(workOrderId)
const { data, error } = await client.supabase.storage
.from(row.bucket_id)
.createSignedUrl(row.storage_path, 3600) // 3600 seconds = 1 hour
if (error) throw error
// data.signedUrl: use for display or download
Update attachment metadata
Set or change the label and/or kind after upload (e.g. when Storage metadata was not used). The caller must be a tenant member and either the attachment creator or an admin/manager. Get attachmentId from client.workOrders.listAttachments(workOrderId) (row id).
client.workOrders.updateAttachmentMetadata(params)
await client.workOrders.updateAttachmentMetadata({
attachmentId: 'uuid-from-list-attachments',
label: 'Before photo',
kind: 'photo',
})
Raw: rpc_update_entity_attachment_metadata
await client.supabase.rpc('rpc_update_entity_attachment_metadata', {
p_attachment_id: attachmentId,
p_label: 'Before photo',
p_kind: 'photo',
})
- Name
attachmentId- Description
Required. Attachment UUID (row
idfromlistAttachments).
- Name
label- Description
Optional. Label. Max 255 characters.
- Name
kind- Description
Optional. Kind key (e.g.
photo,document); format a-z0-9_.