Skip to content

Ví dụ thực tế: Xây dựng REST API Backend

Scenario

Yêu cầu: Xây dựng REST API cho hệ thống quản lý task (Task Management System)

Features:

  • User authentication (JWT)
  • CRUD tasks
  • Assign tasks to users
  • Task status tracking
  • Due date reminders

Cách 1: KHÔNG dùng one-toolkit

Timeline: 5 ngày

Day 1: Nhảy thẳng vào code

Developer: "Tạo REST API cho task management với auth, CRUD tasks, assignments"

AI: "Sure! Here's the code..."

AI sinh code ngay:

typescript
// user.model.ts
export class User {
  id: string;
  email: string;
  password: string; // Plain text - SECURITY ISSUE!
}

// task.controller.ts
@Controller('tasks')
export class TaskController {
  @Post()
  async create(@Body() data: any) { // No validation!
    return this.taskService.create(data);
  }
  
  @Get()
  async findAll() {
    return this.taskService.findAll(); // No pagination!
  }
}

// auth.service.ts
async login(email: string, password: string) {
  const user = await this.findByEmail(email);
  if (user.password === password) { // Plain text comparison!
    return { token: 'some-token' }; // Hardcoded token!
  }
}

Vấn đề:

  • ❌ Password không được hash
  • ❌ Không có validation
  • ❌ Không có pagination
  • ❌ Token hardcoded
  • ❌ Không có error handling
  • ❌ Không có documentation

Day 2: Phát hiện vấn đề, refactor

Developer: "Ủa, password phải hash chứ?"
AI: "Oh yes, let me fix that..."

AI refactor:

typescript
// auth.service.ts
import * as bcrypt from 'bcrypt'; // Thêm dependency mới

async login(email: string, password: string) {
  const user = await this.findByEmail(email);
  const isValid = await bcrypt.compare(password, user.password);
  if (isValid) {
    const token = jwt.sign({ userId: user.id }, 'secret'); // Secret hardcoded!
    return { token };
  }
}

Vấn đề mới:

  • ❌ Secret key hardcoded
  • ❌ Không có token expiry
  • ❌ Không có refresh token

Day 3: Tiếp tục fix

Developer: "Secret key phải để trong env, thêm refresh token"
AI: "OK, updating..."

Refactor lần 2:

typescript
// auth.service.ts
async login(email: string, password: string) {
  const user = await this.findByEmail(email);
  const isValid = await bcrypt.compare(password, user.password);
  if (isValid) {
    const accessToken = jwt.sign(
      { userId: user.id }, 
      process.env.JWT_SECRET,
      { expiresIn: '15m' }
    );
    const refreshToken = jwt.sign(
      { userId: user.id }, 
      process.env.JWT_REFRESH_SECRET,
      { expiresIn: '7d' }
    );
    return { accessToken, refreshToken };
  }
}

Vấn đề:

  • ❌ Refresh token không được lưu DB (không thể revoke)
  • ❌ Không có rate limiting
  • ❌ Không có audit log

Day 4: Thêm features, phát hiện thêm vấn đề

Developer: "Implement task assignment"
AI: *implement*

Developer: "Test thử... Ủa, sao user A assign được task cho user B mà không check permission?"
AI: "Let me add authorization..."

Thêm authorization:

typescript
// task.controller.ts
@Post(':id/assign')
async assign(@Param('id') id: string, @Body() data: any) {
  // Thêm logic check permission
  const task = await this.taskService.findOne(id);
  if (task.createdBy !== currentUser.id) {
    throw new ForbiddenException(); // Vừa mới thêm
  }
  return this.taskService.assign(id, data.userId);
}

Vấn đề:

  • ❌ Authorization logic nằm rải rác trong controllers
  • ❌ Không consistent
  • ❌ Khó maintain

Day 5: Viết tests (cuối cùng)

Developer: "Viết tests đi"
AI: *viết tests*

Tests:

typescript
describe('TaskController', () => {
  it('should create task', async () => {
    const result = await controller.create(mockData);
    expect(result).toBeDefined(); // Test quá đơn giản
  });
  
  // Coverage: 45%
  // Nhiều edge cases không được test
});

Vấn đề:

  • ❌ Coverage thấp (45%)
  • ❌ Không test edge cases
  • ❌ Không test authorization
  • ❌ Không test error scenarios

Kết quả sau 5 ngày

Code:

src/
├── controllers/
│   ├── auth.controller.ts (refactored 3 lần)
│   ├── task.controller.ts (refactored 4 lần)
│   └── user.controller.ts (refactored 2 lần)
├── services/
│   ├── auth.service.ts (refactored 3 lần)
│   ├── task.service.ts (refactored 3 lần)
│   └── user.service.ts (refactored 2 lần)
└── __tests__/
    └── task.test.ts (coverage: 45%)

Vấn đề tồn tại:

  • ❌ Không có documentation
  • ❌ Không biết tại sao chọn architecture này
  • ❌ Authorization logic không consistent
  • ❌ Security issues vẫn còn (rate limiting, audit log)
  • ❌ Test coverage thấp
  • ❌ Code bị refactor nhiều lần → technical debt cao

Thời gian:

  • Coding: 3 ngày
  • Refactoring: 1.5 ngày
  • Testing: 0.5 ngày
  • Total: 5 ngày

Code quality: ⭐⭐ (2/5)


Cách 2: DÙNG one-toolkit

Timeline: 4 ngày

Day 1 Morning: Requirements Phase

bash
one-toolkit init --all
Developer: /new-requirement
AI: "What is the feature name?"
Developer: "task-management-api"

AI: "Creating documentation structure..."
AI: "What problem does this solve?"
Developer: "Teams need to track tasks, assign work, and monitor progress"

AI: "Let me help you write detailed requirements..."

AI điền vào docs/agent/requirements/feature-task-management-api.md:

markdown
## Problem Statement
Teams lack a centralized system to track tasks, assign work to members, 
and monitor progress. Current solution (spreadsheets) is inefficient and 
doesn't support real-time collaboration.

## User Stories

### Authentication
- As a user, I want to register an account so that I can use the system
- As a user, I want to login securely so that my data is protected
- As a user, I want to refresh my token so that I don't have to login frequently

### Task Management
- As a user, I want to create tasks so that I can track my work
- As a user, I want to view all my tasks so that I can see what needs to be done
- As a user, I want to update task status so that I can track progress
- As a user, I want to delete tasks so that I can remove completed/cancelled work

### Task Assignment
- As a task owner, I want to assign tasks to team members so that work is distributed
- As an assignee, I want to see tasks assigned to me so that I know what to work on
- As a task owner, I want to reassign tasks so that I can adjust workload

### Notifications
- As a user, I want to receive reminders for due tasks so that I don't miss deadlines

## Success Criteria
- User can register and login in < 5 seconds
- API response time < 200ms
- Support 1000+ concurrent users
- 99.9% uptime
- All passwords encrypted
- JWT tokens with refresh mechanism
- Tasks can be filtered by status, assignee, due date
- Email notifications for due tasks

## Constraints
- Must use JWT for authentication
- Must support PostgreSQL database
- Must follow REST API best practices
- Must have comprehensive error handling
- Must have audit logging

## Security Requirements
- Passwords must be hashed (bcrypt)
- JWT tokens must expire (15 min access, 7 day refresh)
- Rate limiting on auth endpoints (5 attempts/minute)
- Authorization checks on all endpoints
- Audit log for sensitive operations

## Edge Cases
- What if user tries to assign task they don't own?
- What if user tries to delete task with assignees?
- What if token expires during operation?
- What if user changes password (invalidate all tokens)?
- What if multiple users update same task simultaneously?

## Open Questions
- Should we support task comments?
- Should we support file attachments?
- Should we support task dependencies?

→ Decided: Not in v1, add to backlog

Time: 2 hours

Day 1 Afternoon: Design Phase

Developer: /review-design
AI: "Based on requirements, proposing architecture..."

AI tạo docs/agent/design/feature-task-management-api.md:

markdown
## Architecture Overview

```mermaid
graph TD
    Client[Client App] -->|HTTPS| Gateway[API Gateway]
    Gateway --> Auth[Auth Service]
    Gateway --> Task[Task Service]
    Gateway --> Notif[Notification Service]
    
    Auth --> UserDB[(User DB)]
    Auth --> TokenDB[(Token Store - Redis)]
    
    Task --> TaskDB[(Task DB)]
    Task --> Queue[Message Queue]
    
    Queue --> Notif
    Notif --> Email[Email Service]
    
    Task --> Audit[Audit Service]
    Audit --> AuditDB[(Audit Log)]

Data Models

typescript
// User Model
interface User {
  id: string;
  email: string;
  passwordHash: string;
  name: string;
  createdAt: Date;
  updatedAt: Date;
}

// Task Model
interface Task {
  id: string;
  title: string;
  description?: string;
  status: 'todo' | 'in_progress' | 'done';
  priority: 'low' | 'medium' | 'high';
  createdBy: string; // User ID
  assignedTo?: string; // User ID
  dueDate?: Date;
  createdAt: Date;
  updatedAt: Date;
}

// RefreshToken Model
interface RefreshToken {
  id: string;
  userId: string;
  token: string;
  expiresAt: Date;
  createdAt: Date;
}

// AuditLog Model
interface AuditLog {
  id: string;
  userId: string;
  action: string;
  resource: string;
  resourceId: string;
  timestamp: Date;
  metadata: Record<string, any>;
}

API Design

Authentication Endpoints

POST /api/auth/register
POST /api/auth/login
POST /api/auth/refresh
POST /api/auth/logout

Task Endpoints

POST   /api/tasks              - Create task
GET    /api/tasks              - List tasks (with filters)
GET    /api/tasks/:id          - Get task details
PUT    /api/tasks/:id          - Update task
DELETE /api/tasks/:id          - Delete task
POST   /api/tasks/:id/assign   - Assign task

Request/Response Examples

POST /api/auth/register

json
Request:
{
  "email": "user@example.com",
  "password": "SecurePass123!",
  "name": "John Doe"
}

Response 201:
{
  "id": "user_123",
  "email": "user@example.com",
  "name": "John Doe",
  "createdAt": "2024-01-15T10:00:00Z"
}

POST /api/auth/login

json
Request:
{
  "email": "user@example.com",
  "password": "SecurePass123!"
}

Response 200:
{
  "accessToken": "eyJhbGc...",
  "refreshToken": "eyJhbGc...",
  "expiresIn": 900
}

POST /api/tasks

json
Request:
{
  "title": "Implement user authentication",
  "description": "Add JWT-based auth",
  "priority": "high",
  "dueDate": "2024-01-20"
}

Response 201:
{
  "id": "task_123",
  "title": "Implement user authentication",
  "status": "todo",
  "priority": "high",
  "createdBy": "user_123",
  "dueDate": "2024-01-20",
  "createdAt": "2024-01-15T10:00:00Z"
}

Design Decisions

Why PostgreSQL?

  • Need ACID transactions
  • Complex queries (filters, joins)
  • Strong data consistency
  • Mature ecosystem

Why Redis for token storage?

  • Fast access for token validation
  • Built-in expiration (TTL)
  • Reduce DB load
  • Easy to scale

Why separate Audit Service?

  • Decouple audit logic from business logic
  • Can scale independently
  • Easier to query audit logs
  • Compliance requirements

Why Message Queue for notifications?

  • Async processing (don't block API)
  • Retry failed notifications
  • Can add more notification channels later (SMS, push)

Authorization Strategy

  • Use middleware for authentication (verify JWT)
  • Use guards for authorization (check permissions)
  • Resource-based access control:
    • Task owner can: update, delete, assign
    • Task assignee can: update status
    • Others: read-only (if public)

Security Measures

Password Security

  • Hash with bcrypt (salt rounds: 10)
  • Minimum length: 8 characters
  • Must contain: uppercase, lowercase, number, special char

Token Security

  • Access token: 15 minutes expiry
  • Refresh token: 7 days expiry
  • Store refresh tokens in DB (can revoke)
  • Invalidate all tokens on password change

Rate Limiting

  • Auth endpoints: 5 requests/minute per IP
  • API endpoints: 100 requests/minute per user
  • Use Redis for rate limit counters

Input Validation

  • Use class-validator for DTO validation
  • Sanitize all inputs
  • Validate email format
  • Validate date formats

Non-Functional Requirements

Performance

  • API response time: < 200ms (p95)
  • Database queries: < 50ms
  • Use indexes on frequently queried fields
  • Use caching for user data (Redis)

Scalability

  • Stateless API (can scale horizontally)
  • Database connection pooling
  • Message queue for async tasks

Reliability

  • Graceful error handling
  • Retry logic for external services
  • Health check endpoints
  • Logging at all layers

Monitoring

  • Log all API requests
  • Log all errors with stack traces
  • Audit log for sensitive operations
  • Metrics: response time, error rate, active users

**Time**: 3 hours

#### Day 1 End: Planning Phase

Developer: /update-planning AI: "Breaking down design into tasks..."


**AI tạo** `docs/agent/planning/feature-task-management-api.md`:

```markdown
## Task Breakdown

