DemografiEngine (Account) — Full Current Functional Flow

Dokumen ini memetakan perilaku current DemografiEngine Account dari intake, persistensi, query, cache/rule consumer, sampai scoring. Ini baseline source saat ini, bukan desain target. Account dipakai melalui dua field transaksi (srcAccNumber dan destAccNumber), tetapi keduanya menunjuk ke source of truth dan score yang sama: data_account berdasarkan accountNumber.

Status Verifikasi

Area Status Batas verifikasi
REST/XML intake, command, DB/cache/search SOURCE-TRACED Controller, service, entity, repository ditelusuri.
Score action dan alert auto-increment SOURCE-TRACED Alert/action/score source ditelusuri.
Schema/threshold seed SOURCE-TRACED Liquibase ditelusuri.
Filesystem, cascade nested data, actual cron NOT RUNTIME-VERIFIED Tidak menjalankan aplikasi.
Production profile/data NOT PRODUCTION-VERIFIED Tidak memeriksa environment produksi.

Peta Komponen Utama

Concern Komponen current Tanggung jawab
API AccountController Save batch dan search.
Batch file AccountServiceImpl.saveAccountPath Cron XML dan lifecycle file.
Command processSingleAccount CREX/CRUP/IGNR dan sanitasi.
Entity Account / data_account Account profile, nested relations, score/level.
Rule consumer AccountCache, ResolverTypeSrcAccNumber, ResolverTypeDestAccNumber Mengambil profile untuk source/destination transaction.
Scoring ScoringService / evaluator Semua entity type SOURCE_ACCOUNT, DESTINATION_ACCOUNT, atau ACCOUNT menuju Account.

Ringkasan End-to-End

[Diagram]

Flow 1 — Dua Jalur Intake

REST

POST /account-data/save menerima JSON AccountApps.application[]. Per-record exception ditangkap di saveAccountData, menjadi counter failed, dan controller mengembalikan HTTP 200 dengan summary bila method selesai normal.

Scheduler XML

saveAccountPath memakai ${demographic.account.cron.save}, membuat folder jika belum ada, hanya mengambil .xml, mengisolasi record gagal sebagai <source>_FAILED_<account>.xml, dan memindahkan source valid ke output walaupun terdapat error item.

[Diagram]

[!DANGER] data.getApplication() tidak memiliki null check di REST maupun batch loop. application=null menyebabkan exception, bukan summary yang terstruktur.

[!DANGER] Variabel log accountNumber pada REST tidak diisi sebelum catch sehingga selalu UNKNOWN saat error.

[!DANGER] IGNR dihitung sebagai success scheduler meski tidak melakukan persistensi.

Flow 2 — Command, Persistensi dan Cache

Lookup menggunakan accountNumber; Liquibase dan entity sama-sama menyatakan unique constraint. Object disanitasi hingga panjang 255 dan mengandung ManyToOne(cascade=ALL) untuk Credit, Customer, Limit, dan Device.

[Diagram]
Command Existing account Current result Cache
CREX Absent Insert Tidak di-evict.
CREX Present Ignore Tidak berubah.
CRUP Absent Insert Tidak di-evict.
CRUP Present Full replacement menggunakan old id Evict.
IGNR Any No write No change.
State Storage current
Identity data_account.account_number; unique constraint uk_data_account_account_number.
Profile currency/type/status, avalBalance BigDecimal, createDate String.
Nested relation Credit, Customer, Limit, Device; seluruhnya cascade ALL.
Score score, scoringLevel di data_account; input payload dapat membawa nilainya.

[!DANGER] CRUP melakukan full replacement dan cascade ALL. Payload parsial dapat mengubah association Credit/Customer/Limit/Device karena tidak ada patch/merge field-level.

[!DANGER] Insert CREX/CRUP absent tidak mengevict cache. Jika CacheSupport menyimpan null result atau ada interleaving lookup, consumer bisa melihat stale state hingga 30 menit; behavior null cache NOT RUNTIME-VERIFIED.

[!DANGER] Tidak ada @Transactional pada service/batch method. Source class ini tidak menampakkan boundary transaksi untuk seluruh batch atau record.

Flow 3 — Search dan Rule Consumer

POST /account-data/search menggunakan Criteria API. Rule engine memiliki dua resolver yang berbeda, tetapi keduanya menggunakan AccountCache dan lookup account yang sama: source account dari srcAccNumber, destination dari destAccNumber.

[Diagram]

[!DANGER] order dan fallback key filter dipakai sebagai root.get(...) tanpa allowlist; invalid field menjadi exception/HTTP 500.

[!DANGER] createDate adalah string. Filter date mengubah ISO Instant ke yyMMddHHmmss dengan timezone sistem dan lalu membandingkan string, bukan timestamp database.

