Skip to main content

7.2 Build the MVP: From Zero to Working

In the last section we wrote the PRD. Now it's time to actually write code.

Don't worry. You don't need to hand-write every line from scratch. Our strategy: use AI as your pair programming partner — you steer, AI builds.

Step 1: Initialize the Project

Open your terminal and run:

npx create-next-app@latest daily-focus --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"

This command will ask a few questions — just press Enter through all of them. It creates a Next.js project with TypeScript and Tailwind CSS pre-configured.

Once created, enter the project directory:

cd daily-focus
npm run dev

Open your browser and visit http://localhost:3000. You'll see the default Next.js page.

Congratulations, your project is running. It doesn't have any features yet, but it's running — and that's the most important step.

Step 2: Create the Main Page

Now open your AI coding tool (Claude Code or Cursor) and enter your first prompt:

I'm building a web app called "AI Daily Focus Helper."

Please modify src/app/page.tsx to create the main page with these requirements:

1. Page title: "🎯 AI Daily Focus Helper"
2. Subtitle: "Focus on the 3 most important things every day"
3. Three input fields with placeholders "Most important thing today #1" "#2" "#3"
4. A save button
5. Tailwind CSS styling, clean modern design, centered layout

Use React useState to manage input state.

The AI will generate something like this:

"use client";

import { useState } from "react";

export default function Home() {
const [tasks, setTasks] = useState(["", "", ""]);

const handleChange = (index: number, value: string) => {
const newTasks = [...tasks];
newTasks[index] = value;
setTasks(newTasks);
};

return (
<main className="min-h-screen flex items-center justify-center bg-gradient-to-b from-orange-50 to-white">
<div className="max-w-md w-full px-6 py-10">
<h1 className="text-3xl font-bold text-center text-orange-600">
🎯 AI Daily Focus Helper
</h1>
<p className="text-center text-gray-500 mt-2 mb-8">
Focus on the 3 most important things every day
</p>

<div className="space-y-4">
{tasks.map((task, index) => (
<input
key={index}
type="text"
value={task}
onChange={(e) => handleChange(index, e.target.value)}
placeholder={`Most important thing today #${index + 1}`}
className="w-full px-4 py-3 border border-gray-200 rounded-xl
focus:outline-none focus:ring-2 focus:ring-orange-300
text-gray-700"
/>
))}
</div>

<button className="w-full mt-6 bg-orange-500 text-white py-3 rounded-xl
hover:bg-orange-600 transition font-medium">
Save Today's Focus
</button>
</div>
</main>
);
}

Save the file and refresh the browser. You should see a beautiful orange-themed page with three input fields and a button.

What to Do When You Hit an Error

If you see red error messages, check two places first:

  1. Terminal — look for compilation errors
  2. Browser console — press F12 to open DevTools

Most common errors:

  • Module not found: Probably a wrong file path — check your import statements
  • Type error: TypeScript type issue — paste the error message to AI and ask it to fix it
  • Hydration mismatch: Server and client rendering mismatch — add the "use client" directive

Universal fix: copy the full error message, paste it to AI, and say "fix this error." It works 90% of the time.

Step 3: Add Checkbox Completion

Next, add a checkbox to each task. Prompt:

Add a checkbox to the left of each task input. Users can check it to mark a task as completed.
When checked, the task text gets a strikethrough and turns gray.
Use another useState array to manage completion state.

The AI will update the code, adding a checkbox before each input field with visual feedback for the completed state.

Test it: enter tasks → check them off → see the strikethrough effect. At this point, your app has basic interactivity.

Step 4: Connect to Supabase Database

Data can't only live in the browser (it disappears on refresh). We need a database.

4.1 Create a Supabase Project

  1. Go to supabase.com and sign up
  2. Click "New Project," give it a name, pick a region close to you
  3. Wait 1-2 minutes for the database to initialize

4.2 Create the Data Table

Run this in the Supabase console's SQL Editor:

CREATE TABLE tasks (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
content TEXT NOT NULL,
is_completed BOOLEAN DEFAULT FALSE,
position INTEGER NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
user_id TEXT NOT NULL
);

-- Create index to speed up queries
CREATE INDEX idx_tasks_user_date ON tasks(user_id, created_at);

4.3 Install the Supabase Client

npm install @supabase/supabase-js

4.4 Configure Environment Variables

Create a .env.local file:

NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key

You can find these values in the Supabase console under Settings → API.

4.5 Create the Supabase Client

In src/lib/supabase.ts:

import { createClient } from "@supabase/supabase-js";

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;

export const supabase = createClient(supabaseUrl, supabaseAnonKey);

4.6 Update the Page Logic

Prompt:

Modify page.tsx to implement the following:

1. Use localStorage to generate or retrieve an anonymous user ID (format: "anon-" + random string)
2. On page load, read today's tasks from Supabase (query by user_id and created_at)
3. When the save button is clicked, save the 3 tasks to Supabase (use upsert — update if today's tasks already exist)
4. When a checkbox is toggled, update the is_completed field in Supabase in real-time
5. Show a loading state while data is loading

Import the supabase client from @/lib/supabase.

Test after saving: enter tasks → save → refresh the page → tasks are still there!

Troubleshooting Common Issues

Problem: Save returns 401/403 error Check Supabase's Row Level Security (RLS) settings. For development, you can disable RLS:

ALTER TABLE tasks DISABLE ROW LEVEL SECURITY;

Problem: Query returns an empty array Check the date filtering logic for created_at. Supabase uses UTC time, which may differ from your local time by a day. Have AI filter by the day's start and end times in the prompt.

Problem: Data saves but doesn't appear after refresh Check that the anonymous user ID is consistent across requests (it should be stored in localStorage, not randomly generated each time).

Step 5: Add the AI Encouragement Feature

This is the fun part — letting AI cheer you on.

5.1 Create the API Route

Create src/app/api/motivate/route.ts:

Prompt:

Create a Next.js API Route at /api/motivate.

Functionality:
1. Accept POST requests with a body containing a tasks array (three task strings)
2. Call the OpenAI API (model: gpt-4o-mini — affordable and sufficient)
3. Have AI generate a short encouragement message (under 100 words) based on the user's three tasks
4. Also generate a practical tip (how to efficiently complete today's tasks)
5. Return JSON: { message: "encouragement", tip: "tip" }

Use the OPENAI_API_KEY environment variable.

5.2 Install the OpenAI SDK

npm install openai

5.3 Set Up the OpenAI API Key

Add to .env.local:

OPENAI_API_KEY=sk-your-key

Go to platform.openai.com to sign up and create an API Key. New accounts usually have free credits.

5.4 Call from the Frontend

Prompt:

Below the save button in page.tsx, add a "✨ Get Today's Encouragement" button.

When clicked:
1. Button shows a loading state: "Generating..."
2. POST request to /api/motivate with body { tasks: [...] }
3. After receiving the response, display the encouragement and tip below the button
4. Display in a card style with an orange-themed border
5. If the request fails, show a friendly error message

Test: enter tasks → click "Get Today's Encouragement" → wait a few seconds → see the AI-generated encouragement.

If "Generating..." gets stuck, check the terminal for errors. The most common issues are a misconfigured API Key or an OpenAI account with no balance.

Step 6: Add Statistics

The last core feature — completion stats.

Prompt:

Add a stats area at the top of the page:

1. Today's completion count: X/3
2. If all 3 are complete, show a celebration animation (use emoji 🎉 and simple CSS animation)
3. Show consecutive completion days (how many days in a row all 3/3 were completed)

Stats are queried from Supabase, filtered by user ID.

At this point, all the core features of your MVP are complete.

The Build-Test-Fix Cycle

The six steps above look smooth, but in practice you'll hit all kinds of errors. That's completely normal.

The real development flow looks like this:

Write code → Error → Copy error to AI → AI fixes it → Another error → Back to AI → It works → Next feature

Don't get discouraged by errors. Errors are a daily part of programming — not evidence that you're not cut out for this. Senior developers hit countless errors every day too; the difference is they're more practiced at searching for answers.

A few debugging tips:

  1. Change one thing at a time — if you change three things and get an error, you won't know which one caused it
  2. Save and test frequently — test after each small feature, don't wait until the whole page is done
  3. Use console.log — not sure what a variable's value is? console.log(variable) and take a look
  4. Error messages are your friends — they tell you which line has what problem, and 90% of the time that's enough to locate the issue

Chapter Summary

StepWhat Was Accomplished
1. InitializeCreated Next.js + Tailwind project
2. Main pageThree task inputs + save button
3. Checkbox completionCheckboxes + strikethrough effect
4. DatabaseSupabase stores task data, persists across refreshes
5. AI encouragementCalls OpenAI API for encouragement and tips
6. StatisticsCompletion count + streak days

You now have a working application. It might not look pretty, but it works.

In the next section, we'll make it look good.