Skip to content

Commit 9bd40cc

Browse files
committed
feat: add CLAUDE.md for project guidance and enhance file upload support in MagicRouter
1 parent 0fd76f6 commit 9bd40cc

File tree

7 files changed

+500
-304
lines changed

7 files changed

+500
-304
lines changed

CLAUDE.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Development Commands
6+
7+
- **Development server**: `pnpm run dev` - Starts both backend and email template development server
8+
- **Backend only**: `pnpm run start:dev` - Starts just the backend with hot reload
9+
- **Build**: `pnpm run build` - Builds the project using tsup
10+
- **Production start**: `pnpm run start:prod` - Starts production build with .env.production
11+
- **Local start**: `pnpm run start:local` - Starts production build with .env.local
12+
- **Database seeder**: `pnpm run seeder` - Runs database seeding scripts
13+
- **Linting**: `pnpm run lint` - Runs ESLint, `pnpm run lint:fix` - Auto-fixes linting issues
14+
- **Email templates**: `pnpm run email:dev` - Starts email template development server
15+
16+
## Architecture Overview
17+
18+
This is a TypeScript Express.js backend toolkit with the following key architectural components:
19+
20+
### Core Architecture
21+
- **MagicRouter System**: Custom routing ([src/openapi/magic-router.ts](src/openapi/magic-router.ts)) that automatically generates OpenAPI/Swagger documentation from Zod schemas
22+
- **Module-based structure**: Features organized in modules under [src/modules/](src/modules/) (auth, user)
23+
- **Configuration management**: Type-safe config using Zod validation in [src/config/config.service.ts](src/config/config.service.ts)
24+
- **Database**: MongoDB with Mongoose ODM, connection managed in [src/lib/database.ts](src/lib/database.ts)
25+
26+
### Key Features
27+
- **Authentication**: JWT-based with optional OTP verification, Google OAuth support
28+
- **File Uploads**: Multer with S3 integration via [src/lib/aws.service.ts](src/lib/aws.service.ts)
29+
- **Email System**: React Email templates with Mailgun provider, queue-based sending
30+
- **Real-time**: Socket.io integration with Redis adapter
31+
- **Background Jobs**: BullMQ with Redis for email queues and other background tasks
32+
- **API Documentation**: Auto-generated Swagger docs at `/api-docs` from MagicRouter
33+
- **Queue Dashboard**: BullMQ admin dashboard at `/admin/queues`
34+
35+
### Middleware Stack
36+
- Request validation with Zod schemas ([src/middlewares/validate-zod-schema.middleware.ts](src/middlewares/validate-zod-schema.middleware.ts))
37+
- JWT extraction and authorization ([src/middlewares/extract-jwt-schema.middleware.ts](src/middlewares/extract-jwt-schema.middleware.ts))
38+
- File upload handling with S3 ([src/middlewares/multer-s3.middleware.ts](src/middlewares/multer-s3.middleware.ts))
39+
- Access control middleware ([src/middlewares/can-access.middleware.ts](src/middlewares/can-access.middleware.ts))
40+
41+
### Environment Setup
42+
1. Start Docker services: `docker compose up -d` (MongoDB + Redis)
43+
2. Install dependencies: `pnpm i`
44+
3. Configure environment variables using `.env.sample` as template
45+
46+
### Key Patterns
47+
- **MagicRouter**: All API routes use MagicRouter for automatic OpenAPI generation
48+
- **Zod Schemas**: Every route uses Zod for request/response validation
49+
- **Service Layer**: Business logic separated into service files
50+
- **Queue-based**: Email sending and background jobs use BullMQ queues
51+
- **Type Safety**: Full TypeScript coverage with Zod for runtime validation
52+
53+
### File Upload & Storage
54+
- Multer middleware handles file uploads
55+
- AWS S3 integration for file storage
56+
- File upload routes in [src/upload/](src/upload/)
57+
58+
### Email System
59+
- React Email for template development
60+
- Mailgun for email delivery
61+
- Queue-based sending system in [src/queues/email.queue.ts](src/queues/email.queue.ts)
62+
63+
## Important Notes
64+
- All expiration times in config are in milliseconds (converted from strings)
65+
- The project uses pnpm as package manager
66+
- Database seeding is available via the seeder script
67+
- Global error handling in [src/utils/globalErrorHandler.ts](src/utils/globalErrorHandler.ts)
68+
- Logging uses Pino logger with pretty printing in development