### Milestone 1: Project Setup (Est: 0.5 day)
- [ ] Initialize NestJS project
- [ ] Setup PostgreSQL database
- [ ] Setup Redis
- [ ] Configure environment variables
- [ ] Setup TypeORM
- [ ] Create database migrations
- [ ] Setup logging (Winston)

### Milestone 2: Authentication (Est: 1 day)
- [ ] Create User entity
- [ ] Create RefreshToken entity
- [ ] Implement password hashing (bcrypt)
- [ ] Implement JWT service
- [ ] Implement POST /auth/register
- [ ] Implement POST /auth/login
- [ ] Implement POST /auth/refresh
- [ ] Implement POST /auth/logout
- [ ] Add input validation (DTOs)
- [ ] Add rate limiting
- [ ] Add error handling

### Milestone 3: Authorization Middleware (Est: 0.5 day)
- [ ] Create JWT auth guard
- [ ] Create role-based guard
- [ ] Add user context to requests
- [ ] Test middleware

### Milestone 4: Task Management (Est: 1 day)
- [ ] Create Task entity
- [ ] Implement POST /tasks
- [ ] Implement GET /tasks (with filters, pagination)
- [ ] Implement GET /tasks/:id
- [ ] Implement PUT /tasks/:id
- [ ] Implement DELETE /tasks/:id
- [ ] Implement POST /tasks/:id/assign
- [ ] Add authorization checks
- [ ] Add input validation
- [ ] Add error handling

### Milestone 5: Audit Logging (Est: 0.5 day)
- [ ] Create AuditLog entity
- [ ] Create audit interceptor
- [ ] Log sensitive operations
- [ ] Add audit endpoints (admin only)

### Milestone 6: Notification System (Est: 0.5 day)
- [ ] Setup message queue (Bull)
- [ ] Create notification service
- [ ] Implement email notifications
- [ ] Create cron job for due date reminders

### Milestone 7: Testing (Est: 1 day)
- [ ] Unit tests for auth service
- [ ] Unit tests for task service
- [ ] Integration tests for auth endpoints
- [ ] Integration tests for task endpoints
- [ ] E2E tests for critical flows
- [ ] Test authorization scenarios
- [ ] Test error scenarios

### Milestone 8: Documentation & Polish (Est: 0.5 day)
- [ ] API documentation (Swagger)
- [ ] README with setup instructions
- [ ] Environment variables documentation
- [ ] Deployment guide

## Dependencies

```mermaid
graph TD
    A[Project Setup] --> B[Authentication]
    A --> C[Authorization Middleware]
    B --> D[Task Management]
    C --> D
    D --> E[Audit Logging]
    D --> F[Notification System]
    E --> G[Testing]
    F --> G
    G --> H[Documentation]

Implementation Order

  1. Project Setup (blocking)
  2. Authentication (blocking)
  3. Authorization Middleware (blocking)
  4. Task Management (blocking)
  5. Audit Logging (parallel with Notification)
  6. Notification System (parallel with Audit)
  7. Testing (after all features)
  8. Documentation (final)

Effort Estimates

MilestoneEffortPriority
Project Setup0.5 dayP0
Authentication1 dayP0
Authorization0.5 dayP0
Task Management1 dayP0
Audit Logging0.5 dayP1
Notifications0.5 dayP1
Testing1 dayP0
Documentation0.5 dayP2
Total5.5 days

Note: With one-toolkit structure, estimate is 4 days due to fewer refactors.

Risks & Mitigation

RiskMitigation
Token invalidation complexityUse Redis for token blacklist
Concurrent task updatesUse optimistic locking (version field)
Email delivery failuresRetry with exponential backoff
Database migration issuesTest in staging first, have rollback plan

**Time**: 2 hours

**Day 1 Total**: 7 hours (Requirements + Design + Planning)

#### Day 2-3: Implementation Phase

Developer: /execute-plan AI: "Starting task execution..." AI: "Task 1: Initialize NestJS project"


**AI implement theo plan**, với context đầy đủ từ design doc:

```typescript
// src/auth/auth.service.ts
// Implemented according to design doc

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';

