DEV Community

Rémi Buchaillat
Rémi Buchaillat

Posted on

From Zero to Shipped: How We Built Indiefy.xyz in a Weekend (With AI as Co-Founder)

We built a full-stack SaaS product - auth, database, payments, integrations, leaderboard, i18n, mobile UI, SEO - in a single sprint using AI as a build partner. Here's every step, decision, and dead end. By the end of this post, you'll think "wait, I could actually build that."


The Idea That Wouldn't Shut Up

Every indie hacker has the same problem: you want to build in public, but the tools suck.

You've got your MRR on a Google Sheet. Your equity is in a Notion doc nobody reads. Your expenses live in three different apps. And when someone asks "how's the startup going?" you have to piece together a story from six different tabs.

That's when the idea hit: what if Spotify, but for founders?

Not Spotify the product - Spotify the vibe. The dark design. The stats everywhere. The "Wrapped" that makes you feel like your year actually meant something. A profile page at indiefy.xyz/yourname that tells your whole founder story in one scroll - real MRR, real profit, real equity, real goals.

We called it Indiefy.


Step 0: Write the Spec Before Writing a Single Line of Code

The first thing we did wasn't open a terminal. We wrote an indiefy.md file - a proper product spec. Not a Notion doc, not a tweet thread. A real, structured document with:

  • The concept in one sentence: "Spotify, but for indie hackers"
  • The target audience (5 different profiles: solo founders, early employees with stock options, angels, advisors, minority partners)
  • Every single feature, grouped into sections
  • The monetization model (Free vs Pro)
  • The tech stack
  • A 5-day build timeline

This step is the one most builders skip. Don't skip it. When you have a spec, you have prompts. When you have prompts, AI can actually build your product instead of guessing.

Here's an excerpt from ours:

## Features

### Charges & P&L public
- Real Profit = MRR - project costs - pro-rata fixed costs
- Runway = savings / total monthly costs
- Break-even: at what MRR you cover everything

> First tool that shows REAL project profitability, not just gross MRR.
Enter fullscreen mode Exit fullscreen mode

That last line became our north star for every design decision.


Step 1: The Design System First (Seriously, Do This First)

We started with design tokens, not code. The whole aesthetic was clear from day one: Spotify dark theme. Exactly this palette:

Token Value
Background #0a0a0a
Cards #111111 and #1a1a1a
Accent green #1DB954
Primary text #FFFFFF
Secondary #A3A3A3
Borders #2a2a2a

Two fonts. That's it. DM Sans for body copy. Syne for numbers and titles - that Syne font on a big MRR number hits different.

The prompt we gave the AI was surgical:

Create the complete design system for Indiefy.
Stack: Next.js 16 App Router, Tailwind CSS v4, TypeScript strict.
Design: Spotify-inspired, dark mode only.
Colors: [exact hex values]
Typography: DM Sans (body) + Syne (stats/titles)
Generate: tailwind.config.ts, globals.css, Layout.tsx with left sidebar,
Card.tsx (variants: default/highlight/glass), Typography.tsx
Rules: NO generic Bootstrap-like styles. Server Components by default.
Enter fullscreen mode Exit fullscreen mode

The AI spit out a complete design system in one shot. Because the prompt was specific. Garbage in, garbage out - and vice versa.


Step 2: The Database Schema - Think Hard Before You Click Enter

The spec: 8 models. User, Project, Expense, Revenue, Goal, Milestone, Badge, Follow.

We wrote out the entire Prisma schema by hand in the spec file before generating it. Every relation, every index, every enum. This took 45 minutes and saved us from three migrations later.

model Project {
  id                 String        @id @default(cuid())
  userId             String
  name               String
  slug               String        @unique
  status             ProjectStatus // ACTIVE | ACQUIRED | DEAD | STEALTH
  equityPercent      Float?
  estimatedValuation Float?
  mrr                Float         @default(0)
  isPublic           Boolean       @default(true)
  showFinancials     Boolean       @default(false)
  // ...
}
Enter fullscreen mode Exit fullscreen mode

The showFinancials boolean was a key product decision: people can share their profile publicly without showing the money. This unlocks a whole segment of users who want visibility but not full transparency.

We also added the Integration model from day one - Stripe, RevenueCat, LemonSqueezy, Paddle - even before building the integration pages. Schema-first means you don't paint yourself into a corner later.


Step 3: Auth - The Part Everyone Dreads

Supabase Auth with Google + GitHub OAuth. Two provider buttons. That's it.

The interesting part wasn't the OAuth flow - it was the sync between Supabase Auth (which handles the JWT and session) and Prisma (which owns the business data). We wrote a route app/api/auth/sync/route.ts that fires after OAuth callback and ensures a User row exists in Postgres.

The middleware was three lines of logic:

// middleware.ts
const isProtectedRoute = matcher.some(path => req.nextUrl.pathname.startsWith(path))
const session = await getSession(req)

