Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified .dockerignore
100644 → 100755
Empty file.
Empty file modified .gitignore
100644 → 100755
Empty file.
Empty file modified CATAGORY_API.md
100644 → 100755
Empty file.
127 changes: 127 additions & 0 deletions MODULAR_ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Modular Monolith Architecture

This backend follows a **Modular Monolith** architecture pattern, which provides better organization, maintainability, and scalability compared to traditional layered architecture.

## Architecture Overview

### Traditional vs Modular Approach

**Before (Layered):**
```
src/
├── controllers/ # All controllers
├── services/ # All services
├── routes/ # All routes
├── validators/ # All validators
└── middlewares/ # All middlewares
```

**After (Modular):**
```
src/
└── modules/
├── user/ # User domain
├── category/ # Category domain
├── provider/ # Provider domain
├── company/ # Company domain
├── service/ # Service domain
└── shared/ # Shared components
```

## Module Structure

Each domain module follows a consistent structure:

```
modules/[domain]/
├── index.ts # Module exports
├── types.ts # Domain types & interfaces
├── [domain].controller.ts # HTTP request handling
├── [domain].service.ts # Business logic
├── [domain].route.ts # Route definitions
└── [domain].validator.ts # Input validation schemas
```

### Shared Module

The shared module contains cross-cutting concerns:

```
modules/shared/
├── types/ # Common types & interfaces
├── errors/ # Domain error classes
├── middlewares/ # Reusable middlewares
├── utils/ # Utility functions
└── interfaces/ # Repository patterns
```

## Key Benefits

1. **Domain-Driven Design**: Code is organized by business domains rather than technical layers
2. **Better Separation of Concerns**: Each module handles its own domain logic
3. **Improved Maintainability**: Changes are localized to specific domains
4. **Enhanced Testability**: Modules can be tested in isolation
5. **Scalability**: Individual modules can be extracted into microservices if needed
6. **Clear Boundaries**: Well-defined interfaces between modules

## Design Patterns Used

### 1. Module Pattern
Each domain is encapsulated in its own module with clean exports.

### 2. Repository Pattern (Interface)
Data access is abstracted through repository interfaces in `shared/interfaces/`.

### 3. Domain Error Handling
Custom error classes provide better error handling and HTTP status mapping.

### 4. Dependency Injection Ready
Modules are designed to support dependency injection for better testability.

## Module Dependencies

```mermaid
graph TD
A[User Module] --> E[Shared Module]
B[Category Module] --> E
C[Provider Module] --> E
D[Service Module] --> E
F[Company Module] --> E

C --> A
D --> A
D --> B
D --> C
```

## Usage Examples

### Importing from modules:
```typescript
// Import specific functions
import { userRoutes } from './modules/user/index.js';

// Import domain types
import { User, UserCreateData } from './modules/user/types.js';

// Import shared utilities
import { DomainError, ApiResponse } from './modules/shared/index.js';
```

### Adding new features:
1. Identify the appropriate domain module
2. Add business logic to the service file
3. Add HTTP handlers to the controller
4. Update routes and validation as needed
5. Export new functionality through module index

## Migration Benefits

- ✅ Cleaner codebase organization
- ✅ Better code discoverability
- ✅ Reduced coupling between domains
- ✅ Foundation for microservices migration
- ✅ Improved developer experience
- ✅ Better testing isolation

This architecture provides a solid foundation for scaling the application while maintaining clean separation of concerns and domain boundaries.
Empty file modified README.md
100644 → 100755
Empty file.
Empty file modified SERVICES_API.md
100644 → 100755
Empty file.
Empty file modified category_dataset.json
100644 → 100755
Empty file.
Empty file modified docker-compose.yml
100644 → 100755
Empty file.
12 changes: 8 additions & 4 deletions dockerfile
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


FROM node:18-alpine

# App directory
Expand All @@ -17,8 +15,14 @@ RUN npx prisma generate
# Rest of the source
COPY . .

# Install TypeScript globally
RUN npm install -g typescript

# Transpile TypeScript to JavaScript
RUN npx tsc

# Expose the service port
EXPOSE 3000

# Start the API
CMD ["npm", "start"]
# Run the transpiled JavaScript file
CMD ["node", "dist/index.js"]
20 changes: 12 additions & 8 deletions index.js → index.ts
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ try {

import { PrismaClient } from '@prisma/client';
import { withAccelerate } from '@prisma/extension-accelerate';
import express from 'express';
import express, { type Application } from 'express';
import cors from 'cors';
import userRoutes from './src/routes/user.route.js';
import providerRoutes from './src/routes/provider.route.js';
import companyRoutes from './src/routes/company.route.js';
import servicesRoutes from './src/routes/services.route.js';
import categoryRoutes from './src/routes/catagory.route.js';
import { userRoutes } from './src/modules/user/index.js';
import { providerRoutes } from './src/modules/provider/index.js';
import { companyRoutes } from './src/modules/company/index.js';
import { servicesRoutes } from './src/modules/service/index.js';
import { categoryRoutes } from './src/modules/category/index.js';
import { errorHandler } from './src/modules/shared/index.js';

const prisma = new PrismaClient().$extends(withAccelerate());

const app = express();
const app: Application = express();

// CORS configuration
app.use(cors({
Expand All @@ -39,5 +40,8 @@ app.use('/api/companies', companyRoutes);
app.use('/api/services', servicesRoutes);
app.use('/api/categories', categoryRoutes);

const PORT = process.env.PORT || 3000;
// Global error handler (should be last middleware)
app.use(errorHandler);

const PORT: number = parseInt(process.env.PORT || '3000', 10);
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
177 changes: 163 additions & 14 deletions package-lock.json
100644 → 100755

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading