page.tsx223 lines · main
1import type { Metadata } from 'next';
2import Link from 'next/link';
3
4import { BackgroundGrid } from '../../components/marketing/background-grid';
5import { MigrationLeadForm } from '../../components/marketing/migration-lead-form';
6import { SiteFooter } from '../../components/marketing/site-footer';
7import { SiteHeader } from '../../components/marketing/site-header';
8import { TrackPageView } from '../../components/marketing/track-page-view';
9import { getSessionUser } from '../../lib/session';
10
11export const metadata: Metadata = {
12 title: 'migrate to briven — convex, supabase, firebase, prisma, drizzle',
13 description:
14 'we move your project to briven for you. free during beta. your current platform stays untouched until you press the cutover button.',
15};
16
17interface SourceCard {
18 slug: string;
19 name: string;
20 oneliner: string;
21}
22
23// Mirrors the in-dashboard wizard picker (apps/web/.../projects/new/page.tsx).
24// Keep the two lists in sync — a source that exists here but not there
25// (or vice versa) leaves the customer with a broken click-through.
26const SOURCES: readonly SourceCard[] = [
27 {
28 slug: 'convex',
29 name: 'convex',
30 oneliner: 'your TS schema + handlers port to briven; useQuery stays the same.',
31 },
32 {
33 slug: 'supabase',
34 name: 'supabase',
35 oneliner: 'postgres → postgres via pg_dump. edge functions port directly.',
36 },
37 {
38 slug: 'firebase',
39 name: 'firebase / firestore',
40 oneliner: 'document → relational with shape decisions you approve per collection.',
41 },
42 {
43 slug: 'mongodb',
44 name: 'mongodb',
45 oneliner: 'flatten vs jsonb per field, streaming COPY into postgres.',
46 },
47 {
48 slug: 'drizzle',
49 name: 'drizzle',
50 oneliner: 'lightest path — both ends are postgres with a TS schema.',
51 },
52 {
53 slug: 'prisma',
54 name: 'prisma',
55 oneliner: 'schema.prisma → briven DSL. PrismaClient → ctx.db chains.',
56 },
57 {
58 slug: 'postgres',
59 name: 'raw postgres',
60 oneliner: 'straightest path — pg_dump | pg_restore + briven for the function layer.',
61 },
62 {
63 slug: 'hasura',
64 name: 'hasura',
65 oneliner: 'postgres half is free. permission rules become function guards.',
66 },
67 {
68 slug: 'nextauth',
69 name: 'nextauth / auth.js',
70 oneliner: 'schema maps 1:1 to Better Auth. preserve session IDs or fresh sign-in.',
71 },
72];
73
74const PROMISES: readonly { title: string; body: string }[] = [
75 {
76 title: 'your source stays untouched',
77 body: 'we only read from your current platform. nothing is moved or deleted until you press the cutover button — which we won’t do until you say so.',
78 },
79 {
80 title: 'parallel-run for as long as you need',
81 body: 'reads land on briven, writes stay on your source, until the numbers match. cutover is a button. 7-day rollback if you change your mind.',
82 },
83 {
84 title: 'we do the move, you review',
85 body: 'an operator pulls your schema, ports your handlers, and copies your data. you review every step in the dashboard before anything goes live.',
86 },
87 {
88 title: 'free during beta',
89 body: 'we’re not charging for migration help in the launch window. after beta, concierge moves are paid; the dashboard wizard stays free.',
90 },
91];
92
93export default async function MigratePage() {
94 const user = await getSessionUser().catch(() => null);
95 return (
96 <main className="relative min-h-dvh overflow-hidden bg-[var(--color-bg)] text-[var(--color-text)]">
97 <TrackPageView
98 apiOrigin={process.env.NEXT_PUBLIC_BRIVEN_API_ORIGIN ?? ''}
99 source="hub"
100 />
101 <BackgroundGrid />
102 <SiteHeader user={user} />
103
104 <section className="relative z-10 mx-auto w-full max-w-4xl px-6 pb-12 pt-16 sm:pt-24">
105 <p className="font-mono uppercase tracking-[0.12em] text-[var(--color-primary)] text-[var(--text-xs)]">
106 migrate
107 </p>
108 <h1 className="mt-4 font-sans font-medium leading-[1.05] tracking-[-0.03em] text-[var(--color-text)] text-[var(--text-display-3)] sm:text-[var(--text-display-2)]">
109 bring your project to briven.
110 </h1>
111 <p className="mt-6 max-w-2xl leading-[1.6] text-[var(--color-text-muted)] text-[var(--text-body)]">
112 we move convex, supabase, firebase, mongodb, drizzle, prisma, raw postgres, hasura
113 and nextauth projects to briven for you. free during the beta. your current
114 platform keeps running the entire time — nothing is moved, deleted, or modified
115 until you press cutover.
116 </p>
117
118 <div className="mt-8 flex flex-wrap items-center gap-3">
119 <Link
120 href={user ? '/dashboard/projects/new' : '/signin?next=/dashboard/projects/new'}
121 className="inline-flex h-12 items-center justify-center rounded-[var(--radius-md)] bg-[var(--color-primary)] px-6 font-sans font-medium text-[var(--color-text-inverse)] shadow-[var(--shadow-sm)] transition-colors duration-[var(--duration-fast)] ease-[var(--ease-briven)] hover:bg-[var(--color-primary-hover)] active:bg-[var(--color-primary-pressed)]"
122 >
123 start a migration
124 </Link>
125 <a
126 href="mailto:migrations@flndrn.com"
127 className="inline-flex h-12 items-center justify-center rounded-[var(--radius-md)] border border-[var(--color-border)] bg-transparent px-6 font-sans font-medium text-[var(--color-text)] transition-colors duration-[var(--duration-fast)] ease-[var(--ease-briven)] hover:border-[var(--color-border-strong)] hover:bg-[var(--color-surface-raised)]"
128 >
129 email a human first
130 </a>
131 </div>
132 </section>
133
134 <section className="relative z-10 mx-auto w-full max-w-4xl px-6 pb-16">
135 <h2 className="font-mono uppercase tracking-[0.12em] text-[var(--color-text-subtle)] text-[var(--text-xs)]">
136 what we promise
137 </h2>
138 <div className="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
139 {PROMISES.map((p) => (
140 <div
141 key={p.title}
142 className="flex flex-col gap-2 rounded-[var(--radius-lg)] border border-[var(--color-border-subtle)] bg-[var(--color-surface)] p-5"
143 >
144 <p className="font-mono text-sm text-[var(--color-text)]">{p.title}</p>
145 <p className="leading-[1.6] text-[var(--color-text-muted)] text-[var(--text-small)]">
146 {p.body}
147 </p>
148 </div>
149 ))}
150 </div>
151 </section>
152
153 <section className="relative z-10 mx-auto w-full max-w-4xl px-6 pb-20">
154 <h2 className="font-mono uppercase tracking-[0.12em] text-[var(--color-text-subtle)] text-[var(--text-xs)]">
155 where are you coming from?
156 </h2>
157 <p className="mt-2 leading-[1.6] text-[var(--color-text-muted)] text-[var(--text-small)]">
158 pick your current platform for a detailed look at how the move works — what comes
159 for free, what we automate, what stays manual. start the migration from there.
160 </p>
161 <ul className="mt-6 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
162 {SOURCES.map((s) => (
163 <li key={s.slug}>
164 <Link
165 href={`/migrate/${s.slug}`}
166 className="group flex h-full flex-col gap-2 rounded-[var(--radius-lg)] border border-[var(--color-border-subtle)] bg-[var(--color-surface)] p-5 transition hover:border-[var(--color-border-strong)]"
167 >
168 <p className="font-sans font-medium tracking-[-0.02em] text-[var(--color-text)] text-[var(--text-h4)]">
169 {s.name}
170 </p>
171 <p className="leading-[1.6] text-[var(--color-text-muted)] text-[var(--text-small)]">
172 {s.oneliner}
173 </p>
174 <span className="mt-auto font-mono text-xs text-[var(--color-text-link)] group-hover:underline">
175 read the {s.name} guide →
176 </span>
177 </Link>
178 </li>
179 ))}
180 </ul>
181 </section>
182
183 <section className="relative z-10 mx-auto w-full max-w-4xl px-6 pb-16">
184 <h2 className="font-mono uppercase tracking-[0.12em] text-[var(--color-text-subtle)] text-[var(--text-xs)]">
185 ready when you are
186 </h2>
187 <p className="mt-2 leading-[1.6] text-[var(--color-text-muted)] text-[var(--text-small)]">
188 leave us your email and a couple of words about your project. no signup
189 required. you&apos;ll hear from us within one business day with the next steps.
190 </p>
191 <div className="mt-6">
192 <MigrationLeadForm
193 apiOrigin={process.env.NEXT_PUBLIC_BRIVEN_API_ORIGIN ?? ''}
194 sources={SOURCES}
195 />
196 </div>
197 </section>
198
199 <section className="relative z-10 mx-auto w-full max-w-4xl px-6 pb-24">
200 <div className="rounded-[var(--radius-lg)] border border-[var(--color-border-primary)] bg-[var(--color-primary-subtle)] p-6">
201 <h2 className="font-sans font-medium tracking-[-0.02em] text-[var(--color-text)] text-[var(--text-h3)]">
202 don&apos;t see your platform?
203 </h2>
204 <p className="mt-3 leading-[1.6] text-[var(--color-text-muted)] text-[var(--text-body)]">
205 we still do it. email{' '}
206 <a
207 href="mailto:migrations@flndrn.com"
208 className="text-[var(--color-text-link)] underline underline-offset-2"
209 >
210 migrations@flndrn.com
211 </a>{' '}
212 with a one-paragraph description of where your project lives today and we&apos;ll
213 scope a free beta migration for you. supabase / firebase / mongodb / hasura /
214 nextauth / drizzle / prisma / convex / raw postgres covered; everything else
215 we&apos;ll quote.
216 </p>
217 </div>
218 </section>
219
220 <SiteFooter />
221 </main>
222 );
223}