.cursorrules (deprecated)
rules/mern-stack/.cursorrules.cursorrules
Quality
81/100
Scores the file, not the repository.Length
1,195 words
22 headings · 7 code blocksRepository
16
— · pushed 109 days agoLast changed
2 days ago
First indexed 2 days ago.1# MERN Stack — Cursor Rules2# Comprehensive rules for MongoDB + Express + React + Node.js applications34## Project Context5You are working on a MERN stack application: MongoDB for the database, Express.js for6the API server, React for the frontend, and Node.js as the runtime. The project may be7a monorepo or split into separate client/server directories. The codebase uses modern8JavaScript/TypeScript and follows REST API conventions.910## Tech Stack11- MongoDB with Mongoose ODM (or MongoDB Node driver)12- Express.js 4.x for API server13- React 18+ with TypeScript14- Node.js 20+ LTS15- Vite for React client bundling16- JWT for authentication17- Zod for API validation18- React Query for server state management1920## Coding Style2122### Naming Conventions23- MongoDB collections: plural lowercase (e.g., `users`, `orders`, `orderItems`)24- Mongoose models: PascalCase singular (e.g., `User`, `Order`)25- Express routes: kebab-case URLs (e.g., `/api/order-items`)26- React components: PascalCase (e.g., `OrderList`, `UserProfile`)27- API endpoints: RESTful nouns (e.g., `GET /api/users`, `POST /api/orders`)28- Environment variables: UPPER_SNAKE_CASE with app prefix (e.g., `APP_MONGO_URI`)2930### Project Structure (Monorepo)31```32packages/33 client/ # React frontend34 src/35 components/ # Reusable UI components36 features/ # Feature modules (auth, dashboard, orders)37 auth/38 components/39 hooks/40 api.ts # API calls for this feature41 types.ts42 hooks/ # Shared hooks43 lib/ # Utilities, API client setup44 types/ # Shared types45 server/ # Express backend46 src/47 config/ # Database, env config48 db.ts49 env.ts50 controllers/ # Route handlers51 middleware/ # Auth, validation, error handling52 models/ # Mongoose models53 routes/ # Route definitions54 services/ # Business logic55 utils/ # Utilities56 validators/ # Zod schemas57 app.ts58 server.ts59 shared/ # Shared types/utilities (if monorepo)60 types/61```6263## MongoDB / Mongoose Patterns6465### Model Definition66```ts67import mongoose, { Schema, Document } from 'mongoose';6869export interface IUser extends Document {70 email: string;71 name: string;72 passwordHash: string;73 role: 'user' | 'admin';74 createdAt: Date;75 updatedAt: Date;76}7778const userSchema = new Schema<IUser>(79 {80 email: {81 type: String,82 required: true,83 unique: true,84 lowercase: true,85 trim: true,86 index: true,87 },88 name: { type: String, required: true, trim: true, maxlength: 100 },89 passwordHash: { type: String, required: true, select: false },90 role: { type: String, enum: ['user', 'admin'], default: 'user' },91 },92 {93 timestamps: true,94 toJSON: {95 transform(doc, ret) {96 ret.id = ret._id;97 delete ret._id;98 delete ret.__v;99 delete ret.passwordHash;100 },101 },102 },103);104105userSchema.index({ email: 1 });106userSchema.index({ createdAt: -1 });107108export const User = mongoose.model<IUser>('User', userSchema);109```110111### Query Patterns112```ts113// Use lean() for read-only queries (returns plain objects, ~5x faster)114const users = await User.find({ role: 'user' }).lean().limit(20).skip(0);115116// Use select() to limit returned fields117const user = await User.findById(id).select('name email role');118119// Use populate() sparingly — prefer denormalization for read-heavy data120const order = await Order.findById(id)121 .populate('user', 'name email')122 .populate('items.product', 'name price');123124// Aggregation for complex queries125const stats = await Order.aggregate([126 { $match: { status: 'completed', createdAt: { $gte: startDate } } },127 { $group: { _id: '$user', totalSpent: { $sum: '$total' }, orderCount: { $sum: 1 } } },128 { $sort: { totalSpent: -1 } },129 { $limit: 10 },130]);131```132133### Model Rules134- Always define indexes for fields used in queries and sorts135- Use `select: false` on sensitive fields (passwords, tokens)136- Use `toJSON` transform to clean up response objects137- Use `lean()` on read-only queries for performance138- Validate at both the schema level and the API validation layer139- Use transactions for multi-document operations: `session.withTransaction()`140- Avoid deeply nested subdocuments — use references for entities that grow141142## Express API Patterns143144### Controller Pattern145```ts146export const orderController = {147 async getAll(req: Request, res: Response, next: NextFunction) {148 try {149 const { page = 1, limit = 20, status } = req.query;150 const filter: FilterQuery<IOrder> = { user: req.user.id };151 if (status) filter.status = status;152153 const [orders, total] = await Promise.all([154 Order.find(filter).lean().sort('-createdAt').skip((+page - 1) * +limit).limit(+limit),155 Order.countDocuments(filter),156 ]);157158 res.json({159 data: orders,160 meta: { page: +page, limit: +limit, total, pages: Math.ceil(total / +limit) },161 });162 } catch (error) {163 next(error);164 }165 },166};167```168169### API Validation Middleware170```ts171import { z } from 'zod';172173const createOrderSchema = z.object({174 body: z.object({175 items: z.array(z.object({176 product: z.string().regex(/^[a-f\d]{24}$/i, 'Invalid product ID'),177 quantity: z.number().int().positive().max(100),178 })).min(1, 'At least one item required'),179 shippingAddress: z.object({180 street: z.string().min(1),181 city: z.string().min(1),182 zip: z.string().min(1),183 }),184 }),185});186187function validate(schema: z.ZodSchema) {188 return (req: Request, res: Response, next: NextFunction) => {189 const result = schema.safeParse({ body: req.body, query: req.query, params: req.params });190 if (!result.success) {191 return res.status(400).json({ errors: result.error.flatten().fieldErrors });192 }193 next();194 };195}196```197198## React Frontend Patterns199200### API Layer with React Query201```ts202// features/orders/api.ts203import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';204import { apiClient } from '../../lib/api-client';205206export function useOrders(page = 1) {207 return useQuery({208 queryKey: ['orders', page],209 queryFn: () => apiClient.get(`/api/orders?page=${page}`).then(r => r.data),210 });211}212213export function useCreateOrder() {214 const queryClient = useQueryClient();215 return useMutation({216 mutationFn: (data: CreateOrderInput) => apiClient.post('/api/orders', data),217 onSuccess: () => {218 queryClient.invalidateQueries({ queryKey: ['orders'] });219 },220 });221}222```223224### API Client Setup225```ts226// lib/api-client.ts227import axios from 'axios';228229export const apiClient = axios.create({230 baseURL: import.meta.env.VITE_API_URL || 'http://localhost:5000',231});232233apiClient.interceptors.request.use((config) => {234 const token = localStorage.getItem('token');235 if (token) config.headers.Authorization = `Bearer ${token}`;236 return config;237});238239apiClient.interceptors.response.use(240 (response) => response,241 (error) => {242 if (error.response?.status === 401) {243 localStorage.removeItem('token');244 window.location.href = '/login';245 }246 return Promise.reject(error);247 },248);249```250251## Error Handling252- Centralized Express error handler as the last middleware253- Mongoose validation errors mapped to 400 responses254- Cast errors (invalid ObjectId) mapped to 404255- Duplicate key errors mapped to 409 Conflict256- React error boundaries for component-level errors257- React Query's `onError` for API error handling in the UI258259## Security260- Validate all API inputs with Zod (never trust the client)261- Use `helmet` for secure HTTP headers262- Use CORS with explicit allowed origins263- Hash passwords with bcrypt (cost factor 12)264- Validate ObjectIds before database queries265- Sanitize user input to prevent NoSQL injection (`mongo-sanitize`)266- Rate limit authentication endpoints267- Store JWT secret in environment variables, use short expiry268269## Testing270- Use Jest or Vitest for unit and integration tests271- Use `mongodb-memory-server` for database tests without external MongoDB272- Test API endpoints with supertest273- Test React components with React Testing Library274- Test hooks with `renderHook` from React Testing Library275276## Performance Guidelines277- Use MongoDB indexes — compound indexes for multi-field queries278- Use `lean()` on all read-only Mongoose queries279- Implement pagination on all list endpoints280- Use Redis for caching frequently accessed data281- Compress responses with `compression` middleware282- Use React Query's `staleTime` to reduce API calls283- Lazy-load React routes and heavy components284285## Common Pitfalls286- Not handling MongoDB connection errors at startup287- Using `findOne` without `lean()` when you don't need a Mongoose document288- Not indexing fields used in `find()`, `sort()`, or `aggregate()`289- N+1 queries from looping with `findById` — use `find({ _id: { $in: ids } })`290- Not validating ObjectId format before passing to Mongoose (causes CastError)291- Storing JWT tokens in localStorage without considering XSS (consider httpOnly cookies)292- Not using `.populate()` projection — returning entire related documents293- Forgetting `{ new: true }` on `findByIdAndUpdate` (returns old document by default)294
Also in survivorforge/cursor-rules
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| survivorforge/cursor-rulesrules/ai-ml-python/.cursorrules · 16 | .cursorrules | teststylearchdeployment+2 | 81/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/api-design-rest/.cursorrules · 16 | .cursorrules | lint-formatstylesecurityapi+3 | 69/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/api-microservices/.cursorrules · 16 | .cursorrules | buildteststylearch+5 | 92/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/aws-serverless/.cursorrules · 16 | .cursorrules | teststylearchtypes+6 | 73/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/chrome-extension/.cursorrules · 16 | .cursorrules | teststylearchtesting-strategy+4 | 81/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/clean-code/.cursorrules · 16 | .cursorrules | styledo-notagent-behaviourdocs | 57/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/database-sql/.cursorrules · 16 | .cursorrules | styletypessecuritydatabase+3 | 65/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/devops-docker/.cursorrules · 16 | .cursorrules | setupbuildteststyle+4 | 93/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/devops-infrastructure/.cursorrules · 16 | .cursorrules | buildteststylesecurity+3 | 93/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/django-rest/.cursorrules · 16 | .cursorrules | buildteststylearch+5 | 84/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/docker-devops/.cursorrules · 16 | .cursorrules | setupteststylearch+6 | 85/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/flutter-dart/.cursorrules · 16 | .cursorrules | teststylearchtypes+5 | 89/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/fullstack-nextjs-prisma/.cursorrules · 16 | .cursorrules | teststylearchtypes+7 | 96/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/go-gin/.cursorrules · 16 | .cursorrules | testlint-formatstylearch+5 | 84/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/go-production/.cursorrules · 16 | .cursorrules | teststylearchtesting-strategy+3 | 89/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/golang-api/.cursorrules · 16 | .cursorrules | buildteststylearch+6 | 84/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/langchain-ai/.cursorrules · 16 | .cursorrules | testlint-formatstylearch+4 | 84/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/mcp-server/.cursorrules · 16 | .cursorrules | testlint-formatstylearch+7 | 68/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/mobile-react-native/.cursorrules · 16 | .cursorrules | teststylearchtypes+7 | 89/100 | 2 days ago | |
| survivorforge/cursor-rulesrules/nextjs-14-app-router/.cursorrules · 16 | .cursorrules | teststyletypestesting-strategy+3 | 71/100 | 2 days ago |
Diff against rules/ai-ml-python/.cursorrules Diff against rules/api-design-rest/.cursorrules Diff against rules/api-microservices/.cursorrules Diff against rules/aws-serverless/.cursorrules Diff against rules/chrome-extension/.cursorrules Diff against rules/clean-code/.cursorrules Diff against rules/database-sql/.cursorrules Diff against rules/devops-docker/.cursorrules Diff against rules/devops-infrastructure/.cursorrules Diff against rules/django-rest/.cursorrules Diff against rules/docker-devops/.cursorrules Diff against rules/flutter-dart/.cursorrules Diff against rules/fullstack-nextjs-prisma/.cursorrules Diff against rules/go-gin/.cursorrules Diff against rules/go-production/.cursorrules Diff against rules/golang-api/.cursorrules Diff against rules/langchain-ai/.cursorrules Diff against rules/mcp-server/.cursorrules Diff against rules/mobile-react-native/.cursorrules Diff against rules/nextjs-14-app-router/.cursorrules