@Injectable()
export class AuthService {
  constructor(
    private userService: UserService,
    private jwtService: JwtService,
    private refreshTokenService: RefreshTokenService,
  ) {}

  async register(dto: RegisterDto): Promise<User> {
    // Validate email not exists
    const exists = await this.userService.findByEmail(dto.email);
    if (exists) {
      throw new ConflictException('Email already exists');
    }

    // Hash password (bcrypt, 10 rounds as per design)
    const passwordHash = await bcrypt.hash(dto.password, 10);

    // Create user
    const user = await this.userService.create({
      email: dto.email,
      name: dto.name,
      passwordHash,
    });

    // Audit log
    await this.auditService.log({
      userId: user.id,
      action: 'USER_REGISTERED',
      resource: 'user',
      resourceId: user.id,
    });

    return user;
  }

  async login(dto: LoginDto): Promise<TokenResponse> {
    // Find user
    const user = await this.userService.findByEmail(dto.email);
    if (!user) {
      throw new UnauthorizedException('Invalid credentials');
    }

    // Verify password
    const isValid = await bcrypt.compare(dto.password, user.passwordHash);
    if (!isValid) {
      throw new UnauthorizedException('Invalid credentials');
    }

    // Generate tokens (15 min access, 7 day refresh as per design)
    const accessToken = this.jwtService.sign(
      { userId: user.id },
      { expiresIn: '15m' },
    );

    const refreshToken = this.jwtService.sign(
      { userId: user.id },
      { secret: process.env.JWT_REFRESH_SECRET, expiresIn: '7d' },
    );

    // Store refresh token in DB (for revocation)
    await this.refreshTokenService.create({
      userId: user.id,
      token: refreshToken,
      expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
    });

    // Audit log
    await this.auditService.log({
      userId: user.id,
      action: 'USER_LOGIN',
      resource: 'auth',
      resourceId: user.id,
    });

    return {
      accessToken,
      refreshToken,
      expiresIn: 900, // 15 minutes
    };
  }

  // ... other methods following design doc
}

Lợi ích:

  • ✅ Code follow design doc chính xác
  • ✅ Security measures đầy đủ (hash, expiry, audit)
  • ✅ Error handling proper
  • ✅ Không cần refactor vì đã design kỹ

AI update implementation notes vào docs/agent/implementation/feature-task-management-api.md:

markdown
## Implementation Notes

### Authentication Implementation
- Used bcrypt with 10 salt rounds (as per design)
- JWT tokens stored in Redis for fast validation
- Refresh tokens stored in PostgreSQL for revocation
- All sensitive operations logged to audit table

### Patterns Used
- Repository pattern for data access
- DTO pattern for validation
- Service layer for business logic
- Interceptor for audit logging
- Guard for authorization

### Error Handling Strategy
- Use NestJS built-in exceptions
- Custom exception filter for consistent error format
- Log all errors with context
- Return user-friendly messages (no stack traces to client)

### Performance Optimizations
- Database indexes on: email, userId, taskId, status
- Redis caching for user data (5 min TTL)
- Connection pooling (max 20 connections)
- Pagination for list endpoints (default 20 items)

Time: 2 days (implementation smooth vì có design rõ ràng)

Day 4: Testing Phase

Developer: /writing-test
AI: "Generating tests based on requirements..."

AI viết tests cover tất cả requirements:

typescript
// src/auth/__tests__/auth.service.spec.ts