README.md

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ Before you get started, make sure you have the following installed on your machi
2424
```sh
2525
docker compose up -d
2626
```
27+
2728
2. **Install Dependencies**:
2829

2930
- Use pnpm to install all the necessary dependencies:
3031
```sh
3132
pnpm i
3233
```
34+
3335
3. **Configure Environment Variables**:
3436

3537
- Create a `.env` file in the root directory.
@@ -40,7 +42,7 @@ Before you get started, make sure you have the following installed on your machi
4042
- **OpenAPI Autogenerated Swagger Docs** : Automatically generated Swagger docs through MagicRouter API and Zod, accessible at `/api-docs`.
4143
- **Auth Module**: Includes Google Sign-In support for easy authentication.
4244
- **User Management**: Comprehensive user management functionality.
43-
- **File Upload**: Handles file uploads with Multer and Amazon S3.
45+
- **File Upload**: Handles file uploads with Multer and Amazon S3, with full OpenAPI/Swagger documentation support.
4446
- **Data Validation & Serialization**: Zod is used for validation and serialization of data.
4547
- **Configuration Management**: Managed using dotenv-cli and validated with Zod for accuracy and safety.
4648
- **Middlewares**:
@@ -64,6 +66,7 @@ Before you get started, make sure you have the following installed on your machi
6466
- **PM2 Support**: Out-of-the-box support for PM2 to manage your production processes.
6567

6668
## Folder Structure
69+
6770
```plaintext
6871
├── build.ts
6972
├── docker-compose.yml
@@ -153,6 +156,93 @@ Before you get started, make sure you have the following installed on your machi
153156
└── tsconfig.json
154157
```
155158

159+
## File Upload with MagicRouter
160+
161+
MagicRouter now supports multipart/form-data file uploads with automatic OpenAPI documentation generation. This feature works seamlessly with Multer middleware.
162+
163+
### Usage
164+
165+
#### Single File Upload
166+
167+
```typescript
168+
import { z } from 'zod';
169+
import MagicRouter from './openapi/magic-router';
170+
import { zFile } from './openapi/zod-extend';
171+
import { uploadMiddleware } from './middlewares/multer-s3.middleware';
172+
173+
const router = new MagicRouter('/api');
174+
175+
router.post(
176+
'/upload',
177+
{
178+
requestType: {
179+
body: z.object({
180+
avatar: zFile(),
181+
}),
182+
},
183+
contentType: 'multipart/form-data',
184+
},
185+
uploadMiddleware,
186+
handleUpload,
187+
);
188+
```
189+
190+
#### Multiple Files Upload
191+
192+
```typescript
193+
import { zFiles } from './openapi/zod-extend';
194+
195+
router.post(
196+
'/upload-multiple',
197+
{
198+
requestType: {
199+
body: z.object({
200+
images: zFiles(),
201+
}),
202+
},
203+
contentType: 'multipart/form-data',
204+
},
205+
uploadMiddleware,
206+
handleMultipleUpload,
207+
);
208+
```
209+
210+
#### Mixed Fields (Text + Files)
211+
212+
```typescript
213+
router.post(
214+
'/upload-with-data',
215+
{
216+
requestType: {
217+
body: z.object({
218+
name: z.string(),
219+
email: z.string().email(),
220+
avatar: zFile(),
221+
documents: zFiles().optional(),
222+
}),
223+
},
224+
contentType: 'multipart/form-data',
225+
},
226+
uploadMiddleware,
227+
handleUploadWithData,
228+
);
229+
```
230+
231+
### Content Types
232+
233+
MagicRouter supports three content types:
234+
235+
- `application/json` (default)
236+
- `multipart/form-data` (for file uploads)
237+
- `application/x-www-form-urlencoded` (for form submissions)
238+
239+
### Key Features
240+
241+
- **Automatic OpenAPI Generation**: File upload endpoints are automatically documented in Swagger
242+
- **Multer Compatible**: Works with existing Multer middleware without changes
243+
- **Type-Safe**: Zod validation for text fields while Multer handles file validation
244+
- **Flexible**: Support for single files, multiple files, and mixed text/file fields
245+
156246
## Roadmap
157247
158248
- **Socket.io Support:** Adding support for Redis adapter and a chat module.
Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,49 @@
1-
import type { NextFunction } from "express";
2-
import { StatusCodes } from "http-status-codes";
3-
import multer from "multer";
4-
import multerS3 from "multer-s3";
5-
import s3, { BUCKET_NAME } from "../lib/aws.service";
6-
import { errorResponse } from "../utils/api.utils";
7-
import { checkFiletype } from "../utils/common.utils";
8-
import type { RequestAny, ResponseAny } from "../openapi/magic-router";
1+
import type { NextFunction } from 'express';
2+
import { StatusCodes } from 'http-status-codes';
3+
import multer from 'multer';
4+
import multerS3 from 'multer-s3';
5+
import s3, { BUCKET_NAME } from '../lib/aws.service';
6+
import { errorResponse } from '../utils/api.utils';
7+
import { checkFiletype } from '../utils/common.utils';
8+
import type { RequestAny, ResponseAny } from '../openapi/magic-router';
99

