Start HereOrdered learning track

Large Scale ERP Reference Architecture

Learn Java Large Scale ERP - Part 003

Reference architecture for designing large-scale ERP systems in Java, including modular boundaries, data plane, integration plane, reporting plane, extension model, and operational control plane.

18 min read3411 words
PrevNext
Lesson 0334 lesson track0106 Start Here
#java#erp#enterprise-architecture#reference-architecture+3 more

Part 003 — Large Scale ERP Reference Architecture

1. Target Skill Part Ini

Pada part sebelumnya kita memposisikan ERP sebagai sistem pengendali bisnis, bukan sekadar aplikasi administrasi. Part ini membawa kita ke pertanyaan arsitektural paling penting:

Seperti apa bentuk arsitektur Java ERP berskala besar yang cukup modular untuk berubah, cukup konsisten untuk menjaga data bisnis, cukup terbuka untuk integrasi, dan cukup operasional untuk dipakai bertahun-tahun?

Target part ini bukan menghafal diagram. Targetnya adalah membentuk kemampuan membaca dan mendesain ERP dari beberapa sudut sekaligus:

  • domain architecture: capability apa yang dimiliki sistem;
  • application architecture: bagaimana command, workflow, rule, query, dan integration diatur;
  • data architecture: siapa pemilik data, siapa boleh menulis, siapa hanya membaca;
  • runtime architecture: bagaimana sistem dideploy, diskalakan, diamati, dan dipulihkan;
  • governance architecture: bagaimana audit, security, customization, dan compliance tidak menjadi tambalan belakangan.

Dalam kerangka Kaufman, part ini adalah tahap deconstruct the skill di level architecture. Kita memecah ERP menjadi plane dan boundary yang bisa dilatih secara terpisah.

2. Prinsip Utama: ERP Tidak Punya Satu Arsitektur Tunggal

ERP besar biasanya tidak murni monolith, tidak murni microservices, dan tidak murni event-driven. Bentuk yang realistis sering berupa kombinasi:

  • modular core untuk transaksi yang butuh konsistensi tinggi;
  • service-oriented extensions untuk domain yang berubah cepat atau punya scaling berbeda;
  • event-driven integration untuk propagasi fakta bisnis;
  • read model/reporting plane untuk kebutuhan query berat;
  • batch/data pipeline untuk close period, MRP, aging, reconciliation, dan analytical workload;
  • workflow engine untuk long-running business process;
  • configuration/customization layer untuk perbedaan tenant, negara, legal entity, dan proses bisnis.

Arsitektur ERP yang baik tidak memaksakan satu gaya ke semua masalah. Ia memilih bentuk berdasarkan constraint.

2.1 Constraint yang Menentukan Bentuk Arsitektur

ConstraintDampak Arsitektural
Financial correctnessLedger, posting, period lock, reversal, audit trail harus kuat.
Operational consistencyInventory, fulfillment, procurement, dan production tidak boleh kehilangan fakta transaksional.
Long-running workflowApproval, escalation, delegation, dan SLA membutuhkan state machine eksplisit.
Customization pressureSistem butuh extension point yang aman, bukan patch langsung ke core.
Reporting pressureOLTP tidak boleh dipaksa menjadi mesin analytics.
Integration pressureAPI/event/file/EDI/bank/tax integration perlu idempotency dan reconciliation.
Regulatory pressureData lineage, audit evidence, access control, retention, dan defensibility wajib dari awal.
Multi-company rolloutLegal entity, branch, fiscal calendar, currency, language, tax, dan localization perlu model organisasi kuat.

Arsitektur yang gagal biasanya bukan karena salah memilih framework. Ia gagal karena constraint ini tidak diterjemahkan menjadi boundary teknis.

3. Reference Architecture: View Besar

Diagram berikut adalah bentuk referensi yang akan kita pakai sepanjang seri. Ini bukan template vendor. Ini adalah peta mental untuk menempatkan komponen ERP.

Model ini sengaja dipisahkan menjadi beberapa plane. Dalam ERP, pemisahan plane jauh lebih berguna daripada hanya membicarakan layer teknis seperti controller-service-repository.

4. Plane 1: Experience Layer

