<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="A chronological record of Unravel migration work across product, cloud, data, SDK, and backend systems.">
<title>Migration Control Map | Unravel</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700&family=Source+Sans+3:opsz,wght@8..60,400;8..60,500;8..60,600;8..60,700&display=swap" rel="stylesheet">
<style>
:root { --paper: #f4eddf;
--paper: oklch(95.5% 0.017 78);
--paper-bright: #fbf7ee;
--paper-bright: oklch(98% 0.012 78);
--ink: #24231f;
--ink: oklch(24% 0.015 72);
--ink-soft: #5f594e;
--ink-soft: oklch(45% 0.018 72);
--line: #cfc3b2;
--line: oklch(82% 0.025 75);
--signal: #ed5a22;
--signal: oklch(64% 0.21 41);
--signal-deep: #9d3212;
--signal-deep: oklch(44% 0.16 40);
--signal-wash: #f7c8a8;
--signal-wash: oklch(84% 0.095 50);
--sage: #aeba9f;
--sage: oklch(75% 0.055 135);
--focus: #174f91;
--focus: oklch(43% 0.13 251);
--display: "Barlow Condensed", "Arial Narrow", sans-serif;
--body: "Source Sans 3", "Segoe UI", sans-serif;
--paper: #f4f6f9;
--paper: oklch(96.7% 0.015 257);
--paper-bright: #fbfdff;
--paper-bright: oklch(99.1% 0.01 257);
--ink: #161a24;
--ink: oklch(15% 0.02 262);
--ink-soft: #5a6273;
--ink-soft: oklch(48% 0.04 260);
--line: #dde3ea;
--line: oklch(88% 0.03 257);
--signal: #2f56bd;
--signal: oklch(48% 0.15 260);
--signal-deep: #1e3e8e;
--signal-deep: oklch(35% 0.18 260);
--signal-wash: #d9e2fa;
--signal-wash: oklch(87% 0.09 258);
--sage: #8fa58a;
--sage: oklch(77% 0.04 130);
--focus: #1f4ea0;
--focus: oklch(43% 0.12 260);
--display: -apple-system, "system-ui", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
--body: -apple-system, "system-ui", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}
⋯ 49 unchanged lines
}
.site-header { position: sticky;
top: 0;
z-index: 60;
display: grid;
grid-template-columns: 1fr auto;
gap: 2rem;
align-items: center;
min-height: 5rem;
padding: 1rem clamp(1rem, 4vw, 4.5rem);
border-bottom: 1px solid var(--line);
background: var(--paper-bright);
min-height: 3.75rem;
padding: 0.7rem clamp(1rem, 4vw, 4.5rem);
border-bottom: 1px solid color-mix(in oklch, var(--line) 72%, transparent);
background: color-mix(in oklch, var(--paper) 88%, transparent);
backdrop-filter: blur(6px);
}
.wordmark { display: inline-flex;
align-items: center;
gap: 0.6rem;
font-family: var(--display);
font-size: 1.35rem;
font-size: 1rem;
font-weight: 700;
letter-spacing: 0.02em;
letter-spacing: 0.06em;
text-decoration: none;
}
.wordmark::before { content: "";
width: 0.62rem;
height: 0.62rem;
border-radius: 50%;
background: var(--signal);
}
.site-header nav { display: flex;
flex-wrap: wrap;
⋯ 15 unchanged lines
box-shadow: inset 0 -2px 0 var(--signal);
}
.hero { min-height: min(820px, calc(100vh - 8rem));
display: grid;
grid-template-columns: minmax(0, 1.15fr) minmax(22rem, 0.85fr);
border-bottom: 1px solid var(--ink);
overflow: clip;
}
.hero-copy { display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(4rem, 9vw, 9rem) clamp(1rem, 6vw, 7rem) clamp(4rem, 8vw, 7rem) clamp(1rem, 4vw, 4.5rem);
background: var(--paper-bright);
.simple-hero { border-bottom: 1px solid var(--line);
background: var(--paper);
}
.kicker { margin: 0 0 1.5rem;
font-family: var(--display);
font-size: 1.05rem;
font-weight: 700;
letter-spacing: 0.09em;
text-transform: uppercase;
.simple-hero .hero-inner { width: min(100%, 76ch);
margin: 0 auto;
padding: clamp(3.5rem, 7.8vw, 7rem) clamp(1rem, 4vw, 4.5rem);
}
.hero h1 { max-width: 12ch;
.simple-hero h1 { margin: 0;
font-family: var(--display);
font-size: clamp(4.4rem, 10.5vw, 10rem);
font-weight: 600;
letter-spacing: -0.035em;
line-height: 0.82;
font-size: clamp(3rem, 4.2vw, 4rem);
line-height: 0.98;
letter-spacing: -0.03em;
text-wrap: balance;
}
.hero-deck { max-width: 62ch;
margin: clamp(2rem, 4vw, 3.5rem) 0 0;
font-size: clamp(1.2rem, 1.05rem + 0.6vw, 1.65rem);
line-height: 1.42;
.hero-title-main { display: block;
color: var(--ink);
font-weight: 820;
}
.hero-principles { display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 1rem;
max-width: 48rem;
margin: clamp(2rem, 4vw, 3.5rem) 0 0;
padding: 1.25rem 0 0;
border-top: 1px solid var(--line);
.hero-title-continue { display: block;
margin-top: 0.2rem;
color: var(--ink-soft);
font-weight: 400;
}
.hero-principles p { margin: 0;
font-size: 0.95rem;
line-height: 1.42;
.simple-hero p { max-width: 60ch;
margin: clamp(1.25rem, 3vw, 2rem) 0 0;
color: var(--ink-soft);
font-size: 1.1rem;
line-height: 1.5;
}
.hero-principles b { display: block;
margin-bottom: 0.3rem;
.simple-hero .accent-pill { display: inline-flex;
align-items: center;
gap: 0.45rem;
margin-top: 0.8rem;
color: var(--signal-deep);
font-family: var(--display);
font-size: 1.25rem;
line-height: 1;
font-size: 0.88rem;
font-weight: 700;
letter-spacing: 0.03em;
text-transform: uppercase;
}
.hero-map { position: relative;
min-height: 34rem;
display: grid;
place-items: center;
padding: clamp(2rem, 5vw, 5rem);
.simple-hero .accent-pill::before { content: "";
width: 0.55rem;
height: 0.55rem;
border-radius: 50%;
background: var(--signal);
color: var(--ink);
}
.hero-map svg { width: min(100%, 34rem);
height: auto;
overflow: visible;
}
.hero-map .map-caption { position: absolute;
inset: auto 2rem 2rem;
max-width: 25rem;
margin: 0;
font-size: 0.95rem;
font-weight: 600;
line-height: 1.4;
display: inline-block;
}
.section-shell {⋯ 375 unchanged lines
}
@media (max-width: 980px) { .hero { grid-template-columns: 1fr;
}
.hero-map { min-height: 30rem;
}
.timeline-heading,
.patterns .section-shell,
.discovery-intro,
⋯ 38 unchanged lines
justify-content: flex-start;
}
.hero-principles,
.discovery-weeks { grid-template-columns: 1fr;
}
⋯ 99 unchanged lines
<a class="skip-link" href="#main-content">Skip to main content</a>
<header class="site-header">
<a class="wordmark" href="#top" aria-label="Unravel migration control map home">UNRAVEL / MIGRATION CONTROL MAP</a>
<a class="wordmark" href="#top" aria-label="Unravel migration work home">unravel / migration work</a>
<nav aria-label="Document navigation">
<a href="#timeline">Timeline</a>
<a href="#patterns">What we learned</a>
<a href="#timeline">Timeline</a>
<a href="#discovery">Three-week discovery</a>
</nav>
</header>
<main id="main-content">
<section class="hero" id="top" aria-labelledby="hero-title">
<div class="hero-copy">
<p class="kicker">A decade of system change</p>
<h1 id="hero-title">Keep business moving while core systems change.</h1>
<p class="hero-deck">Eight migrations across frontend, cloud, data, SDKs, and backend systems. Different technologies, same discipline: diagnose before prescribing, preserve continuity, and accelerate only where verification can keep up.</p>
<div class="hero-principles" aria-label="Migration principles">
<p><b>01 / Diagnose</b>Start with business impact, not architecture fashion.</p>
<p><b>02 / Protect</b>Design cutovers around live contracts and operational risk.</p>
<p><b>03 / Accelerate</b>Use AI when evidence and gates can verify machine-speed work.</p>
</div>
<section class="simple-hero reveal" id="top" aria-labelledby="hero-title">
<div class="hero-inner">
<h1 id="hero-title">
<span class="hero-title-main">Changing core systems.</span>
<span class="hero-title-continue">Without stopping the business.</span>
</h1>
<p>Eight verified migrations across frontend, cloud, data, SDK, and backend systems. Each case leads with business impact, elapsed duration, and complexity, then explains continuity constraints and execution choices.</p>
<p class="accent-pill" aria-label="Page tone">Focused on judgment before mechanism.</p>
</div>
<div class="hero-map" aria-hidden="true">
<svg viewBox="0 0 500 620">
<path d="M74 50V162C74 216 118 260 172 260H330C384 260 428 304 428 358V570" fill="none" stroke="currentColor" stroke-width="7"/>
<path d="M74 164H238C292 164 336 120 336 66V50" fill="none" stroke="currentColor" stroke-width="2" stroke-dasharray="8 10"/>
<g fill="var(--paper-bright)" stroke="currentColor" stroke-width="5">
<circle cx="74" cy="72" r="13"/><circle cx="74" cy="164" r="13"/><circle cx="172" cy="260" r="13"/><circle cx="276" cy="260" r="13"/><circle cx="382" cy="284" r="13"/><circle cx="428" cy="382" r="13"/><circle cx="428" cy="474" r="13"/><circle cx="428" cy="570" r="13"/>
</g>
<g fill="currentColor" font-family="Barlow Condensed, sans-serif" font-size="20" font-weight="700">
<text x="102" y="80">YUI → REACT</text>
<text x="102" y="172">CLOUD REGION</text>
<text x="202" y="248">SDK CORE</text>
<text x="300" y="248">DATABASE</text>
<text x="298" y="326">DATA PLATFORM</text>
<text x="278" y="390">CHECKOUT</text>
<text x="278" y="482">RETOOL</text>
<text x="274" y="578">JAVA → PYTHON</text>
</g>
</svg>
<p class="map-caption">Route shows sequence, not a single migration recipe. Every crossing uses its own continuity and verification plan.</p>
</section>
<section class="patterns" id="patterns" aria-labelledby="patterns-title">
<div class="section-shell">
<header class="reveal">
<p class="kicker">What repeated</p>
<h2 id="patterns-title">Judgment before machinery.</h2>
</header>
<ol class="pattern-list reveal">
<li><div><h3>Business continuity sets architecture.</h3><p>Zero downtime, customer-paced upgrades, and continuous feature work each demand different migration shapes.</p></div></li>
<li><div><h3>Parallel paths buy reversibility.</h3><p>Dual databases, coexistence, staged customer cohorts, and versioned opt-in reduce irreversible cutover risk.</p></div></li>
<li><div><h3>Contracts beat source translation.</h3><p>Consumers, wire formats, and data invariants define what must survive. Languages and frameworks are implementation choices.</p></div></li>
<li><div><h3>AI speed needs stronger gates.</h3><p>Four-week delivery was possible because human-defined contracts and live-stack checks could reject machine-speed mistakes.</p></div></li>
</ol>
</div>
</section>
<section id="timeline" class="section-shell" aria-labelledby="timeline-title">
<header class="timeline-heading reveal">
<h2 id="timeline-title">The crossings.</h2>
<p>Each entry leads with business impact, elapsed duration, and a complexity rating with reasons. Technical details follow only to explain how value and continuity were protected.</p>
</header>
<ol class="route-list">
<li class="migration-case reveal" data-case="helpshift-yui-to-react" data-evidence="confirmed" data-sort="2017">
<div class="case-year">2015<br>2017</div>
<li class="migration-case reveal" data-case="celerity-java-to-python" data-evidence="confirmed" data-sort="2026.5">
<div class="case-year">2026</div>
<div class="case-node" aria-hidden="true"></div>
<article class="case-content">
<header class="case-header">
<h3>Helpshift<br>YUI → React</h3>
<span class="case-status">Live system</span>
<h3>Celerity<br>Java → Python backend</h3>
<span class="case-status">Unreleased target</span>
</header>
<div class="case-metrics">
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Product roadmap never paused. React improved future delivery, performance, reliability, consistency, usability, and extensibility.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 2 years elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live product, broad UI surface, long coexistence, and uninterrupted feature work.</p>
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Removed vendor lock-in, returned direct product change control, reduced source maintenance surface 55%, and created 4 independently deployable and scalable processes.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>4 active weeks. Original Java build took about 21 active weeks. Two more weeks would have avoided overtime.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Two strict mobile contracts, Kafka compatibility, hidden framework behavior, data and storage invariants, and a compressed finish.</p>
</div>
<div class="case-facts">
<section><h4>The change</h4><p>YUI frontend to React.</p></section>
<section><h4>The constraint</h4><p>Keep shipping product features throughout migration.</p></section>
<section><h4>The method</h4><p>Move incrementally by product surface while YUI and React coexist.</p></section>
<section><h4>The change</h4><p>Java Quarkus monolith to Python FastAPI API, consumer, renderer, and dispatcher.</p></section>
<section><h4>The constraint</h4><p>Live iOS and Android clients defined compatibility, but Python target was unreleased. This was not a live production cutover.</p></section>
<section><h4>The method</h4><ul><li>Extract contracts from mobile clients.</li><li>Verify API, database, and storage behavior against real stack.</li><li>Use 101 client contract assertions and 247 live-stack checks per gate.</li></ul></section>
</div>
<p class="case-ai"><span>AI-assisted?</span>No. Pre-LLM delivery.</p>
<p class="case-ai"><span>AI-assisted?</span>Yes. Claude Code agents did substantial build and verification work; humans defined contracts, gates, and architectural boundaries.</p>
<a class="deep-dive" data-deep-dive href="https://thing.unravel.tech/kapil/terra-incognita-before-you-migrate" rel="noopener">Read Terra Incognita, the detailed migration account →</a>
</article>
</li>
<li class="migration-case reveal" data-case="helpshift-aws-california-to-virginia" data-evidence="confirmed" data-sort="2021">
<div class="case-year">2021</div>
<li class="migration-case reveal" data-case="reify-retool-to-react-and-clojure" data-evidence="confirmed" data-sort="2026">
<div class="case-year">2025<br>2026</div>
<div class="case-node" aria-hidden="true"></div>
<article class="case-content">
<header class="case-header">
<h3>Helpshift<br>AWS California → Virginia</h3>
<span class="case-status">Zero downtime</span>
<h3>Reify<br>Retool → React + Clojure</h3>
<span class="case-status">Internal operations</span>
</header>
<div class="case-metrics">
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Lower infrastructure cost, higher reliability, and a current critical stack with a clear path to later Java and AWS Graviton modernization.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>9 months from start through production rollout. Active engineering duration remains to be normalized.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Zero downtime, broad dependencies, data and traffic cutover, and a rotating 9 to 25 person roster.</p>
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Higher reliability and lower operating cost for internal workflows.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>Under 3 months elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live staff operations, integrations and data contracts, and multi-team coordination.</p>
</div>
<div class="case-facts">
<section><h4>The change</h4><p>AWS California to AWS Virginia, plus Postgres, Mongo, Kafka, Redis, Flink, Hadoop, Spark, Elasticsearch, ScyllaDB, and Java modernization.</p></section>
<section><h4>The constraint</h4><p>Move a B2B customer portfolio without interruption, including a long tail and very large customers.</p></section>
<section><h4>The method</h4><ul><li>Audit dependencies and upgrade target services in waves.</li><li>Establish dual-run and replication paths.</li><li>Move smallest customers first, then largest.</li></ul></section>
<section><h4>The change</h4><p>Internal operations workflows moved from Retool to a custom React and Clojure implementation.</p></section>
<section><h4>The constraint</h4><p>Keep live staff operations working across integrations and data dependencies.</p></section>
<section><h4>The method</h4><p>Move workflow by workflow from Retool into the custom system.</p></section>
</div>
<p class="case-ai"><span>AI-assisted?</span>No.</p>
<p class="case-ai"><span>AI-assisted?</span>Yes.</p>
</article>
</li>
<li class="migration-case reveal" data-case="helpshift-native-sdks-to-js" data-evidence="confirmed" data-sort="2021.5">
<div class="case-year">2021<br>2022</div>
<li class="migration-case reveal" data-case="healthtech-angular-to-react-checkout" data-evidence="confirmed" data-sort="2024">
<div class="case-year">2024</div>
<div class="case-node" aria-hidden="true"></div>
<article class="case-content">
<header class="case-header">
<h3>Helpshift<br>Native SDKs → shared JS core</h3>
<span class="case-status">Customer-paced rollout</span>
<h3>HealthTech<br>Angular checkout → React</h3>
<span class="case-status">Anonymous client</span>
</header>
<div class="case-metrics">
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Faster SDK delivery, consistent behavior across platforms, lower duplicated maintenance cost, and broader customer upgrade reach.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>4 to 6 months elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Multi-platform compatibility, version support, customer-controlled upgrades, and coordinated releases.</p>
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Checkout conversion increased 6 to 8%. Disruptions caused by navigation or payment-window closure fell 30%.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 3 months elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>Medium. Revenue-critical flow, navigation and payment state risk, bounded frontend scope, and one cutover.</p>
</div>
<div class="case-facts">
<section><h4>The change</h4><p>Separate iOS, Android, and Unity or game-engine SDK implementations to a shared JavaScript core.</p></section>
<section><h4>The constraint</h4><p>Keep existing native versions supported while customers choose their upgrade timing.</p></section>
<section><h4>The method</h4><p>Validate shared behavior across all three platform families, then release through versioned opt-in.</p></section>
<section><h4>The change</h4><p>Angular checkout to React, with checkout reliability improvements delivered during migration.</p></section>
<section><h4>The constraint</h4><p>Protect customer progress and transaction completion through refreshes, back navigation, and payment-window closure.</p></section>
<section><h4>The method</h4><ul><li>Persist early checkout state in local storage.</li><li>Use a reopenable payment popup.</li><li>Release through one controlled cutover.</li></ul></section>
</div>
<p class="case-ai"><span>AI-assisted?</span>No.</p>
<p class="case-ai"><span>AI-assisted?</span>Yes.</p>
</article>
</li>
<li class="migration-case reveal" data-case="helpshift-mongodb-to-yugabyte" data-evidence="confirmed" data-sort="2022">
<li class="migration-case reveal" data-case="helpshift-hadoop-hive-to-spark-redshift" data-evidence="confirmed" data-sort="2022.5">
<div class="case-year">2022</div>
<div class="case-node" aria-hidden="true"></div>
<article class="case-content">
<header class="case-header">
<h3>Helpshift<br>MongoDB → YugabyteDB</h3>
<span class="case-status">Zero downtime</span>
<h3>Helpshift<br>Hadoop + Hive → Spark + Redshift</h3>
<span class="case-status">Live data platform</span>
</header>
<div class="case-metrics">
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>More consistent data operations, greater scalability, and headroom for future load without interrupting customer service.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 6 months elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live 2 TB store, data integrity, dual reads and writes, and a 20-plus phase roadmap.</p>
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Supported 10x platform growth, improved data accuracy from 90% to 99.99% in one year, and strengthened resiliency, scalability, and adoption.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 6 months elapsed. The 1-year accuracy period is an outcome window, not migration duration.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. 2 billion devices, 1 PB daily ingestion, live accuracy requirements, and a broad warehouse change.</p>
</div>
<div class="case-facts">
<section><h4>The change</h4><p>MongoDB primary store to YugabyteDB distributed SQL, with supporting service extraction.</p></section>
<section><h4>The constraint</h4><p>Preserve data integrity and customer availability throughout cutover.</p></section>
<section><h4>The method</h4><ul><li>Build staging environment.</li><li>Run both databases through dual reads and writes.</li><li>Move gradually across more than 20 phases.</li></ul></section>
<section><h4>The change</h4><p>Hadoop and Hive to Spark and Redshift. Supporting stack included Hudi, PostgreSQL, Arrow, Airflow, and DBT.</p></section>
<section><h4>The constraint</h4><p>Maintain processing continuity and data correctness at petabyte daily scale.</p></section>
<section><h4>The method</h4><p>Modernize processing and warehouse architecture around Spark and Redshift, supported by Hudi, PostgreSQL, Arrow, Airflow, and DBT.</p></section>
</div>
<p class="case-ai"><span>AI-assisted?</span>No.</p>
</article>
</li>
<li class="migration-case reveal" data-case="helpshift-hadoop-hive-to-spark-redshift" data-evidence="confirmed" data-sort="2022.5">
<li class="migration-case reveal" data-case="helpshift-mongodb-to-yugabyte" data-evidence="confirmed" data-sort="2022">
<div class="case-year">2022</div>
<div class="case-node" aria-hidden="true"></div>
<article class="case-content">
<header class="case-header">
<h3>Helpshift<br>Hadoop + Hive → Spark + Redshift</h3>
<span class="case-status">Live data platform</span>
<h3>Helpshift<br>MongoDB → YugabyteDB</h3>
<span class="case-status">Zero downtime</span>
</header>
<div class="case-metrics">
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Supported 10x platform growth, improved data accuracy from 90% to 99.99% in one year, and strengthened resiliency, scalability, and adoption.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 6 months elapsed. The 1-year accuracy period is an outcome window, not migration duration.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. 2 billion devices, 1 PB daily ingestion, live accuracy requirements, and a broad warehouse change.</p>
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>More consistent data operations, greater scalability, and headroom for future load without interrupting customer service.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 6 months elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live 2 TB store, data integrity, dual reads and writes, and a 20-plus phase roadmap.</p>
</div>
<div class="case-facts">
<section><h4>The change</h4><p>Hadoop and Hive to Spark and Redshift. Supporting stack included Hudi, PostgreSQL, Arrow, Airflow, and DBT.</p></section>
<section><h4>The constraint</h4><p>Maintain processing continuity and data correctness at petabyte daily scale.</p></section>
<section><h4>The method</h4><p>Modernize processing and warehouse architecture around Spark and Redshift, supported by Hudi, PostgreSQL, Arrow, Airflow, and DBT.</p></section>
<section><h4>The change</h4><p>MongoDB primary store to YugabyteDB distributed SQL, with supporting service extraction.</p></section>
<section><h4>The constraint</h4><p>Preserve data integrity and customer availability throughout cutover.</p></section>
<section><h4>The method</h4><ul><li>Build staging environment.</li><li>Run both databases through dual reads and writes.</li><li>Move gradually across more than 20 phases.</li></ul></section>
</div>
<p class="case-ai"><span>AI-assisted?</span>No.</p>
</article>
</li>
<li class="migration-case reveal" data-case="healthtech-angular-to-react-checkout" data-evidence="confirmed" data-sort="2024">
<div class="case-year">2024</div>
<li class="migration-case reveal" data-case="helpshift-native-sdks-to-js" data-evidence="confirmed" data-sort="2021.5">
<div class="case-year">2021<br>2022</div>
<div class="case-node" aria-hidden="true"></div>
<article class="case-content">
<header class="case-header">
<h3>HealthTech<br>Angular checkout → React</h3>
<span class="case-status">Anonymous client</span>
<h3>Helpshift<br>Native SDKs → shared JS core</h3>
<span class="case-status">Customer-paced rollout</span>
</header>
<div class="case-metrics">
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Checkout conversion increased 6 to 8%. Disruptions caused by navigation or payment-window closure fell 30%.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 3 months elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>Medium. Revenue-critical flow, navigation and payment state risk, bounded frontend scope, and one cutover.</p>
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Faster SDK delivery, consistent behavior across platforms, lower duplicated maintenance cost, and broader customer upgrade reach.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>4 to 6 months elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Multi-platform compatibility, version support, customer-controlled upgrades, and coordinated releases.</p>
</div>
<div class="case-facts">
<section><h4>The change</h4><p>Angular checkout to React, with checkout reliability improvements delivered during migration.</p></section>
<section><h4>The constraint</h4><p>Protect customer progress and transaction completion through refreshes, back navigation, and payment-window closure.</p></section>
<section><h4>The method</h4><ul><li>Persist early checkout state in local storage.</li><li>Use a reopenable payment popup.</li><li>Release through one controlled cutover.</li></ul></section>
<section><h4>The change</h4><p>Separate iOS, Android, and Unity or game-engine SDK implementations to a shared JavaScript core.</p></section>
<section><h4>The constraint</h4><p>Keep existing native versions supported while customers choose their upgrade timing.</p></section>
<section><h4>The method</h4><p>Validate shared behavior across all three platform families, then release through versioned opt-in.</p></section>
</div>
<p class="case-ai"><span>AI-assisted?</span>Yes.</p>
<p class="case-ai"><span>AI-assisted?</span>No.</p>
</article>
</li>
<li class="migration-case reveal" data-case="reify-retool-to-react-and-clojure" data-evidence="confirmed" data-sort="2026">
<div class="case-year">2025<br>2026</div>
<li class="migration-case reveal" data-case="helpshift-aws-california-to-virginia" data-evidence="confirmed" data-sort="2021">
<div class="case-year">2021</div>
<div class="case-node" aria-hidden="true"></div>
<article class="case-content">
<header class="case-header">
<h3>Reify<br>Retool → React + Clojure</h3>
<span class="case-status">Internal operations</span>
<h3>Helpshift<br>AWS California → Virginia</h3>
<span class="case-status">Zero downtime</span>
</header>
<div class="case-metrics">
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Higher reliability and lower operating cost for internal workflows.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>Under 3 months elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live staff operations, integrations and data contracts, and multi-team coordination.</p>
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Lower infrastructure cost, higher reliability, and a current critical stack with a clear path to later Java and AWS Graviton modernization.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>9 months from start through production rollout. Active engineering duration remains to be normalized.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Zero downtime, broad dependencies, data and traffic cutover, and a rotating 9 to 25 person roster.</p>
</div>
<div class="case-facts">
<section><h4>The change</h4><p>Internal operations workflows moved from Retool to a custom React and Clojure implementation.</p></section>
<section><h4>The constraint</h4><p>Keep live staff operations working across integrations and data dependencies.</p></section>
<section><h4>The method</h4><p>Move workflow by workflow from Retool into the custom system.</p></section>
<section><h4>The change</h4><p>AWS California to AWS Virginia, plus Postgres, Mongo, Kafka, Redis, Flink, Hadoop, Spark, Elasticsearch, ScyllaDB, and Java modernization.</p></section>
<section><h4>The constraint</h4><p>Move a B2B customer portfolio without interruption, including a long tail and very large customers.</p></section>
<section><h4>The method</h4><ul><li>Audit dependencies and upgrade target services in waves.</li><li>Establish dual-run and replication paths.</li><li>Move smallest customers first, then largest.</li></ul></section>
</div>
<p class="case-ai"><span>AI-assisted?</span>Yes.</p>
<p class="case-ai"><span>AI-assisted?</span>No.</p>
</article>
</li>
<li class="migration-case reveal" data-case="celerity-java-to-python" data-evidence="confirmed" data-sort="2026.5">
<div class="case-year">2026</div>
<li class="migration-case reveal" data-case="helpshift-yui-to-react" data-evidence="confirmed" data-sort="2017">
<div class="case-year">2015<br>2017</div>
<div class="case-node" aria-hidden="true"></div>
<article class="case-content">
<header class="case-header">
<h3>Celerity<br>Java → Python backend</h3>
<span class="case-status">Unreleased target</span>
<h3>Helpshift<br>YUI → React</h3>
<span class="case-status">Live system</span>
</header>
<div class="case-metrics">
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Removed vendor lock-in, returned direct product change control, reduced source maintenance surface 55%, and created 4 independently deployable and scalable processes.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>4 active weeks. Original Java build took about 21 active weeks. Two more weeks would have avoided overtime.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Two strict mobile contracts, Kafka compatibility, hidden framework behavior, data and storage invariants, and a compressed finish.</p>
<p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Product roadmap never paused. React improved future delivery, performance, reliability, consistency, usability, and extensibility.</p>
<p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 2 years elapsed.</p>
<p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live product, broad UI surface, long coexistence, and uninterrupted feature work.</p>
</div>
<div class="case-facts">
<section><h4>The change</h4><p>Java Quarkus monolith to Python FastAPI API, consumer, renderer, and dispatcher.</p></section>
<section><h4>The constraint</h4><p>Live iOS and Android clients defined compatibility, but Python target was unreleased. This was not a live production cutover.</p></section>
<section><h4>The method</h4><ul><li>Extract contracts from mobile clients.</li><li>Verify API, database, and storage behavior against real stack.</li><li>Use 101 client contract assertions and 247 live-stack checks per gate.</li></ul></section>
<section><h4>The change</h4><p>YUI frontend to React.</p></section>
<section><h4>The constraint</h4><p>Keep shipping product features throughout migration.</p></section>
<section><h4>The method</h4><p>Move incrementally by product surface while YUI and React coexist.</p></section>
</div>
<p class="case-ai"><span>AI-assisted?</span>Yes. Claude Code agents did substantial build and verification work; humans defined contracts, gates, and architectural boundaries.</p>
<a class="deep-dive" data-deep-dive href="https://thing.unravel.tech/kapil/terra-incognita-before-you-migrate" rel="noopener">Read Terra Incognita, the detailed migration account →</a>
<p class="case-ai"><span>AI-assisted?</span>No. Pre-LLM delivery.</p>
</article>
</li>
</ol>
</section>
<section class="patterns" id="patterns" aria-labelledby="patterns-title">
<div class="section-shell">
<header class="reveal">
<p class="kicker">What repeated</p>
<h2 id="patterns-title">Judgment before machinery.</h2>
</header>
<ol class="pattern-list reveal">
<li><div><h3>Business continuity sets architecture.</h3><p>Zero downtime, customer-paced upgrades, and continuous feature work each demand different migration shapes.</p></div></li>
<li><div><h3>Parallel paths buy reversibility.</h3><p>Dual databases, coexistence, staged customer cohorts, and versioned opt-in reduce irreversible cutover risk.</p></div></li>
<li><div><h3>Contracts beat source translation.</h3><p>Consumers, wire formats, and data invariants define what must survive. Languages and frameworks are implementation choices.</p></div></li>
<li><div><h3>AI speed needs stronger gates.</h3><p>Four-week delivery was possible because human-defined contracts and live-stack checks could reject machine-speed mistakes.</p></div></li>
</ol>
</div>
</section>
<section class="discovery" id="discovery" aria-labelledby="discovery-title">
⋯ 77 unchanged lines