if (isProtectedRoute && !session) {
  return NextResponse.redirect(new URL('/login', req.url))
}
Enter fullscreen mode Exit fullscreen mode

Username validation deserves a mention: lowercase, alphanumeric + hyphens, 3-20 chars, unique. We validated this with Zod server-side and debounced API check client-side. Tiny detail, important UX.


Step 4: The Dashboard - Making Numbers Feel Alive

This is where the product really started to look like something.

Four KPI cards at the top:

  1. Total MRR
  2. Net Profit
  3. Total Users
  4. Paper Wealth (equity x valuations)

That last one is what makes Indiefy different from every other dashboard tool. Paper wealth - the sum of all your equity stakes multiplied by estimated valuations - is a number no other tool shows you. It might be zero. It might be fictional. But it's yours, and it's there, and it feels good.

The MRRChart component used Recharts AreaChart with a gradient fill. One snippet made the whole chart feel premium:

<defs>
  <linearGradient id="mrrGradient" x1="0" y1="0" x2="0" y2="1">
    <stop offset="5%"  stopColor="#1DB954" stopOpacity={0.3} />
    <stop offset="95%" stopColor="#1DB954" stopOpacity={0} />
  </linearGradient>
</defs>
Enter fullscreen mode Exit fullscreen mode

Step 5: Projects - The Core Loop

The project form was the most complex UI we built. A slider for equity percentage (0-100) with a live calculation beneath it: "Your estimated stake: 47,000". A tech stack tag input. Status badges that actually looked like badges, not dropdowns.

The killer feature was the acquisition simulator. You type a valuation. The number updates instantly:

const yourShare = (estimatedSale * equityPercent) / 100
// Displayed in real-time as you type
Enter fullscreen mode Exit fullscreen mode

Status colors:

Status Color Vibe
ACTIVE #1DB954 green Go time
ACQUIRED Blue Congrats
DEAD Red RIP
STEALTH Gray We see you

After creating a project, we auto-generated a milestone: "Launch de projet". Small touch. Makes the product feel alive immediately.


Step 6: Expenses & Real P&L

This is the feature that makes Indiefy honest.

Most "MRR dashboards" just show you gross revenue. Indiefy shows you the real number:

Gross Revenue (MRR):           2,400
Project costs (Vercel, etc): -    89
Fixed costs (pro-rata):      -   340
                             --------
Net Profit:                    1,971  
Margin rate:                      82%
Runway:                    14 months
Break-even MRR:                  429
Enter fullscreen mode Exit fullscreen mode

The getPnLSummary() server action ran a single Prisma query that joined revenues, project expenses, and fixed costs pro-rated across all active projects. The math isn't complex - it's just honest math nobody else was doing.


Step 7: Integrations - The Part That Made It Real

Instead of just supporting Stripe, we ended up integrating five payment providers:

  • Stripe - OAuth Connect, read-only access
  • RevenueCat - API key, for mobile apps
  • LemonSqueezy - API key
  • Paddle - API key
  • Polar - the new open-source one
  • Dodo Payments - emerging market focus

The git log tells the story:

e98928d Polar
2f675fd leaderboard
7457233 dodo payments
67366a0 paddle
829add8 coming soon integrations
Enter fullscreen mode Exit fullscreen mode

Each integration followed the same pattern:

// lib/integrations/syncEngine.ts
async function syncProjectRevenue(projectId: string): Promise<SyncResult> {
  const integration = await getActiveIntegration(projectId)
  const data = await fetchFromProvider(integration)

  await prisma.project.update({
    where: { id: projectId },
    data: { mrr: data.mrr, arr: data.arr, totalRevenue: data.totalRevenue }
  })

  await createRevenueEntry(projectId, data)
  await checkAndGenerateMilestones(projectId)
  await updateLastSynced(integration.id)

  return { success: true, mrr: data.mrr, lastSyncedAt: new Date() }
}
Enter fullscreen mode Exit fullscreen mode

API keys were stored encrypted with AES-256-GCM. Not optional. You're handling people's financial data.

The Vercel cron job synced everything at 6am daily:

// vercel.json
{
  "crons": [{
    "path": "/api/cron/sync-revenues",
    "schedule": "0 6 * * *"
  }]
}
Enter fullscreen mode Exit fullscreen mode

Step 8: Leaderboard - The Viral Loop

The leaderboard was the feature we almost cut. "Do we really need a ranking system?"

Yes. We really did.

2f675fd leaderboard
a2e22b5 explore algo
a17f087 trending algo
Enter fullscreen mode Exit fullscreen mode

Three commits across leaderboard features. The ranking algorithm wasn't just "sort by MRR" - we built a momentum score: a composite of MRR velocity (month-over-month growth %), user growth, and update frequency.

A 200 MRR project growing 30% monthly ranks higher than a 5k MRR project that hasn't been updated in three months.

The Explore page had its own trending algorithm. Same logic: recent activity + growth velocity > absolute numbers. This made the platform feel fair for people who are just getting started.


