DEV Community

Cover image for Title: Building a "Smart" Markdown Note-Taker with Next.js 15 and OpenAI
Abhishek Mishra
Abhishek Mishra

Posted on

Title: Building a "Smart" Markdown Note-Taker with Next.js 15 and OpenAI

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
``

Enter fullscreen mode Exit fullscreen mode

**

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())
}
`
Enter fullscreen mode Exit fullscreen mode

**

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;
}
Enter fullscreen mode Exit fullscreen mode

**

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

**

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)