Skip to main content

Core Concepts

Before diving into code, understand the mental models that shape Terra’s design.
Terra is a forms platform for government benefit programs. But it’s not just a form builder—it’s an intake infrastructure that handles identity, file storage, multi-language support, and downstream integrations. To work effectively with the codebase, internalize these five core concepts.

1. Forms Are Trees, Not Tables

Traditional form builders store fields in database tables. Terra stores entire forms as recursive JSON trees. This design emerged from a specific problem: government forms have deeply nested conditional logic. “If you have dependents, list them. If any dependent has a disability, show the accommodation questions.” Relational tables require complex joins for this; JSON trees handle it naturally. What this means for you:
  • Form definitions live in a single JSONB column
  • Adding new field types doesn’t require migrations
  • The FormElement type is recursive—groups contain elements that can themselves be groups
  • Export/import works by serializing the entire tree
See Schema Design for the full implementation.

2. Identity Is Decoupled

Terra separates authentication (who are you?) from authorization (what can you do?). WorkOS handles authentication—login flows, SSO with enterprise identity providers, session tokens. But WorkOS doesn’t know about your forms or permissions. Supabase stores your data, but we don’t use Supabase Auth. Instead, server actions use a service_role client that bypasses Row Level Security, then manually enforce permissions. Why this split? Government agencies often require SAML/OIDC integration with Azure AD or Okta. WorkOS makes this trivial. Meanwhile, keeping authorization in application code (not RLS) makes permission logic explicit and auditable. What this means for you:
  • The getSession() helper returns WorkOS user data
  • All Supabase queries use supabaseAdmin (service role)
  • Permission checks happen in server actions, not database policies
  • Roles are stored in a local user_profiles table, not WorkOS
See Authentication and Authorization for details.

3. Submissions Succeed, Integrations Retry

When an applicant submits a form, many things need to happen: save to database, sync to Airtable, send confirmation email, fire webhooks. If the Airtable sync fails, should the submission fail? No. The applicant’s data is sacred. We save it first, then process everything else asynchronously. The async_operations table is a persistent queue. Jobs have states (pending, processing, completed, failed), retry with exponential backoff, and eventually land in a dead-letter state for manual review. What this means for you:
  • Submission success is independent of integration success
  • Look at async_operations to debug webhook failures
  • Background jobs run via /api/queue/process (cron-triggered)
  • Never block submission on external API calls
See Queue Architecture for the full system.

4. Multi-Tenancy Through Folders

Terra supports multiple organizations, but not through a traditional tenant model. Instead, folders (internally called workspaces) provide logical grouping. Each folder can have:
  • Its own custom domain
  • Shared branding (logo, colors)
  • Team members with folder-scoped access
Agencies are a layer above folders—an agency can have multiple folders across different programs. This enables a single organization to run many benefit programs under different brands. What this means for you:
  • Forms belong to folders (nullable—some are “uncategorized”)
  • Custom domains are resolved in middleware
  • Team permissions cascade: org admins see all, folder members see their folder
  • The agencies system is for external partners managing multiple clients
See Multi-Tenancy for the full model.

5. Security Is Layered

Government platforms handle SSNs, bank accounts, medical records. A single security bug could expose thousands of applicants. Terra uses defense-in-depth: every security-sensitive operation has multiple independent checks. For file uploads:
  1. Client: cleanFileName() removes path traversal attempts
  2. Server: buildSafeStoragePath() constructs validated paths
  3. Storage: sanitizeStoragePath() validates before saving
For redirects:
  1. Input: Parse URL and check protocol
  2. Validation: Ensure same-origin or allowed list
  3. Default: Fail-secure to home page if anything is suspicious
What this means for you:
  • Use centralized security utilities in src/lib/security.ts
  • Never trust user input, even after client validation
  • When in doubt, fail secure (deny access, redirect home)
  • XSS: Always sanitize with DOMPurify before rendering HTML
See Security for implementation details.

How These Concepts Connect

A typical flow:
  1. User authenticates via WorkOS
  2. Permission check determines what they can do
  3. Form builder modifies the JSON schema
  4. Schema renders into a public form
  5. Applicant submits → data saved to Supabase
  6. Queue picks up async jobs
  7. Integrations sync to external systems

Next Steps