Skip to content

Commit e6bd3fc

Browse files
authored
Merge pull request #61 from BIC-DevSphere/develop
Merge Develop in Main
2 parents 65a41c6 + 1eee52d commit e6bd3fc

51 files changed

Lines changed: 2768 additions & 1427 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ BETTER_AUTH_URL=
55
NODE_ENV=
66
JWT_ACCESS_SECRET=
77
JWT_REFRESH_SECRET=
8+
CLOUDINARY_CLOUD_NAME=
9+
CLOUDINARY_API_KEY=
10+
CLOUDINARY_API_SECRET=
11+
GITHUB_SECRET=
12+
GITHUB_CLIENT_ID=
813
GITHUB_TOKEN=

.prettierrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"printWidth": 100,
3+
"tabWidth": 2,
4+
"useTabs": false,
5+
"semi": true,
6+
"singleQuote": true,
7+
"trailingComma": "es5",
8+
"bracketSpacing": true,
9+
"arrowParens": "always",
10+
"endOfLine": "lf"
11+
}

CONTRIBUTING.md

Lines changed: 96 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,6 @@ Welcome to the DevSphere Backend project! This guide will help you understand ou
1717
- [Authentication & Authorization](#authentication--authorization)
1818
- [Code Style Guidelines](#code-style-guidelines)
1919

20-
## Getting Started
21-
22-
### Prerequisites
23-
- Node.js (v18+)
24-
- PostgreSQL database
25-
- npm or yarn package manager
26-
27-
### Setup
28-
1. Clone the repository
29-
2. Install dependencies: `npm install`
30-
3. Set up environment variables (see `.env.example`)
31-
4. Generate Prisma client: `npm run generate`
32-
5. Run migrations: `npm run migrate`
33-
6. Start development server: `npm run dev`
34-
3520
## Project Structure
3621

3722
```
@@ -44,7 +29,7 @@ src/
4429
├── utils/ # Utility functions and constants
4530
├── types/ # TypeScript type definitions
4631
├── dtos/ # Data Transfer Objects for responses
47-
├── parser/ # Input validation and parsing logic
32+
├── jobs/ # Background jobs and cron tasks
4833
├── db/ # Database configuration
4934
└── index.ts # Application entry point
5035
@@ -58,14 +43,17 @@ docs/ # API documentation
5843
## Naming Conventions
5944

6045
### File Naming
46+
6147
- Use **kebab-case** for file names: `event.controller.ts`, `member.service.ts`
6248
- Use **camelCase** for directories: `controllers/`, `services/`
6349

6450
### Class Naming
51+
6552
- Use **PascalCase** for class names: `EventController`, `MemberService`
6653
- Export instances using **camelCase**: `export const eventController = new EventController()`
6754

6855
### Function Naming
56+
6957
- Use **camelCase** for function names: `createEvent`, `getUserRole`
7058
- Use descriptive verbs for CRUD operations:
7159
- `create` for POST operations
@@ -74,6 +62,7 @@ docs/ # API documentation
7462
- `remove`/`delete` for DELETE operations
7563

7664
### Variable Naming
65+
7766
- Use **camelCase** for variables: `eventData`, `userId`
7867
- Use **SCREAMING_SNAKE_CASE** for constants: `HTTP.INTERNAL`, `DATABASE_URL`
7968

@@ -103,34 +92,34 @@ Services contain the core business logic and database operations. They follow a
10392
### Service Class Structure
10493

10594
```typescript
106-
import prisma from "@/db/prisma";
107-
import { prismaSafe } from "@/lib/prismaSafe";
95+
import prisma from '@/db/prisma';
96+
import { prismaSafe } from '@/lib/prismaSafe';
10897

10998
class ExampleService {
110-
async createExample(data: ExampleType) {
111-
try {
112-
const [dbError, result] = await prismaSafe(
113-
prisma.example.create({
114-
data: {
115-
...data
116-
}
117-
})
118-
);
119-
120-
if (dbError) {
121-
return { success: false, error: dbError };
122-
}
123-
124-
if (!result) {
125-
return { success: false, error: 'Failed to create example' };
126-
}
127-
128-
return { success: true, data: result };
129-
} catch (error) {
130-
console.log(`Failed to create example: ${error}`);
131-
return { success: false, error: 'Failed to create example' };
132-
}
99+
async createExample(data: ExampleType) {
100+
try {
101+
const [dbError, result] = await prismaSafe(
102+
prisma.example.create({
103+
data: {
104+
...data,
105+
},
106+
})
107+
);
108+
109+
if (dbError) {
110+
return { success: false, error: dbError };
111+
}
112+
113+
if (!result) {
114+
return { success: false, error: 'Failed to create example' };
115+
}
116+
117+
return { success: true, data: result };
118+
} catch (error) {
119+
console.log(`Failed to create example: ${error}`);
120+
return { success: false, error: 'Failed to create example' };
133121
}
122+
}
134123
}
135124

136125
export const exampleService = new ExampleService();
@@ -143,48 +132,51 @@ export const exampleService = new ExampleService();
143132
- `update{Resource}` - Update existing resource
144133
- `remove{Resource}` or `delete{Resource}` - Delete resource
145134

135+
### Method Organization
136+
137+
- **Public methods at the top**
138+
- **Private helpers at the bottom** (prefixed with `_`)
139+
146140
## Controller Layer Conventions
147141

148142
Controllers handle HTTP requests, validate input, call services, and return responses.
149143

150144
### Controller Structure
151145

152146
```typescript
153-
import type { Request, Response } from "express";
147+
import type { Request, Response } from 'express';
154148
import { ErrorResponse, SuccessResponse } from '@/dtos';
155149
import { HTTP } from '@/utils/constants';
156150
import { exampleService } from '@/services/example.service';
157151
import exampleParser from '@/parser/example/example.parser';
158152

159153
class ExampleController {
160-
async createExample(req: Request, res: Response) {
161-
try {
162-
// 1. Parse and validate input
163-
const parseResult = await exampleParser(req.body);
164-
if (!parseResult.success) {
165-
return res.status(HTTP.BAD_REQUEST).json(
166-
ErrorResponse(HTTP.BAD_REQUEST, parseResult.error || 'Invalid data')
167-
);
168-
}
169-
170-
// 2. Call service
171-
const serviceResult = await exampleService.createExample(parseResult.data);
172-
if (!serviceResult.success) {
173-
return res.status(HTTP.INTERNAL).json(
174-
ErrorResponse(HTTP.INTERNAL, serviceResult.error || 'Failed to create')
175-
);
176-
}
177-
178-
// 3. Return success response
179-
return res.status(HTTP.CREATED).json(
180-
SuccessResponse(HTTP.CREATED, 'Created successfully', serviceResult.data)
181-
);
182-
} catch (error) {
183-
return res.status(HTTP.INTERNAL).json(
184-
ErrorResponse(HTTP.INTERNAL, 'Internal Server Error')
185-
);
186-
}
154+
async createExample(req: Request, res: Response) {
155+
try {
156+
// 1. Parse and validate input
157+
const parseResult = await exampleParser(req.body);
158+
if (!parseResult.success) {
159+
return res
160+
.status(HTTP.BAD_REQUEST)
161+
.json(ErrorResponse(HTTP.BAD_REQUEST, parseResult.error || 'Invalid data'));
162+
}
163+
164+
// 2. Call service
165+
const serviceResult = await exampleService.createExample(parseResult.data);
166+
if (!serviceResult.success) {
167+
return res
168+
.status(HTTP.INTERNAL)
169+
.json(ErrorResponse(HTTP.INTERNAL, serviceResult.error || 'Failed to create'));
170+
}
171+
172+
// 3. Return success response
173+
return res
174+
.status(HTTP.CREATED)
175+
.json(SuccessResponse(HTTP.CREATED, 'Created successfully', serviceResult.data));
176+
} catch (error) {
177+
return res.status(HTTP.INTERNAL).json(ErrorResponse(HTTP.INTERNAL, 'Internal Server Error'));
187178
}
179+
}
188180
}
189181

190182
export const exampleController = new ExampleController();
@@ -213,10 +205,6 @@ Routes should be organized by resource and follow RESTful conventions.
213205
### Route File Structure
214206
215207
```typescript
216-
import { Router } from 'express';
217-
import { exampleController } from '@/controllers/example.controller';
218-
import { authMiddleware, isAdmin } from '@/middleware/auth.middleware';
219-
220208
const exampleRouter = Router();
221209

222210
// Public routes
@@ -236,14 +224,14 @@ export default exampleRouter;
236224
237225
### RESTful Route Conventions
238226
239-
| HTTP Method | Route Pattern | Purpose | Controller Method |
240-
|-------------|---------------|---------|-------------------|
241-
| `GET` | `/api/resource` | Get all resources | `getResources` |
242-
| `GET` | `/api/resource/:id` | Get single resource | `getResource` |
243-
| `POST` | `/api/resource` | Create new resource | `createResource` |
244-
| `PUT` | `/api/resource/:id` | Update entire resource | `updateResource` |
245-
| `PATCH` | `/api/resource/:id` | Partial update | `patchResource` |
246-
| `DELETE` | `/api/resource/:id` | Delete resource | `deleteResource` |
227+
| HTTP Method | Route Pattern | Purpose | Controller Method |
228+
| ----------- | ------------------- | ---------------------- | ----------------- |
229+
| `GET` | `/api/resource` | Get all resources | `getResources` |
230+
| `GET` | `/api/resource/:id` | Get single resource | `getResource` |
231+
| `POST` | `/api/resource` | Create new resource | `createResource` |
232+
| `PUT` | `/api/resource/:id` | Update entire resource | `updateResource` |
233+
| `PATCH` | `/api/resource/:id` | Partial update | `patchResource` |
234+
| `DELETE` | `/api/resource/:id` | Delete resource | `deleteResource` |
247235
248236
### Route Registration in Main App
249237
@@ -260,30 +248,15 @@ app.use('/api/members', memberRouter);
260248
261249
Use the constants from `@/utils/constants`:
262250
263-
```typescript
264-
export const HTTP = {
265-
OK: 200,
266-
CREATED: 201,
267-
BAD_REQUEST: 400,
268-
UNAUTHORIZED: 401,
269-
FORBIDDEN: 403,
270-
NOT_FOUND: 404,
271-
CONFLICT: 409,
272-
INTERNAL: 500,
273-
} as const;
274-
```
275-
276251
### Database Error Handling
277252
278253
Always use `prismaSafe` for database operations:
279254
280255
```typescript
281-
const [error, result] = await prismaSafe(
282-
prisma.model.operation()
283-
);
256+
const [error, result] = await prismaSafe(prisma.model.operation());
284257

285258
if (error) {
286-
return { success: false, error };
259+
return { success: false, error };
287260
}
288261
```
289262
@@ -297,25 +270,26 @@ if (error) {
297270
298271
```typescript
299272
const [error, user] = await prismaSafe(
300-
prisma.user.findUnique({
301-
where: { id: userId }
302-
})
273+
prisma.user.findUnique({
274+
where: { id: userId },
275+
})
303276
);
304277

305278
if (error) {
306-
return { success: false, error };
279+
return { success: false, error };
307280
}
308281

309282
if (!user) {
310-
return { success: false, error: 'User not found' };
283+
return { success: false, error: 'User not found' };
311284
}
312285
```
313286
314287
### Schema Changes
315288
316289
After any Prisma schema changes:
317-
1. Run `npm run push` to update the database
318-
2. Run `npm run generate` to update the Prisma client
290+
291+
1. Run `npx prisma migrate dev` to update the database
292+
2. Run `npx prisma generate` to update the Prisma client
319293
320294
## Type Definitions
321295
@@ -328,15 +302,15 @@ After any Prisma schema changes:
328302
```typescript
329303
// src/types/example.types.ts
330304
export interface Example {
331-
id: string;
332-
name: string;
333-
createdAt: Date;
334-
updatedAt: Date;
305+
id: string;
306+
name: string;
307+
createdAt: Date;
308+
updatedAt: Date;
335309
}
336310

337311
export interface CreateExampleRequest {
338-
name: string;
339-
description?: string;
312+
name: string;
313+
description?: string;
340314
}
341315
```
342316
@@ -347,16 +321,19 @@ Place validation schemas in `src/utils/types/`:
347321
```typescript
348322
import { z } from 'zod';
349323

350-
export const exampleSchema = z.object({
351-
name: z.string().min(1, "Name is required"),
324+
export const exampleSchema = z
325+
.object({
326+
name: z.string().min(1, 'Name is required'),
352327
description: z.string().optional(),
353-
}).strict();
328+
})
329+
.strict();
354330

355331
export type Example = z.infer<typeof exampleSchema>;
356332
```
357333
358334
## Validation & Parsing
359-
use Zod validation middleware
335+
336+
use Zod validation middleware
360337
361338
## Authentication & Authorization
362339
@@ -420,11 +397,10 @@ import { exampleService } from '@/services/example.service';
420397
421398
## Pull Request Guidelines
422399
423-
1. **Create feature branches** from `main`
424-
2. **Write descriptive commit messages**
425-
3. **Test your changes** thoroughly
426-
4. **Update documentation** if needed
427-
5. **Follow all conventions** outlined in this guide
400+
1. **Write descriptive commit messages**
401+
2. **Test your changes** thoroughly
402+
3. **Update documentation** if needed
403+
4. **Follow all conventions** outlined in this guide
428404
429405
### Commit Message Format
430406

0 commit comments

Comments
 (0)