Skip to content

The Document Lifecycle: A Zero-Trust Approach

On legacy enterprise platforms, file uploads are a notorious security minefield and a performance bottleneck. They typically require piping sensitive data through the application server, creating complex state management, and exposing a significant attack surface.

Simple treats file handling as a solved, secure-by-design primitive.

Our entire document lifecycle is built on a Zero-Trust architecture. The core principle is simple but powerful: your application server never touches file content. The user's browser uploads files directly to secure, isolated storage. This design provides unparalleled security, effortless scalability, and a revolutionary developer experience.

The Developer Experience: The Pending Handle

To enable powerful, real-time workflows (like AI extraction) the moment a user adds a file, the platform uses a concept called a Pending Handle.

A Pending Handle is a secure, temporary JSON object that acts as a pointer to a file that has been selected by the user but is still in the process of being uploaded to permanent storage. It is created instantly when a file is added to a form.

This Pending Handle contains all the necessary metadata about the file:

  • file_hash: The SHA-256 hash of the file content.
  • filename: The original name of the file.
  • size: The file size in bytes.
  • mime_type: The file's MIME type.
  • pending: true: A flag indicating the file is not yet in permanent storage.

The immediate availability of this handle is what makes the Simple Platform's document processing so powerful.

The End-to-End Flow: From Upload to Insight

The moment a user drops a file onto a form, a seamless, secure, and event-driven process begins. As a developer, you only need to care about the first and last steps; the platform transparently handles the rest.

The Magic

Notice that your Record Behavior does not care whether the file is "pending" or "permanent." You simply receive a handle and use it. The platform's SDK and backend services transparently handle the underlying state, whether that means streaming a file that's still being uploaded or fetching one that's already in storage.

Working with Documents in Record Behaviors

Accessing document handles in your scripts is straightforward. The value of a document field is either a single DocumentHandle object or an array of them.

Single File Fields

For fields that accept a single document, the value is a single handle object or null.

javascript
export default async ({ $form, $ai }) => {
  if ($form.updated('invoice_pdf')) {
    const documentHandle = $form('invoice_pdf').value();

    if (documentHandle) {
      // Pass the handle directly to the AI engine.
      const { data } = await $ai.extract(documentHandle, {
        prompt: "Extract the total amount.",
        schema: { /* ... */ }
      });
      
      $form('total_amount').set(data.total_amount);
    }
  }
}

Multiple File Fields

For fields configured with multiple: true, the value is an array of DocumentHandle objects.

javascript
export default async ({ $form, $ai }) => {
  if ($form.updated('receipt_images')) {
    const allHandles = $form('receipt_images').value() || [];

    // You can process all of them...
    const allTotals = await Promise.all(
      allHandles.map(handle => 
        $ai.extract(handle, { prompt: "Extract total" })
      )
    );
    const combinedTotal = allTotals.reduce((sum, result) => sum + result.data.total, 0);
    $form('combined_total').set(combinedTotal);

    // ...or just the most recently added one.
    const latestHandle = allHandles[allHandles.length - 1];
    if (latestHandle) {
      // Process the latest receipt
    }
  }
}

Next Steps

Now that you understand the document lifecycle, you're ready to use the APIs.