Intro
In 2025, a standard CRUD app isn't enough to impress. Users expect applications to think. Today, we’re going to build a Smart Note-Taking App that doesn't just store Markdown but uses AI to automatically generate tags and summaries for your notes.
The Stack:
- Frontend/Backend: Next.js 15 (App Router)
- Styling: Tailwind CSS
- Database: Prisma + PostgreSQL (via Supabase)
- AI: OpenAI API
**
1. Setting Up the Project
**
First, initialize your project with the latest Next.js features:
bash
``
npx create-next-app@latest smart-notes --typescript --tailwind --eslint
cd smart-notes
npm install @prisma/client lucide-react openai
npx prisma init
``
**
2. The Database Schema
**
We need a simple but effective model. In prisma/schema.prisma:
PostgreSQL
`
model Note {
id String @id @default(cuid())
title String
content String @db.Text
tags String[]
summary String? @db.Text
createdAt DateTime @default(now())
}
`
**
3. The "Smart" Logic (Server Action)
**
Instead of a separate API route, we’ll use a Next.js Server Action. This keeps our logic bundled and secure on the server.
Create a file at app/actions/notes.ts:
typescript
"use server";
import { PrismaClient } from "@prisma/client";
import OpenAI from "openai";
const prisma = new PrismaClient();
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export async function createSmartNote(formData: FormData) {
const title = formData.get("title") as string;
const content = formData.get("content") as string;
// AI Magic: Generate Summary and Tags
const aiResponse = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: "Analyze the following note. Return a JSON object with a 'summary' (1 sentence) and 'tags' (array of strings)." },
{ role: "user", content: content }
],
response_format: { type: "json_object" }
});
const { summary, tags } = JSON.parse(aiResponse.choices[0].message.content || "{}");
const note = await prisma.note.create({
data: { title, content, summary, tags },
});
return note;
}
**
4. The UI: Clean and Functional
**
In your app/page.tsx, create a simple form to handle the input. We'll use useFormStatus to show a loading state while the AI is "thinking."
typescript
import { createSmartNote } from "./actions/notes";
export default function Home() {
return (
<main className="max-w-4xl mx-auto p-8">
<h1 className="text-3xl font-bold mb-6">Smart Markdown Notes 📝</h1>
<form action={createSmartNote} className="flex flex-col gap-4 bg-gray-50 p-6 rounded-lg shadow">
<input name="title" placeholder="Note Title" className="p-2 border rounded" required />
<textarea name="content" placeholder="Write your markdown here..." rows={6} className="p-2 border rounded" required />
<button type="submit" className="bg-blue-600 text-white py-2 rounded hover:bg-blue-700 transition">
Save Smart Note
</button>
</form>
{/* Logic to fetch and map notes would go here */}
</main>
);
}
**
5. Why this matters in 2025
**
Server Actions: We eliminated the need for complex useEffect and fetch calls.
AI Integration: We moved from "Full Stack" to "AI-Native" by integrating intelligence directly into the data flow.
Type Safety: Using TypeScript ensures that our AI response matches our database schema.
**
Conclusion
**
Building full-stack apps today is about orchestrating services. By combining the power of Next.js with AI, you can create tools that provide actual utility beyond just data storage.
Top comments (0)