Experience layer adalah semua permukaan interaksi manusia dan sistem eksternal:

  • internal ERP web UI;
  • mobile app untuk warehouse, field service, approval, receiving, delivery;
  • supplier portal;
  • customer portal;
  • public/private API client;
  • admin/support console.

Kesalahan umum adalah membiarkan UI menentukan bentuk domain. Di ERP besar, UI boleh berbeda-beda, tetapi fakta bisnis harus tetap masuk melalui command model yang sama.

4.1 Rule Praktis

UI boleh punya workflow presentation sendiri, tetapi tidak boleh punya business authority sendiri.

Contoh buruk:

Button "Approve Invoice" langsung update status invoice menjadi APPROVED.

Contoh lebih defensible:

UI mengirim ApproveInvoiceCommand.
Application layer memvalidasi actor, SoD, approval policy, period, amount threshold, dan current state.
Domain menghasilkan InvoiceApproved fact.
Audit evidence ditulis dalam transaksi yang sama.

4.2 Java Implication

Di Java ERP, experience layer biasanya diterjemahkan sebagai:

  • REST controller / GraphQL resolver / server-side UI endpoint;
  • DTO khusus UI;
  • request validation ringan;
  • authorization pre-check;
  • mapping ke command/query;
  • correlation id dan request context.

Yang tidak boleh berada di layer ini:

  • posting ledger;
  • perhitungan tax final;
  • approval authority final;
  • mutation terhadap aggregate tanpa command;
  • data access langsung ke tabel core.

5. Plane 2: Edge and Access Layer

ERP besar membutuhkan access control yang jauh lebih kaya daripada “user punya role admin”. Banyak bug ERP serius berasal dari access model yang terlalu dangkal.

Layer ini bertanggung jawab atas:

  • authentication;
  • session/token validation;
  • tenant resolution;
  • organization context;
  • role dan permission;
  • attribute-based policy;
  • segregation of duties;
  • delegated authority;
  • data scope;
  • approval authority.

5.1 Execution Context

ERP command tidak cukup menerima userId. Ia butuh konteks yang lebih lengkap:

public record ErpExecutionContext(
    TenantId tenantId,
    UserId actorId,
    LegalEntityId legalEntityId,
    BranchId branchId,
    Set<RoleCode> roles,
    Set<PermissionCode> permissions,
    Set<DataScope> dataScopes,
    Instant requestedAt,
    CorrelationId correlationId
) {}

Konteks ini bukan sekadar convenience object. Ia adalah boundary antara sistem keamanan dan domain transaction.

5.2 Access Control Sebagai Invariant

Dalam ERP, access control sering menjadi bagian dari invariant bisnis. Contoh:

  • user yang membuat purchase order tidak boleh menjadi approver akhir untuk PO yang sama;
  • user finance boleh posting invoice tetapi tidak boleh mengubah bank account vendor;
  • branch manager hanya boleh approve expense di branch miliknya;
  • CFO boleh override credit hold tetapi override harus tercatat sebagai audit evidence.

Artinya, authorization tidak boleh hanya dipasang sebagai annotation generik di controller. Sebagian policy harus dievaluasi dalam command handler atau domain service karena bergantung pada state dokumen.

6. Plane 3: Application Control Plane

Application control plane adalah pusat orkestrasi use case. Di sini command, workflow, rules, configuration, dan domain dipertemukan.

Komponen utamanya:

  • command handler;
  • query handler;
  • workflow/application service;
  • validation coordinator;
  • rule/calculation engine;
  • configuration runtime;
  • transaction boundary manager;
  • event publisher/outbox writer;
  • audit evidence writer.

6.1 Command vs Query

ERP besar sebaiknya eksplisit membedakan command dan query.

JenisKarakterContoh
CommandMengubah state bisnis, harus tervalidasi, audited, idempotent bila perluSubmitPurchaseOrder, PostInvoice, ReverseJournal
QueryMembaca state atau read model, tidak mengubah invariantFindOpenInvoices, GetInventoryPosition, GetApprovalInbox

Command harus melewati invariant. Query boleh dioptimalkan dengan read model.

public interface ErpCommandHandler<C extends ErpCommand, R> {
    R handle(C command, ErpExecutionContext context);
}

public record PostVendorInvoiceCommand(
    InvoiceId invoiceId,
    IdempotencyKey idempotencyKey,
    PostingDate postingDate
) implements ErpCommand {}

