Welcome to the first lesson of the Task Manager API backend course.
This entire course is about building a backend-first Task Manager using Next.js + TypeScript, but we’re not starting with API routes or UI. We’re starting with the core of the domain: what a “task” is, how we store it in memory, and how our backend code should operate on it.
In this lesson, you’ll use Codex as your coding partner to:
- Define a shared Task model and in-memory tasks store
- Implement a service layer that knows how to create, read, update, delete, and filter tasks
- Expose that service through a first
/api/tasksHTTP endpoint
By the end of the lesson, you won’t just have some helper functions—you’ll have the core task engine of your API, built with clear layers and Codex-powered implementation.
Before you ever touch a route, it’s important to answer three questions:
-
What is the “thing” my API manages?
For us, that “thing” is a task: it has an id, a title, some content, whether it’s completed, and optionally a due date. -
Where does that data live?
In this unit, it lives in a simple in-memory array (tasks), so you can focus on logic and structure without worrying about databases or files. -
Who is allowed to touch that data?
That’s the service layer: a small set of functions that are responsible for all reads and writes. Routes don’t manipulate arrays directly; they call service functions.
This layered design gives you:
- A single, shared Task type used everywhere in the backend
- A clear place to put business rules (for example, how IDs are generated or what “completed” means)
- Thin, predictable API route handlers that just translate HTTP into service calls
Later lessons and units will add validation, security, logging, and persistence, but all of that will depend on the foundations you’re building here.
You are not expected to hand-code every function from scratch. Instead, this lesson is about learning to direct Codex like a senior engineer directing a junior:
- You decide the shape of the Task type and how the service functions should behave.
- You tell Codex exactly which file it’s allowed to touch.
- You describe the required behavior in natural language.
- You ask Codex to show the full file so you can review its work.
A typical Codex prompt in this lesson will include:
- A clear file scope
"Modify only
src/lib/tasks.ts." - The required types or functions and their fields/return types
- Any important rules (e.g., auto-increment IDs, default
completedto false) - A safety note
"Do not change any other files."
- A request for the final content
"Show the full updated contents of
src/lib/tasks.ts."
Everything you build in this lesson is done through these kinds of carefully constructed prompts.
Your first practice is all about designing the Task domain and giving the backend a single source of truth.
Conceptually, you are answering:
- What properties does every task have?
- What types should those properties be?
- Where do all tasks live in this application right now?
You’ll collaborate with Codex to fill in src/lib/tasks.ts so it contains:
-
A
Tasktype with:id: numbertitle: stringcontent: stringcompleted: booleandueDate?: string(optional ISO date string)
-
An exported, in-memory
tasks: Task[]array, initially empty
At this point, you’re not worrying about how tasks get created or updated yet. You’re just defining “what a task is” and where the collection of tasks lives.
A typical high-quality prompt for this practice might look like:
Codex, modify only
src/lib/tasks.ts.Define a
Tasktype with fieldsid: number,title: string, , , and optional (ISO date string).
Once you have a defined Task type and tasks store, the next question is: who manipulates it?
That’s the job of the service layer, implemented in src/lib/services/taskService.ts.
The service layer will be responsible for:
getAllTasks()— listing everythingcreateTask(...)— generating a new task with a new idgetTaskById(id)— finding a single taskupdateTaskById(id, data, partial)— editing an existing taskdeleteTaskById(id)— removing a taskfilterTaskByStatus(completed)— filtering tasks by completion status
All of these functions operate on the shared tasks array. The routes won’t need to know how IDs are generated, how tasks are stored, or how updates are applied—they just call the service.
In this practice, you’ll ask Codex to:
- Import
Taskandtasksfrom@/lib/tasks - Implement each service function with the correct types and behavior
- Keep everything in-memory for now (no databases, no files)
A strong Codex prompt for this might be:
Codex, modify only
src/lib/services/taskService.ts. Use and from and implement:
Once your Task model and service functions are in place, you’re ready to let HTTP clients talk to them through a route: src/app/api/tasks/route.ts.
The purpose of this route file is to:
- Map HTTP methods to service-layer calls
- Handle basic validation of incoming data
- Return structured JSON responses with appropriate HTTP status codes
For this first collection-level route, you’ll support:
- GET
/api/tasks— return all tasks as JSON - POST
/api/tasks— validate the body and create a new task
Conceptually, the handlers will:
-
For GET:
- Call
getAllTasks() - Return the list with status 200
- Call
-
For POST:
- Parse the JSON body
- Check that
titleandcontentare non-empty strings - If
dueDateis provided, confirm it’s a valid date string - On validation failure, return a 400 JSON error
- On success, call
createTask(...)and return the created task with status 201
You’ll still use NextResponse.json in this unit; more advanced response helpers will come later.
An example Codex prompt might be:
In this first lesson, you:
- Defined a shared Task model and in-memory tasks store
- Implemented a focused
taskServicethat centralizes all task operations - Exposed the service through a
/api/tasksroute that speaks HTTP and JSON
Everything else in the course builds on this layered foundation. In later units, you will:
- Add stronger validation flows
- Introduce more robust response helpers
- Expand the API with additional routes and behaviors
- Evolve from a simple in-memory store toward more realistic persistence strategies
But all of that depends on today’s work: a clear domain model, a clean service layer, and a thin route that uses them—built with precise, high-quality prompts to Codex.
You’re now ready to dive into the practices and start guiding Codex through implementing each piece of the Task core.