describe('AuthService', () => {
  describe('register', () => {
    it('should register user with hashed password', async () => {
      const dto = {
        email: 'test@example.com',
        password: 'SecurePass123!',
        name: 'Test User',
      };

      const result = await service.register(dto);

      expect(result.email).toBe(dto.email);
      expect(result.passwordHash).not.toBe(dto.password); // Hashed
      expect(result.passwordHash).toMatch(/^\$2[aby]\$/); // bcrypt format
    });

    it('should throw ConflictException if email exists', async () => {
      mockUserService.findByEmail.mockResolvedValue(existingUser);

      await expect(service.register(dto)).rejects.toThrow(ConflictException);
    });

    it('should log audit entry on registration', async () => {
      await service.register(dto);

      expect(mockAuditService.log).toHaveBeenCalledWith({
        userId: expect.any(String),
        action: 'USER_REGISTERED',
        resource: 'user',
        resourceId: expect.any(String),
      });
    });
  });

  describe('login', () => {
    it('should return tokens on valid credentials', async () => {
      const result = await service.login(loginDto);

      expect(result.accessToken).toBeDefined();
      expect(result.refreshToken).toBeDefined();
      expect(result.expiresIn).toBe(900); // 15 minutes
    });

    it('should throw UnauthorizedException on invalid password', async () => {
      mockUserService.findByEmail.mockResolvedValue(user);
      bcrypt.compare = jest.fn().mockResolvedValue(false);

      await expect(service.login(loginDto)).rejects.toThrow(
        UnauthorizedException,
      );
    });

    it('should store refresh token in database', async () => {
      await service.login(loginDto);

      expect(mockRefreshTokenService.create).toHaveBeenCalledWith({
        userId: user.id,
        token: expect.any(String),
        expiresAt: expect.any(Date),
      });
    });

    // Test rate limiting
    it('should block after 5 failed attempts', async () => {
      for (let i = 0; i < 5; i++) {
        await service.login(invalidDto).catch(() => {});
      }

      await expect(service.login(invalidDto)).rejects.toThrow(
        TooManyRequestsException,
      );
    });
  });
});

// Integration tests
describe('AuthController (e2e)', () => {
  it('POST /auth/register should create user', () => {
    return request(app.getHttpServer())
      .post('/auth/register')
      .send({
        email: 'test@example.com',
        password: 'SecurePass123!',
        name: 'Test User',
      })
      .expect(201)
      .expect((res) => {
        expect(res.body.email).toBe('test@example.com');
        expect(res.body.passwordHash).toBeUndefined(); // Not exposed
      });
  });

  it('POST /auth/login should return tokens', () => {
    return request(app.getHttpServer())
      .post('/auth/login')
      .send({
        email: 'test@example.com',
        password: 'SecurePass123!',
      })
      .expect(200)
      .expect((res) => {
        expect(res.body.accessToken).toBeDefined();
        expect(res.body.refreshToken).toBeDefined();
      });
  });

  // Test authorization
  it('GET /tasks should require authentication', () => {
    return request(app.getHttpServer())
      .get('/tasks')
      .expect(401);
  });

  it('GET /tasks should work with valid token', () => {
    return request(app.getHttpServer())
      .get('/tasks')
      .set('Authorization', `Bearer ${validToken}`)
      .expect(200);
  });

  // Test edge cases from requirements
  it('should not allow assigning task user does not own', async () => {
    const task = await createTask(user1);

    return request(app.getHttpServer())
      .post(`/tasks/${task.id}/assign`)
      .set('Authorization', `Bearer ${user2Token}`)
      .send({ assignedTo: user3.id })
      .expect(403);
  });
});

Coverage report:

File                    | % Stmts | % Branch | % Funcs | % Lines |
------------------------|---------|----------|---------|---------|
auth.service.ts         |   98.5  |   95.2   |   100   |   98.7  |
task.service.ts         |   97.8  |   93.5   |   100   |   97.9  |
auth.controller.ts      |   100   |   100    |   100   |   100   |
task.controller.ts      |   98.2  |   94.1   |   100   |   98.3  |
------------------------|---------|----------|---------|---------|
Total                   |   98.1  |   94.7   |   100   |   98.2  |

Time: 1 day

Kết quả sau 4 ngày

Code structure:

