Vercel Logo

Set Up the Project

Every cooking school collects opinions. Instructors hear them through emails, sticky notes, and hallway conversations.

We'll collect that feedback in a JSON-backed API with enough structure to query, filter, and summarize it. This course stays in the terminal because the API is the project.

Outcome

Scaffold a Next.js project with a Feedback type and a JSON file of seed data.

Fast Track

  1. Deploy the starter repo to Vercel, then clone it locally
  2. Review the Feedback interface in lib/types.ts and the seed data in data/feedback.json
  3. Implement the three functions in lib/data.ts

Hands-on exercise

Start by deploying the starter repo. This gets you a live URL right away, which we'll need when we add agent-friendly docs later in the course.

Deploy with Vercel

Once Vercel creates your project, clone it locally and install dependencies:

git clone <your-repo-url>
cd cooking-school-feedback
pnpm install

The starter provides a Next.js app with App Router and TypeScript configured. This API project does not need a styling library.

The starter includes the type definition and seed data. You'll implement the data utility.

lib/types.ts already has the Feedback interface. Open it and confirm it has these fields:

  • id (string), unique identifier like "fb-001"
  • courseSlug (string), which course the feedback belongs to
  • lessonSlug (string), which lesson within the course
  • rating (number), integer from 1 to 5
  • comment (string), the feedback text
  • author (string), who submitted it
  • createdAt (string), ISO 8601 timestamp

data/feedback.json contains 10 feedback entries for knife-skills, bread-baking, and pasta-from-scratch. The range of ratings will make the summary endpoint useful later.

Open lib/data.ts. The function signatures are present, but the implementations are stubs:

  • getAllFeedback(), reads the file and returns the parsed array
  • getFeedbackById(id), finds a single entry by its id
  • addFeedback(entry), generates an id and createdAt, appends to the file, returns the new entry

Use fs/promises for file operations and path.join(process.cwd(), "data", "feedback.json") for the file path.

ID generation

Count the existing entries and pad the number. If there are 10 entries, the next id is fb-011. This approach is sufficient for the course project.

Try It

After implementing the functions, verify the setup by running the dev server and checking that the project compiles:

pnpm dev

You should see:

▲ Next.js 16.2.1 (Turbopack)
- Local: http://localhost:3000

The project should compile cleanly. The data utility will become reachable after you add API routes in the next lesson.

You can also verify the types work by opening lib/data.ts in your editor and confirming there are no TypeScript errors on the Feedback import.

JSON file path

The process.cwd() approach works in development and in next build. If you see a "file not found" error, make sure the data/ folder is at the project root, not inside app/.

If you see 'fs is not defined'

Make sure you're importing from fs/promises, not fs. And double-check the import is import fs from "fs/promises", not a named import like import { readFile } from "fs". The data utility runs on the server, so Node built-ins are available, but the import path matters.

If TypeScript complains about your function signatures

Each function needs to be async since fs.readFile and fs.writeFile return Promises. If your editor shows a type error on the return value, check that you have async before the function keyword and that the return type matches (Promise<Feedback[]>, Promise<Feedback | undefined>, Promise<Feedback>).

Commit

git add -A && git commit -m "feat(api): scaffold project with feedback types and seed data"

Done-When

  • lib/types.ts exports a Feedback interface with all 7 fields (provided by starter)
  • data/feedback.json contains 10 seed feedback entries across three courses (provided by starter)
  • lib/data.ts has working implementations of getAllFeedback, getFeedbackById, and addFeedback
  • pnpm dev starts without errors

You now have a typed interface, structured seed data, and a utility that reads and writes JSON. The next lesson exposes that data through an API route.

Solution

lib/types.ts
export interface Feedback {
  id: string;
  courseSlug: string;
  lessonSlug: string;
  rating: number;
  comment: string;
  author: string;
  createdAt: string;
}
lib/data.ts
import fs from "fs/promises";
import path from "path";
import type { Feedback } from "./types";
 
const DATA_PATH = path.join(process.cwd(), "data", "feedback.json");
 
export async function getAllFeedback(): Promise<Feedback[]> {
  const raw = await fs.readFile(DATA_PATH, "utf-8");
  return JSON.parse(raw);
}
 
