kiro-spec-engine 1.2.3 → 1.4.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 (78) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/README.md +239 -213
  3. package/README.zh.md +0 -330
  4. package/bin/kiro-spec-engine.js +62 -0
  5. package/docs/README.md +223 -0
  6. package/docs/agent-hooks-analysis.md +815 -0
  7. package/docs/command-reference.md +252 -0
  8. package/docs/cross-tool-guide.md +554 -0
  9. package/docs/examples/add-export-command/design.md +194 -0
  10. package/docs/examples/add-export-command/requirements.md +110 -0
  11. package/docs/examples/add-export-command/tasks.md +88 -0
  12. package/docs/examples/add-rest-api/design.md +855 -0
  13. package/docs/examples/add-rest-api/requirements.md +323 -0
  14. package/docs/examples/add-rest-api/tasks.md +355 -0
  15. package/docs/examples/add-user-dashboard/design.md +192 -0
  16. package/docs/examples/add-user-dashboard/requirements.md +143 -0
  17. package/docs/examples/add-user-dashboard/tasks.md +91 -0
  18. package/docs/faq.md +696 -0
  19. package/docs/integration-modes.md +525 -0
  20. package/docs/integration-philosophy.md +313 -0
  21. package/docs/manual-workflows-guide.md +417 -0
  22. package/docs/quick-start-with-ai-tools.md +374 -0
  23. package/docs/quick-start.md +711 -0
  24. package/docs/spec-workflow.md +453 -0
  25. package/docs/steering-strategy-guide.md +196 -0
  26. package/docs/tools/claude-guide.md +653 -0
  27. package/docs/tools/cursor-guide.md +705 -0
  28. package/docs/tools/generic-guide.md +445 -0
  29. package/docs/tools/kiro-guide.md +308 -0
  30. package/docs/tools/vscode-guide.md +444 -0
  31. package/docs/tools/windsurf-guide.md +390 -0
  32. package/docs/troubleshooting.md +795 -0
  33. package/docs/zh/README.md +275 -0
  34. package/docs/zh/quick-start.md +711 -0
  35. package/docs/zh/tools/claude-guide.md +348 -0
  36. package/docs/zh/tools/cursor-guide.md +280 -0
  37. package/docs/zh/tools/generic-guide.md +498 -0
  38. package/docs/zh/tools/kiro-guide.md +342 -0
  39. package/docs/zh/tools/vscode-guide.md +448 -0
  40. package/docs/zh/tools/windsurf-guide.md +377 -0
  41. package/lib/adoption/detection-engine.js +14 -4
  42. package/lib/commands/adopt.js +117 -3
  43. package/lib/commands/context.js +99 -0
  44. package/lib/commands/prompt.js +105 -0
  45. package/lib/commands/status.js +225 -0
  46. package/lib/commands/task.js +199 -0
  47. package/lib/commands/watch.js +569 -0
  48. package/lib/commands/workflows.js +240 -0
  49. package/lib/commands/workspace.js +189 -0
  50. package/lib/context/context-exporter.js +378 -0
  51. package/lib/context/prompt-generator.js +482 -0
  52. package/lib/steering/adoption-config.js +164 -0
  53. package/lib/steering/steering-manager.js +289 -0
  54. package/lib/task/task-claimer.js +430 -0
  55. package/lib/utils/tool-detector.js +383 -0
  56. package/lib/watch/action-executor.js +458 -0
  57. package/lib/watch/event-debouncer.js +323 -0
  58. package/lib/watch/execution-logger.js +550 -0
  59. package/lib/watch/file-watcher.js +499 -0
  60. package/lib/watch/presets.js +266 -0
  61. package/lib/watch/watch-manager.js +533 -0
  62. package/lib/workspace/workspace-manager.js +370 -0
  63. package/lib/workspace/workspace-sync.js +356 -0
  64. package/package.json +3 -1
  65. package/template/.kiro/tools/backup_manager.py +295 -0
  66. package/template/.kiro/tools/configuration_manager.py +218 -0
  67. package/template/.kiro/tools/document_evaluator.py +550 -0
  68. package/template/.kiro/tools/enhancement_logger.py +168 -0
  69. package/template/.kiro/tools/error_handler.py +335 -0
  70. package/template/.kiro/tools/improvement_identifier.py +444 -0
  71. package/template/.kiro/tools/modification_applicator.py +737 -0
  72. package/template/.kiro/tools/quality_gate_enforcer.py +207 -0
  73. package/template/.kiro/tools/quality_scorer.py +305 -0
  74. package/template/.kiro/tools/report_generator.py +154 -0
  75. package/template/.kiro/tools/ultrawork_enhancer_refactored.py +0 -0
  76. package/template/.kiro/tools/ultrawork_enhancer_v2.py +463 -0
  77. package/template/.kiro/tools/ultrawork_enhancer_v3.py +606 -0
  78. package/template/.kiro/tools/workflow_quality_gate.py +100 -0
