Skip to main content

Tideswell / Jester / Zuiyo β†’ Terra Parity Matrix

How the Current Stack Works

Before comparing, it helps to understand that β€œTideswell” is actually three systems working together:
Applicant fills form β†’ Tideswell (form builder, Firebase auth, MongoDB)
                            ↓ webhook on submit
                        Jester (ingestion middleware, normalizes data β†’ PostgreSQL)
                            ↓ cron sync (Zuiyo)
                        Airtable (reviewer works here, marks outcomes)
                            ↓ outcome sync back (Zuiyo)
                        Tideswell (outcome visible to applicant)
Terra replaces Tideswell and Jester natively. The Airtable sync is built into Terra directly. The open question is the outcome sync back β€” Zuiyo currently writes approval/denial outcomes back to Tideswell so applicants can see them. Terra needs equivalent behavior.

Form Field Types

Field TypeTideswellJester Stores AsTerraStatusNotes
Single line textSingleLineQuestionTEXTText fieldβœ… Parity
Multi-line textSingleLineQuestion (multiLine flag)TEXTText field (multiline variant)βœ… Parity
Radio / checkboxChoiceQuestionTEXT[] arrayChoice fieldβœ… Parity
DropdownChoiceQuestion (displayFormat: dropdown)TEXT[] arrayChoice field (dropdown variant)βœ… Parity
DateDateQuestionDATEDate fieldβœ… ParityBoth support min/max date constraints
NumberNumericalQuestionNUMERICNumber fieldβœ… ParityBoth support integer, whole, currency, decimal
AddressAddressQuestion5+ TEXT columnsAddress fieldβœ… ParityBoth use Smarty for validation
File uploadFilesQuestionfile_id, orig_name, urlFiles fieldβœ… ParityTideswell: Google Drive only. Terra: Supabase Storage + Google Drive
ID verificationIdVerificationQuestion60+ Plaid columnsPlaid IDV fieldβœ… Parity
Bank verificationBankVerificationQuestionaccount_id, routing, maskPlaid Bank fieldβœ… Parity
Info / display blockInfoQuestionNot storedInfo blockβœ… ParityTerra adds markdown + alert variants
Grouped sectionGroupedQuestion (nested container)N/A⚠️ VerifyπŸ”² ValidateTideswell supports nested question groups β€” confirm Terra handles same nesting depth
Repeated / referenced questionRepeatedQuestion (references another question by name)N/A❌ Not foundπŸ”΄ GapTideswell can reference an existing question elsewhere in the form. Terra equivalent unclear
SignatureNot in TideswellN/ASignature fieldβž• Terra extra
PaymentNot in TideswellN/APayment fieldβž• Terra extra

Conditional Logic

CapabilityTideswellTerraStatusNotes
AND groupsβœ…βœ…βœ… Parity
OR groupsβœ…βœ…βœ… Parity
Greater than (numeric)FLOAT_GTgt, gteβœ… Parity
Less than (numeric)FLOAT_LTlt, lteβœ… Parity
Equals / not equalsImpliedeq, neqβœ… Terra moreTerra explicit
Array intersection (multi-select)INTERSECTS_WITHinβœ… Parity
Text contains / starts / ends❌contains, starts_with, ends_withβž• Terra extra
Age-based rules❌minAge, maxAgeβž• Terra extra
Field exists check❌existsβž• Terra extra
Recursive nestingβœ…βœ…βœ… Parity
Reference another question’s valueβœ… (answerRaw by name)βœ…βœ… Parity
Legacy logicInRules (2D array)βœ… (older forms)βŒπŸ”΄ GapSome older forms may use this. Check which active forms rely on it

Submission Storage & Data Integrity

CapabilityTideswell/JesterTerraStatusNotes
Submission IDβœ… <formId><8chars>βœ…βœ… Parity
Status trackingβœ… incomplete / submitted / withdrawnβœ…βœ… Parity
Timestamp trackingβœ… createdAt, submittedAtβœ…βœ… Parity
IP geolocation on submitβœ… address, country, city, lat, lonβœ…βœ… Parity
Language on submitβœ…βœ…βœ… Parity
Outcome field (admin-set, visible to applicant)βœ…βš οΈ VerifyπŸ”² ValidateTideswell has a dedicated outcome field admins set per submission. Verify Terra exposes this to applicants
Submission freezing after submitβœ…βœ…βœ… Parity
Answer match / double-entry verificationβœ… (isAnswerMatchRequired)βœ…βœ… Parity
Upsert on re-submission (same ID)βœ… Jester uses ON CONFLICT DO UPDATE⚠️ VerifyπŸ”² ValidateConfirm Terra handles re-submissions of same ID correctly
Silent failure prevention⚠️ Jester can fail silently on webhook errorsβœ… Betterβœ… Terra betterTerra has queue with retry. Verify retry logic on Airtable sync