6.2 Command Handler Sebagai Use Case Boundary

Contoh bentuk command handler:

@Transactional
public PostingResult handle(PostVendorInvoiceCommand command, ErpExecutionContext ctx) {
    idempotencyGuard.ensureNotProcessed(command.idempotencyKey());

    VendorInvoice invoice = invoiceRepository.getForUpdate(command.invoiceId());
    policy.checkCanPost(invoice, ctx);
    periodPolicy.checkOpen(invoice.legalEntityId(), command.postingDate());

    PostingBatch batch = postingService.createPosting(invoice, command.postingDate(), ctx);
    ledgerRepository.append(batch.entries());

    invoice.markPosted(batch.postingId(), ctx.actorId());
    auditEvidence.record(InvoicePostedEvidence.from(invoice, batch, ctx));
    outbox.add(DomainEventEnvelope.from(new VendorInvoicePosted(invoice.id(), batch.postingId())));

    idempotencyGuard.markProcessed(command.idempotencyKey(), batch.postingId());
    return new PostingResult(batch.postingId());
}

Yang penting bukan syntax-nya. Yang penting adalah urutan tanggung jawab:

  1. deduplicate/idempotency;
  2. load state dengan concurrency policy yang benar;
  3. access dan business policy;
  4. period/accounting constraint;
  5. domain calculation/posting;
  6. state transition;
  7. audit evidence;
  8. outbox event;
  9. idempotency completion.

7. Plane 4: ERP Domain Core

Domain core berisi capability yang membentuk sistem ERP:

  • General Ledger;
  • Accounts Payable;
  • Accounts Receivable;
  • Inventory;
  • Procurement;
  • Sales;
  • Manufacturing;
  • Assets;
  • Projects;
  • Tax;
  • Pricing;
  • Workflow;
  • Master Data;
  • Organization Model.

Tetapi domain core tidak berarti semua modul harus berada dalam satu database dan satu deployment. Domain core berarti ada area yang memegang business authority.

7.1 Authority Lebih Penting dari Tabel

Pertanyaan arsitektural yang benar:

Siapa yang memiliki authority untuk menyatakan fakta bisnis ini benar?

Contoh:

Fakta BisnisAuthority Utama
Vendor invoice postedAP/Subledger + GL posting pipeline
Stock decreased karena shipmentInventory/warehouse ledger
Customer credit hold dilepasAR/Credit control
Purchase order approvedProcurement workflow/policy
Accounting period closedFinance period control
Tax amount finalTax calculation authority + localization policy

Jika ownership authority tidak jelas, sistem akan menciptakan duplikasi logic dan rekonsiliasi manual.

7.2 Domain Core Tidak Sama Dengan Shared Kernel Besar

Banyak ERP internal gagal karena membuat paket core yang berisi semuanya:

core/
  Customer
  Vendor
  Product
  Invoice
  PurchaseOrder
  SalesOrder
  Ledger
  Approval
  Workflow
  Tax
  Config

Ini terlihat rapi, tetapi secara evolusi buruk. Semua modul menjadi saling bergantung. Perubahan kecil di Product bisa memicu build dan regression seluruh sistem.

Lebih baik memisahkan authority:

modules/
  organization/
  masterdata/
  finance-gl/
  finance-ap/
  finance-ar/
  inventory/
  procurement/
  sales/
  manufacturing/
  workflow/
  tax/
  integration/
  reporting/

Shared kernel harus kecil dan stabil:

shared-kernel/
  TenantId
  LegalEntityId
  Money
  CurrencyCode
  Quantity
  UomCode
  DocumentNumber
  FiscalPeriod
  AuditActor

8. Plane 5: Transactional Data Plane

Transactional data plane adalah tempat fakta bisnis yang authoritative ditulis. Dalam ERP, ini bukan sekadar “database”. Ini adalah sistem memori legal dan operasional perusahaan.

Komponennya:

  • OLTP tables;
  • ledger tables;
  • document tables;
  • state transition history;
  • audit evidence store;
  • transactional outbox;
  • idempotency records;
  • import staging;
  • reconciliation tables.

