Skip to content
AI-Native PM
Field Notes

Field Note

Why Our Migrations Start as Research Briefs

We wanted FuelTheFam's app on Cloudflare and its database with it. Each move started as a research brief instead of a migration: one came back not yet, one came back no, and the freed days went into hardening the stack we kept.

· 5 min read

In late July we shipped the redesign of FuelTheFam, the family nutrition app we run, and the next morning we asked a bigger question. Everything else we operate lives on Cloudflare, while the app sat on Vercel with its database on Supabase, and we wanted everything in one place. That meant two moves: the app onto Cloudflare Workers, and, if it could be done well, the database onto something Cloudflare-native.

Neither move started as a migration. Each started as a research brief: a fleet of agents sent to verify the current facts of the move, with separate tracks checking the same claims independently against the primary sources, and one dated brief at the end that had to open with a verdict. The format is the point: a brief that must open with a verdict can open with no.

Before any move you cannot easily undo, commission the brief that is free to come back with no.

Two migrations, each decided by a research brief before it startedTwo rows. In the first, the ask to move the app to Cloudflare passes through a research brief and returns the verdict not yet, because the adapter refuses Next 14; the outcome is upgrade first, then move. In the second, the ask to leave Supabase returns the verdict no, because the target has no row-level security and no sign-in product; the outcome is stay, rotate keys, and harden.TWO MOVES, TWO BRIEFS, TWO ANSWERSMove the appto CloudflareRESEARCH6 agents, 5 tracksNOT YETthe adapterrefuses Next 14Upgrade to 15,then moveLeave Supabase fora Cloudflare DBRESEARCH8 agents, 4 tracksNOno row-level security,no sign-in productStay, rotatekeys, hardenBoth answers arrived before anything moved.

The first brief came back with "not yet"

The Cloudflare brief opened with a hard stop. OpenNext, the adapter that runs Next.js apps on Cloudflare Workers, had dropped support for Next.js 14 months earlier, and its package declares the requirement outright: next >=15.5.21. Two research tracks confirmed that range against npm independently, while the adapter's own documentation still claimed Next 14 worked. Our app ran Next 14. Without the brief, the migration would have failed an hour in, with the documentation saying it should not have.

The verdict changed the order of the work and nothing else. One commit upgraded the app to Next.js 15, and then the move went through in a day: the marketing page split out as a static site, the app onto Workers, the domain cut over, and Sentry, our error monitoring, removed so the whole thing runs on the free plan.

The second brief came back with "no"

Halfway through the cutover we asked the more ambitious question: could the database leave Supabase and live inside Cloudflare too? The second brief answered in its first line: do not move. Cloudflare has no database with row-level security (RLS), the database-side rule that keeps one family's rows unreadable to another, and no consumer sign-in product. Going all-Cloudflare would have meant hand-writing the authorization for a database that holds children's names, ages, and food logs, weeks after an authorization bug had already slipped through our own review. If we ever leave, the brief said, the destination is a hosted Postgres such as Neon plus a dedicated sign-in service such as Clerk, and not D1, the database Cloudflare does offer.

We stayed, and staying cost us nothing, because the wish to be all-Cloudflare was tidiness rather than a requirement. The price of that tidiness would have been hand-building the security layer for a product that stores information about children, and once the brief stated it that way, declining was easy.

What the freed days bought

Saying no did not hand the days back; they still got spent, on the stack we kept. Straight after the cutover, we made the hardening pass that had been waiting behind the migration.

The hardening that landed in the days the migration did not consumeA ledger of five completed fixes: authorization checks before the RLS-bypassing client, email subject sanitization, the open nutrition proxy closed, per-family cache isolation, and secrets that fail loudly with a webhook that fails closed.WHAT THE FREED DAYS BOUGHTEvery route validates the user before the RLS-bypassing client runsAUTHORIZATIONThe notification email subject is sanitized against injectionINJECTIONThe open proxy to the nutrition database is closedEXPOSURECache tags scoped per family, and family rows made uniqueISOLATIONMissing secrets fail loudly, and the billing webhook fails closedSECRETSEvery fix landed on the stack the second brief told us to keep.

Every route that uses the database client capable of bypassing row-level security now validates the signed-in user first. The notification email's subject line is sanitized against injection. A proxy the app exposed in front of the public nutrition database, open to anyone who found it, is closed. Cache tags are scoped per family and family rows are unique, so one household's data cannot bleed into another's view. Secrets fail loudly when they are missing, the billing webhook fails closed instead of open, refusing what it cannot verify, and the database keys were rotated to Supabase's new key format on the way out. None of it was migration work, and that was the point: the risk budget went into closing real holes on the platform we already understood.

The paperwork that trails every move

A replatform also rewrites pages you rarely open. The rebrand had already forced one pass through the legal pages, renaming the old working title, Family Nutrition Dashboard, to Fuel the Fam everywhere, including a terms opener that a literal find-and-replace would have turned into "Fuel the Fam, operated by Fuel the Fam," and which now defines who "we" and "us" bind instead. The platform change queues a second pass, because a privacy page lists the services that process user data, and that list has to follow the infrastructure: the hosting entry moves off Vercel, and Sentry comes off the list entirely. That list is the slowest-moving part of any migration and the easiest to forget, and ours is mid-move as we write this.

Where this goes next

The product all of this happened to is examined end to end in the FuelTheFam case study. The standing instruction this tactic grew from is Why We Told the AI to Disagree With Us, and the same verification instinct pointed at finished work instead of plans is How We Caught AI Mistakes With a Second Agent. The mechanics of running research as a fleet, with independent tracks and adversarial checks, is the Frontier's Multi-Agent Orchestration part.

Sources

  • The two decision briefs, both prepared 2026-07-25: "Cloudflare Migration: Decision Brief" (six agents, five research tracks) and "Decision brief: replacing Supabase in Fuel the Fam" (eight agents, four tracks). Internal documents.
  • The FuelTheFam repository, July 24 to 25, 2026: the redesign merge and the eight pull requests that followed it, covering the migration, the monitoring removal, and the secrets, authorization, injection, and proxy fixes.
  • The Workers adapter's requirement, next >=15.5.21, with Next.js 14 support removed in adapter v1.16.0 on 2026-01-26; verified against the npm registry on 2026-07-25.