Step 9: Mobile - The Feature You Can't Skip Anymore

b8ff2e8 mobile ui
b4fc4a6 bottom nav
471fcce bubbles: mobile nav icons, verified-only badges
3a8410b loading pages
Enter fullscreen mode Exit fullscreen mode

Mobile was a late sprint but not an afterthought. We replaced the left sidebar with a bottom navigation bar on mobile. Standard pattern, but the implementation matters: same server components, just conditional layout based on viewport. The Tailwind breakpoints did the heavy lifting.

The "bubble" nav icons made the mobile UI feel native rather than "responsive web." Five tabs: Dashboard, Explore, Profile, Goals, Settings.

Loading states were added systematically across all pages - skeleton screens, not spinners. The difference between a product that feels fast and one that feels slow is often just skeleton screens.


Step 10: i18n - Because Half Your Users Aren't English

d2ca272 i18n
ba6d47f i18n
40a060b Goal i18n
Enter fullscreen mode Exit fullscreen mode

We used next-intl for internationalization. The routing structure:

app/
  [locale]/
    dashboard/
    profile/
    ...
Enter fullscreen mode Exit fullscreen mode

Every user-facing string became a key:

const t = useTranslations('dashboard')
// t('kpi.totalMrr') -> "Total MRR" or "MRR Total"
Enter fullscreen mode Exit fullscreen mode

Three commits for i18n because the first one was "we need i18n", the second was "actually doing i18n", and the third was "ok goals weren't translated yet."


Step 11: Security, Legal, Pricing

b4fc4a6 legals
a78c03e SECU
5023241 pricing page
Enter fullscreen mode Exit fullscreen mode

Security was a dedicated commit because integrations meant we had real sensitive data: OAuth tokens, API keys, payment provider access. We audited every route for:

  • Auth checks on every server action
  • User ownership verification before any data mutation
  • Encrypted storage for all third-party credentials
  • Rate limiting on public API endpoints

Legal pages (Privacy Policy, Terms of Service) were generated but reviewed. You need them. Especially when you're storing financial data and connecting to payment processors.

The pricing page was the last non-feature piece. Simple: Free (1 project, basic stats) vs Pro (~7/month, everything).


Step 12: SEO - The Long Game Starts at Launch

7928c7b SEO
eb6e47b SEO
2312193 Analytics
6e88960 Remove from sitemap the not public accounts
Enter fullscreen mode Exit fullscreen mode

Dynamic OG images for every public profile (using @vercel/og). Proper <meta> tags. Sitemap generation that excluded private accounts - you don't want to index profiles people marked private.

Vercel Analytics + Speed Insights went in at the same time. You can't improve what you don't measure.


The Final Stack

After 115 commits, here's what Indiefy runs on:

Layer Technology
Framework Next.js 16 (App Router)
Styling Tailwind CSS v4
Database Supabase (PostgreSQL)
ORM Prisma 7
Auth Supabase Auth (Google + GitHub OAuth)
Payments Stripe (subscriptions)
Integrations Stripe, RevenueCat, LemonSqueezy, Paddle, Polar, Dodo
Charts Recharts
i18n next-intl
Validation Zod v4
Toasts Sonner
Deployment Vercel
OG Images @vercel/og
Analytics Vercel Analytics + Speed Insights

What Made This Possible

The honest answer: structured prompts written by a human who knew exactly what to build.

Every build step was a complete, specific prompt:

  • "Generate X with these exact fields"
  • "Use Zod for validation"
  • "No any types"
  • "Server Components by default, use client only when necessary"
  • "Match this exact design system"

The AI didn't make product decisions. It executed them. The product thinking - what to build, why, in what order - that was 100% human.

Three things made the AI useful here:

  1. Specificity - vague prompts get vague code
  2. Existing design system - the AI respected our tokens because we defined them first
  3. Step-by-step - small, focused tasks beat "build me an app"

The Numbers

Metric Count
Git commits 115
Major features ~15
Payment integrations 6
Languages at launch 2
Bootstrap CSS used 0

Could You Build This?

Yes. Genuinely, yes.

The technical complexity here isn't exceptional. Next.js App Router is mature. Supabase handles auth beautifully. Prisma removes the pain from database work. Stripe's documentation is excellent.

What's rare isn't the ability to build it - it's the discipline to spec it first, prompt it right, and ship before perfecting.

The features we shipped aren't perfect. Some UI could be cleaner. The mobile experience could be smoother. The analytics could be deeper. But the product exists, it works, and it's live.

Perfect is the enemy of shipped.


What's Next for Indiefy

  • Indiefy Wrapped (December): your year as a founder, Spotify-style, shareable card
  • Enjoy life

If you're an indie hacker who wants to display your real journey - not just a landing page, but actual MRR, real profit, equity you might never cash out but still own - create your profile at indiefy.xyz.

Top comments (0)