8.1 Prinsip Data Plane

  1. Write authority harus jelas.
  2. Ledger harus append-friendly dan dapat direkonsiliasi.
  3. Audit evidence tidak boleh bergantung pada log aplikasi saja.
  4. Outbox event harus ikut transaction boundary.
  5. Read model tidak boleh menjadi sumber kebenaran.
  6. Correction harus melalui reversal/adjustment, bukan silent update.

8.2 Transactional Outbox

Dalam ERP, event bukan dekorasi. Event sering dipakai untuk menyinkronkan invoice, payment, shipment, stock, dan financial posting. Jika event publish gagal setelah database commit, downstream bisa kehilangan fakta bisnis. Karena itu, transactional outbox menjadi pattern penting.

Outbox tidak membuat sistem “exactly once”. Ia membuat state change dan event intent berada dalam satu commit. Downstream tetap harus idempotent.

9. Plane 6: Integration Plane

ERP jarang hidup sendiri. Ia berhubungan dengan:

  • CRM;
  • WMS;
  • MES;
  • e-commerce;
  • bank;
  • tax authority;
  • payment gateway;
  • payroll;
  • BI platform;
  • supplier/customer EDI;
  • document management;
  • identity provider.

Integration plane harus mengakui bahwa dunia luar tidak konsisten, tidak selalu online, dan tidak selalu idempotent.

9.1 Mode Integrasi

ModeCocok UntukRisiko
Synchronous APIValidasi cepat, lookup, low-latency commandCoupling, timeout, partial failure
Async eventPropagasi fakta bisnis, decouplingEventual consistency, duplicate, ordering
File/EDIPartner enterprise legacyLate failure, mapping ambiguity
Batch ETL/ELTReporting, analytics, migrationStaleness, reconciliation gap
WebhookExternal notificationRetry semantics tidak seragam
PollingSistem eksternal tanpa eventLoad, delay, duplicate processing

9.2 Rule Praktis Integrasi ERP

Tidak ada integrasi ERP yang selesai tanpa idempotency, retry policy, dead-letter handling, dan reconciliation.

Minimal setiap integration flow punya:

  • correlation id;
  • external reference id;
  • internal document id;
  • idempotency key;
  • received/sent timestamp;
  • payload hash;
  • processing status;
  • retry count;
  • failure reason;
  • reconciliation status.

10. Plane 7: Read and Analytics Plane

ERP workload berat bukan hanya transaksi. Reporting bisa menjadi beban terbesar:

  • trial balance;
  • profit and loss;
  • balance sheet;
  • aging AR/AP;
  • inventory valuation;
  • stock position;
  • MRP projection;
  • sales margin;
  • tax report;
  • audit report;
  • close checklist.

Jika semua laporan membaca OLTP langsung dengan join raksasa, sistem transaksi akan melambat dan risk of lock/contention naik.

10.1 Pemisahan Read Model

Read model bukan tempat memperbaiki data. Jika read model menemukan anomali, koreksi harus kembali ke authoritative domain melalui command/reconciliation process.

10.2 Jenis Read Model

Read ModelContohFreshness
Operationalapproval inbox, open PO, stock positionnear real-time
Searchinvoice search, customer search, item searchseconds/minutes
Financial reporttrial balance, aging, close reportcontrolled batch/near real-time
Analyticsmargin analysis, spend analysisbatch/warehouse
Audit evidence viewwho changed what, when, whystrongly traceable

11. Plane 8: Configuration and Extension Plane

ERP besar selalu dikustomisasi. Pertanyaannya bukan apakah customization dibutuhkan. Pertanyaannya:

Apakah customization dapat dilakukan tanpa merusak core invariant dan upgrade path?

Configuration dan extension plane mencakup:

  • feature flags;
  • tenant/business parameters;
  • approval matrix;
  • tax localization;
  • custom fields;
  • custom validations;
  • custom workflow steps;
  • integration mapping;
  • report layout;
  • document numbering rules;
  • extension events/hooks;
  • plugin/module lifecycle.

11.1 Config Bukan Sekadar Key-Value

Contoh buruk:

config_key = "allow_negative_stock"
config_value = "true"

Contoh lebih defensible:

public record StockPolicy(
    TenantId tenantId,
    LegalEntityId legalEntityId,
    BranchId branchId,
    boolean allowNegativeStock,
    EffectiveDateRange effectiveDateRange,
    PolicyVersion version,
    ApprovalStatus status
) {}

