Hello! Welcome to the first lesson of our Final Capstone: Full-Stack Task Manager module.
Throughout this course, you've acquired all the individual skills needed to be a full-stack developer. You've built React components, created Express API endpoints, queried a PostgreSQL database, and even implemented a complete authentication system. Now, it's time to bring all those pieces together.
Today, we're not focused on implementing a specific feature. Instead, we're taking on the role of an architect. Our goal is to design and implement the foundational architecture for our full-stack application. This involves understanding the high-level data flow, planning a professional and scalable project structure, and setting up the initial, empty project "skeletons" for both our frontend and backend. By the end of this lesson, you'll have a solid blueprint and a clean slate, ready to start building the Task Manager.
The Big Picture: PERN Stack Architecture
Our task manager will be built using the PERN stack: PostgreSQL, Express, React, and Node.js. Let's visualize how these technologies work together to create a cohesive application.

This flow can be broken down into a few key steps:
- A user performs an action in the React application (e.g., clicks "Add Task").
- The React app sends an HTTP request (like
POST,GET,PUT) to our Express/Node.js API. - The API receives the request, validates it, and executes the necessary business logic. This involves running a SQL query against our PostgreSQL database.
- The database processes the query and returns the requested data (or a confirmation of success) to the API.
- The API formats this data into a JSON response and sends it back to the React app.
- The React app uses this response to update its state, causing the UI to re-render and show the new information to the user.
To hear this flow explained, watch this short introductory clip.
PERN Stack Course - Postgres, Express, React, and Node
The video 'PERN Stack Course' by freeCodeCamp.org provides an excellent overview of how the components of the PERN stack interact. This clip explains the high-level architecture we will be using.
Please watch from 01:50 to 03:22. Focus on how HTTP requests from the React client instruct the backend API, which in turn performs CRUD operations on the database.
Designing the Project's Blueprint: Folder Structure
A well-organized folder structure is critical for any software project. It makes the code easier to navigate, maintain, and scale. For our full-stack application, we will adopt a common and effective pattern: a single root folder containing two distinct sub-projects: one for the client (React) and one for the server (Node.js).
task-manager/
├── client/ # React Frontend
│ ├── src/
│ ├── package.json
│ └── ...
└── server/ # Node.js/Express Backend
├── src/
├── package.json
└── ...
This structure is a best practice for several reasons. Let's consult an article that explains the benefits.
How To Develop and Build PERN Stack
The article 'How To Develop and Build PERN Stack' discusses the practical setup of a PERN project. We'll read the section on project structure to understand the reasoning behind this separation.
Please read the section titled 'Project Structure'. The key takeaway is that separating the ui (our client) and api (our server) keeps their dependencies isolated and makes the overall application more modular.
Architecting the Backend for Scalability
In previous lessons, we often placed our database queries and business logic directly inside the Express route handlers for simplicity. This is fine for small examples, but for a real-world application like our capstone, we need a more robust structure.
We will use a Three-Layer Architecture for our backend. This pattern separates concerns into distinct layers:
- Router Layer (
routes/): Defines the API endpoints (e.g.,GET /tasks) and points them to the appropriate controller function. - Controller Layer (
controllers/): Acts as the intermediary. It receives the HTTP request, calls the necessary service(s) to handle the business logic, and sends the final HTTP response. It does not talk to the database directly. - Service Layer (
services/): Contains the core business logic of your application. For example, calculating values, orchestrating calls to multiple data sources, or deciding what to do after a database operation. - Data Access Layer (
data/ordb/): The only layer that communicates directly with the database. It contains all the SQL queries.
This separation makes your code more organized, easier to test, and much simpler to maintain as the application grows.
This short video provides a clear explanation of this architectural pattern and why it's superior to mixing all your logic together.
Node.js Project Structure and Architecture Best Practices
The video 'Node.js Project Structure and Architecture Best Practices' explains the three-layer architecture. It will give you a solid mental model for how we'll build our backend.
Please watch from 00:10 to 04:07. Pay attention to the diagram explaining the flow from Controller -> Service -> Data Layer, and how this translates into a clean folder structure.
Let's Build the Skeleton: Initial Project Setup
Now that we have our architectural plan, let's create the project's foundational structure.
Step 1: Backend Setup (server folder)
We'll start by initializing our Node.js project and creating the directory structure for our three-layer architecture.
-
Create a main project folder:
mkdir task-manager -
Navigate into it and create the server folder:
cd task-managerandmkdir server -
Navigate into the server folder:
cd server -
Initialize a new Node.js project:
npm init -y -
Install the essential backend dependencies:
npm install express pg cors dotenvnpm install --save-dev nodemon(for automatic server restarts during development)
-
In your
server/package.json, add adevscript to run the server withnodemon:"scripts": { "dev": "nodemon index.js" } -
Create the initial folder structure inside
server:mkdir srccd srcmkdir routes controllers services db
-
Create a placeholder entry file
server/src/index.jswith a basic Express server setup:require('dotenv').config(); const express = require('express'); const cors = require('cors'); const app = express(); app.use(cors()); app.use(express.json()); app.get('/', (req, res) => { res.send('Task Manager API is running...'); }); const PORT = process.env.PORT || 5000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); });
Step 2: Frontend Setup (client folder)
Next, we'll set up the React project using Vite, our chosen build tool.
- Navigate back to the root
task-managerfolder. - Create the client folder:
mkdir client - Navigate into it:
cd client - Initialize a new React project using Vite:
npm create vite@latest . -- --template react- (Note: The
.tells it to create the project in the current folder).
- (Note: The
- Install the project dependencies:
npm install - Install
axios, our library for making API calls:npm install axios
Test your understanding!
In our client application, we'll need to make API calls to our backend server, which will be running on http://localhost:5000. To avoid CORS issues during development, create-react-app (and Vite, by extension) allows you to specify a proxy.
Where would you configure the proxy settings for your Vite React application to forward API requests to your backend server?
Show answer
You would configure the proxy in the vite.config.js file in the root of your client directory. You would add a server object with a proxy configuration like this:
// client/vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': { // We'll prefix our API routes with /api
target: 'http://localhost:5000', // The address of our backend
changeOrigin: true,
secure: false,
}
}
}
})
This tells the Vite development server to forward any request starting with /api to our backend on port 5000.
Step 3: Database Setup
Finally, we need to create the database our application will use. The freeCodeCamp video shows how to do this from the command line, which is an excellent skill to have.
PERN Stack Course - Postgres, Express, React, and Node
Let's revisit the 'PERN Stack Course' video to see how to create a database and a table using psql commands.
Watch from 08:35 to 12:25. You don't have to follow along exactly, but understand the process of: Connecting to PostgreSQL using psql. Creating a new database (CREATE DATABASE ...). Connecting to that new database (\c database_name). Creating a table with specific columns and data types (CREATE TABLE ...).
For our Task Manager, we will need at least two tables: users and tasks. Here are the initial SQL commands you can use to create them in your own database.
-- For the 'users' table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(50) DEFAULT 'user',
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- For the 'tasks' table
CREATE TABLE tasks (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
title VARCHAR(255) NOT NULL,
description TEXT,
is_completed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
);
Conclusion
Excellent work! You have successfully designed the architecture for our capstone project and laid the digital foundation upon which we will build. This initial planning and setup is one of the most important steps in any software engineering project.
Key Takeaways:
- You can now visualize the complete data flow in a PERN stack application, from the React frontend to the PostgreSQL database and back.
- You understand the importance of a separated client/server project structure for modularity and maintenance.
- You are ready to implement a scalable three-layer architecture (Controller, Service, Data Layer) on the backend.
- You have created the initial project folders, installed dependencies, and defined the database schema, giving us a clean and organized starting point.
Preview of the Next Lesson:
With our architecture in place, we're ready to start coding. The next lesson focuses on building the core of our backend API: "Build a complete REST API with secure user authentication and CRUD functionality for tasks and projects". We'll begin by implementing the user registration and login endpoints within our new, organized three-layer structure.