Project Status: In Development π§
- About The Project
- β¨ Key Features
- π Key Concepts Implemented
- π οΈ Tech Stack
- π Getting Started
- π§ͺ Testing the API (with Insomnia/Postman)
- π Available Scripts
- π CI/CD Pipeline
- π License
This is a robust RESTful API developed as the backend for a GymPass-style application. The project was built following SOLID design principles and Clean Architecture, ensuring clean, scalable, and easily maintainable code.
The application allows users to register, find gyms, perform check-ins, and more, featuring a role-based access control system (Member vs. Admin).
- Authentication & Profile: User registration and login with JWT authentication, as well as profile viewing.
- Gym Management: Registration of new gyms (restricted to administrators).
- Gym Search: Search for gyms by name or proximity (within a 10km radius).
- Check-in System: Users can check into nearby gyms.
- Check-in Validation: Administrators can validate user check-ins within 20 minutes of their creation.
- History & Metrics: Users can view their check-in history and metrics.
In addition to its features, the project implements industry-standard patterns to ensure security and a great user experience.
Access control is based on user roles (Role). There are two access levels:
MEMBER: Standard user, can search for gyms and perform check-ins.ADMIN: User with elevated privileges, can register gyms and validate check-ins.
This is implemented via middleware that verifies the user's role on specific routes, such as POST /gyms and PATCH /check-ins/:checkInId/validate.
To enhance security and user experience, the API uses a Refresh Token system:
- Upon authenticating, the user receives a short-lived
tokenand arefreshToken. - The
tokenis used to access protected routes. - When the
tokenexpires, instead of forcing a new login, the client application can use therefreshToken(which is stored securely, e.g., in an HTTP Only cookie) to request a new access token via thePATCH /token/refreshroute.
| Technology | Description |
|---|---|
| Node.js | JavaScript runtime environment for the backend. |
| TypeScript | JavaScript superset that adds static typing. |
| Fastify | High-performance, low-overhead web framework. |
| Prisma | Next-generation ORM for Node.js and TypeScript. |
| PostgreSQL | Robust, open-source relational database. |
| Vitest | Blazing fast unit and integration testing framework. |
| Zod | Schema and type validation library. |
| Docker | Platform for developing, deploying, and running applications in containers. |
| GitHub Actions | CI/CD automation for tests and builds. |
Follow the steps below to get the project running locally.
-
Clone the repository:
git clone [https://github.com/YOUR_USERNAME/YOUR_REPOSITORY.git](https://github.com/YOUR_USERNAME/YOUR_REPOSITORY.git) cd YOUR_REPOSITORY -
Install dependencies:
npm install
-
Set up environment variables:
- Create a copy of the example file
.env.exampleand rename it to.env.cp .env.example .env
- Fill in the variables in the
.envfile. For the Docker environment, the default values should work.# .env DATABASE_URL="postgresql://docker:docker@db:5432/apisolid?schema=public" JWT_SECRET="your-jwt-secret-here" PORT=3333
- Create a copy of the example file
-
Start the environment with Docker:
- This command will build the image, start the API and database containers, run migrations, and seed the database with initial data.
npm run docker:dev
π The API will be running at http://localhost:3333.
When you start the application with npm run docker:dev, an Administrator user is automatically created by the seed script to make it easier to test protected routes.
The following guide demonstrates the key user flows: creating a standard Member account, using the pre-seeded Admin account, and performing the complete check-in process.
First, let's simulate the flow of a standard user.
-
Create a new user:
POSThttp://localhost:3333/users- Body (JSON):
{ "name": "John Doe", "email": "john.doe@example.com", "password": "password123" }
-
Authenticate as the new user:
POSThttp://localhost:3333/sessions- Body (JSON):
{ "email": "john.doe@example.com", "password": "password123" } - Save the
tokenfrom the response. This is yourMEMBERtoken.
Now, let's use the pre-seeded administrator account to test admin-only features.
-
Authenticate as the Admin:
POSThttp://localhost:3333/sessions- Body (JSON):
{ "email": "andre@andre.com", "password": "123456" } - Save this new
token. This is yourADMINtoken.
-
Access an Admin-only route (creating a gym):
POSThttp://localhost:3333/gyms- Add the
ADMINtoken to theAuthorization: Bearer <TOKEN>header. - Body (JSON):
{ "title": "Code Gym", "description": "The best gym for devs", "phone": "11999999999", "latitude": -23.563853, "longitude": -46.656507 } - The gym will be created successfully. Save the
idof the created gym from the response for the next step.
This flow requires actions from both a MEMBER and an ADMIN.
-
Create a Check-in (as a
MEMBER):- Use the
MEMBERtoken (John Doe'stoken) in theAuthorizationheader. POSThttp://localhost:3333/gyms/YOUR_GYM_ID/check-ins- (Replace
YOUR_GYM_IDwith the ID you saved from Step 2).
- (Replace
- Body (JSON): This is required to validate the user's distance from the gym. Use coordinates close to the gym's location.
{ "latitude": -23.563899, "longitude": -46.656599 } - A new check-in will be created. Save the
idof the check-in from the response.
- Use the
-
Validate the Check-in (as an
ADMIN):- Now, switch to the
ADMINtoken in theAuthorizationheader. PATCHhttp://localhost:3333/check-ins/YOUR_CHECK_IN_ID/validate- (Replace
YOUR_CHECK_IN_IDwith the ID you saved from the previous request).
- (Replace
- This request does not need a body.
- The check-in will be successfully validated. This demonstrates the RBAC perfectly, as a
MEMBERcannot perform this action.
- Now, switch to the
When your token expires, use the refresh route. Insomnia/Postman handles cookies automatically.
PATCHhttp://localhost:3333/token/refresh- This request does not need a body or an
Authorizationheader. - The response will contain a new, valid
token.
npm run start:dev: Starts the application in development mode with hot-reload.npm run build: Compiles the TypeScript code to JavaScript.npm run test: Runs unit tests.npm run test:e2e: Runs End-to-End tests (requires a test database).npm run docker:dev: Starts the complete environment (API + Database) with Docker.npm run docker:down: Stops and removes the Docker containers and volumes.
This project uses GitHub Actions for continuous integration and testing.
- Trigger: The workflows are triggered on every
pull_requestopened against themasterbranch. - Workflows:
- Unit Tests: A fast job that installs dependencies and runs
npm run test. It ensures that the core business logic is correct. - E2E Tests: A more comprehensive job that spins up a temporary PostgreSQL service container, installs dependencies, and runs
npm run test:e2e. It guarantees that the integration between the API and the database is working perfectly.
- Unit Tests: A fast job that installs dependencies and runs
This automation ensures that new code is only merged into the main branch if it passes all tests, maintaining the project's quality and stability.
This project is under the MIT license. See the LICENSE file for more details.