Config ERP perlu:

  • scope;
  • effective dating;
  • version;
  • approval;
  • audit trail;
  • validation;
  • fallback hierarchy;
  • migration semantics.

11.2 Extension Safety

Extension point harus diberi batas:

ExtensionAman JikaBahaya Jika
Custom fieldTyped, scoped, indexed bila perluMengubah meaning field core
Custom validationDeterministic, timeout, versionedBisa bypass invariant core
Workflow hookTidak mengubah ledger langsungMenulis status tanpa state machine
Integration mapperSchema versionedMapping diam-diam berubah
Script ruleSandboxed, observableTidak ada limit/trace/audit

12. Plane 9: Operations and Governance Plane

ERP yang bagus bukan hanya benar ketika demo. Ia harus bisa dioperasikan saat:

  • posting batch gagal di tengah malam;
  • invoice tertahan karena workflow stuck;
  • period close menghasilkan imbalance;
  • integrasi bank mengirim file duplikat;
  • MRP run memakan waktu terlalu lama;
  • tenant besar menghasilkan report burst;
  • auditor meminta bukti perubahan data;
  • support perlu menjelaskan kenapa dokumen tidak bisa diposting.

Operations plane mencakup:

  • observability teknis;
  • observability bisnis;
  • batch scheduler;
  • reconciliation jobs;
  • support console;
  • retry dashboard;
  • stuck workflow detector;
  • data quality monitor;
  • audit extraction;
  • retention management.

12.1 Business Observability

Metric teknis seperti CPU dan latency penting, tetapi tidak cukup. ERP perlu metric bisnis:

  • count invoice failed to post;
  • aging of approval tasks;
  • unmatched goods receipt vs invoice;
  • stock ledger imbalance;
  • outbox backlog;
  • number of documents stuck in submitted state;
  • period close checklist completion;
  • integration dead-letter count by partner;
  • reconciliation difference by account/currency/legal entity.

13. Deployment Shapes

Reference architecture bisa diwujudkan dalam beberapa deployment shape. Tidak ada satu jawaban universal.

13.1 Modular Monolith

Satu deployable, banyak modul internal dengan boundary kuat.

Cocok ketika:

  • tim masih relatif kecil/medium;
  • domain masih cepat berubah;
  • transaksi lintas modul sangat kuat;
  • operational maturity belum cukup untuk banyak service;
  • kebutuhan deployment independence belum dominan.

Risiko:

  • boundary mudah dilanggar;
  • database menjadi shared dumping ground;
  • build/test bisa melambat;
  • scaling kurang granular.

Struktur contoh:

erp-platform/
  shared-kernel/
  module-organization/
  module-masterdata/
  module-finance-gl/
  module-finance-ap/
  module-procurement/
  module-inventory/
  module-sales/
  module-workflow/
  module-reporting/
  app-runtime/

13.2 Distributed Modular ERP

Beberapa modul menjadi service terpisah, tetapi boundary tetap berdasarkan capability, bukan berdasarkan tabel atau tim yang kebetulan ada.

Cocok ketika:

  • domain tertentu butuh scaling terpisah;
  • integrasi eksternal berat;
  • tim sudah punya ownership jelas;
  • release cadence berbeda;
  • failure isolation bernilai tinggi.

Risiko:

  • distributed transaction temptation;
  • duplicate master data;
  • event ordering issue;
  • debugging lintas service;
  • operational overhead;
  • distributed monolith.

13.3 Hybrid Shape yang Paling Umum

Untuk ERP besar, bentuk realistis sering seperti ini:

Core transaction tetap dekat dengan database yang konsisten. Extension, integration, reporting, dan batch bisa dipisah jika pressure-nya berbeda.

14. Java Stack View

Seri ini tidak akan mengunci pada satu framework, tetapi asumsi praktisnya adalah Java modern dengan salah satu keluarga platform berikut:

  • Spring Boot / Spring Framework untuk service runtime, web, transaction management, dependency injection, observability, batch, dan integration;
  • Jakarta EE untuk enterprise standard APIs seperti persistence, REST, messaging, validation, batch, concurrency, dan security;
  • plain Java modules/libraries untuk domain core yang tidak bergantung langsung pada framework;
  • relational database sebagai authoritative OLTP store;
  • message broker untuk event/integration;
  • warehouse/lakehouse/search untuk read-heavy workload.

