Designing Data-Intensive Applications
Case 10

Steps, Drafts, and Validation

Wizards span sessions and devices. Persist partial progress; validate per step and on submit.

Mortgage and insurance forms take days. Users expect to pause on mobile and finish on desktop. That requires durable draft storage, not session cookies.

typescript — Multistep draft autosave
// Autosave wizard draft across sessions
async function saveDraft(userId: string, formVersion: number, step: number, data: Json) {
  await db.formDrafts.upsert({
    where: { userId_formVersion: { userId, formVersion } },
    create: { userId, formVersion, step, data, updatedAt: new Date() },
    update: { step, data, updatedAt: new Date() },
  });
}
Stripe at scale

Connect onboarding is a hosted multistep form with saved progress — merchants resume KYC without re-entering verified fields.

Key Takeaways
  • Explicit step graph: some steps skippable based on prior answers.
  • Draft record keyed by user + form version; autosave debounced.
  • Server-side validation authoritative — client hints are UX only.
  • Schema versioning: in-flight drafts pinned to form version they started.
  • Resume token in email link maps to draft without exposing PII in URL.
  • Final submit is idempotent — duplicate clicks do not create two applications.
wizarddraftvalidationstate machineautosave