@@ -0,0 +1,855 @@
1
+ # RESTful API with Authentication - Design
2
+
3
+ > Technical design and architecture for the task management API
4
+
5
+ ---
6
+
7
+ **Version**: 1.0.0
8
+ **Last Updated**: 2026-01-23
9
+ **Spec Type**: Example - API Feature
10
+
11
+ ---
12
+
13
+ ## Overview
14
+
15
+ This design document specifies the technical implementation of a RESTful task management API with JWT authentication. The architecture follows Express.js best practices with a layered approach: routes → controllers → services → repositories.
16
+
17
+ **Architecture Pattern:** Layered Architecture (MVC-inspired)
18
+ **Technology Stack:** Node.js + Express + PostgreSQL + JWT
19
+
20
+ ---
21
+
22
+ ## Architecture Diagram
23
+
24
+ ```mermaid
25
+ graph TD
26
+ Client[Client Application] --> Router[Express Router]
27
+ Router --> AuthMW[Auth Middleware]
28
+ AuthMW --> Controller[Controllers]
29
+ Controller --> Service[Services]
30
+ Service --> Repository[Repositories]
31
+ Repository --> DB[(PostgreSQL)]
32
+
33
+ Controller --> Validator[Validators]
34
+ Controller --> ErrorHandler[Error Handler]
35
+ ```
36
+
37
+ ---
38
+
39
+ ## System Architecture
40
+
41
+ ### Layer Responsibilities
42
+
43
+ **1. Routes Layer** (`routes/`)
44
+ - Define API endpoints
45
+ - Map HTTP methods to controller functions
46
+ - Apply middleware (authentication, validation)
47
+
48
+ **2. Controllers Layer** (`controllers/`)
49
+ - Handle HTTP requests and responses
50
+ - Validate input using express-validator
51
+ - Call service layer for business logic
52
+ - Format responses
53
+
54
+ **3. Services Layer** (`services/`)
55
+ - Implement business logic
56
+ - Coordinate between multiple repositories
57
+ - Handle transactions
58
+ - Throw domain-specific errors
59
+
60
+ **4. Repositories Layer** (`repositories/`)
61
+ - Database access layer
62
+ - Execute SQL queries
63
+ - Map database rows to domain objects
64
+ - Handle database errors
65
+
66
+ **5. Middleware Layer** (`middleware/`)
67
+ - Authentication (JWT verification)
68
+ - Error handling
69
+ - Request logging
70
+ - Rate limiting
71
+
72
+ ---
73
+
74
+ ## Component Design
75
+
76
+ ### 1. Authentication System
77
+
78
+ #### AuthController
79
+ **File:** `src/controllers/auth.controller.js`
80
+
81
+ **Responsibilities:**
82
+ - Handle registration and login requests
83
+ - Validate input data
84
+ - Return JWT tokens
85
+
86
+ **Methods:**
87
+ ```javascript
88
+ class AuthController {
89
+ /**
90
+ * Register new user
91
+ * POST /api/v1/auth/register
92
+ */
93
+ async register(req, res, next) {
94
+ // 1. Validate input (email, password)
95
+ // 2. Call authService.register()
96
+ // 3. Return success response
97
+ }
98
+
99
+ /**
100
+ * Login user
101
+ * POST /api/v1/auth/login
102
+ */
103
+ async login(req, res, next) {
104
+ // 1. Validate input (email, password)
105
+ // 2. Call authService.login()
106
+ // 3. Return JWT token
107
+ }
108
+ }
109
+ ```
110
+
111
+ ---
112
+
113
+ #### AuthService
114
+ **File:** `src/services/auth.service.js`
115
+
116
+ **Responsibilities:**
117
+ - User registration logic
118
+ - User authentication logic
119
+ - Password hashing and verification
120
+ - JWT token generation
121
+
122
+ **Methods:**
123
+ ```javascript
124
+ class AuthService {
125
+ /**
126
+ * Register new user
127
+ * @param {string} email
128
+ * @param {string} password
129
+ * @returns {Promise<User>}
130
+ * @throws {ConflictError} if email exists
131
+ */
132
+ async register(email, password) {
133
+ // 1. Check if email exists
134
+ // 2. Hash password with bcrypt
135
+ // 3. Create user via userRepository
136
+ // 4. Return user (without password)
137
+ }
138
+
139
+ /**
140
+ * Authenticate user and generate token
141
+ * @param {string} email
142
+ * @param {string} password
143
+ * @returns {Promise<{token: string, user: User}>}
144
+ * @throws {UnauthorizedError} if credentials invalid
145
+ */
146
+ async login(email, password) {
147
+ // 1. Find user by email
148
+ // 2. Verify password with bcrypt
149
+ // 3. Generate JWT token
150
+ // 4. Return token and user
151
+ }
152
+
153
+ /**
154
+ * Generate JWT token
155
+ * @param {User} user
156
+ * @returns {string} JWT token
157
+ */
158
+ generateToken(user) {
159
+ // Use jsonwebtoken to create token
160
+ // Payload: { userId, email }
161
+ // Expiration: 24 hours
162
+ }
163
+ }
164
+ ```
165
+
166
+ ---
167
+
168
+ #### AuthMiddleware
169
+ **File:** `src/middleware/auth.middleware.js`
170
+
171
+ **Responsibilities:**
172
+ - Verify JWT tokens
173
+ - Extract user from token
174
+ - Attach user to request object
175
+
176
+ **Implementation:**
177
+ ```javascript
178
+ const jwt = require('jsonwebtoken');
179
+
180
+ /**
181
+ * Verify JWT token and attach user to request
182
+ */
183
+ async function authenticate(req, res, next) {
184
+ try {
185
+ // 1. Extract token from Authorization header
186
+ const token = req.headers.authorization?.replace('Bearer ', '');
187
+
188
+ if (!token) {
189
+ throw new UnauthorizedError('No token provided');
190
+ }
191
+
192
+ // 2. Verify token
193
+ const decoded = jwt.verify(token, process.env.JWT_SECRET);
194
+
195
+ // 3. Attach user to request
196
+ req.user = {
197
+ id: decoded.userId,
198
+ email: decoded.email
199
+ };
200
+
201
+ next();
202
+ } catch (error) {
203
+ next(new UnauthorizedError('Invalid token'));
204
+ }
205
+ }
206
+ ```
207
+
208
+ ---
209
+
210
+ ### 2. Task Management System
211
+
212
+ #### TaskController
213
+ **File:** `src/controllers/task.controller.js`
214
+
215
+ **Responsibilities:**
216
+ - Handle task CRUD requests
217
+ - Validate input data
218
+ - Enforce authorization
219
+
220
+ **Methods:**
221
+ ```javascript
222
+ class TaskController {
223
+ /**
224
+ * Create new task
225
+ * POST /api/v1/tasks
226
+ */
227
+ async create(req, res, next) {
228
+ // 1. Validate input (title, description, status)
229
+ // 2. Call taskService.create() with req.user.id
230
+ // 3. Return created task
231
+ }
232
+
233
+ /**
234
+ * List all user's tasks
235
+ * GET /api/v1/tasks
236
+ */
237
+ async list(req, res, next) {
238
+ // 1. Call taskService.findByUserId(req.user.id)
239
+ // 2. Return tasks array
240
+ }
241
+
242
+ /**
243
+ * Get single task
244
+ * GET /api/v1/tasks/:id
245
+ */
246
+ async getById(req, res, next) {
247
+ // 1. Call taskService.findById(req.params.id)
248
+ // 2. Check if task belongs to req.user.id
249
+ // 3. Return task or 403 Forbidden
250
+ }
251
+
252
+ /**
253
+ * Update task
254
+ * PUT /api/v1/tasks/:id
255
+ */
256
+ async update(req, res, next) {
257
+ // 1. Validate input
258
+ // 2. Check task ownership
259
+ // 3. Call taskService.update()
260
+ // 4. Return updated task
261
+ }
262
+
263
+ /**
264
+ * Delete task
265
+ * DELETE /api/v1/tasks/:id
266
+ */
267
+ async delete(req, res, next) {
268
+ // 1. Check task ownership
269
+ // 2. Call taskService.delete()
270
+ // 3. Return 204 No Content
271
+ }
272
+ }
273
+ ```
274
+
275
+ ---
276
+
277
+ #### TaskService
278
+ **File:** `src/services/task.service.js`
279
+
280
+ **Responsibilities:**
281
+ - Task business logic
282
+ - Coordinate with taskRepository
283
+ - Validate business rules
284
+
285
+ **Methods:**
286
+ ```javascript
287
+ class TaskService {
288
+ /**
289
+ * Create new task
290
+ * @param {string} userId
291
+ * @param {Object} taskData
292
+ * @returns {Promise<Task>}
293
+ */
294
+ async create(userId, taskData) {
295
+ // 1. Validate business rules
296
+ // 2. Create task via taskRepository
297
+ // 3. Return created task
298
+ }
299
+
300
+ /**
301
+ * Find all tasks for user
302
+ * @param {string} userId
303
+ * @returns {Promise<Task[]>}
304
+ */
305
+ async findByUserId(userId) {
306
+ // 1. Query taskRepository
307
+ // 2. Sort by createdAt DESC
308
+ // 3. Return tasks
309
+ }
310
+
311
+ /**
312
+ * Find task by ID
313
+ * @param {string} taskId
314
+ * @returns {Promise<Task>}
315
+ * @throws {NotFoundError} if task doesn't exist
316
+ */
317
+ async findById(taskId) {
318
+ // 1. Query taskRepository
319
+ // 2. Throw NotFoundError if not found
320
+ // 3. Return task
321
+ }
322
+
323
+ /**
324
+ * Update task
325
+ * @param {string} taskId
326
+ * @param {Object} updates
327
+ * @returns {Promise<Task>}
328
+ */
329
+ async update(taskId, updates) {
330
+ // 1. Find task
331
+ // 2. Apply updates
332
+ // 3. Save via taskRepository
333
+ // 4. Return updated task
334
+ }
335
+
336
+ /**
337
+ * Delete task
338
+ * @param {string} taskId
339
+ * @returns {Promise<void>}
340
+ */
341
+ async delete(taskId) {
342
+ // 1. Delete via taskRepository
343
+ }
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ### 3. Data Access Layer
350
+
351
+ #### UserRepository
352
+ **File:** `src/repositories/user.repository.js`
353
+
354
+ **Responsibilities:**
355
+ - User database operations
356
+ - SQL query execution
357
+
358
+ **Methods:**
359
+ ```javascript
360
+ class UserRepository {
361
+ /**
362
+ * Create new user
363
+ * @param {Object} userData
364
+ * @returns {Promise<User>}
365
+ */
366
+ async create(userData) {
367
+ const query = `
368
+ INSERT INTO users (id, email, password, created_at, updated_at)
369
+ VALUES ($1, $2, $3, NOW(), NOW())
370
+ RETURNING id, email, created_at, updated_at
371
+ `;
372
+ // Execute query and return user
373
+ }
374
+
375
+ /**
376
+ * Find user by email
377
+ * @param {string} email
378
+ * @returns {Promise<User|null>}
379
+ */
380
+ async findByEmail(email) {
381
+ const query = `
382
+ SELECT id, email, password, created_at, updated_at
383
+ FROM users
384
+ WHERE email = $1
385
+ `;
386
+ // Execute query and return user or null
387
+ }
388
+
389
+ /**
390
+ * Find user by ID
391
+ * @param {string} userId
392
+ * @returns {Promise<User|null>}
393
+ */
394
+ async findById(userId) {
395
+ const query = `
396
+ SELECT id, email, created_at, updated_at
397
+ FROM users
398
+ WHERE id = $1
399
+ `;
400
+ // Execute query and return user or null
401
+ }
402
+ }
403
+ ```
404
+
405
+ ---
406
+
407
+ #### TaskRepository
408
+ **File:** `src/repositories/task.repository.js`
409
+
410
+ **Responsibilities:**
411
+ - Task database operations
412
+ - SQL query execution
413
+
414
+ **Methods:**
415
+ ```javascript
416
+ class TaskRepository {
417
+ /**
418
+ * Create new task
419
+ * @param {Object} taskData
420
+ * @returns {Promise<Task>}
421
+ */
422
+ async create(taskData) {
423
+ const query = `
424
+ INSERT INTO tasks (id, user_id, title, description, status, created_at, updated_at)
425
+ VALUES ($1, $2, $3, $4, $5, NOW(), NOW())
426
+ RETURNING *
427
+ `;
428
+ // Execute query and return task
429
+ }
430
+
431
+ /**
432
+ * Find all tasks for user
433
+ * @param {string} userId
434
+ * @returns {Promise<Task[]>}
435
+ */
436
+ async findByUserId(userId) {
437
+ const query = `
438
+ SELECT * FROM tasks
439
+ WHERE user_id = $1
440
+ ORDER BY created_at DESC
441
+ `;
442
+ // Execute query and return tasks
443
+ }
444
+
445
+ /**
446
+ * Find task by ID
447
+ * @param {string} taskId
448
+ * @returns {Promise<Task|null>}
449
+ */
450
+ async findById(taskId) {
451
+ const query = `
452
+ SELECT * FROM tasks
453
+ WHERE id = $1
454
+ `;
455
+ // Execute query and return task or null
456
+ }
457
+
458
+ /**
459
+ * Update task
460
+ * @param {string} taskId
461
+ * @param {Object} updates
462
+ * @returns {Promise<Task>}
463
+ */
464
+ async update(taskId, updates) {
465
+ const query = `
466
+ UPDATE tasks
467
+ SET title = $1, description = $2, status = $3, updated_at = NOW()
468
+ WHERE id = $4
469
+ RETURNING *
470
+ `;
471
+ // Execute query and return updated task
472
+ }
473
+
474
+ /**
475
+ * Delete task
476
+ * @param {string} taskId
477
+ * @returns {Promise<void>}
478
+ */
479
+ async delete(taskId) {
480
+ const query = `DELETE FROM tasks WHERE id = $1`;
481
+ // Execute query
482
+ }
483
+ }
484
+ ```
485
+
486
+ ---
487
+
488
+ ## API Routes
489
+
490
+ ### Authentication Routes
491
+ **File:** `src/routes/auth.routes.js`
492
+
493
+ ```javascript
494
+ const express = require('express');
495
+ const router = express.Router();
496
+ const authController = require('../controllers/auth.controller');
497
+ const { validateRegistration, validateLogin } = require('../validators/auth.validator');
498
+
499
+ // POST /api/v1/auth/register
500
+ router.post('/register', validateRegistration, authController.register);
501
+
502
+ // POST /api/v1/auth/login
503
+ router.post('/login', validateLogin, authController.login);
504
+
505
+ module.exports = router;
506
+ ```
507
+
508
+ ---
509
+
510
+ ### Task Routes
511
+ **File:** `src/routes/task.routes.js`
512
+
513
+ ```javascript
514
+ const express = require('express');
515
+ const router = express.Router();
516
+ const taskController = require('../controllers/task.controller');
517
+ const { authenticate } = require('../middleware/auth.middleware');
518
+ const { validateTask, validateTaskUpdate } = require('../validators/task.validator');
519
+
520
+ // All task routes require authentication
521
+ router.use(authenticate);
522
+
523
+ // POST /api/v1/tasks
524
+ router.post('/', validateTask, taskController.create);
525
+
526
+ // GET /api/v1/tasks
527
+ router.get('/', taskController.list);
528
+
529
+ // GET /api/v1/tasks/:id
530
+ router.get('/:id', taskController.getById);
531
+
532
+ // PUT /api/v1/tasks/:id
533
+ router.put('/:id', validateTaskUpdate, taskController.update);
534
+
535
+ // DELETE /api/v1/tasks/:id
536
+ router.delete('/:id', taskController.delete);
537
+
538
+ module.exports = router;
539
+ ```
540
+
541
+ ---
542
+
543
+ ## Database Schema
544
+
545
+ ### Users Table
546
+ ```sql
547
+ CREATE TABLE users (
548
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
549
+ email VARCHAR(255) UNIQUE NOT NULL,
550
+ password VARCHAR(255) NOT NULL,
551
+ created_at TIMESTAMP NOT NULL DEFAULT NOW(),
552
+ updated_at TIMESTAMP NOT NULL DEFAULT NOW()
553
+ );
554
+
555
+ CREATE INDEX idx_users_email ON users(email);
556
+ ```
557
+
558
+ ### Tasks Table
559
+ ```sql
560
+ CREATE TABLE tasks (
561
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
562
+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
563
+ title VARCHAR(200) NOT NULL,
564
+ description TEXT,
565
+ status VARCHAR(20) NOT NULL DEFAULT 'pending',
566
+ created_at TIMESTAMP NOT NULL DEFAULT NOW(),
567
+ updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
568
+
569
+ CONSTRAINT chk_status CHECK (status IN ('pending', 'in_progress', 'completed'))
570
+ );
571
+
572
+ CREATE INDEX idx_tasks_user_id ON tasks(user_id);
573
+ CREATE INDEX idx_tasks_created_at ON tasks(created_at DESC);
574
+ ```
575
+
576
+ ---
577
+
578
+ ## Error Handling
579
+
580
+ ### Custom Error Classes
581
+ **File:** `src/errors/index.js`
582
+
583
+ ```javascript
584
+ class AppError extends Error {
585
+ constructor(message, statusCode, errorCode) {
586
+ super(message);
587
+ this.statusCode = statusCode;
588
+ this.errorCode = errorCode;
589
+ }
590
+ }
591
+
592
+ class ValidationError extends AppError {
593
+ constructor(message, details = {}) {
594
+ super(message, 400, 'INVALID_INPUT');
595
+ this.details = details;
596
+ }
597
+ }
598
+
599
+ class UnauthorizedError extends AppError {
600
+ constructor(message = 'Unauthorized') {
601
+ super(message, 401, 'UNAUTHORIZED');
602
+ }
603
+ }
604
+
605
+ class ForbiddenError extends AppError {
606
+ constructor(message = 'Forbidden') {
607
+ super(message, 403, 'FORBIDDEN');
608
+ }
609
+ }
610
+
611
+ class NotFoundError extends AppError {
612
+ constructor(message = 'Resource not found') {
613
+ super(message, 404, 'NOT_FOUND');
614
+ }
615
+ }
616
+
617
+ class ConflictError extends AppError {
618
+ constructor(message = 'Resource already exists') {
619
+ super(message, 409, 'CONFLICT');
620
+ }
621
+ }
622
+ ```
623
+
624
+ ---
625
+
626
+ ### Error Handler Middleware
627
+ **File:** `src/middleware/error.middleware.js`
628
+
629
+ ```javascript
630
+ function errorHandler(err, req, res, next) {
631
+ // Log error
632
+ console.error(err);
633
+
634
+ // Handle known errors
635
+ if (err instanceof AppError) {
636
+ return res.status(err.statusCode).json({
637
+ error: {
638
+ code: err.errorCode,
639
+ message: err.message,
640
+ details: err.details || {}
641
+ }
642
+ });
643
+ }
644
+
645
+ // Handle unknown errors
646
+ res.status(500).json({
647
+ error: {
648
+ code: 'INTERNAL_ERROR',
649
+ message: 'An unexpected error occurred'
650
+ }
651
+ });
652
+ }
653
+ ```
654
+
655
+ ---
656
+
657
+ ## Input Validation
658
+
659
+ ### Auth Validators
660
+ **File:** `src/validators/auth.validator.js`
661
+
662
+ ```javascript
663
+ const { body, validationResult } = require('express-validator');
664
+
665
+ const validateRegistration = [
666
+ body('email')
667
+ .isEmail().withMessage('Invalid email format')
668
+ .isLength({ max: 255 }).withMessage('Email too long'),
669
+ body('password')
670
+ .isLength({ min: 8, max: 128 }).withMessage('Password must be 8-128 characters'),
671
+
672
+ (req, res, next) => {
673
+ const errors = validationResult(req);
674
+ if (!errors.isEmpty()) {
675
+ throw new ValidationError('Validation failed', errors.mapped());
676
+ }
677
+ next();
678
+ }
679
+ ];
680
+
681
+ const validateLogin = [
682
+ body('email').isEmail(),
683
+ body('password').notEmpty(),
684
+
685
+ (req, res, next) => {
686
+ const errors = validationResult(req);
687
+ if (!errors.isEmpty()) {
688
+ throw new ValidationError('Validation failed', errors.mapped());
689
+ }
690
+ next();
691
+ }
692
+ ];
693
+ ```
694
+
695
+ ---
696
+
697
+ ### Task Validators
698
+ **File:** `src/validators/task.validator.js`
699
+
700
+ ```javascript
701
+ const { body, validationResult } = require('express-validator');
702
+
703
+ const validateTask = [
704
+ body('title')
705
+ .notEmpty().withMessage('Title is required')
706
+ .isLength({ max: 200 }).withMessage('Title too long'),
707
+ body('description')
708
+ .optional()
709
+ .isLength({ max: 2000 }).withMessage('Description too long'),
710
+ body('status')
711
+ .optional()
712
+ .isIn(['pending', 'in_progress', 'completed']).withMessage('Invalid status'),
713
+
714
+ (req, res, next) => {
715
+ const errors = validationResult(req);
716
+ if (!errors.isEmpty()) {
717
+ throw new ValidationError('Validation failed', errors.mapped());
718
+ }
719
+ next();
720
+ }
721
+ ];
722
+ ```
723
+
724
+ ---
725
+
726
+ ## Configuration
727
+
728
+ ### Environment Variables
729
+ **File:** `.env`
730
+
731
+ ```bash
732
+ # Server
733
+ PORT=3000
734
+ NODE_ENV=development
735
+
736
+ # Database
737
+ DB_HOST=localhost
738
+ DB_PORT=5432
739
+ DB_NAME=taskmanager
740
+ DB_USER=postgres
741
+ DB_PASSWORD=password
742
+
743
+ # JWT
744
+ JWT_SECRET=your-secret-key-change-in-production
745
+ JWT_EXPIRATION=24h
746
+
747
+ # Rate Limiting
748
+ RATE_LIMIT_WINDOW_MS=60000
749
+ RATE_LIMIT_MAX_REQUESTS=100
750
+ ```
751
+
752
+ ---
753
+
754
+ ## Requirements Traceability
755
+
756
+ | Requirement | Design Component | Implementation |
757
+ |-------------|------------------|----------------|
758
+ | US-1: User Registration | AuthController.register() | auth.controller.js |
759
+ | US-2: User Login | AuthController.login() | auth.controller.js |
760
+ | US-3: Create Task | TaskController.create() | task.controller.js |
761
+ | US-4: List Tasks | TaskController.list() | task.controller.js |
762
+ | US-5: Update Task | TaskController.update() | task.controller.js |
763
+ | US-6: Delete Task | TaskController.delete() | task.controller.js |
764
+ | FR-1: Authentication | AuthService + AuthMiddleware | auth.service.js, auth.middleware.js |
765
+ | FR-2: Task CRUD | TaskService + TaskRepository | task.service.js, task.repository.js |
766
+ | FR-3: Authorization | AuthMiddleware + ownership checks | auth.middleware.js |
767
+ | FR-4: Input Validation | express-validator | auth.validator.js, task.validator.js |
768
+ | FR-5: Error Handling | Error classes + middleware | errors/index.js, error.middleware.js |
769
+ | FR-6: API Versioning | Route prefixes | routes/index.js |
770
+ | NFR-2: Security | bcrypt + JWT + validation | Throughout |
771
+ | NFR-4: Maintainability | Layered architecture | Project structure |
772
+
773
+ ---
774
+
775
+ ## Technology Stack
776
+
777
+ ### Core Dependencies
778
+ ```json
779
+ {
780
+ "express": "^4.18.0",
781
+ "pg": "^8.11.0",
782
+ "jsonwebtoken": "^9.0.0",
783
+ "bcrypt": "^5.1.0",
784
+ "express-validator": "^7.0.0",
785
+ "dotenv": "^16.0.0",
786
+ "uuid": "^9.0.0"
787
+ }
788
+ ```
789
+
790
+ ### Dev Dependencies
791
+ ```json
792
+ {
793
+ "jest": "^29.0.0",
794
+ "supertest": "^6.3.0",
795
+ "nodemon": "^3.0.0"
796
+ }
797
+ ```
798
+
799
+ ---
800
+
801
+ ## Project Structure
802
+
803
+ ```
804
+ src/
805
+ ├── controllers/
806
+ │ ├── auth.controller.js
807
+ │ └── task.controller.js
808
+ ├── services/
809
+ │ ├── auth.service.js
810
+ │ └── task.service.js
811
+ ├── repositories/
812
+ │ ├── user.repository.js
813
+ │ └── task.repository.js
814
+ ├── routes/
815
+ │ ├── index.js
816
+ │ ├── auth.routes.js
817
+ │ └── task.routes.js
818
+ ├── middleware/
819
+ │ ├── auth.middleware.js
820
+ │ ├── error.middleware.js
821
+ │ └── rate-limit.middleware.js
822
+ ├── validators/
823
+ │ ├── auth.validator.js
824
+ │ └── task.validator.js
825
+ ├── errors/
826
+ │ └── index.js
827
+ ├── config/
828
+ │ ├── database.js
829
+ │ └── jwt.js
830
+ ├── utils/
831
+ │ └── logger.js
832
+ └── app.js
833
+
834
+ tests/
835
+ ├── unit/
836
+ │ ├── services/
837
+ │ └── repositories/
838
+ └── integration/
839
+ ├── auth.test.js
840
+ └── tasks.test.js
841
+ ```
842
+
843
+ ---
844
+
845
+ ## Related Documentation
846
+
847
+ - [Requirements Document](requirements.md) - Feature requirements
848
+ - [Tasks Document](tasks.md) - Implementation plan
849
+ - [Spec Workflow Guide](../../spec-workflow.md) - Understanding Specs
850
+
851
+ ---
852
+
853
+ **Version**: 1.0.0
854
+ **Last Updated**: 2026-01-23
855
+ **Status**: Example Spec