Skip to main content

SLA Policy Evaluator Structure Rules (Prompt-Ready)

Dokumen ini adalah standar struktur folder dan tanggung jawab file untuk apps/worker-workflow/src/sla-policy-evaluator.

Tujuan:

  • menjaga struktur tetap konsisten dan mudah diikuti tim
  • memudahkan refactor tanpa mengubah behavior runtime
  • menjadi prompt/aturan kerja saat membuat context baru

1. Prinsip Utama

Gunakan pola:

  • context-first
  • flat per context (hindari nested adapters/, application/, domain/, infrastructure/ di dalam context)
  • nama file menjelaskan peran

Konsep yang dipakai:

  • consumer = adapter transport (NATS/JetStream, ack/nak)
  • service = use-case utama per context atau service pendukung reusable
  • checker/support = service pendukung reusable internal checker
  • contracts = boundary agreement (type, interface, DTO, abstract contract)
  • custom decorator JetStream:
    • @JetStreamConsumer(...) = metadata subscribe (class-level)
    • @MessageHandler() = penanda method handler message (method-level)

2. Struktur Folder Standar

apps/worker-workflow/src/sla-policy-evaluator/
├── sla-policy-evaluator.module.ts
├── constants/
├── contracts/
├── docs/
├── services/
│ ├── cdc-forwarder/
│ ├── transition/
│ ├── schedule/
│ └── checker/
│ └── support/
└── utils/

Aturan:

  • services/cdc-forwarder, services/transition, services/schedule, services/checker = sub-context/flow runtime
  • services/checker/support = service pendukung internal checker
  • contracts tetap di root (bukan di services)
  • utils tetap di root untuk pure function

3. Tanggung Jawab Tiap Folder

3.1 constants/

  • Konstanta stream subject, consumer group, token literal global context SLA Policy Evaluator
  • Tidak berisi logic runtime

3.2 contracts/

  • Boundary agreement antar komponen/context
  • Boleh berisi:
    • type
    • interface
    • DTO
    • abstract contract/port (jika memang dipakai)
  • Tidak boleh berisi:
    • @Injectable()
    • query DB
    • business logic

Contoh:

  • sla-check.contract.ts
  • sla-schedule.contract.ts

3.3 docs/

  • Dokumen behavior, refactor plan, study notes
  • Bukan source runtime

3.4 services/cdc-forwarder/

  • Semua flow adapter CDC dari wxl_submission_log ke payload SLA
  • Termasuk:
    • sla-cdc-forwarder.consumer.ts

3.5 services/transition/

  • Semua consumer runtime topic SLA
  • Termasuk:
    • transition-check consumer
    • aging consumer

3.6 services/schedule/

  • Semua flow delay dispatcher topic schedule
  • Termasuk:
    • schedule consumer

3.7 services/checker/

  • Main service/use-case evaluator SLA
  • Termasuk:
    • sla-checker.service.ts
    • sla-transition-check.service.ts
    • sla-aging.service.ts

3.8 services/checker/support/

  • Service reusable pendukung checker
  • Contoh:
    • transaction helper
    • query helper (TypeORM)
    • lifecycle instance SLA
    • outcome policy executor
    • event publisher
    • policy matcher

3.9 utils/

  • Pure function/helper tanpa DI (@Injectable)
  • Tidak akses DB/NATS
  • Tidak menyimpan state

4. Aturan Naming File

