@devmunna/agent-skillkit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -0
  3. package/bin/ai-skills.js +5 -0
  4. package/dist/cli/commands/add.d.ts +2 -0
  5. package/dist/cli/commands/add.d.ts.map +1 -0
  6. package/dist/cli/commands/add.js +66 -0
  7. package/dist/cli/commands/add.js.map +1 -0
  8. package/dist/cli/commands/doctor.d.ts +2 -0
  9. package/dist/cli/commands/doctor.d.ts.map +1 -0
  10. package/dist/cli/commands/doctor.js +33 -0
  11. package/dist/cli/commands/doctor.js.map +1 -0
  12. package/dist/cli/commands/init.d.ts +10 -0
  13. package/dist/cli/commands/init.d.ts.map +1 -0
  14. package/dist/cli/commands/init.js +145 -0
  15. package/dist/cli/commands/init.js.map +1 -0
  16. package/dist/cli/commands/list.d.ts +5 -0
  17. package/dist/cli/commands/list.d.ts.map +1 -0
  18. package/dist/cli/commands/list.js +55 -0
  19. package/dist/cli/commands/list.js.map +1 -0
  20. package/dist/cli/commands/update.d.ts +2 -0
  21. package/dist/cli/commands/update.d.ts.map +1 -0
  22. package/dist/cli/commands/update.js +49 -0
  23. package/dist/cli/commands/update.js.map +1 -0
  24. package/dist/cli/commands/validate.d.ts +2 -0
  25. package/dist/cli/commands/validate.d.ts.map +1 -0
  26. package/dist/cli/commands/validate.js +22 -0
  27. package/dist/cli/commands/validate.js.map +1 -0
  28. package/dist/cli/index.d.ts +2 -0
  29. package/dist/cli/index.d.ts.map +1 -0
  30. package/dist/cli/index.js +49 -0
  31. package/dist/cli/index.js.map +1 -0
  32. package/dist/cli/prompts/agent-selector.d.ts +3 -0
  33. package/dist/cli/prompts/agent-selector.d.ts.map +1 -0
  34. package/dist/cli/prompts/agent-selector.js +23 -0
  35. package/dist/cli/prompts/agent-selector.js.map +1 -0
  36. package/dist/cli/prompts/stack-selector.d.ts +3 -0
  37. package/dist/cli/prompts/stack-selector.d.ts.map +1 -0
  38. package/dist/cli/prompts/stack-selector.js +60 -0
  39. package/dist/cli/prompts/stack-selector.js.map +1 -0
  40. package/dist/core/config-manager.d.ts +20 -0
  41. package/dist/core/config-manager.d.ts.map +1 -0
  42. package/dist/core/config-manager.js +107 -0
  43. package/dist/core/config-manager.js.map +1 -0
  44. package/dist/core/detector.d.ts +3 -0
  45. package/dist/core/detector.d.ts.map +1 -0
  46. package/dist/core/detector.js +50 -0
  47. package/dist/core/detector.js.map +1 -0
  48. package/dist/core/doctor.d.ts +12 -0
  49. package/dist/core/doctor.d.ts.map +1 -0
  50. package/dist/core/doctor.js +102 -0
  51. package/dist/core/doctor.js.map +1 -0
  52. package/dist/core/skill-registry.d.ts +11 -0
  53. package/dist/core/skill-registry.d.ts.map +1 -0
  54. package/dist/core/skill-registry.js +174 -0
  55. package/dist/core/skill-registry.js.map +1 -0
  56. package/dist/core/skill-resolver.d.ts +3 -0
  57. package/dist/core/skill-resolver.d.ts.map +1 -0
  58. package/dist/core/skill-resolver.js +36 -0
  59. package/dist/core/skill-resolver.js.map +1 -0
  60. package/dist/core/validator.d.ts +13 -0
  61. package/dist/core/validator.d.ts.map +1 -0
  62. package/dist/core/validator.js +99 -0
  63. package/dist/core/validator.js.map +1 -0
  64. package/dist/generators/agent-installer.d.ts +5 -0
  65. package/dist/generators/agent-installer.d.ts.map +1 -0
  66. package/dist/generators/agent-installer.js +20 -0
  67. package/dist/generators/agent-installer.js.map +1 -0
  68. package/dist/generators/agents-md.d.ts +3 -0
  69. package/dist/generators/agents-md.d.ts.map +1 -0
  70. package/dist/generators/agents-md.js +70 -0
  71. package/dist/generators/agents-md.js.map +1 -0
  72. package/dist/generators/claude-md.d.ts +3 -0
  73. package/dist/generators/claude-md.d.ts.map +1 -0
  74. package/dist/generators/claude-md.js +47 -0
  75. package/dist/generators/claude-md.js.map +1 -0
  76. package/dist/generators/skill-generator.d.ts +5 -0
  77. package/dist/generators/skill-generator.d.ts.map +1 -0
  78. package/dist/generators/skill-generator.js +34 -0
  79. package/dist/generators/skill-generator.js.map +1 -0
  80. package/dist/generators/workflows.d.ts +3 -0
  81. package/dist/generators/workflows.d.ts.map +1 -0
  82. package/dist/generators/workflows.js +57 -0
  83. package/dist/generators/workflows.js.map +1 -0
  84. package/dist/index.d.ts +13 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +13 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/types/index.d.ts +55 -0
  89. package/dist/types/index.d.ts.map +1 -0
  90. package/dist/types/index.js +2 -0
  91. package/dist/types/index.js.map +1 -0
  92. package/dist/utils/file-utils.d.ts +12 -0
  93. package/dist/utils/file-utils.d.ts.map +1 -0
  94. package/dist/utils/file-utils.js +39 -0
  95. package/dist/utils/file-utils.js.map +1 -0
  96. package/dist/utils/logger.d.ts +10 -0
  97. package/dist/utils/logger.d.ts.map +1 -0
  98. package/dist/utils/logger.js +11 -0
  99. package/dist/utils/logger.js.map +1 -0
  100. package/package.json +73 -0
  101. package/skills/clean-architecture/SKILL.md +324 -0
  102. package/skills/express-mvc-prisma/SKILL.md +168 -0
  103. package/skills/express-mvc-prisma/references/auth.md +190 -0
  104. package/skills/express-mvc-prisma/references/boilerplate.md +196 -0
  105. package/skills/express-mvc-prisma/references/error-handling.md +121 -0
  106. package/skills/express-mvc-prisma/references/module-scaffold.md +253 -0
  107. package/skills/express-mvc-prisma/references/prisma-setup.md +97 -0
  108. package/skills/express-mvc-prisma/references/response-helpers.md +157 -0
  109. package/skills/express-mvc-prisma/references/zod-validation.md +157 -0
  110. package/skills/fastify-rest/SKILL.md +287 -0
  111. package/skills/mongoose-odm/SKILL.md +281 -0
  112. package/skills/nextjs-fullstack/SKILL.md +328 -0
  113. package/skills/nextjs-fullstack/references/auth.md +270 -0
  114. package/skills/nextjs-fullstack/references/caching.md +157 -0
  115. package/skills/nextjs-fullstack/references/route-handlers.md +194 -0
  116. package/skills/nextjs-fullstack/references/server-actions.md +214 -0
  117. package/skills/nextjs-fullstack/references/server-components.md +190 -0
  118. package/skills/node-base/SKILL.md +139 -0
  119. package/skills/prisma-orm/SKILL.md +334 -0
  120. package/skills/react-feature-arch/SKILL.md +208 -0
  121. package/skills/react-feature-arch/references/api-layer.md +110 -0
  122. package/skills/react-feature-arch/references/components.md +192 -0
  123. package/skills/react-feature-arch/references/data-fetching.md +198 -0
  124. package/skills/react-feature-arch/references/forms.md +194 -0
  125. package/skills/react-feature-arch/references/routing.md +148 -0
  126. package/skills/react-feature-arch/references/state-management.md +107 -0
  127. package/skills/tailwind-css/SKILL.md +236 -0
  128. package/skills/tailwind-css/references/components.md +340 -0
  129. package/skills/tailwind-css/references/design-tokens.md +230 -0
  130. package/skills/tailwind-css/references/patterns.md +375 -0
  131. package/skills/tailwind-css/references/setup.md +165 -0
  132. package/skills/zod-validation/SKILL.md +267 -0