Airtable Sync (The Critical Path)

This is the most important section. The Zuiyoβ†’Airtable sync is the handoff to reviewers. If this breaks, reviewers don’t see applications.
CapabilityZuiyo (current)TerraStatusNotes
Postgres β†’ Airtable field mappingβœ… Via struct tags or field name matchingβœ… Native integrationβœ… ParityMechanism differs; outcome same
Supported Airtable field typessingleLineText, email, url, multilineText, phoneNumber, number, currency, singleSelect, multipleSelects, date, dateTime, checkbox, multipleAttachmentsβœ… Most typesπŸ”² ValidateConfirm Terra maps all Zuiyo-supported types
Batch inserts (Airtable API limit)βœ… 10 records/batchβœ…πŸ”² ValidateConfirm Terra respects Airtable rate limits
Retry on Airtable API failureβœ… 3 retries⚠️ VerifyπŸ”² ValidateConfirm Terra retries failed syncs
Rate limitingβœ… 8 concurrent max⚠️ VerifyπŸ”² Validate
Mapping admin UIβœ… Zuiyo has UI for managing columnβ†’field mappingsβœ… Terra has Airtable integration configπŸ”² ValidateConfirm Terra’s mapping config is as flexible as Zuiyo’s
Incremental sync (only new records)βœ… By submitted_at timestamp⚠️ VerifyπŸ”² Validate
Refresh existing records on updateβœ… ~10% refresh each sync to catch updates⚠️ VerifyπŸ”² Validate
Outcome sync: Airtable β†’ Terraβœ… Zuiyo reads outcome field from Airtable, writes back to Tideswell via GraphQL⚠️ UnclearπŸ”΄ Critical gap to verifyThis closes the loop β€” reviewer approves in Airtable, applicant sees status in Terra. Does Terra receive status back from Airtable?
Sync history / logsβœ… Zuiyo UI shows last 5 syncs with detailed logsβœ… Terra has webhook event historyβœ… Parity
Manual sync triggerβœ… Via Zuiyo API⚠️ VerifyπŸ”² Validate
Decision required before validation: The Airtable field mapping currently lives in Zuiyo’s database (jester_airtable_mappings table). For Terra, this mapping can either:
  • Be configured identically to replicate current Zuiyo behavior (1:1 parity)
  • Be redesigned to take advantage of Terra’s richer data model
This needs Brian and David to align β€” it affects how validation is done.

Authentication

CapabilityTideswellTerraStatusNotes
Applicant authenticationFirebase Identity PlatformWorkOSπŸ”² ValidateDifferent providers. Behavior should be equivalent but existing Firebase accounts don’t auto-migrate
Tenant supportβœ… Firebase tenant isolationβœ… WorkOS orgsβœ… Parity
SSO / enterprise OAuthβœ… Firebaseβœ… WorkOSβœ… Parity
MFAβœ… Group-level MFA required flagβœ… WorkOSβœ… Parity
API key auth for automationβœ… <uuid>:<form_id> formatβœ…βœ… Parity
Anonymous / guest submissionsβœ… Groups allow unauthenticated submit⚠️ VerifyπŸ”² ValidateSome programs allow no-account submissions
Existing Tideswell accountsFirebase UIDsN/AπŸ”΄ Migration neededApplicants with existing Tideswell accounts need migration path to WorkOS if they need to log in to Terra

File Uploads

CapabilityTideswellTerraStatusNotes
Google Drive storageβœ… Primary storageβœ… Supportedβœ… Parity
Supabase StorageβŒβœ…βž• Terra extra
Per-question drive folder configβœ… driveFolderId per questionβœ…βœ… Parity
File size limit16 MBConfigurableβœ… Parity
MIME type restrictionsβœ… accept fieldβœ…βœ… Parity
File count limitsβŒβœ…βž• Terra extra

Notifications

CapabilityTideswellTerraStatusNotes
Email on submission❌ (webhook-based only)βœ… Resendβž• Terra extra
SMSβŒβœ… Twilioβž• Terra extra
Plain text emailβœ… SendGridβœ…βœ… Parity
HTML/template emailβŒβœ…βž• Terra extra
Webhook on submitβœ… (primary mechanism)βœ…βœ… Parity
Webhook retry (exponential backoff)βœ… 12 attempts, ~24hr windowβœ…πŸ”² ValidateConfirm Terra’s retry behavior matches or exceeds Tideswell’s
Webhook event historyβœ…βœ…βœ… Parity

Admin Interface