Catatan faktual: dokumentasi Spring Boot 4.1 menyatakan minimal Java 17 dan kompatibel sampai Java 26; Jakarta EE Platform 11 juga mensyaratkan Java SE 17 atau lebih tinggi dan menambahkan dukungan seperti Jakarta Data 1.0 serta runtime-aware support untuk virtual threads. Apache OFBiz relevan sebagai referensi open-source karena proyek resminya mendeskripsikannya sebagai ERP berbasis Java dengan entity engine, service engine, dan widget-based UI.

14.1 Dependency Direction yang Disarankan

Rule:

  • domain tidak bergantung pada Spring/Jakarta;
  • application layer boleh memakai transaction boundary framework;
  • infrastructure mengimplementasikan port;
  • adapter menerjemahkan protokol eksternal ke command/query;
  • shared kernel kecil dan stabil.

14.2 Package Contoh

com.company.erp
  shared
    money
    time
    tenant
    audit
  finance.gl
    domain
    application
    adapter.persistence
    adapter.rest
    adapter.events
  procurement
    domain
    application
    adapter.persistence
    adapter.rest
    adapter.events
  inventory
    domain
    application
    adapter.persistence
    adapter.rest
    adapter.events
  platform.workflow
  platform.config
  platform.integration
  platform.observability

Pemisahan package bukan jaminan boundary. Boundary harus diuji dengan architecture test, dependency rule, ownership rule, dan database write policy.

15. Architecture Decision Matrix

Gunakan matrix ini saat memilih bentuk implementasi.

KeputusanPilih A JikaPilih B JikaWarning
Modular monolith vs serviceKonsistensi tinggi dan domain belum stabilScaling/release/ownership butuh isolasiJangan split hanya karena “microservices modern”
Shared DB vs database per serviceModul masih satu transactional coreService benar-benar punya data authorityShared DB lintas service sering menjadi distributed monolith
Sync API vs async eventButuh jawaban langsungFakta bisa diproses eventualSync call di tengah transaction ERP berisiko timeout/rollback kompleks
Read from OLTP vs read modelQuery sederhana dan boundedQuery berat, cross-domain, analyticalReporting-on-OLTP bisa menghancurkan performa posting
Config vs codePerubahan bisnis rutin dan aman diparameterisasiInvariant core atau calculation kritisOver-config menciptakan bahasa ERP liar tanpa governance
Workflow engine vs hardcoded stateApproval berubah, long-running, SLALifecycle sederhana dan stabilWorkflow generic tanpa invariant domain bisa membahayakan

16. Failure Modes Arsitektur ERP

16.1 God ERP Core

Semua domain masuk ke satu module core. Awalnya cepat, lalu semua perubahan menjadi regression besar.

Gejala:

  • dependency graph melingkar;
  • semua repository bisa diakses dari semua service;
  • class DocumentService menangani semua jenis dokumen;
  • test sulit diisolasi;
  • deployment selalu all-or-nothing.

Perbaikan:

  • buat capability map;
  • pisahkan ownership write model;
  • kurangi shared kernel;
  • enforce module dependency;
  • mulai dari boundary paling berisiko: ledger, inventory, workflow.

16.2 Distributed Monolith

Service terpisah secara deployment tetapi saling memanggil sinkron secara rapat dan berbagi skema mental yang sama.

Gejala:

  • satu transaction bisnis butuh 5 service sinkron;
  • deployment satu service sering menunggu service lain;
  • failure satu service menjatuhkan use case utama;
  • data ownership tidak jelas;
  • event hanya dipakai sebagai notifikasi setelah coupling terjadi.

Perbaikan:

  • definisikan authority per capability;
  • ubah fakta bisnis menjadi event authoritative;
  • gunakan command boundary yang jelas;
  • hindari query lintas service untuk decision kritis;
  • buat local read model untuk kebutuhan lintas domain.

16.3 Reporting-on-OLTP Collapse

Laporan berat membaca tabel transaksi langsung.

Gejala:

  • posting invoice lambat saat jam laporan;
  • index dibuat khusus report dan memperlambat write;
  • query ad-hoc dari BI mengunci tabel besar;
  • batch close mengganggu operasional harian.