Flow 4 — Scoring Account

Score Account tidak dipanggil oleh intake. RunAction dapat memanggil createScore/updateScore; di ScoringService, SOURCE_ACCOUNT dan DESTINATION_ACCOUNT keduanya masuk branch Account yang sama. Alert eligible memanggil incrementScore("ACCOUNT", srcAccNumber) dan lagi untuk destAccNumber bila keduanya nonblank.

[Diagram]
Entry Formula Special current behavior
createScore clamp initial 0..100 Skip bila existing score >0.
updateScore clamp(previous + newScore) newScore adalah delta.
incrementScore clamp(previous + threshold autoIncrement) Skip bila ≥100.
level first active matching threshold, else LOW Seed ACCOUNT LOW <40, MEDIUM 40..70, HIGH ≥70, increment 10.

[!DANGER] Satu alert bisa increment account yang sama dua kali bila srcAccNumber dan destAccNumber identik, karena triggerScoring tidak melakukan deduplication antar dua pemanggilan Account.

[!DANGER] ScoringService tidak mengevict AccountCache. Resolver rule dapat melihat score atau scoringLevel stale sampai TTL 30 menit.

[!DANGER] tryScore pada alert menelan exception. Account tidak ditemukan tidak membatalkan pembuatan alert/case atau memberi response error ke caller.

[!DANGER] Threshold overlap/range invalid tidak dicegah oleh update threshold; evaluator memilih match pertama berurutan value1 DESC.

Matriks Skenario Operasional

Scenario Persist/result Cache/score Next step
REST CREX new Insert account/cascades No automatic score Summary 200.
CREX existing No write Unchanged Ignored.
CRUP existing Full replacement Cache evicted Reload on rule lookup.
Invalid command Item failure No expected write REST can still report 200.
XML corrupt File error path No data write Continue.
XML partial error Isolation XML Parent output Manual retry failure.
Alert source and dest distinct Two increments Both scores saved Level recalculated.
Alert source equals dest Two increments same Account Can add twice Score may rise by 20 seed default.
Unknown account during score IllegalStateException caught by alert No score Alert continues.

State Ownership Current

State Authoritative source Projection/consumer
Account profile data_account REST, cache, rule and scoring.
Identity Unique account_number All Account lookup pathways.
Nested profile Credit/Customer/Limit/Device tables Cascade from Account payload.
Cache projection account:<accountNumber>, TTL 30m src/dest rule resolvers.
Score/level data_account.score, scoring_level Scoring; cache consumer may lag.
Threshold Active ACCOUNT settings Evaluator.
File lifecycle configured account paths Scheduled intake.

Known Current Gaps

Gap current Dampak
Intake does not call scoring Account baru tak otomatis mendapatkan normalized level.
Same src/dest double increment Self-transfer dapat mengerek score dua kali per alert.
Full CRUP cascade replacement Payload partial dapat mutasi nested records.
Cache unchanged after inserts/score Rule can read stale profile/score.
REST success for partial failure Client must parse summary string.
Date-as-string filtering Timezone/lexical date issue.
Dynamic search fields/order Invalid input returns 500.
Threshold ambiguity Overlap determines evaluation by sorting behavior.

Endpoint Surface

Surface Endpoint family Capability
Account intake POST /account-data/save CREX/CRUP/IGNR batch.
Account search POST /account-data/search Filter/pagination/order.
Threshold /scoring-threshold/* Shared ACCOUNT threshold management.
XML intake ${demographic.account.cron.save} Scheduled XML processing.

Source Trace

Flow/Area Primary source
Account API/intake/search DemografiEngine/Account/AccountController.java; DemografiEngine/Account/AccountServiceImpl.java
Model/cache DemografiEngine/Domain/Account.java; DemografiEngine/Application/Account/AccountApp.java; DemografiEngine/Application/Account/AccountApps.java; DemografiEngine/Account/AccountRepository.java; DemografiEngine/Cache/AccountCache.java
Rule consumers Rule/Engine/CoreNew/Processor/Resolver/Component/NonAggregate/Type/Component/ResolverTypeSrcAccNumber.java; ResolverTypeDestAccNumber.java
Score AlertManagement/Resource/ActionRequest/RunAction.java; AlertManagement/Abstract/BaseAlertServiceImpl.java; DemografiEngine/Scoring/ScoringService.java; ScoringEvaluatorService.java
Schema/seed db/changelog/DataDemographic/20260406100017_fadhiilabiyyi_create_data_account.xml; db/changelog/DataDemographic/Seed/20260401165730_alfin-wildan_seed_account-demographic.xml; db/changelog/DataDemographic/Seed/20260428000007_alfin-wildan_seed_scoring_threshold_setting.xml

Catatan Verifikasi Lanjutan