Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs-terra.withunify.org/llms.txt

Use this file to discover all available pages before exploring further.

Server Actions

Terra uses Next.js Server Actions for all data mutations.

Action Files

FilePurpose
airtable.tsAirtable OAuth and sync
notifications.tsEmail/SMS sending
insights.tsAnalytics queries
applicants.tsApplicant management
status.tsSubmission status
domains.tsCustom domain config
workspaces.tsFolder management
agencies.tsAgency management
form-versions.tsDraft/publish
webhooks.tsWebhook config
team.tsPermissions
settings.tsOrg settings

Common Patterns

Permission Check

"use server";

export async function updateSubmission(id: string, data: Data) {
  const user = await requireAdmin();  // Throws if unauthorized

  await supabaseAdmin
    .from("form_submissions")
    .update(data)
    .eq("id", id);

  await logAudit(user.id, "submission.updated", { id });

  return { success: true };
}

ActionResult Pattern

type ActionResult<T> =
  | { success: true; data: T }
  | { success: false; error: string };

export async function createForm(data: FormData): Promise<ActionResult<Form>> {
  try {
    const user = await requireAdmin();
    const form = await insertForm(data);
    return { success: true, data: form };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

Revalidation

import { revalidatePath } from "next/cache";

export async function publishForm(id: string) {
  await updateFormStatus(id, "published");
  revalidatePath(`/forms/${id}`);
  revalidatePath("/forms");
}

Database Schema

Table reference

Authorization

Permission checks