> ## 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.

# Tideswell vs Terra

> How Terra relates to Tideswell and our approach to building a modern successor

# Tideswell vs Terra

> Terra is a modern reimagining of Tideswell, built with lessons learned from years of operating government intake infrastructure.

Terra isn't a fork of Tideswell—it's a clean-slate rebuild that achieves feature parity while fundamentally rethinking the architecture. This page explains the relationship, the differences, and why we made the choices we did.

***

## The Relationship

**Tideswell** was the original government intake platform, built to handle benefit applications at scale. It served its purpose well, processing hundreds of thousands of applications. But like all software, it accumulated technical debt.

**Terra** is the successor. Same mission, new architecture. We took what worked in Tideswell, fixed what didn't, and rebuilt from first principles with modern tools.

```mermaid theme={null}
flowchart LR
    subgraph Tideswell["Tideswell (Legacy)"]
        T1[MongoDB]
        T2[Express + EJS]
        T3[Custom Auth]
        T4[File + Memory Queue]
    end

    subgraph Terra["Terra (Current)"]
        N1[PostgreSQL]
        N2[Next.js + RSC]
        N3[WorkOS Auth]
        N4[Database Queue]
    end

    Tideswell -->|Lessons Learned| Terra
```

***

## Feature Parity Status

Terra has achieved full feature parity with Tideswell. Here's how the features map:

### Core Intake Features

| Feature           | Tideswell  | Terra            | Notes                          |
| ----------------- | ---------- | ---------------- | ------------------------------ |
| Form builder      | Drag-drop  | Drag-drop        | Terra uses dnd-kit, modern UX  |
| Conditional logic | JSON rules | JSON conditions  | Same power, cleaner syntax     |
| Multi-language    | ✓          | ✓                | Terra has auto-translation     |
| File uploads      | S3         | Supabase + Drive | Terra adds Google Drive option |
| Submissions       | MongoDB    | PostgreSQL       | Terra adds encryption at rest  |
| Status tracking   | ✓          | ✓                | Same statuses                  |
| Applicant portal  | ✓          | ✓                | Terra rebuilt with RSC         |

### Form Lifecycle

| Feature                  | Tideswell       | Terra          | Notes                                 |
| ------------------------ | --------------- | -------------- | ------------------------------------- |
| Draft/Published versions | ✓               | ✓              | Terra stores both schemas             |
| Scheduled publishing     | `autoPublishAt` | `published_at` | Same feature, clearer naming          |
| Scheduled closing        | `autoCloseAt`   | `closes_at`    | Same feature, clearer naming          |
| Form freezing            | `frozen` flag   | `frozen` flag  | Prevents edits after first submission |
| Outcome field            | ✓               | ✓              | Applicant-visible result text         |

### Identity & Verification

| Feature            | Tideswell     | Terra              | Notes                         |
| ------------------ | ------------- | ------------------ | ----------------------------- |
| ID verification    | Plaid         | Plaid              | Same integration              |
| Bank verification  | Plaid         | Plaid              | Same integration              |
| Address lookup     | Smarty        | Smarty             | Same integration              |
| Anonymous forms    | ✓             | ✓                  | `is_anonymous` flag           |
| Applicant identity | Account model | `applicants` table | Terra normalizes across forms |

### Integrations

| Feature             | Tideswell       | Terra           | Notes                            |
| ------------------- | --------------- | --------------- | -------------------------------- |
| Webhooks            | Custom triggers | Webhook configs | Terra adds event history         |
| Airtable sync       | ✓               | ✓               | Terra adds connection testing    |
| Email notifications | Custom          | Resend          | Terra uses React Email templates |
| SMS notifications   | Twilio          | Twilio          | Same integration                 |
| Google Drive        | ✓               | ✓               | File uploads to shared drives    |

### Compliance & Audit

| Feature             | Tideswell       | Terra                 | Notes                        |
| ------------------- | --------------- | --------------------- | ---------------------------- |
| Audit logging       | MongoDB events  | `audit_logs` table    | Terra is more comprehensive  |
| Geolocation capture | IP + Cloudflare | IP + Vercel/CF        | Same data, anonymized        |
| PII encryption      | Partial         | Field-level           | Terra encrypts at submission |
| Data retention      | Manual          | Soft delete + cleanup | Terra has automated cleanup  |

***

## Architectural Differences

### Database: MongoDB → PostgreSQL

**Why we changed:**

| MongoDB (Tideswell) | PostgreSQL (Terra)    |
| ------------------- | --------------------- |
| Flexible schema     | Flexible via JSONB    |
| Document queries    | SQL + JSONB operators |
| Manual relations    | Foreign keys          |
| GridFS for files    | Supabase Storage      |
| Mongoose ODM        | Raw SQL + DAL         |

PostgreSQL gives us:

* **ACID transactions** for multi-step operations
* **Foreign key constraints** that prevent orphaned records
* **Row Level Security** at the database layer
* **JSONB** for schema flexibility without sacrificing structure

### Auth: Custom → WorkOS

**Why we changed:**

Tideswell rolled its own authentication. It worked, but required ongoing maintenance for security patches, session management, and OAuth providers.

