Set Up the Project
Every cooking school has opinions. The knife skills instructor thinks the claw grip lesson is flawless. The bread baking teacher is convinced nobody reads the hydration guide. And the students? They have their own opinions, scattered across emails, sticky notes, and hallway conversations.
We're going to collect those opinions in one place. A feedback API backed by a JSON file, with real course names, real comments, and enough structure that we can query it, filter it, and summarize it. Nothing fancy on the frontend. We're building an API, so the terminal is our kitchen.
Outcome
Scaffold a Next.js project with a Feedback type and a JSON file of seed data.
Fast Track
- Deploy the starter repo to Vercel, then clone it locally
- Review the
Feedbackinterface inlib/types.tsand the seed data indata/feedback.json - 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.
Once Vercel creates your project, clone it locally and install dependencies:
git clone <your-repo-url>
cd cooking-school-feedback
pnpm installThe starter gives you a Next.js app with the App Router and TypeScript already configured. No styling libraries needed for this course since we're building an API, not a UI.
The starter includes the type definition and seed data already. Your job is to implement the data utility. Here's what's in the box:
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 tolessonSlug(string), which lesson within the courserating(number), integer from 1 to 5comment(string), the feedback textauthor(string), who submitted itcreatedAt(string), ISO 8601 timestamp
data/feedback.json already contains 10 seed feedback entries across three courses at our cooking school: knife-skills, bread-baking, and pasta-from-scratch. Real names, real comments, and a range of ratings. A mix of glowing reviews and constructive criticism that will make the summary endpoint more interesting later.
The real work is in lib/data.ts. Open it up. The function signatures are there, but the implementations are stubs. You'll need to fill in three functions:
getAllFeedback(), reads the file and returns the parsed arraygetFeedbackById(id), finds a single entry by itsidaddFeedback(entry), generates anidandcreatedAt, 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.
A simple pattern: count the existing entries and pad the number. If there are 10 entries, the next id is fb-011. Not production-grade, but perfect for a course project.
Try It
After implementing the functions, verify the setup by running the dev server and checking that the project compiles:
pnpm devYou should see:
▲ Next.js 16.2.1 (Turbopack)
- Local: http://localhost:3000
No errors. The data utility won't be reachable from the browser yet (we'll wire up the API routes in the next lesson), but the project should compile cleanly.
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.
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/.
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.
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.tsexports aFeedbackinterface with all 7 fields (provided by starter)data/feedback.jsoncontains 10 seed feedback entries across three courses (provided by starter)lib/data.tshas working implementations ofgetAllFeedback,getFeedbackById, andaddFeedbackpnpm devstarts without errors
A typed interface, structured seed data, and a data utility that reads and writes actual JSON. The foundation is in place for an API that agents can understand without guessing.
Solution
export interface Feedback {
id: string;
courseSlug: string;
lessonSlug: string;
rating: number;
comment: string;
author: string;
createdAt: string;
}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;
}[
{
"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?