A backend-only task manager API built with Express, TypeScript, PostgreSQL, and JWT authentication. This project was created as a first serious backend project to understand how real server-side applications are structured, while intentionally keeping the stack minimal to learn the core concepts first.
This project focuses on backend fundamentals rather than UI. The goal was to build a practical API that demonstrates:
- request validation
- authentication and authorization
- layered backend architecture
- database access with PostgreSQL
- error handling and response consistency
- Node.js
- Express.js
- TypeScript
- PostgreSQL
- JWT for authentication
- bcryptjs for password hashing
- Zod for request validation
- express-rate-limit for securing auth routes
- Vitest & Supertest for basic testing of some routes
server/src/
├── app.ts
├── server.ts
├── docs/
│ └── APIs.md
├── config/
│ ├── db.config.ts
│ └── env.config.ts
├── schemas/
│ ├── auth.zod-schemas.ts
│ ├── db/
│ │ └── primary-db-schema.sql
│ ├── db.zod-schemas.draft.ts
│ ├── env.zod-schema.ts
│ ├── projects.zod-schemas.ts
│ └── tasks.zod-schemas.ts
├── routes/
│ ├── auth.routes.ts
│ ├── index.routes.ts
│ ├── projects.routes.ts
│ └── tasks.routes.ts
├── middlewares/
│ ├── auth-rate-limit.middleware.ts
│ ├── authenticate.middleware.ts
│ ├── global-error-handler.middleware.ts
│ └── validate-requests.middleware.ts
├── controllers/
│ ├── auth.controllers.ts
│ ├── projects.controllers.ts
│ └── tasks.controllers.ts
├── services/
│ ├── auth.services.ts
│ ├── projects.services.ts
│ └── tasks.services.ts
├── repositories/
│ ├── projects.repository.ts
│ ├── tasks.repository.ts
│ └── users.repository.ts
├── utils/
│ ├── db/
│ │ └── patch-query-builder.util.ts
│ ├── errors/
│ │ └── errors.util.ts
│ └── validate-env.util.ts
├── tests/
│ ├── auth/
│ │ ├── login.test.ts
│ │ └── register.test.ts
│ ├── projects/
│ │ ├── createProject.test.ts
│ │ ├── deleteProject.test.ts
│ │ ├── getAllProjects.test.ts
│ │ ├── getProject.test.ts
│ │ └── updateProject.test.ts
│ └── tasks/
│ ├── createTask.test.ts
│ ├── deleteTask.test.ts
│ ├── getAllTasks.test.ts
│ ├── getTask.test.ts
│ └── updateTask.test.ts
└── types/
├── express.d.ts
└── schema.interfaces.ts
- User registration and login endpoints
- Input validation for auth, project, and task requests
- JWT-based authentication middleware
- Password hashing before storing credentials
- Project & Task CRUD operations
- Ownership checks so users can only access their own data, enforcing authorization
- Centralized error handling using a custom AppError class & global error handler
- Service layer for business logic
- Repository layer for database queries
The codebase is organized in a simple layered structure:
- Routes: define API endpoints and middleware order
- Controllers: handle request and response flow
- Services: contain business logic and domain checks
- Repositories: handle database queries
- Middlewares: handle auth, validation, and errors
- Schemas: define request validation rules with Zod
This structure keeps the code easier to test, reason about, and extend.
POST /api/v1/auth/register- create a new userPOST /api/v1/auth/login- authenticate and receive a JWT
POST /api/v1/projects- create a projectGET /api/v1/projects- get all projects for the logged-in userGET /api/v1/projects/:projectId- get a single projectPATCH /api/v1/projects/:projectId- update a projectDELETE /api/v1/projects/:projectId- delete a project
POST /api/v1/projects/:projectId/tasks- create a task inside a projectGET /api/v1/projects/:projectId/tasks- get all tasks inside a projectGET /api/v1/projects/:projectId/tasks/:taskId- get a single taskPATCH /api/v1/projects/:projectId/tasks/:taskId- update a taskDELETE /api/v1/projects/:projectId/tasks/:taskId- delete a task
This project shows practical understanding of backend concepts that matter in real applications:
- how authentication flows work with JWT
- how to protect routes with middleware
- how to validate input before it reaches business logic
- how to keep database logic separate from request handling
- how to enforce ownership checks at the backend level
- how to avoid unsafe SQL patterns by using parameterized queries
The server expects the following environment variables:
PORTDATABASE_URLJWT_SECRET
- Install dependencies inside the
serverfolder. - Create a
.envfile with the required environment variables. - Start the server with the dev script.
Example:
cd server
npm install
npm run devThis project was intentionally built without a frontend so the focus stays on backend fundamentals. It is meant to show understanding of API design, data flow, validation, authentication, and code organization rather than UI polish.
If I continue this project later, the next improvements would be:
- automated tests
- structured logging
- more detailed API documentation
- transaction handling for multi-step workflows