project/
├── docs/
│   └── agent/
│       ├── requirements/
│       │   └── feature-task-management-api.md ✅
│       ├── design/
│       │   └── feature-task-management-api.md ✅
│       ├── planning/
│       │   └── feature-task-management-api.md ✅
│       ├── implementation/
│       │   └── feature-task-management-api.md ✅
│       └── testing/
│           └── feature-task-management-api.md ✅
├── src/
│   ├── auth/
│   │   ├── auth.service.ts
│   │   ├── auth.controller.ts
│   │   ├── jwt.strategy.ts
│   │   ├── dto/
│   │   └── __tests__/
│   ├── tasks/
│   │   ├── task.service.ts
│   │   ├── task.controller.ts
│   │   ├── dto/
│   │   └── __tests__/
│   ├── audit/
│   └── notifications/
├── .one-toolkit.json
└── README.md

Chất lượng:

  • ✅ Đầy đủ documentation
  • ✅ Security measures đúng chuẩn
  • ✅ Test coverage 98%
  • ✅ Code không bị refactor (design tốt từ đầu)
  • ✅ Authorization consistent
  • ✅ Error handling đầy đủ
  • ✅ Audit logging complete

Thời gian:

  • Requirements: 0.25 ngày
  • Design: 0.25 ngày
  • Planning: 0.25 ngày
  • Implementation: 2 ngày
  • Testing: 1 ngày
  • Total: 4 ngày

Code quality: ⭐⭐⭐⭐⭐ (5/5)


So sánh tổng quan

Tiêu chíKhông dùng toolkitDùng one-toolkitChênh lệch
Thời gian5 ngày4 ngày-20%
Số lần refactor15+ lần2-3 lần-80%
Test coverage45%98%+118%
DocumentationKhông cóĐầy đủ
Security issues5+ issues0 issues-100%
Code quality2/55/5+150%
Technical debtCaoThấp-70%
MaintainabilityKhóDễ+200%

Chất lượng code và tư duy khác nhau ra sao

Tư duy

Không dùng toolkit:

"Làm nhanh đã, sửa sau"
→ Code → Bug → Fix → Bug → Fix → ...
→ Reactive thinking

Dùng one-toolkit:

"Suy nghĩ trước, code sau"
→ Requirements → Design → Plan → Code → Test
→ Proactive thinking

Chất lượng code

Không dùng toolkit:

  • Code bị refactor nhiều → inconsistent
  • Security issues phát hiện muộn
  • Tests viết sau → coverage thấp
  • Không có documentation → khó maintain

Dùng one-toolkit:

  • Code consistent từ đầu (follow design)
  • Security được design từ đầu
  • Tests viết song song → coverage cao
  • Documentation đầy đủ → dễ maintain

Output khác nhau

Không dùng toolkit:

project/
└── src/
    └── *.ts (code only, no docs)

Dùng one-toolkit:

project/
├── docs/agent/          ← Đầy đủ documentation
│   ├── requirements/
│   ├── design/
│   ├── planning/
│   ├── implementation/
│   └── testing/
└── src/
    └── *.ts (clean code + tests)

ROI (Return on Investment)

Không dùng toolkit:

  • Thời gian dev: 5 ngày
  • Thời gian maintain: 10 ngày (vì thiếu docs, nhiều bugs)
  • Total: 15 ngày

Dùng one-toolkit:

  • Thời gian dev: 4 ngày
  • Thời gian maintain: 2 ngày (vì có docs, ít bugs)
  • Total: 6 ngày

Tiết kiệm: 60%


Kết luận

one-toolkit không phải là magic tool làm code nhanh hơn. Nó là framework giúp bạn:

  1. Suy nghĩ có hệ thống trước khi code
  2. Giảm refactor vì design tốt từ đầu
  3. Tăng chất lượng vì có quy trình rõ ràng
  4. Dễ maintain vì có documentation đầy đủ

Trade-off:

  • Phải spend thời gian ở phase đầu (requirements, design)
  • Nhưng tiết kiệm được nhiều thời gian ở phase sau (implementation, testing, maintenance)

Khi nào đáng dùng:

  • ✅ Project dài hạn (> 1 tháng)
  • ✅ Team > 1 người
  • ✅ Cần chất lượng cao
  • ✅ Cần maintain lâu dài

Khi nào không cần:

  • ❌ Prototype nhanh (< 1 ngày)
  • ❌ Script đơn giản
  • ❌ Deadline cực gấp

Tiếp theo: Phân tích ưu điểm cốt lõi của one-toolkit → Xem phần tiếp theo.

Internal documentation for iNET Portal