Skip to main content

Job Title API - Dokumentasi Teknis

Overview

Dokumentasi teknis untuk developer yang akan maintain atau develop lebih lanjut pada Job Title API module.

Arsitektur

Job Title module menggunakan pola Command & Query dengan struktur sebagai berikut:

job-title/
├── commands/ # Command handlers untuk write operations
│ ├── create.cmd.ts
│ ├── update.cmd.ts
│ └── soft-delete.cmd.ts
├── queries/ # Query handlers untuk read operations
│ ├── get.query.ts
│ └── get-by-id.query.ts
├── dto/ # Data Transfer Objects
├── helper/ # Helper (mapping)
├── validation/ # Validators
├── job-title.controller.ts
├── job-title.service.ts
├── job-title.module.ts
└── docs/ # Dokumentasi

Tech Stack

  • Framework: NestJS
  • Database: PostgreSQL dengan Prisma ORM
  • Validation: class-validator, class-transformer
  • API Documentation: Swagger/OpenAPI
  • Auth: AuthGuard (JWT), tenant dari current user
  • RLS: createTenantClient untuk tenant-scoped Prisma client

Database Schema

Table: job_titles

Berdasarkan Prisma model JobTitle:

ColumnTypeKeterangan
idUUIDPK, default uuid()
tenant_idUUIDNOT NULL
nameVARCHAR(100)NOT NULL
descriptionVARCHAR(255)NULL
family_idUUIDNULL, FK → job_families
level_idUUIDNULL, FK → job_levels
grade_idUUIDNULL, FK → job_grades
is_activeBOOLEANDEFAULT true
created_byUUIDNULL
created_by_nameVARCHAR(100)NULL
created_atTIMESTAMPTZDEFAULT now()
updated_byUUIDNULL
updated_by_nameVARCHAR(100)NULL
updated_atTIMESTAMPTZNULL, @updatedAt
deleted_byUUIDNULL
deleted_by_nameVARCHAR(100)NULL
deleted_atTIMESTAMPTZNULL

Relasi:

  • JobTitle.family_idJobFamily.id
  • JobTitle.level_idJobLevel.id
  • JobTitle.grade_idJobGrade.id
  • JobPosition.title_idJobTitle.id

Module Structure

1. Commands (Write Operations)

CreateJobTitleCommand

  • File: commands/create.cmd.ts
  • Handler: JobTitleService.create()
  • Alur:
    1. createTenantClient(tenantId)
    2. JobLevelValidation.validateNotFound(client, { id: dto.level_id })
    3. JobGradeValidation.validateNotFound(client, { id: dto.grade_id })
    4. JobFamilyValidation.validateNotFound(client, { id: dto.family_id })
    5. Transaction: jobTitle.create({ tenantId, name, levelId, familyId, gradeId, description, isActive: true })
    6. mapToDetailResponse(result)
  • Validations: DTO + FK validation (level, grade, family harus ada).

UpdateJobTitleCommand

  • File: commands/update.cmd.ts
  • Alur: validateNotFound → validasi FK jika dikirim → update → mapToDetailResponse

SoftDeleteJobTitleCommand

  • File: commands/soft-delete.cmd.ts
  • Alur: validateNotFound → update deleted_at, deleted_by

2. Queries (Read Operations)

GetJobTitleQuery

  • File: queries/get.query.ts
  • Query params: search, is_active, order_by, order_direction, page, page_size
  • Return: JobTitlePaginatedResponseDto

GetJobTitleByIdQuery

  • File: queries/get-by-id.query.ts
  • Validations: Jika tidak ketemu → NotFoundException
  • Return: JobTitleDetailResponseDto

3. Validation

JobTitleValidation

  • File: validation/index.ts
  • validateExistence(client, where) — Jika record ada, throw BadRequestException, reason job-title.is_exist
  • validateNotFound(client, where) — Jika record tidak ada, throw NotFoundException, reason job-title.is_not_found

Controller Endpoints

  • Base route: job-titles
  • Endpoints:
    • POST / — create
    • GET / — findAll (query params)
    • GET /:id — findOne
    • PATCH /:id — update
    • DELETE /:id — softDelete

Error Handling

Reason Codes

  • job-title.is_not_found — Record tidak ditemukan
  • job-title.is_exist — Job title sudah ada (validateExistence)

Security & Tenant Isolation

  • Semua akses database melalui createTenantClient(user.tenantId).
  • Tenant ID dari CurrentUser (AuthGuard).