1010
const storageEngineProfile: multer.StorageEngine = multerS3({
11-
s3: s3,
12-
bucket: BUCKET_NAME,
13-
metadata: (_, file, cb) => {
14-
cb(null, { fieldName: file.fieldname });
15-
},
16-
key: (req: RequestAny, file, cb) => {
17-
const key = `user-${req.user.id}/profile/${file.originalname}`;
11+
s3: s3,
12+
bucket: BUCKET_NAME,
13+
metadata: (_, file, cb) => {
14+
cb(null, { fieldName: file.fieldname });
15+
},
16+
key: (req: RequestAny, file, cb) => {
17+
const key = `user-${req.user.id}/profile/${file.originalname}`;
1818

19-
if (checkFiletype(file)) {
20-
cb(null, key);
21-
} else {
22-
cb("File format is not valid", key);
23-
}
24-
},
19+
if (checkFiletype(file)) {
20+
cb(null, key);
21+
} else {
22+
cb('File format is not valid', key);
23+
}
24+
},
2525
});
2626

2727
export const uploadProfile = (
28-
req: RequestAny,
29-
res: ResponseAny,
30-
next: NextFunction,
28+
req: RequestAny,
29+
res: ResponseAny,
30+
next?: NextFunction,
3131
) => {
32-
const upload = multer({
33-
storage: storageEngineProfile,
34-
limits: { fileSize: 1000000 * 10 },
35-
}).single("avatar");
32+
const upload = multer({
33+
storage: storageEngineProfile,
34+
limits: { fileSize: 1000000 * 10 },
35+
}).single('avatar');
3636

37-
upload(req, res, (err) => {
38-
if (err) {
39-
return errorResponse(
40-
res,
41-
(err as Error).message,
42-
StatusCodes.BAD_REQUEST,
43-
err,
44-
);
45-
}
37+
upload(req, res, (err) => {
38+
if (err) {
39+
return errorResponse(
40+
res,
41+
(err as Error).message,
42+
StatusCodes.BAD_REQUEST,
43+
err,
44+
);
45+
}
4646

47-
next();
48-
});
47+
next?.();
48+
});
4949
};

0 commit comments

Comments
 (0)