Perbaikan:

  • operational read model;
  • warehouse/lakehouse;
  • CDC/event projection;
  • report snapshot;
  • workload isolation.

16.4 Extension Tanpa Governance

Customization bisa mengubah apa saja.

Gejala:

  • script custom menulis tabel core;
  • upgrade gagal karena extension bergantung pada detail internal;
  • audit tidak tahu logic mana yang berlaku saat transaksi dibuat;
  • tenant A rusak karena perubahan tenant B.

Perbaikan:

  • extension sandbox;
  • stable extension API;
  • versioned config;
  • extension approval lifecycle;
  • observability per extension;
  • prohibition terhadap direct core write.

17. Practice: Mendesain One-Slice ERP Architecture

Latihan 90 menit:

  1. Pilih satu use case: PostVendorInvoice.
  2. Gambar plane yang terlibat: UI, access, command, AP, GL, data, outbox, audit, reporting.
  3. Tentukan authoritative write model.
  4. Tentukan event yang keluar.
  5. Tentukan read model yang diperbarui.
  6. Tentukan failure mode: duplicate command, period closed, missing vendor account, ledger imbalance, outbox backlog.
  7. Tulis minimal 5 invariant.
  8. Tulis architecture decision record pendek.

Template ADR:

## Decision
Kita mem-post vendor invoice melalui AP command handler yang membuat subledger posting dan GL journal dalam satu transactional boundary.

## Context
Invoice posting harus menjaga double-entry invariant, period lock, audit evidence, dan idempotency.

## Consequences
- AP dan GL harus berada dekat di core transactional runtime.
- Event keluar melalui transactional outbox.
- Reporting membaca projection, bukan tabel posting langsung.
- Integrasi payment memakai event `VendorInvoicePosted`.

18. Review Checklist

Gunakan checklist ini untuk menilai reference architecture ERP:

  • Apakah setiap capability punya owner write authority?
  • Apakah command dan query dipisahkan secara eksplisit?
  • Apakah ledger dan dokumen legal punya audit trail yang kuat?
  • Apakah workflow mengontrol transisi state, bukan sekadar status field?
  • Apakah authorization mempertimbangkan tenant, legal entity, branch, role, data scope, dan SoD?
  • Apakah integration flow punya idempotency, retry, DLQ, dan reconciliation?
  • Apakah reporting berat dipisahkan dari OLTP?
  • Apakah extension point aman dari direct write ke core table?
  • Apakah config punya versioning, scope, effective date, dan approval?
  • Apakah observability mencakup business metrics, bukan hanya latency/CPU?
  • Apakah deployment shape dipilih berdasarkan constraint, bukan tren?
  • Apakah ada rescue path saat posting, workflow, batch, atau integration gagal?

19. Mental Model Akhir

Reference architecture ERP bukan diagram statis. Ia adalah sistem boundary.

Boundary yang harus selalu terlihat:

  • siapa boleh menulis fakta bisnis;
  • siapa boleh membaca dan dari mana;
  • transaksi mana harus atomic;
  • transaksi mana boleh eventual;
  • state mana legal;
  • correction mana harus reversal;
  • extension mana aman;
  • integrasi mana perlu rekonsiliasi;
  • laporan mana boleh membaca data real-time dan mana harus membaca snapshot/projection;
  • evidence apa yang dibutuhkan ketika transaksi dipertanyakan.

Jika boundary ini tidak eksplisit, ERP akan tetap bisa berjalan, tetapi sulit dipercaya ketika skala, audit, customization, dan integrasi mulai meningkat.

20. Source Notes

Beberapa referensi faktual yang relevan untuk konteks arsitektur Java ERP modern:

  • Spring Boot System Requirements: https://docs.spring.io/spring-boot/system-requirements.html
  • Jakarta EE Platform 11: https://jakarta.ee/specifications/platform/11/
  • Apache OFBiz Project: https://ofbiz.apache.org/
  • Martin Fowler, Monolith First: https://martinfowler.com/bliki/MonolithFirst.html
  • Martin Fowler, Microservices: https://martinfowler.com/articles/microservices.html

Referensi ini tidak dipakai sebagai template tunggal. Seri ini mengambil prinsip yang stabil: modularity, ownership, integration reliability, transactional correctness, dan evolvability.

Lesson Recap

You just completed lesson 03 in start here. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.