Terra uses WorkOS because:

* SSO (SAML, OIDC) is built-in for enterprise clients
* MFA is handled by the provider
* Security patches are their responsibility
* We focus on intake, not auth

### Queue: File + Memory → Database

**Why we changed:**

Tideswell used a file-based queue with in-memory fallback. This caused problems:

* Jobs lost on server restart
* No visibility into queue state
* Hard to debug failed operations

Terra uses a database-backed queue:

```sql theme={null}
-- Every async operation is a row
CREATE TABLE async_operations (
  id UUID PRIMARY KEY,
  operation_type TEXT,
  status TEXT DEFAULT 'pending',
  payload JSONB,
  attempts INTEGER DEFAULT 0,
  max_attempts INTEGER DEFAULT 3,
  next_attempt_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW()
);
```

Benefits:

* **Durable**: Jobs survive restarts
* **Visible**: Query the table to see queue health
* **Debuggable**: Failed jobs have error messages
* **Scalable**: Multiple workers can claim jobs

### Frontend: Express + EJS → Next.js + RSC

**Why we changed:**

| Express/EJS (Tideswell)  | Next.js/RSC (Terra)      |
| ------------------------ | ------------------------ |
| Server-rendered HTML     | Server Components        |
| jQuery for interactivity | React for interactivity  |
| Manual bundling          | Automatic code splitting |
| API routes for data      | Server Actions           |
| Separate admin app       | Unified app              |

React Server Components give us:

* **Type safety** across client/server boundary
* **Automatic code splitting** per route
* **Streaming** for large pages
* **Server Actions** that are just function calls

***

## What We Kept

Not everything changed. These patterns worked well in Tideswell and survived into Terra:

### JSON Form Schema

Both platforms store form definitions as JSON. The schema structure is similar:

```typescript theme={null}
// Works in both platforms (with minor differences)
{
  elements: [
    { type: "text", id: "name", label: { en: "Full Name" } },
    { type: "choice", id: "program", options: [...] },
    { type: "group", id: "address", elements: [...] }
  ]
}
```

### Async-First Submission Flow

Both platforms follow the same pattern:

1. Validate and save submission (sync)
2. Queue integrations (async)
3. Process queue (background worker)

This ensures submissions never fail due to integration issues.

### Multi-Language as Core

Both platforms treat translations as first-class citizens. Every label, error message, and piece of content supports multiple languages through the `I18nString` pattern.

### Audit Everything

Both platforms log every significant action. The implementation differs (MongoDB events vs PostgreSQL table), but the philosophy is identical.

***

## Migration Path

Moving from Tideswell to Terra isn't automatic—the data models are different enough that a migration script is required. Key mappings:

| Tideswell                 | Terra                                    |
| ------------------------- | ---------------------------------------- |
| `Form` document           | `forms` row + JSONB schema               |
| `Submission` document     | `submissions` row + encrypted JSONB data |
| `Account` document        | `applicants` row                         |
| `WebhookTrigger` document | `webhook_configs` row                    |
| `WebhookEvent` document   | `webhook_events` row                     |
| `Question` embedded       | Element in schema JSONB                  |

The form schema itself is largely compatible—Terra can import Tideswell form definitions with minor transformations.

***

## Why Not Fork?

We could have forked Tideswell and incrementally improved it. We didn't because:

1. **Tech debt compounds**: Tideswell's architecture made certain improvements expensive. Changing the database, auth system, or queue would have required touching every file.

2. **Clean slate enables experimentation**: We could try RSC, Zustand, Zod, and other modern tools without worrying about breaking existing code.

3. **Documentation opportunity**: A fresh codebase meant we could document everything from day one, rather than trying to document organic growth.

4. **Type safety throughout**: TypeScript in a greenfield project is trivial. TypeScript retrofitted onto a JavaScript codebase is painful.

The tradeoff: we lost Tideswell's battle-tested edge cases. But we gained a codebase that's maintainable for the next decade.

***

## Going Forward

Terra is now the primary platform. Tideswell remains operational for existing deployments, but new features land in Terra first.

Our commitment:

* **Feature parity**: Anything Tideswell can do, Terra can do
* **Migration support**: We'll help teams move from Tideswell to Terra
* **Shared learnings**: Bugs found in Tideswell inform Terra's design

***

## Summary

| Aspect    | Tideswell     | Terra           |
| --------- | ------------- | --------------- |
| Database  | MongoDB       | PostgreSQL      |
| Framework | Express + EJS | Next.js + RSC   |
| Auth      | Custom        | WorkOS          |
| Queue     | File + Memory | Database        |
| Language  | JavaScript    | TypeScript      |
| State     | Redux         | Zustand         |
| Forms     | Formik        | react-hook-form |
| Styling   | SCSS          | Tailwind        |

**Same mission. Modern architecture. Lessons learned.**

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Design Philosophy" icon="lightbulb" href="/foundation/design-philosophy">
    The principles behind Terra's decisions
  </Card>

  <Card title="Core Concepts" icon="diagram-project" href="/foundation/core-concepts">
    Mental models for understanding Terra
  </Card>
</CardGroup>