@@ -0,0 +1,287 @@
1
+ ---
2
+ name: fastify-rest
3
+ version: 1.0.0
4
+ description: >
5
+ Apply this skill for any Fastify project task: server setup, route declaration, schema validation, plugins, hooks, authentication, error handling, or performance optimization. Triggers: "Fastify server", "Fastify route", "Fastify plugin", "Fastify schema", "Fastify hooks", "Fastify JWT", "register plugin".
6
+ stack: [fastify]
7
+ depends: [node-base]
8
+ ---
9
+
10
+ # Fastify REST API Skill
11
+
12
+ Production-ready Fastify patterns: plugin architecture, JSON schema validation, hooks, and performance-first design.
13
+
14
+ ---
15
+
16
+ ## Project Structure
17
+
18
+ ```
19
+ src/
20
+ ├── app.js # Fastify instance builder (no listen)
21
+ ├── server.js # Entry point (listen here)
22
+ ├── config/
23
+ │ └── env.js # Validated env (Zod)
24
+ ├── plugins/
25
+ │ ├── db.js # Database plugin (Prisma / Mongoose)
26
+ │ ├── auth.js # JWT plugin
27
+ │ └── sensible.js # @fastify/sensible
28
+ ├── modules/
29
+ │ └── {module}/
30
+ │ ├── {module}.routes.js # Route declarations
31
+ │ ├── {module}.schema.js # JSON schemas
32
+ │ ├── {module}.service.js # Business logic
33
+ │ └── {module}.repository.js
34
+ └── utils/
35
+ └── AppError.js
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Application Bootstrap
41
+
42
+ ```js
43
+ // src/app.js
44
+ import Fastify from 'fastify';
45
+ import { env } from './config/env.js';
46
+
47
+ export async function buildApp(opts = {}) {
48
+ const app = Fastify({
49
+ logger: env.NODE_ENV === 'development'
50
+ ? { level: 'info', transport: { target: 'pino-pretty' } }
51
+ : { level: 'warn' },
52
+ ...opts,
53
+ });
54
+
55
+ // Register plugins
56
+ await app.register(import('./plugins/db.js'));
57
+ await app.register(import('./plugins/auth.js'));
58
+
59
+ // Register routes with prefix
60
+ await app.register(import('./modules/user/user.routes.js'), { prefix: '/api/v1/users' });
61
+ await app.register(import('./modules/auth/auth.routes.js'), { prefix: '/api/v1/auth' });
62
+
63
+ // Health check
64
+ app.get('/health', async () => ({ status: 'ok' }));
65
+
66
+ return app;
67
+ }
68
+
69
+ // src/server.js
70
+ import { buildApp } from './src/app.js';
71
+ import { env } from './src/config/env.js';
72
+
73
+ const app = await buildApp();
74
+
75
+ try {
76
+ await app.listen({ port: env.PORT, host: '0.0.0.0' });
77
+ } catch (err) {
78
+ app.log.error(err);
79
+ process.exit(1);
80
+ }
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Plugin Registration
86
+
87
+ ```js
88
+ // src/plugins/db.js
89
+ import fp from 'fastify-plugin';
90
+ import { PrismaClient } from '@prisma/client';
91
+
92
+ async function dbPlugin(app) {
93
+ const prisma = new PrismaClient({
94
+ log: app.config.NODE_ENV === 'development' ? ['query', 'warn', 'error'] : ['error'],
95
+ });
96
+
97
+ await prisma.$connect();
98
+
99
+ // Decorate app so all routes can use app.prisma
100
+ app.decorate('prisma', prisma);
101
+
102
+ app.addHook('onClose', async () => {
103
+ await prisma.$disconnect();
104
+ });
105
+ }
106
+
107
+ // fp() makes the plugin available app-wide (not scoped)
108
+ export default fp(dbPlugin, { name: 'prisma' });
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Route Declaration with JSON Schema
114
+
115
+ ```js
116
+ // src/modules/user/user.routes.js
117
+ import { userService } from './user.service.js';
118
+ import { createUserSchema, getUserSchema, listUsersSchema } from './user.schema.js';
119
+
120
+ export default async function userRoutes(app) {
121
+ // List users
122
+ app.get('/', { schema: listUsersSchema }, async (req, reply) => {
123
+ const result = await userService.getAll(req.query);
124
+ return result;
125
+ });
126
+
127
+ // Get user by ID
128
+ app.get('/:id', { schema: getUserSchema }, async (req, reply) => {
129
+ const user = await userService.getById(req.params.id);
130
+ return user;
131
+ });
132
+
133
+ // Create user (protected)
134
+ app.post('/', {
135
+ schema: createUserSchema,
136
+ preHandler: [app.authenticate], // JWT guard
137
+ }, async (req, reply) => {
138
+ const user = await userService.create(req.body);
139
+ reply.status(201);
140
+ return user;
141
+ });
142
+
143
+ // Delete user
144
+ app.delete('/:id', {
145
+ schema: { params: { type: 'object', properties: { id: { type: 'string', format: 'uuid' } } } },
146
+ preHandler: [app.authenticate, app.authorize('ADMIN')],
147
+ }, async (req, reply) => {
148
+ await userService.delete(req.params.id);
149
+ reply.status(204).send();
150
+ });
151
+ }
152
+ ```
153
+
154
+ ---
155
+
156
+ ## JSON Schema Validation
157
+
158
+ ```js
159
+ // src/modules/user/user.schema.js
160
+
161
+ const userResponse = {
162
+ type: 'object',
163
+ properties: {
164
+ id: { type: 'string', format: 'uuid' },
165
+ name: { type: 'string' },
166
+ email: { type: 'string', format: 'email' },
167
+ role: { type: 'string', enum: ['USER', 'ADMIN'] },
168
+ createdAt: { type: 'string', format: 'date-time' },
169
+ },
170
+ };
171
+
172
+ export const createUserSchema = {
173
+ body: {
174
+ type: 'object',
175
+ required: ['name', 'email', 'password'],
176
+ properties: {
177
+ name: { type: 'string', minLength: 2, maxLength: 100 },
178
+ email: { type: 'string', format: 'email' },
179
+ password: { type: 'string', minLength: 8 },
180
+ },
181
+ additionalProperties: false,
182
+ },
183
+ response: {
184
+ 201: userResponse,
185
+ },
186
+ };
187
+
188
+ export const listUsersSchema = {
189
+ querystring: {
190
+ type: 'object',
191
+ properties: {
192
+ page: { type: 'integer', minimum: 1, default: 1 },
193
+ limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
194
+ search: { type: 'string' },
195
+ },
196
+ },
197
+ };
198
+
199
+ export const getUserSchema = {
200
+ params: {
201
+ type: 'object',
202
+ required: ['id'],
203
+ properties: {
204
+ id: { type: 'string', format: 'uuid' },
205
+ },
206
+ },
207
+ response: {
208
+ 200: userResponse,
209
+ },
210
+ };
211
+ ```
212
+
213
+ ---
214
+
215
+ ## JWT Authentication Plugin
216
+
217
+ ```js
218
+ // src/plugins/auth.js
219
+ import fp from 'fastify-plugin';
220
+ import jwt from '@fastify/jwt';
221
+ import { env } from '../config/env.js';
222
+
223
+ async function authPlugin(app) {
224
+ await app.register(jwt, { secret: env.JWT_SECRET });
225
+
226
+ // Decorate with authenticate hook
227
+ app.decorate('authenticate', async function (req, reply) {
228
+ try {
229
+ await req.jwtVerify();
230
+ } catch {
231
+ reply.status(401).send({ error: 'Unauthorized' });
232
+ }
233
+ });
234
+
235
+ // Role-based authorization
236
+ app.decorate('authorize', (role) => async function (req, reply) {
237
+ if (req.user.role !== role) {
238
+ reply.status(403).send({ error: 'Forbidden' });
239
+ }
240
+ });
241
+ }
242
+
243
+ export default fp(authPlugin, { name: 'auth' });
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Error Handling
249
+
250
+ ```js
251
+ // In app.js — global error handler
252
+ app.setErrorHandler(async (error, req, reply) => {
253
+ const statusCode = error.statusCode ?? 500;
254
+
255
+ if (statusCode >= 500) {
256
+ app.log.error(error);
257
+ return reply.status(500).send({ success: false, message: 'Internal server error' });
258
+ }
259
+
260
+ return reply.status(statusCode).send({
261
+ success: false,
262
+ message: error.message,
263
+ ...(error.validation && { validation: error.validation }),
264
+ });
265
+ });
266
+
267
+ // In routes — throw to trigger error handler
268
+ app.get('/example', async (req, reply) => {
269
+ const item = await service.getById(req.params.id);
270
+ if (!item) {
271
+ const err = new Error('Not found');
272
+ err.statusCode = 404;
273
+ throw err;
274
+ }
275
+ return item;
276
+ });
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Performance Rules
282
+
283
+ - Define `response` JSON schemas to activate fast serialization (ajv-compiler bypasses JSON.stringify)
284
+ - Use `app.log` (pino) — never `console.log` in handlers
285
+ - Use `async/await` in handlers and plugins — Fastify handles the promise lifecycle
286
+ - Register all plugins with `fastify-plugin` (`fp`) if they should be available in all scopes
287
+ - Use `onRequest` hook for auth guards over route-level `preHandler` when applying globally
@@ -0,0 +1,281 @@
1
+ ---
2
+ name: mongoose-odm
3
+ version: 1.0.0
4
+ description: >
5
+ Apply this skill for any MongoDB/Mongoose task: schema design, model creation, virtuals, indexes, population, aggregation, transactions, or repository abstraction. Triggers: "Mongoose schema", "MongoDB model", "populate relations", "aggregation pipeline", "MongoDB index", "Mongoose middleware", "MongoDB transaction".
6
+ stack: [mongoose, mongodb]
7
+ depends: []
8
+ ---
9
+
10
+ # Mongoose ODM Skill
11
+
12
+ Production patterns for MongoDB/Mongoose: schema design, repository abstraction, performance, and transactions.
13
+
14
+ ---
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install mongoose
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Connection
25
+
26
+ ```js
27
+ // src/config/db.js
28
+ import mongoose from 'mongoose';
29
+ import { env } from './env.js';
30
+
31
+ let isConnected = false;
32
+
33
+ export async function connectDB() {
34
+ if (isConnected) return;
35
+
36
+ mongoose.set('strictQuery', true);
37
+
38
+ await mongoose.connect(env.MONGODB_URI, {
39
+ dbName: env.DB_NAME,
40
+ });
41
+
42
+ isConnected = true;
43
+ console.log('✅ MongoDB connected');
44
+ }
45
+
46
+ // Handle connection events
47
+ mongoose.connection.on('error', (err) => console.error('MongoDB error:', err));
48
+ mongoose.connection.on('disconnected', () => { isConnected = false; });
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Schema Design Conventions
54
+
55
+ ```js
56
+ // src/modules/user/user.model.js
57
+ import mongoose from 'mongoose';
58
+ import bcrypt from 'bcryptjs';
59
+
60
+ const userSchema = new mongoose.Schema(
61
+ {
62
+ name: {
63
+ type: String,
64
+ required: [true, 'Name is required'],
65
+ trim: true,
66
+ maxlength: [100, 'Name max 100 characters'],
67
+ },
68
+ email: {
69
+ type: String,
70
+ required: [true, 'Email is required'],
71
+ unique: true,
72
+ lowercase: true,
73
+ trim: true,
74
+ match: [/^\S+@\S+\.\S+$/, 'Invalid email format'],
75
+ },
76
+ password: {
77
+ type: String,
78
+ required: true,
79
+ minlength: 8,
80
+ select: false, // never returned by default
81
+ },
82
+ role: {
83
+ type: String,
84
+ enum: ['user', 'admin', 'moderator'],
85
+ default: 'user',
86
+ },
87
+ isActive: {
88
+ type: Boolean,
89
+ default: true,
90
+ },
91
+ },
92
+ {
93
+ timestamps: true, // adds createdAt + updatedAt automatically
94
+ versionKey: false, // removes __v field
95
+ toJSON: { virtuals: true }, // include virtuals in JSON output
96
+ toObject: { virtuals: true },
97
+ }
98
+ );
99
+
100
+ // Index on frequently queried fields
101
+ userSchema.index({ email: 1 });
102
+ userSchema.index({ role: 1, isActive: 1 });
103
+
104
+ // Virtual: computed property (not stored in DB)
105
+ userSchema.virtual('fullName').get(function () {
106
+ return `${this.firstName} ${this.lastName}`;
107
+ });
108
+
109
+ // Pre-save middleware: hash password
110
+ userSchema.pre('save', async function (next) {
111
+ if (!this.isModified('password')) return next();
112
+ this.password = await bcrypt.hash(this.password, 12);
113
+ next();
114
+ });
115
+
116
+ // Instance method
117
+ userSchema.methods.comparePassword = async function (candidate) {
118
+ return bcrypt.compare(candidate, this.password);
119
+ };
120
+
121
+ // Static method
122
+ userSchema.statics.findByEmail = function (email) {
123
+ return this.findOne({ email: email.toLowerCase() });
124
+ };
125
+
126
+ export const User = mongoose.model('User', userSchema);
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Repository Pattern
132
+
133
+ ```js
134
+ // src/modules/user/user.repository.js
135
+ import { User } from './user.model.js';
136
+ import { AppError } from '../../utils/AppError.js';
137
+
138
+ export const userRepository = {
139
+ async findAll({ page = 1, limit = 10, search, role }) {
140
+ const query = {};
141
+ if (search) query.$text = { $search: search };
142
+ if (role) query.role = role;
143
+
144
+ const skip = (page - 1) * limit;
145
+
146
+ const [data, total] = await Promise.all([
147
+ User.find(query)
148
+ .select('-password')
149
+ .skip(skip)
150
+ .limit(limit)
151
+ .lean(), // lean() returns plain objects — faster
152
+ User.countDocuments(query),
153
+ ]);
154
+
155
+ return { data, total, page, limit };
156
+ },
157
+
158
+ async findById(id) {
159
+ const user = await User.findById(id).select('-password').lean();
160
+ if (!user) throw new AppError('User not found', 404);
161
+ return user;
162
+ },
163
+
164
+ async create(data) {
165
+ const user = await User.create(data);
166
+ const { password, ...safe } = user.toObject();
167
+ return safe;
168
+ },
169
+
170
+ async update(id, data) {
171
+ const user = await User.findByIdAndUpdate(id, data, {
172
+ new: true, // return updated document
173
+ runValidators: true, // run schema validators on update
174
+ }).select('-password');
175
+ if (!user) throw new AppError('User not found', 404);
176
+ return user;
177
+ },
178
+
179
+ async delete(id) {
180
+ const user = await User.findByIdAndDelete(id);
181
+ if (!user) throw new AppError('User not found', 404);
182
+ return user;
183
+ },
184
+ };
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Population (Relations)
190
+
191
+ ```js
192
+ // Reference (like FK)
193
+ const postSchema = new Schema({
194
+ author: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
195
+ tags: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Tag' }],
196
+ });
197
+
198
+ // Populate at query time
199
+ const posts = await Post.find()
200
+ .populate('author', 'name email') // select specific fields
201
+ .populate('tags', 'name slug')
202
+ .lean();
203
+
204
+ // Nested population
205
+ await Post.find().populate({
206
+ path: 'author',
207
+ select: 'name',
208
+ populate: { path: 'profile', select: 'avatar' },
209
+ });
210
+ ```
211
+
212
+ **Rule**: Use `.lean()` with population when you don't need Mongoose document methods. It's 3-10x faster.
213
+
214
+ ---
215
+
216
+ ## Aggregation Pipeline
217
+
218
+ ```js
219
+ // Complex reporting query
220
+ const stats = await Order.aggregate([
221
+ { $match: { status: 'completed', createdAt: { $gte: startDate } } },
222
+ {
223
+ $group: {
224
+ _id: '$userId',
225
+ totalOrders: { $sum: 1 },
226
+ totalRevenue: { $sum: '$total' },
227
+ avgOrderValue: { $avg: '$total' },
228
+ },
229
+ },
230
+ { $sort: { totalRevenue: -1 } },
231
+ { $limit: 10 },
232
+ {
233
+ $lookup: {
234
+ from: 'users',
235
+ localField: '_id',
236
+ foreignField: '_id',
237
+ as: 'user',
238
+ pipeline: [{ $project: { name: 1, email: 1 } }],
239
+ },
240
+ },
241
+ { $unwind: '$user' },
242
+ ]);
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Transactions
248
+
249
+ ```js
250
+ const session = await mongoose.startSession();
251
+
252
+ try {
253
+ session.startTransaction();
254
+
255
+ const order = await Order.create([orderData], { session });
256
+ await Product.findByIdAndUpdate(
257
+ productId,
258
+ { $inc: { stock: -quantity } },
259
+ { session, new: true, runValidators: true }
260
+ );
261
+
262
+ await session.commitTransaction();
263
+ return order[0];
264
+ } catch (err) {
265
+ await session.abortTransaction();
266
+ throw err;
267
+ } finally {
268
+ session.endSession();
269
+ }
270
+ ```
271
+
272
+ ---
273
+
274
+ ## Rules
275
+
276
+ - Always use `timestamps: true` and `versionKey: false` in schema options
277
+ - Use `select: false` on sensitive fields (password, tokens)
278
+ - Add `lean()` to read-heavy queries not needing Mongoose methods
279
+ - Index all fields used in `find()`, `sort()`, and `$lookup` foreign keys
280
+ - Use `runValidators: true` on `findByIdAndUpdate` — it's off by default
281
+ - Prefer aggregation over application-level data processing for large datasets