Bluewoo HRMS
AI Development GuideDevelopment

Code Patterns

Exact code patterns to follow - no variations allowed

Code Patterns

These are the exact patterns to follow. AI assistants must use these patterns without modification.

Service Pattern

Structure:

  • Injectable class with constructor injection
  • Methods take tenantId as first parameter
  • Return domain objects (not DTOs)
  • Throw NestJS exceptions for errors

Simple Rule:

  • WRITES (create, update, delete) → Always use Service layer
  • READS (get, list) → Can use Repository directly

Why this rule?

  • Write operations often need validation, audit logging, events
  • Starting with Service layer makes it easy to add logic later
  • Read operations rarely need business logic

When Service is REQUIRED:

  • Business logic or validation
  • Multiple repository calls
  • External service calls
  • Complex transactions
  • Any write operation

When Repository direct is OK:

  • Simple read operations (get by ID, list with filters)
  • No business logic needed

Controller Pattern

Structure:

  • Controller class with route prefix
  • Use guards: @UseGuards(TenantGuard) (MVP uses session-based auth via Auth.js, not JWT)
  • Use decorators: @TenantId() or @Tenant() for tenant context
  • Use @RequirePermissions() for permission checks
  • Return { data, error } format

Simple Pattern (Controller → Repository):

  • For simple CRUD without business logic
  • Direct repository calls
  • No service layer

Full Pattern (Controller → Service → Repository):

  • For operations with business logic
  • Service handles validation and coordination
  • Repository handles data access

Repository Pattern

Structure:

  • All methods take tenantId as first parameter
  • Always filter by tenantId in queries
  • Use Prisma client directly
  • Return domain objects

Required:

  • Tenant filtering on every query
  • Soft delete support (deletedAt field)
  • Standard CRUD methods: findAll, findOne, create, update, remove

Response Format

Standard Response:

{
  "data": { ... },
  "error": null
}

Error Response:

{
  "data": null,
  "error": "Error message"
}

Permission Pattern

Format: resource:action:scope

Examples:

  • employees:read:department
  • time_off:approve:all
  • documents:delete:own

Usage:

  • Decorator: @RequirePermissions('employees:read:department')
  • Service: PermissionService.hasPermission(userId, tenantId, resource, action, scope)

Error Handling Pattern

Use NestJS exceptions:

  • NotFoundException - Resource not found
  • BadRequestException - Invalid input
  • UnauthorizedException - Auth failure
  • ForbiddenException - Permission denied
  • ConflictException - Resource conflict

Pattern:

  • Throw exceptions in services
  • Let NestJS exception filter handle responses
  • Return standard error format

DTO Pattern

Structure:

  • Use class-validator decorators
  • Use class-transformer for serialization
  • Validate in controller with ValidationPipe

Naming:

  • CreateEntityDto - For creation
  • UpdateEntityDto - For updates (all fields optional)
  • EntityResponseDto - For responses (if needed)

Database Pattern

Prisma Usage:

  • Use Prisma 5.x (NOT 6.x)
  • All IDs are UUIDs (NOT auto-increment)
  • All models have createdAt, updatedAt
  • Tenant isolation via tenantId field

Queries:

  • Always include tenantId in where clause
  • Use transactions for multi-step operations
  • Use soft deletes (deletedAt field)

Module Pattern

Structure:

  • One module per feature
  • Import PrismaModule
  • Export service (if used by other modules)
  • Register controllers and providers

Testing Pattern

Unit Tests:

  • Test services with mocked repositories
  • Test repositories with mocked Prisma
  • Test business logic in isolation

Integration Tests:

  • Test full request flow
  • Use test database
  • Clean up after tests

Anti-Patterns (DO NOT USE)

  • ❌ Repository pattern abstractions (use Prisma directly)
  • ❌ Generic base classes (copy-paste instead)
  • ❌ Complex inheritance hierarchies
  • ❌ Event-driven architecture (use direct calls)
  • ❌ GraphQL (use REST only)
  • ❌ Microservices (use monolith)

Test-Driven Development Pattern (Optional)

When TDD is appropriate:

  • Complex business logic
  • Edge cases are critical
  • Refactoring existing code

TDD Workflow with AI

Step 1: Write Tests First

"Write tests for [feature] based on these expected behaviors:
- Input X should return Y
- Input A should throw error B
DO NOT write implementation code yet."

Step 2: Verify Tests Fail

"Run the tests and confirm they fail.
Show me the failure output."

Step 3: Implement

"Now implement the code to make tests pass.
DO NOT modify the tests."

Step 4: Verify Tests Pass

"Run tests again. All should pass.
If any fail, fix implementation (not tests)."

When NOT to Use TDD

  • Simple CRUD operations
  • UI components (use visual testing)
  • Configuration changes
  • Prototyping/exploration

Gate Integration

For steps requiring TDD:

Gate: All tests pass (`npm test [file]` returns 0 failures)