Gunakan suffix untuk menjelaskan peran:

  • *.consumer.ts

    • adapter transport
    • contoh: sla-aging.consumer.ts
  • *.service.ts

    • use-case utama context (mis. sla-aging.service.ts) atau reusable supporting service (services/checker/support)
    • contoh: sla-transition-check.service.ts, sla-instance-query.service.ts
  • *.contract.ts

    • boundary contract (type/interface/DTO)
    • contoh: sla-check.contract.ts
  • *.spec.ts

    • test colocated dengan file runtime (jangan pindah ke folder test global)
  • *.types.ts

    • tempatkan di contracts/internal/ untuk internal reusable types (non-boundary)
    • jangan taruh *.types.ts di dalam services/*

5. Pembagian Tanggung Jawab File (Penting)

5.1 consumer (adapter transport)

Boleh:

  • deklarasi metadata subscribe via @JetStreamConsumer(...)
  • decode payload
  • validasi payload minimum
  • ack/nak
  • memanggil service use-case context (*.service.ts)

Tidak boleh:

  • query DB kompleks
  • business rule SLA yang panjang
  • orchestration multi-step yang sulit dibaca

Catatan pola current SLA Policy Evaluator:

  • bootstrap/registrasi consumer dilakukan oleh JetStreamConsumerRegistryService
  • waitUntilReady() dijalankan oleh registry (berdasarkan metadata consumer)
  • consumer tetap memegang manual ack/nak di method handler (jangan disembunyikan)

5.2 service (di context)

Boleh:

  • flow bisnis/use-case end-to-end
  • keputusan proses (resolve/start/breach/reschedule)
  • memanggil services/checker/support/* secara langsung (query/lifecycle/outcome/publisher)

Tidak boleh:

  • transport concern (ack/nak/subscribe)
  • menjadi "god service" lintas semua context

5.3 services/checker/support/*

Boleh:

  • query helper reusable
  • lifecycle service reusable
  • publisher reusable
  • transaction wrapper reusable

Tidak boleh:

  • flow spesifik satu context jika tidak reusable

6. Aturan Penempatan Type (Hitam Putih)

Gunakan aturan ini tanpa asumsi:

  1. Boundary payload/event lintas context/module -> contracts/*.contract.ts
  2. Type internal reusable (bukan boundary) -> contracts/internal/*.types.ts
  3. Type yang hanya dipakai di test -> tetap di file *.spec.ts
  4. Hindari menaruh top-level type/interface di file runtime (*.service.ts, *.consumer.ts)

Contoh:

  • SlaTransitionCheckPayload -> contracts/sla-check.contract.ts
  • SlaBreachPublishPayload -> contracts/sla-outcome.contract.ts
  • StartPolicyInstanceResult -> contracts/internal/sla-instance-lifecycle.types.ts

7. Kapan File Masuk checker/support vs Context

Masuk services/checker/support jika:

  • dipakai minimal 2 context
  • sifatnya helper/service reusable
  • bukan transport adapter

Tetap di context jika:

  • hanya dipakai context itu
  • logic sangat spesifik ke flow context tersebut
  • naming akan lebih jelas bila dekat dengan flow

Rule praktis:

  • kalau ragu, taruh di context dulu
  • pindahkan ke checker/support setelah benar-benar reusable

8. Pola Custom Decorator Untuk Consumer (Standar Saat Ini)

Gunakan pola ini untuk consumer JetStream baru agar konsisten:

  1. Class consumer diberi @JetStreamConsumer({...})
  2. Method penerima message diberi @MessageHandler()
  3. Method handler melakukan:
    • safeDecode(...)
    • validasi minimum
    • manual ack/nak
    • call context service (*.service.ts)
  4. Jangan implement OnApplicationBootstrap / OnModuleDestroy di consumer yang sudah memakai registry

8.1 Contoh (ringkas)

import {
JetStreamConsumer,
MessageHandler,
} from '@lib/service/nats/jetstream-consumer/jetstream-consumer.decorator';
import { JetStreamConsumableMessage } from '@lib/service/nats/jetstream-consumer/jetstream-consumer.types';
import { Injectable } from '@nestjs/common';
import { consumerOpts } from 'nats';

@JetStreamConsumer({
name: 'SLA Aging Checker',
subject: String(SLA_AGING_CHECK_CONSUMER.SUBJECT),
waitUntilReady: true,
unhandledErrorNakDelayMs: 8000,
buildOpts: () =>
consumerOpts()
.durable(SLA_AGING_CHECK_CONSUMER.DURABLE)
.deliverGroup(SLA_AGING_CHECK_CONSUMER.GROUP)
.deliverTo(SLA_AGING_CHECK_CONSUMER.DELIVER)
.manualAck()
.ackExplicit()
.deliverNew()
.maxDeliver(SLA_AGING_CHECK_CONSUMER.MAX_REDELIVERY),
})
@Injectable()
export class SlaAgingConsumerAdapter {
constructor(private readonly agingService: SlaAgingService) {}

@MessageHandler()
async handleMessage(msg: JetStreamConsumableMessage) {
try {
const decoded = this.safeDecode(msg.data);
if (!decoded) {
await msg.ack();
return;
}

await this.agingService.handle(decoded);
await msg.ack();
} catch {
await msg.nak(8000);
}
}
}

8.2 Kenapa begini (rule hitam-putih)

  • metadata subscribe berada di decorator (rapi, konsisten)
  • consumerOpts() chain tetap terlihat di file consumer (readable)
  • ack/nak tetap terlihat di file consumer (debuggable)
  • waitUntilReady tetap ada, tetapi dijalankan registry (bukan tiap consumer copy-paste)

8.3 Registry yang wajib tersedia di module

  • import DiscoveryModule (@nestjs/core)
  • register JetStreamConsumerRegistryService sebagai provider module

9. Aturan Refactor (Safety Rules)

Saat refactor struktur:

  • utamakan behavior-preserving
  • ubah struktur/naming dulu, jangan ubah logic bisnis sekaligus
  • setelah rename/move:
    • update import path
    • jalankan typecheck
    • jalankan test sla-policy-evaluator

Checklist minimum:

  • pnpm exec tsc -p apps/worker-workflow/tsconfig.json --noEmit
  • pnpm exec jest $(rg --files apps/worker-workflow/src/sla-policy-evaluator -g '*.spec.ts') packages/lib/src/service/nats/jetstream-consumer/jetstream-consumer-registry.service.spec.ts --runInBand

10. Template Context Baru (Standar)

Jika menambah context baru (contoh replay), gunakan template:

services/replay/
├── README.md
├── sla-replay.consumer.ts # jika ada transport (prefer pakai decorator JetStream standar)
├── sla-replay.service.ts # use-case utama context
├── replay.query.ts # optional (query spesifik context)
├── sla-replay.consumer.spec.ts
└── sla-replay.service.spec.ts

Jika context sangat kecil:

  • boleh hanya consumer + spec
  • jangan memaksa ada service tambahan kalau logic masih trivial

11. Prompt Refactor (Siap Pakai)

Gunakan teks ini sebagai prompt untuk menjaga konsistensi:

Refactor folder/file di `apps/worker-workflow/src/sla-policy-evaluator` mengikuti aturan:
- context-first
- sub-context runtime berada di `services/` (`cdc-forwarder`, `transition`, `schedule`, `checker`, dst)
- reusable supporting services berada di `services/checker/support`
- boundary types/interfaces/DTO berada di `contracts/*.contract.ts`
- transport adapter memakai suffix `*.consumer.ts`
- jika consumer memakai JetStream:
- gunakan `@JetStreamConsumer(...)` pada class
- gunakan `@MessageHandler()` pada method handler
- simpan `consumerOpts()` chain di file consumer
- `ack/nak` tetap manual di method handler
- use-case utama context memakai suffix `*.service.ts`
- test colocated (`*.spec.ts`)
- jangan ubah behavior runtime kecuali diminta

Setelah refactor:
1. update seluruh import path
2. jalankan typecheck worker-workflow
3. jalankan seluruh test `sla-policy-evaluator`
4. laporkan file yang dipindah/di-rename dan risiko perubahan

12. Prompt Create Context Baru (Siap Pakai)

Buat context baru di `apps/worker-workflow/src/sla-policy-evaluator/services/<context-name>` dengan standar SLA Policy Evaluator:
- `README.md`
- `*.consumer.ts` jika ada transport message
- jika consumer JetStream:
- gunakan `@JetStreamConsumer(...)` + `@MessageHandler()`
- jangan implement bootstrap/drain sendiri jika memakai registry
- simpan `consumerOpts()` chain dan manual `ack/nak` di file consumer
- `*.service.ts` untuk use-case utama context (jika logic tidak trivial)
- `*.spec.ts` colocated
- gunakan `contracts/` untuk payload boundary
- gunakan `services/checker/support/` untuk reusable pendukung checker
- gunakan `utils/` hanya untuk pure function

Jangan buat nested folder `adapters/` atau `application/` di dalam context kecuali ada alasan kuat dan disetujui.