Skip to main content

Job Level API - Dokumentasi Teknis

Overview

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

Arsitektur

Job Level module menggunakan pola Command & Query:

job-level/
├── commands/
│ ├── create.cmd.ts
│ ├── update.cmd.ts
│ └── soft-delete.cmd.ts
├── queries/
│ ├── get-job-level.query.ts
│ └── get-job-level-by-id.query.ts
├── DTO/
├── helper/ # generateSlug, getOrderIndex, mapToDetailResponse
├── validation/
├── job-level.controller.ts
├── job-level.service.ts
├── job-level.module.ts
└── docs/

Tech Stack

  • Framework: NestJS
  • Database: PostgreSQL dengan Prisma ORM
  • Validation: class-validator, class-transformer
  • Auth: AuthGuard (JWT), tenant dari current user
  • RLS: createTenantClient

Database Schema

Table: job_levels

ColumnTypeKeterangan
idUUIDPK
tenant_idUUIDNOT NULL
keyVARCHAR(50)UNIQUE, slug dari name
nameVARCHAR(100)NOT NULL
descriptionVARCHAR(255)NULL
order_indexINTNOT NULL, untuk urutan
is_activeBOOLEANDEFAULT true
created_byUUIDNULL
created_by_nameVARCHAR(100)NULL
created_atTIMESTAMPTZDEFAULT now()
updated_byUUIDNULL
updated_by_nameVARCHAR(100)NULL
updated_atTIMESTAMPTZ@updatedAt
deleted_byUUIDNULL
deleted_by_nameVARCHAR(100)NULL
deleted_atTIMESTAMPTZNULL

Relasi:

  • JobGrade.level_idJobLevel.id
  • JobTitle.level_idJobLevel.id

Module Structure

1. Commands

CreateJobLevelCommand

  • File: commands/create.cmd.ts
  • Alur:
    1. createTenantClient(tenantId)
    2. key = JobLevelHelper.generateSlug(dto.name)
    3. JobLevelValidation.validateExistence(client, { key }) — key harus belum dipakai (throw jika ada)
    4. orderIndex = JobLevelHelper.getOrderIndex(client) — max(order_index) + 1
    5. Transaction: jobLevel.create({ tenantId, key, name, description, orderIndex, isActive: true })
    6. mapToDetailResponse(result)

UpdateJobLevelCommand

  • File: commands/update.cmd.ts
  • Alur: validateExistence({ id }) — Catatan: Implementasi menggunakan validateExistence; untuk update seharusnya validateNotFound (record harus ada). Key di-regenerate dari dto.name. → update

SoftDeleteJobLevelCommand

  • File: commands/soft-delete.cmd.ts

2. Helper

  • generateSlug(str) — Lowercase, non-alphanumeric → -, trim
  • getOrderIndex(client) — max(orderIndex) + 1 (dari record yang tidak soft-deleted)
  • mapToDetailResponse(jl) — Map ke response DTO

3. Validation

JobLevelValidation

  • validateExistence(client, where) — Throw 400 job-level.is_exist jika record ada (dipakai untuk validasi key unik pada create)
  • validateNotFound(client, where) — Throw 404 job-level.is_not_found jika record tidak ada

Controller Endpoints

  • Base route: job-levels
  • POST / — create
  • GET / — findAll
  • GET /:id — findOne
  • PATCH /:id — update
  • DELETE /:id — softDelete (remove)

Error Codes

  • job-level.is_not_found — Record tidak ditemukan
  • job-level.is_exist — Key sudah dipakai (create)