@intentsolutionsio/fullstack-starter-pack 1.0.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.
@@ -0,0 +1,659 @@
1
+ ---
2
+ name: express-api-scaffold
3
+ description: >
4
+ Generate production-ready Express.js REST API with TypeScript and auth
5
+ shortcut: eas
6
+ category: backend
7
+ difficulty: intermediate
8
+ estimated_time: 5-10 minutes
9
+ ---
10
+ # Express API Scaffold
11
+
12
+ Generates a complete Express.js REST API boilerplate with TypeScript, authentication, database integration, and testing setup.
13
+
14
+ ## What This Command Does
15
+
16
+ **Generated Project:**
17
+ - Express.js with TypeScript
18
+ - JWT authentication
19
+ - Database integration (Prisma or TypeORM)
20
+ - Input validation (Zod)
21
+ - Error handling middleware
22
+ - Rate limiting & security (Helmet, CORS)
23
+ - Testing setup (Jest + Supertest)
24
+ - Docker configuration
25
+ - Example CRUD endpoints
26
+
27
+ **Output:** Complete API project ready for development
28
+
29
+ **Time:** 5-10 minutes
30
+
31
+ ---
32
+
33
+ ## Usage
34
+
35
+ ```bash
36
+ # Generate full Express API
37
+ /express-api-scaffold "Task Management API"
38
+
39
+ # Shortcut
40
+ /eas "E-commerce API"
41
+
42
+ # With specific database
43
+ /eas "Blog API" --database postgresql
44
+
45
+ # With authentication type
46
+ /eas "Social API" --auth jwt --database mongodb
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Example Output
52
+
53
+ **Input:**
54
+ ```
55
+ /eas "Task Management API" --database postgresql
56
+ ```
57
+
58
+ **Generated Project Structure:**
59
+ ```
60
+ task-api/
61
+ ├── src/
62
+ │ ├── controllers/ # Request handlers
63
+ │ │ ├── auth.controller.ts
64
+ │ │ └── task.controller.ts
65
+ │ ├── middleware/ # Express middleware
66
+ │ │ ├── auth.middleware.ts
67
+ │ │ ├── error.middleware.ts
68
+ │ │ └── validation.middleware.ts
69
+ │ ├── models/ # Database models
70
+ │ │ └── task.model.ts
71
+ │ ├── routes/ # API routes
72
+ │ │ ├── auth.routes.ts
73
+ │ │ └── task.routes.ts
74
+ │ ├── services/ # Business logic
75
+ │ │ ├── auth.service.ts
76
+ │ │ └── task.service.ts
77
+ │ ├── utils/ # Utilities
78
+ │ │ ├── jwt.util.ts
79
+ │ │ └── password.util.ts
80
+ │ ├── config/ # Configuration
81
+ │ │ └── database.ts
82
+ │ ├── types/ # TypeScript types
83
+ │ │ └── express.d.ts
84
+ │ ├── app.ts # Express app setup
85
+ │ └── server.ts # Server entry point
86
+ ├── tests/
87
+ │ ├── auth.test.ts
88
+ │ └── task.test.ts
89
+ ├── prisma/
90
+ │ └── schema.prisma # Database schema
91
+ ├── .env.example
92
+ ├── .gitignore
93
+ ├── package.json
94
+ ├── tsconfig.json
95
+ ├── jest.config.js
96
+ ├── Dockerfile
97
+ ├── docker-compose.yml
98
+ └── README.md
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Generated Files
104
+
105
+ ### 1. **src/server.ts** (Entry Point)
106
+
107
+ ```typescript
108
+ import app from './app'
109
+ import { config } from './config'
110
+
111
+ const PORT = process.env.PORT || 3000
112
+
113
+ app.listen(PORT, () => {
114
+ console.log(`Server running on port ${PORT}`)
115
+ console.log(`Environment: ${process.env.NODE_ENV}`)
116
+ })
117
+ ```
118
+
119
+ ### 2. **src/app.ts** (Express Setup)
120
+
121
+ ```typescript
122
+ import express, { Application } from 'express'
123
+ import cors from 'cors'
124
+ import helmet from 'helmet'
125
+ import morgan from 'morgan'
126
+ import rateLimit from 'express-rate-limit'
127
+
128
+ import authRoutes from './routes/auth.routes'
129
+ import taskRoutes from './routes/task.routes'
130
+ import { errorHandler } from './middleware/error.middleware'
131
+ import { notFoundHandler } from './middleware/notFound.middleware'
132
+
133
+ const app: Application = express()
134
+
135
+ // Security middleware
136
+ app.use(helmet())
137
+ app.use(cors({
138
+ origin: process.env.ALLOWED_ORIGINS?.split(',') || '*',
139
+ credentials: true
140
+ }))
141
+
142
+ // Rate limiting
143
+ const limiter = rateLimit({
144
+ windowMs: 15 * 60 * 1000, // 15 minutes
145
+ max: 100, // 100 requests per window
146
+ message: 'Too many requests, please try again later'
147
+ })
148
+ app.use('/api/', limiter)
149
+
150
+ // Parsing middleware
151
+ app.use(express.json())
152
+ app.use(express.urlencoded({ extended: true }))
153
+
154
+ // Logging
155
+ if (process.env.NODE_ENV !== 'test') {
156
+ app.use(morgan('combined'))
157
+ }
158
+
159
+ // Health check
160
+ app.get('/health', (req, res) => {
161
+ res.json({ status: 'ok', timestamp: new Date().toISOString() })
162
+ })
163
+
164
+ // Routes
165
+ app.use('/api/auth', authRoutes)
166
+ app.use('/api/tasks', taskRoutes)
167
+
168
+ // Error handling
169
+ app.use(notFoundHandler)
170
+ app.use(errorHandler)
171
+
172
+ export default app
173
+ ```
174
+
175
+ ### 3. **src/controllers/auth.controller.ts**
176
+
177
+ ```typescript
178
+ import { Request, Response, NextFunction } from 'express'
179
+ import { AuthService } from '../services/auth.service'
180
+ import { ApiError } from '../utils/ApiError'
181
+
182
+ const authService = new AuthService()
183
+
184
+ export class AuthController {
185
+ async register(req: Request, res: Response, next: NextFunction) {
186
+ try {
187
+ const { email, password, name } = req.body
188
+
189
+ const result = await authService.register({ email, password, name })
190
+
191
+ res.status(201).json({
192
+ data: {
193
+ user: result.user,
194
+ token: result.token
195
+ }
196
+ })
197
+ } catch (error) {
198
+ next(error)
199
+ }
200
+ }
201
+
202
+ async login(req: Request, res: Response, next: NextFunction) {
203
+ try {
204
+ const { email, password } = req.body
205
+
206
+ const result = await authService.login(email, password)
207
+
208
+ res.json({
209
+ data: {
210
+ user: result.user,
211
+ token: result.token
212
+ }
213
+ })
214
+ } catch (error) {
215
+ next(error)
216
+ }
217
+ }
218
+
219
+ async getProfile(req: Request, res: Response, next: NextFunction) {
220
+ try {
221
+ const userId = req.user!.id
222
+
223
+ const user = await authService.getUserById(userId)
224
+
225
+ res.json({ data: user })
226
+ } catch (error) {
227
+ next(error)
228
+ }
229
+ }
230
+ }
231
+ ```
232
+
233
+ ### 4. **src/middleware/auth.middleware.ts**
234
+
235
+ ```typescript
236
+ import { Request, Response, NextFunction } from 'express'
237
+ import jwt from 'jsonwebtoken'
238
+ import { ApiError } from '../utils/ApiError'
239
+
240
+ interface JwtPayload {
241
+ userId: string
242
+ email: string
243
+ }
244
+
245
+ declare global {
246
+ namespace Express {
247
+ interface Request {
248
+ user?: {
249
+ id: string
250
+ email: string
251
+ }
252
+ }
253
+ }
254
+ }
255
+
256
+ export function authenticate(req: Request, res: Response, next: NextFunction) {
257
+ try {
258
+ const authHeader = req.headers.authorization
259
+
260
+ if (!authHeader?.startsWith('Bearer ')) {
261
+ throw new ApiError(401, 'No token provided')
262
+ }
263
+
264
+ const token = authHeader.split(' ')[1]
265
+
266
+ const decoded = jwt.verify(
267
+ token,
268
+ process.env.JWT_SECRET!
269
+ ) as JwtPayload
270
+
271
+ req.user = {
272
+ id: decoded.userId,
273
+ email: decoded.email
274
+ }
275
+
276
+ next()
277
+ } catch (error) {
278
+ if (error instanceof jwt.JsonWebTokenError) {
279
+ next(new ApiError(401, 'Invalid token'))
280
+ } else {
281
+ next(error)
282
+ }
283
+ }
284
+ }
285
+ ```
286
+
287
+ ### 5. **src/middleware/error.middleware.ts**
288
+
289
+ ```typescript
290
+ import { Request, Response, NextFunction } from 'express'
291
+ import { ApiError } from '../utils/ApiError'
292
+ import { ZodError } from 'zod'
293
+
294
+ export function errorHandler(
295
+ err: Error,
296
+ req: Request,
297
+ res: Response,
298
+ next: NextFunction
299
+ ) {
300
+ console.error('Error:', err)
301
+
302
+ // Handle known API errors
303
+ if (err instanceof ApiError) {
304
+ return res.status(err.statusCode).json({
305
+ error: {
306
+ code: err.name,
307
+ message: err.message,
308
+ ...(err.details && { details: err.details })
309
+ }
310
+ })
311
+ }
312
+
313
+ // Handle validation errors (Zod)
314
+ if (err instanceof ZodError) {
315
+ return res.status(400).json({
316
+ error: {
317
+ code: 'VALIDATION_ERROR',
318
+ message: 'Validation failed',
319
+ details: err.errors.map(e => ({
320
+ field: e.path.join('.'),
321
+ message: e.message
322
+ }))
323
+ }
324
+ })
325
+ }
326
+
327
+ // Handle unexpected errors
328
+ res.status(500).json({
329
+ error: {
330
+ code: 'INTERNAL_SERVER_ERROR',
331
+ message: process.env.NODE_ENV === 'production'
332
+ ? 'An unexpected error occurred'
333
+ : err.message
334
+ }
335
+ })
336
+ }
337
+ ```
338
+
339
+ ### 6. **src/routes/task.routes.ts**
340
+
341
+ ```typescript
342
+ import { Router } from 'express'
343
+ import { TaskController } from '../controllers/task.controller'
344
+ import { authenticate } from '../middleware/auth.middleware'
345
+ import { validate } from '../middleware/validation.middleware'
346
+ import { createTaskSchema, updateTaskSchema } from '../schemas/task.schema'
347
+
348
+ const router = Router()
349
+ const taskController = new TaskController()
350
+
351
+ // All routes require authentication
352
+ router.use(authenticate)
353
+
354
+ router.get('/', taskController.list)
355
+ router.post('/', validate(createTaskSchema), taskController.create)
356
+ router.get('/:id', taskController.getById)
357
+ router.patch('/:id', validate(updateTaskSchema), taskController.update)
358
+ router.delete('/:id', taskController.delete)
359
+
360
+ export default router
361
+ ```
362
+
363
+ ### 7. **src/services/task.service.ts**
364
+
365
+ ```typescript
366
+ import { PrismaClient } from '@prisma/client'
367
+ import { ApiError } from '../utils/ApiError'
368
+
369
+ const prisma = new PrismaClient()
370
+
371
+ export class TaskService {
372
+ async create(userId: string, data: { title: string; description?: string }) {
373
+ return await prisma.task.create({
374
+ data: {
375
+ ...data,
376
+ userId
377
+ }
378
+ })
379
+ }
380
+
381
+ async findAll(userId: string) {
382
+ return await prisma.task.findMany({
383
+ where: { userId },
384
+ orderBy: { createdAt: 'desc' }
385
+ })
386
+ }
387
+
388
+ async findById(id: string, userId: string) {
389
+ const task = await prisma.task.findUnique({
390
+ where: { id }
391
+ })
392
+
393
+ if (!task) {
394
+ throw new ApiError(404, 'Task not found')
395
+ }
396
+
397
+ if (task.userId !== userId) {
398
+ throw new ApiError(403, 'Access denied')
399
+ }
400
+
401
+ return task
402
+ }
403
+
404
+ async update(id: string, userId: string, data: Partial<{ title: string; description: string; completed: boolean }>) {
405
+ await this.findById(id, userId) // Check ownership
406
+
407
+ return await prisma.task.update({
408
+ where: { id },
409
+ data
410
+ })
411
+ }
412
+
413
+ async delete(id: string, userId: string) {
414
+ await this.findById(id, userId) // Check ownership
415
+
416
+ await prisma.task.delete({
417
+ where: { id }
418
+ })
419
+ }
420
+ }
421
+ ```
422
+
423
+ ### 8. **prisma/schema.prisma** (Database Schema)
424
+
425
+ ```prisma
426
+ generator client {
427
+ provider = "prisma-client-js"
428
+ }
429
+
430
+ datasource db {
431
+ provider = "postgresql"
432
+ url = env("DATABASE_URL")
433
+ }
434
+
435
+ model User {
436
+ id String @id @default(uuid())
437
+ email String @unique
438
+ password String
439
+ name String
440
+ tasks Task[]
441
+ createdAt DateTime @default(now())
442
+ updatedAt DateTime @updatedAt
443
+
444
+ @@map("users")
445
+ }
446
+
447
+ model Task {
448
+ id String @id @default(uuid())
449
+ title String
450
+ description String?
451
+ completed Boolean @default(false)
452
+ userId String
453
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
454
+ createdAt DateTime @default(now())
455
+ updatedAt DateTime @updatedAt
456
+
457
+ @@index([userId])
458
+ @@map("tasks")
459
+ }
460
+ ```
461
+
462
+ ### 9. **tests/task.test.ts** (Integration Tests)
463
+
464
+ ```typescript
465
+ import request from 'supertest'
466
+ import app from '../src/app'
467
+ import { PrismaClient } from '@prisma/client'
468
+
469
+ const prisma = new PrismaClient()
470
+
471
+ describe('Task API', () => {
472
+ let authToken: string
473
+ let userId: string
474
+
475
+ beforeAll(async () => {
476
+ // Create test user and get token
477
+ const res = await request(app)
478
+ .post('/api/auth/register')
479
+ .send({
480
+ email: '[email protected]',
481
+ password: 'password123',
482
+ name: 'Test User'
483
+ })
484
+
485
+ authToken = res.body.data.token
486
+ userId = res.body.data.user.id
487
+ })
488
+
489
+ afterAll(async () => {
490
+ // Cleanup
491
+ await prisma.task.deleteMany({ where: { userId } })
492
+ await prisma.user.delete({ where: { id: userId } })
493
+ await prisma.$disconnect()
494
+ })
495
+
496
+ describe('POST /api/tasks', () => {
497
+ it('should create a new task', async () => {
498
+ const res = await request(app)
499
+ .post('/api/tasks')
500
+ .set('Authorization', `Bearer ${authToken}`)
501
+ .send({
502
+ title: 'Test Task',
503
+ description: 'Test description'
504
+ })
505
+
506
+ expect(res.status).toBe(201)
507
+ expect(res.body.data).toHaveProperty('id')
508
+ expect(res.body.data.title).toBe('Test Task')
509
+ })
510
+
511
+ it('should require authentication', async () => {
512
+ const res = await request(app)
513
+ .post('/api/tasks')
514
+ .send({ title: 'Test' })
515
+
516
+ expect(res.status).toBe(401)
517
+ })
518
+ })
519
+
520
+ describe('GET /api/tasks', () => {
521
+ it('should list user tasks', async () => {
522
+ const res = await request(app)
523
+ .get('/api/tasks')
524
+ .set('Authorization', `Bearer ${authToken}`)
525
+
526
+ expect(res.status).toBe(200)
527
+ expect(Array.isArray(res.body.data)).toBe(true)
528
+ })
529
+ })
530
+ })
531
+ ```
532
+
533
+ ### 10. **package.json**
534
+
535
+ ```json
536
+ {
537
+ "name": "task-api",
538
+ "version": "1.0.0",
539
+ "scripts": {
540
+ "dev": "ts-node-dev --respawn --transpile-only src/server.ts",
541
+ "build": "tsc",
542
+ "start": "node dist/server.js",
543
+ "test": "jest --coverage",
544
+ "lint": "eslint src/**/*.ts",
545
+ "format": "prettier --write \"src/**/*.ts\"",
546
+ "db:migrate": "prisma migrate dev",
547
+ "db:push": "prisma db push",
548
+ "db:generate": "prisma generate"
549
+ },
550
+ "dependencies": {
551
+ "express": "^4.18.2",
552
+ "cors": "^2.8.5",
553
+ "helmet": "^7.1.0",
554
+ "express-rate-limit": "^7.1.5",
555
+ "morgan": "^1.10.0",
556
+ "bcrypt": "^5.1.1",
557
+ "jsonwebtoken": "^9.0.2",
558
+ "zod": "^3.22.4",
559
+ "@prisma/client": "^5.8.0",
560
+ "dotenv": "^16.3.1"
561
+ },
562
+ "devDependencies": {
563
+ "@types/express": "^4.17.21",
564
+ "@types/node": "^20.10.6",
565
+ "@types/cors": "^2.8.17",
566
+ "@types/morgan": "^1.9.9",
567
+ "@types/bcrypt": "^5.0.2",
568
+ "@types/jsonwebtoken": "^9.0.5",
569
+ "@types/jest": "^29.5.11",
570
+ "@types/supertest": "^6.0.2",
571
+ "typescript": "^5.3.3",
572
+ "ts-node-dev": "^2.0.0",
573
+ "jest": "^29.7.0",
574
+ "ts-jest": "^29.1.1",
575
+ "supertest": "^6.3.3",
576
+ "prisma": "^5.8.0",
577
+ "eslint": "^8.56.0",
578
+ "prettier": "^3.1.1"
579
+ }
580
+ }
581
+ ```
582
+
583
+ ---
584
+
585
+ ## Features
586
+
587
+ **Security:**
588
+ - Helmet.js for HTTP headers
589
+ - CORS with configurable origins
590
+ - Rate limiting (100 req/15min)
591
+ - JWT authentication
592
+ - Password hashing (bcrypt)
593
+ - Input validation (Zod)
594
+
595
+ **Database:**
596
+ - Prisma ORM with TypeScript
597
+ - Automatic migrations
598
+ - Type-safe queries
599
+ - Supports PostgreSQL, MySQL, SQLite
600
+
601
+ **Testing:**
602
+ - Jest + Supertest
603
+ - Integration tests
604
+ - Coverage reporting
605
+ - Test database isolation
606
+
607
+ **Development:**
608
+ - Hot reload (ts-node-dev)
609
+ - TypeScript with strict mode
610
+ - ESLint + Prettier
611
+ - Environment variables
612
+
613
+ **Production:**
614
+ - Docker support
615
+ - Health check endpoint
616
+ - Error logging
617
+ - Graceful shutdown
618
+
619
+ ---
620
+
621
+ ## Getting Started
622
+
623
+ **1. Install dependencies:**
624
+ ```bash
625
+ npm install
626
+ ```
627
+
628
+ **2. Configure environment:**
629
+ ```bash
630
+ cp .env.example .env
631
+ # Edit .env with your database URL and secrets
632
+ ```
633
+
634
+ **3. Run database migrations:**
635
+ ```bash
636
+ npm run db:migrate
637
+ ```
638
+
639
+ **4. Start development server:**
640
+ ```bash
641
+ npm run dev
642
+ ```
643
+
644
+ **5. Run tests:**
645
+ ```bash
646
+ npm test
647
+ ```
648
+
649
+ ---
650
+
651
+ ## Related Commands
652
+
653
+ - `/fastapi-scaffold` - Generate FastAPI boilerplate
654
+ - Backend Architect (agent) - Architecture review
655
+ - API Builder (agent) - API design guidance
656
+
657
+ ---
658
+
659
+ **Build production-ready APIs. Ship faster. Scale confidently.**