export async function getFeedbackById(
  id: string
): Promise<Feedback | undefined> {
  const all = await getAllFeedback();
  return all.find((fb) => fb.id === id);
}
 
export async function addFeedback(
  entry: Omit<Feedback, "id" | "createdAt">
): Promise<Feedback> {
  const all = await getAllFeedback();
  const newEntry: Feedback = {
    ...entry,
    id: `fb-${String(all.length + 1).padStart(3, "0")}`,
    createdAt: new Date().toISOString(),
  };
  all.push(newEntry);
  await fs.writeFile(DATA_PATH, JSON.stringify(all, null, 2));
  return newEntry;
}
data/feedback.json
[
  {
    "id": "fb-001",
    "courseSlug": "knife-skills",
    "lessonSlug": "the-claw-grip",
    "rating": 5,
    "comment": "Finally understand why my onion cuts were uneven. The claw grip changed everything.",
    "author": "Priya Sharma",
    "createdAt": "2026-03-01T10:30:00Z"
  },
  {
    "id": "fb-002",
    "courseSlug": "knife-skills",
    "lessonSlug": "dicing-onions",
    "rating": 4,
    "comment": "Great technique breakdown but I wish there was a slow-motion video. Hard to follow the horizontal cut at full speed.",
    "author": "Marcus Chen",
    "createdAt": "2026-03-01T14:15:00Z"
  },
  {
    "id": "fb-003",
    "courseSlug": "bread-baking",
    "lessonSlug": "hydration-basics",
    "rating": 5,
    "comment": "I had no idea that flour-to-water ratio mattered this much. My loaves have been bricks for months. Not anymore.",
    "author": "Aisha Johnson",
    "createdAt": "2026-03-02T09:00:00Z"
  },
  {
    "id": "fb-004",
    "courseSlug": "knife-skills",
    "lessonSlug": "the-claw-grip",
    "rating": 3,
    "comment": "Felt a bit rushed. Would have liked more time on finger positioning before jumping to speed drills.",
    "author": "Tom Kowalski",
    "createdAt": "2026-03-02T11:45:00Z"
  },
  {
    "id": "fb-005",
    "courseSlug": "bread-baking",
    "lessonSlug": "shaping-boules",
    "rating": 5,
    "comment": "The surface tension explanation finally clicked. My dough used to spread flat every time.",
    "author": "Sofia Reyes",
    "createdAt": "2026-03-03T08:20:00Z"
  },
  {
    "id": "fb-006",
    "courseSlug": "bread-baking",
    "lessonSlug": "sourdough-starter",
    "rating": 4,
    "comment": "Good lesson, but the difference between a stiff starter and a liquid starter took me a second read.",
    "author": "James Okafor",
    "createdAt": "2026-03-03T16:00:00Z"
  },
  {
    "id": "fb-007",
    "courseSlug": "knife-skills",
    "lessonSlug": "julienne-cuts",
    "rating": 5,
    "comment": "Matchstick carrots used to take me forever. The guide-hand technique cut my prep time in half.",
    "author": "Lin Wei",
    "createdAt": "2026-03-04T10:10:00Z"
  },
  {
    "id": "fb-008",
    "courseSlug": "bread-baking",
    "lessonSlug": "hydration-basics",
    "rating": 2,
    "comment": "I already knew this from other baking courses. Wish there was a fast-track for people who have the fundamentals.",
    "author": "Derek Miles",
    "createdAt": "2026-03-04T13:30:00Z"
  },
  {
    "id": "fb-009",
    "courseSlug": "knife-skills",
    "lessonSlug": "dicing-onions",
    "rating": 5,
    "comment": "Best lesson in the course. No more crying over mangled onion pieces.",
    "author": "Nora Eriksson",
    "createdAt": "2026-03-05T09:45:00Z"
  },
  {
    "id": "fb-010",
    "courseSlug": "pasta-from-scratch",
    "lessonSlug": "egg-dough",
    "rating": 4,
    "comment": "The well method is so satisfying. Dough came together on the first try, which never happens to me.",
    "author": "Priya Sharma",
    "createdAt": "2026-03-05T15:20:00Z"
  }
]

Was this helpful?

supported.