CapabilityTideswellTerraStatusNotes
Form builderβœ…βœ…βœ… Parity
Drag-drop reorderβœ…βœ…βœ… Parity
Submission list viewβœ…βœ…βœ… Parity
Filter submissions by statusβœ…βœ…βœ… Parity
Update submission statusβœ…βœ…βœ… Parity
Update outcome field (admin-set)βœ…βš οΈ VerifyπŸ”² Validate
CSV bulk importβœ… With header-to-question mapping⚠️ VerifyπŸ”² ValidateCheck if Terra has CSV import for submissions
CSV exportβœ…βœ…βœ… Parity
i18n string customization per formβœ…βœ…βœ… Parity
Groups / team submissionsβœ… Multiple accounts per group⚠️ VerifyπŸ”² ValidateTideswell supports group-scoped submissions where multiple accounts can view the same submission
Featured questions (submission preview)βœ… Select which questions show in list view⚠️ VerifyπŸ”² Validate
Form scheduling (auto-publish / auto-close)βœ…βœ…βœ… Parity
Post-submit redirect URLβœ…βœ…βœ… Parity

Validation

CapabilityTideswellTerraStatusNotes
Required / optionalβœ…βœ…βœ… Parity
Min / max lengthβœ…βœ…βœ… Parity
Numeric type validationβœ… integer, whole, currency, floatβœ…βœ… Parity
Date min / maxβœ…βœ…βœ… Parity
Address validation (Smarty)βœ…βœ…βœ… Parity
Answer match (double-entry)βœ… isAnswerMatchRequiredβœ…βœ… Parity
Age-based validationβŒβœ…βž• Terra extra
Legacy logicInRulesβœ… (some older forms)βŒπŸ”΄ GapCheck which active forms use this pattern

Summary: Gaps That Block v1

These must be resolved before Terra can replace Tideswell/Jester/Zuiyo for any live program:
#GapSeverityOwnerAction
1Outcome sync: Airtable β†’ TerraπŸ”΄ CriticalDavidVerify or build β€” reviewers approve in Airtable, applicants must see status in Terra
2GroupedQuestion nesting🟑 HighDavid + MayTest: does Terra support the same nesting depth as Tideswell’s GroupedQuestion?
3RepeatedQuestion🟑 HighDavidDoes Terra have a way to reference/reuse a question from elsewhere in the form? If not, check which forms use this
4Legacy logicInRules🟑 HighBrian + MayIdentify which active forms use the legacy 2D rule format β€” can they be rewritten as standard conditions?
5Anonymous / guest submissions🟑 HighDavidConfirm Terra supports unauthenticated submissions for programs that don’t require applicant accounts
6Airtable sync retry reliability🟑 HighDavidConfirm Terra retries failed Airtable syncs and that no submissions can silently fail to sync
7Outcome field exposed to applicant🟑 HighDavid + MayConfirm the admin-set outcome (e.g., β€œApproved: $3,000”) is visible to the applicant in Terra
8Airtable mapping config🟑 HighBrian + DavidDecide: replicate Zuiyo mapping 1:1, or redesign? This decision gates the validation checklist

Validation Checklist (to be completed by Brian + May)

Once the gaps above are resolved, this is the sign-off list for Terra v1 production.

Form Building

  • All field types used in current active programs exist in Terra
  • Conditional logic on at least one complex form produces same show/hide behavior as Tideswell
  • Multi-language form renders correctly in at least 2 languages
  • Form scheduling (auto-publish, auto-close) works as expected

Submission Integrity

  • Test submission on a real form: data lands in Terra database completely and accurately
  • File upload attaches correctly to submission
  • Failed submission does not silently disappear β€” produces visible error
  • Re-submission of same ID behaves correctly (upsert, not duplicate)

Airtable Sync

  • Sync a test submission: correct fields appear in correct Airtable columns
  • Sync failure is logged and retried β€” data does not silently fail to reach Airtable
  • Outcome sync: reviewer marks outcome in Airtable β†’ applicant sees updated status in Terra

Security

  • Submission is not accessible without proper authorization
  • PII does not appear in error logs or Sentry
  • File uploads are not publicly accessible URLs

Admin

  • Submission list shows correct data for a test program
  • Status can be updated on a submission
  • Outcome field can be set by admin and is visible to applicant
Sign-off: Brian _______ May _______ Date _______

What Terra Has That Tideswell Does Not

These are capabilities Terra ships with that can be unlocked after v1 is stable:
  • Field block library (reusable groups of fields across forms)
  • Per-field encryption for PII
  • Audit logging on all data changes
  • SMS notifications (Twilio)
  • Rich email templates (Resend)
  • Program hierarchy (workspace β†’ program β†’ form)
  • Form versioning and immutable submission records
  • Age-based conditional logic operators
  • Advanced file handling (count limits, size limits, Supabase Storage)
  • Signature field
  • Markdown info blocks with alert variants