Skip to content

Commit 3eefee8

Browse files
committed
Aggressive lint, format, and RESTful cleanup: codebase ready for CI/CD and Docker
1 parent d214b8f commit 3eefee8

19 files changed

Lines changed: 84 additions & 79 deletions

File tree

.github/workflows/ci-cd.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,4 @@ jobs:
5555
IMAGE=your-dockerhub-username/your-repo-name
5656
docker tag $IMAGE:latest $IMAGE:${{ github.sha }}
5757
docker push $IMAGE:latest
58-
docker push $IMAGE:${{ github.sha }}
58+
docker push $IMAGE:${{ github.sha }}

.lintstagedrc.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
11
{
2-
"*.js": [
3-
"prettier --write",
4-
"eslint --fix"
5-
]
6-
}
2+
"*.js": ["prettier --write", "eslint --fix"]
3+
}

.prettierrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
"tabWidth": 2,
55
"trailingComma": "es5",
66
"printWidth": 100
7-
}
7+
}

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
A Node.js REST API for a digital marketplace, structured according to Uncle Bob's Clean Architecture principles. This project demonstrates separation of concerns, testability, and scalability by organizing code into distinct layers: Enterprise Business Rules, Application Business Rules, Interface Adapters, and Frameworks & Drivers.
66

77
## Table of Contents
8+
89
- [Introduction](#introduction)
910
- [Architecture Overview](#architecture-overview)
1011
- [Features](#features)
@@ -19,9 +20,11 @@ A Node.js REST API for a digital marketplace, structured according to Uncle Bob'
1920
- [License](#license)
2021

2122
## Introduction
23+
2224
This backend API allows users to register, authenticate, and interact with products, blogs, and ratings. It is designed for maintainability and extensibility, following Clean Architecture best practices.
2325

2426
## Architecture Overview
27+
2528
The project is organized into the following layers:
2629

2730
- **Enterprise Business Rules**: Core business logic and domain models (`enterprise-business-rules/`).
@@ -45,6 +48,7 @@ public/ # Static files and HTML views
4548
```
4649

4750
## Features
51+
4852
- User registration and authentication (JWT)
4953
- Product CRUD operations
5054
- Blog and rating management
@@ -55,10 +59,12 @@ public/ # Static files and HTML views
5559
## Getting Started
5660

5761
### Prerequisites
62+
5863
- Node.js (v18+ recommended)
5964
- MongoDB instance (local or cloud)
6065

6166
### Installation
67+
6268
1. Clone the repository:
6369
```bash
6470
git clone <repo-url>
@@ -84,6 +90,7 @@ public/ # Static files and HTML views
8490
The server will run at [http://localhost:5000](http://localhost:5000).
8591

8692
## Project Structure
93+
8794
- `index.js` - Main entry point, sets up Express, routes, and middleware
8895
- `routes/` - Express route definitions for products, users, blogs
8996
- `interface-adapters/` - Controllers, DB access, adapters, and middleware
@@ -94,6 +101,7 @@ The server will run at [http://localhost:5000](http://localhost:5000).
94101
## API Endpoints
95102

96103
### Products
104+
97105
- `POST /products/` - Create a new product
98106
- `GET /products/` - Get all products
99107
- `GET /products/:productId` - Get a product by ID
@@ -102,11 +110,13 @@ The server will run at [http://localhost:5000](http://localhost:5000).
102110
- `POST /products/:productId/:userId/rating` - Rate a product
103111

104112
### Users & Auth
113+
105114
- `POST /users/register` - Register a new user
106115
- `POST /users/login` - User login
107116
- `GET /users/profile` - Get user profile (auth required)
108117

109118
### Blogs
119+
110120
- `GET /blogs/` - Get all blogs
111121
- `POST /blogs/` - Create a new blog
112122

@@ -163,4 +173,4 @@ The server will run at [http://localhost:5000](http://localhost:5000).
163173

164174
## License
165175

166-
This project is licensed under the ISC License. See the [LICENSE](LICENSE) file for details.
176+
This project is licensed under the ISC License. See the [LICENSE](LICENSE) file for details.

application-business-rules/use-cases/products/product-handlers.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
const productValidationFcts = require('../../../enterprise-business-rules/validate-models/product-validation-fcts');
2+
// const { findAllProductUseCaseHandler } = require('./product-handlers');
3+
14
/**
25
* Creates a new product in the database using the provided product data.
36
*
@@ -48,7 +51,7 @@ const findOneProductUseCase = ({ productValidation }) =>
4851

4952
// find all product use case handler
5053
const findAllProductsUseCase = () =>
51-
(findAllProductUseCaseHandler = async ({ dbProductHandler, filterOptions }) => {
54+
async function findAllProductUseCaseHandler({ dbProductHandler, filterOptions }) {
5255
try {
5356
const allProducts = await dbProductHandler.findAllProductsDbHandler(filterOptions);
5457
// console.log("from find all products use case: ", allProducts);
@@ -57,7 +60,7 @@ const findAllProductsUseCase = () =>
5760
console.log('Error from fetch all product handler: ', e);
5861
throw new Error(e.message);
5962
}
60-
});
63+
};
6164

6265
// delete product use case
6366
const deleteProductUseCase = () =>
@@ -66,7 +69,7 @@ const deleteProductUseCase = () =>
6669
const { InvalidPropertyError } = errorHandlers;
6770
try {
6871
// validate id
69-
const uuid = productValidation.validateObjectId(productId, InvalidPropertyError);
72+
const uuid = productValidationFcts.validateObjectId(productId, InvalidPropertyError);
7073
// check first that the product exists
7174
const existingProduct = await findOneProductDbHandler({ productId: uuid });
7275
if (!existingProduct) {
@@ -97,7 +100,7 @@ const updateProductUseCase = ({ makeProductModelHandler }) =>
97100
const { InvalidPropertyError } = errorHandlers;
98101
try {
99102
// validate id
100-
const uuid = productValidation.validateObjectId(productId, InvalidPropertyError);
103+
const uuid = productValidationFcts.validateObjectId(productId, InvalidPropertyError);
101104
// check first that the product exists
102105
const existingProduct = await findOneProductDbHandler({ productId: uuid });
103106
if (!existingProduct) {

docker-compose.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ services:
44
build: .
55
container_name: clean-arch-app
66
ports:
7-
- "5000:5000"
7+
- '5000:5000'
88
environment:
99
- PORT=5000
1010
- MONGODB_URI=mongodb://mongo:27017/cleanarchdb
@@ -16,9 +16,9 @@ services:
1616
image: mongo:6.0
1717
container_name: clean-arch-mongo
1818
ports:
19-
- "27017:27017"
19+
- '27017:27017'
2020
volumes:
2121
- mongo_data:/data/db
2222
restart: unless-stopped
2323
volumes:
24-
mongo_data:
24+
mongo_data:

enterprise-business-rules/validate-models/product-validation-fcts.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ function validateTitle({ title, InvalidPropertyError }) {
55
return title.charAt(0).toUpperCase() + title.slice(1).toLowerCase();
66
}
77

8-
//validate title length
9-
108
//validate and normalise product description
119
function validateDescription({ description, InvalidPropertyError }) {
1210
if (description.length < 50) {
@@ -98,11 +96,11 @@ function validateBrands(brands, InvalidPropertyError) {
9896
}
9997

10098
//validate and normalize product rating: rating is an array of refences to users in the users collection
101-
function validateRating(rating, InvalidPropertyError) {
102-
const ratingObj = {};
99+
// function validateRating(rating, InvalidPropertyError) {
100+
// const ratingObj = {};
103101

104-
return rating;
105-
}
102+
// return rating;
103+
// }
106104

107105
// validate image type for png jpg
108106
const validateImageType = (image, InvalidPropertyError) => {

enterprise-business-rules/validate-models/user-validation-functions.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,6 @@ function validateRole(roles) {
9797
return roles;
9898
}
9999

100-
const validActive = new Set(['true', 'false']);
101-
function validateActive(active) {
102-
if (!validActive.has(active)) {
103-
throw new InvalidPropertyError(`A user's active must be either 'true' or 'false'.`);
104-
}
105-
if (!Array.isArray(active)) {
106-
active = [active];
107-
}
108-
return active;
109-
}
110-
111100
//validate mongodb id
112101
function validateId(id) {
113102
if (!ObjectId.isValid(id)) {
@@ -153,7 +142,6 @@ async function validateUserData(userData) {
153142
if (!email) errors.push('user must have an email.');
154143
if (!password) errors.push('user must have a password.');
155144
if (!roles) errors.push('user must have a role');
156-
if (typeof active !== 'boolean') errors.push('user must have an active status');
157145

158146
if (errors.length) {
159147
throw new RequiredParameterError(errors.join(', '));

interface-adapters/controllers/products/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { dbProductHandler } = require('../../database-access');
1+
// const { dbProductHandler } = require('../../database-access');
22
const productControllerHandlsers = require('./product-controller')();
33
const productUseCaseHandlers = require('../../../application-business-rules/use-cases/products');
44

interface-adapters/controllers/users/user-auth-controller.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const { makeHttpError } = require('../../validators-errors/http-error');
2+
13
module.exports = {
24
/**
35
* Registers a new user using the provided user case handler.
@@ -410,13 +412,13 @@ module.exports = {
410412
}
411413
try {
412414
const blockedUser = await blockUserUseCaseHandler({ userId });
413-
console.log(' from blockUserController controller handler: ', e);
415+
console.log(' from blockUserController controller handler: ', blockedUser);
414416
return {
415417
headers: {
416418
'Content-Type': 'application/json',
417419
},
418420
statusCode: 201,
419-
data: JSON.stringify({ message: 'user blocked successfully' }),
421+
data: JSON.stringify({ message: 'user blocked successfully', blockedUser }),
420422
};
421423
} catch (e) {
422424
logEvents(
@@ -470,8 +472,6 @@ module.exports = {
470472
// user controller for forgot password
471473
forgotPasswordController: ({
472474
forgotPasswordUseCaseHandler,
473-
UniqueConstraintError,
474-
InvalidPropertyError,
475475
makeHttpError,
476476
logEvents,
477477
sendEmail,

0 commit comments

Comments
 (0)