Writing custom Loan COB business steps in Apache Fineract

Add country or institution specific end-of-day logic to the Fineract Loan COB job by writing a business step, registering it through a database migration and ordering it with the steps API.

On this page

When a custom Loan COB business step in Apache Fineract is the right change

A custom Loan COB business step is a piece of your own Spring Batch logic that runs inside the Close of Business job, the end-of-day process that Apache Fineract uses to update loan accounts. It fits when an institution needs a country or institution specific end-of-day rule on loans, such as a provisioning adjustment, a regulatory flag or a supplementary accrual, and the standard job does not perform it. Before writing code, confirm that the rule must run at close of business and cannot be handled by a product setting, a scheduled batch job that runs at another time, or a repayment transaction processor. Those alternatives are usually cheaper to test and easier to upgrade.

The Close of Business job processes loan accounts in sequence of business steps, and on deployments with millions of accounts it can run for several hours. Each step you add extends that window and, if it fails, can hold up the business date rollover for the whole tenant. Ask the business owner for the exact trigger, the accounts it applies to, the expected run time per account and the action if the step fails. Ask your platform team how the job is partitioned across worker nodes, since a step that is safe in a single node may behave differently under remote partitioning coordinated through ActiveMQ or Kafka.

Custom steps belong in a custom module, not in the Fineract core sources. A module keeps your logic separate from the upstream code, so you can rebuild it against each new 1.x release and show auditors exactly what changed. Plan for the module to ship in your container image, with its database migration and job configuration versioned alongside it. Confirm the target release with the Apache Fineract platform documentation before you start, because the Spring Batch and job registration details must match the version you run in production.

How to build and register a custom COB business step

This sequence takes a business step from a Java class in a custom module to a registered, ordered part of the Loan COB job running on your batch instance. Each stage ends with a check you can run, so you know the step is wired in correctly before it touches production loans.

  1. Create the custom module

    A developer creates a new module under the custom folder of your Fineract build, following the project's custom module convention so that it packages with the core application without editing core sources. They set up the build file, declare dependencies on the Fineract modules the step needs, and confirm the module compiles alongside the core code. The check is a local build that succeeds and an application start in which the module's auto-configuration loads with no errors in the startup log.

  2. Implement the business step

    The developer writes the step as a Spring Batch step that the Loan COB job can pick up, limited to the country or institution rule it exists to apply. The step must be restartable, because a COB run can fail partway and be retried, so re-running it must not post the same accounting entry twice. Confirm which loans the step reads, how it obtains the business date, and where it sits relative to the core COB steps in the documentation for your target release. The check is passing unit tests on a sample loan set that cover normal and retried execution.

  3. Register the step with a Liquibase migration

    The developer adds a versioned Liquibase changelog that inserts the registration record for the step into the batch configuration tables, so that every environment receives the same registration through the migration path rather than through manual database edits. Confirm the table names and columns against the release you target before writing the changeset. The check is that, after startup on a write instance, the changelog appears in Liquibase's change history table with the expected identifier and the step is visible to the application.

  4. Set the step order through the steps API

    An operator uses the steps API to place the custom step at a position in the Loan COB sequence chosen during design, such as before a core step that posts interest or after a step that finalizes balances. The position should be recorded in a change request with the reason for it, because the order determines which data the step sees. Confirm the endpoint, request format and ordering rules in the documentation for your release. The check is a read of the configured sequence that shows the custom step at the intended position, matching the signed-off design.

  5. Deploy to write and batch instances

    The operator deploys the image containing the module to the write instance first, because Liquibase migrations run only on write instances, and then to the batch instance that runs the COB job. On Kubernetes, the migration can run separately using the liquibase-only Spring profile. Read instances serve API traffic and do not need the job. The check is that the write instance logs show the changelog executed once, the batch instance starts without running any changelog, and the new step is reported as part of the job configuration.

  6. Verify the step in a test environment

    The team runs a full Loan COB in a test environment with a copy of representative data and a controlled business date, then compares balances, schedules and accounting entries with expected results written from the country or institution rule. The Fineract README notes that COB can run for several hours on deployments with millions of accounts, so schedule test runs with that in mind. The check is a completed job with the custom step recorded as successful in the job execution history, outputs that match the signed-off test cases, and a restarted run that produces no duplicate postings. See the Fineract platform documentation for release-specific details.

Which step ordering and placement option fits your logic

This table compares three places custom logic can sit in the Loan COB sequence: before the standard loan steps, after them, or in place of one. Read each row for when the placement fits, what it changes for accruals and postings, and the main risk. Behaviors the Fineract documentation does not confirm are marked for checking in your own version before you commit to an order.

PlacementWhen it fits and what it changesMain risk and what to verify
Before standard loan stepsFits when standard steps must read a value you set, such as a corrected status or flag. Accruals and postings then use your output.Changes to balances flow into every later step. Verify the step order and the data each standard step reads in your version.
After standard loan stepsFits when logic reads finished accruals and postings, for example a country specific fee or regulatory report. Your postings appear as separate entries.Standard results are not adjusted for your logic, and reversing committed results is harder. Verify whether your step shares a transaction with earlier steps.
Replacing a standard stepFits when a national rule changes how a standard calculation works. Your step must produce every output that later steps depend on.Missing outputs cause silent accrual gaps, and upgrades may conflict with the replaced logic. Verify how your release allows removal or override of a step.
Separate job outside COBFits when the logic does not need to run inside the day close. COB accruals are unchanged, but timing relative to close is yours to manage.Results can drift from COB balances. Verify the job's dependency on the business date and how you sequence it against COB.
Partition aware stepFits when the logic must process large account volumes. Work may split across remote worker nodes coordinated through ActiveMQ or Kafka.A step that assumes all accounts are in one run can miss or double count accounts. Verify partition behavior in your version before production.
Decision ruleChoose the earliest position where your logic has the inputs it needs, and the narrowest change that meets the rule.Wider overrides raise upgrade cost. Test each candidate order against existing products and balances before you commit.

How the step behaves across single node and partitioned deployments

On a single-node deployment, one Fineract instance serves API traffic, applies Liquibase migrations and runs the Close of Business Day job. Your custom step runs in the same process as everything else, so ordering is straightforward and there is no partition coordination to reason about. The risk is restart behavior. On large books, COB can run for hours, and a process restart partway through the step must not leave loans half processed or postings duplicated.

  • Idempotency: Design the step so that a rerun for the same business date produces the same result. Key writes to the business date and loan identifier, and check for existing output before inserting.
  • Liquibase: Migrations run at startup on the only instance, so the step registration is applied before the job first executes. Confirm this order in a non-production environment.
  • Concurrent API activity: Other requests can still change loans while COB runs. Confirm how the business date and locking behave for your version before the step reads or writes loan balances.
  • Restart checks: After a failure, inspect the job execution status and whether the step's output exists for the business date before you rerun anything.
  • Test coverage: Force a restart in the middle of the step in a test environment and confirm that no postings are duplicated.

Before go-live, confirm that an interrupted run followed by a rerun leaves the ledger and loan schedules in the same state as a clean run.

Where custom COB steps fail in production

Custom business steps run inside the Loan COB job, which touches every account on the institution's books and can run for hours. The failures below share one root cause: a step that works on a test tenant can post wrong money, skip work or break on upgrade when it meets production volume, partitioning and business date state. Each card names a check you can run before go-live.

Non-idempotent posting on retry

A remote partition can be retried after a worker fails, so the same account may pass through your step twice. If the step posts a journal entry or applies interest without checking whether it already ran for that account and business date, the entry is duplicated. Make the step derive its effect from account state, such as a marker keyed by account and business date, and test it by running the same partition twice in a non-production tenant and comparing ledger balances.

Hidden dependence on business date

COB steps run against the tenant's business date, which may differ from the server clock and can be moved for testing or catch-up. A step that reads the system date instead of the business date will accrue or age loans on the wrong day. Review every date call in the step, use the date supplied through the job context, and run the step with a back-dated business date to confirm the result matches the intended day.

Ordering changes interest and accrual results

The steps API sets the sequence in which COB steps run, and built-in steps such as interest accrual and posting produce different results depending on whether a custom step runs before or after them. A step that adjusts a balance before accrual changes the amount accrued. Write down the required order for each custom step, set it explicitly through the steps API, and compare accrued interest for a sample loan set under both orders before you choose one.

Migration not applied on the write instance

The database migration that registers your step is a Liquibase change, and Liquibase migrations run only on write instances. If the migration is never applied, the step class exists in the image but is not registered, so it silently never runs. Confirm the change set was applied in the schema history table of the write database, check the step appears in the steps configuration, and on Kubernetes confirm the liquibase-only profile job completed before the application pods rolled.

Runtime growth on large books

The Close of Business Day job can run for several hours on deployments with millions of accounts, and a step that loads each loan with extra queries multiplies that time. Measure the step on a copy of production data with realistic account counts, look for per-account queries that could be batched, and confirm with your operations team how the step affects the COB window. If the job runs on remote partitions, check the step is safe to run on several worker nodes at once.

Upgrades that break the step interface

Custom steps depend on Fineract classes and Spring Batch wiring that can change between releases, and Fineract publishes releases quarterly. A step compiled against one release may fail to load or behave differently after an upgrade. Pin the Fineract version your step was built against, add a test that runs the step through the COB job in CI, and review the release notes for changes to the batch and loan transaction code before planning each upgrade.

Questions teams ask before writing a custom COB step

How much effort does a custom COB business step take to build?

Effort depends mostly on how precisely the institution can state the end-of-day rule, not on the Java code itself. A step that adds one accrual or flag for a single product is small. A step that changes balances, posts journal entries or depends on several products and offices grows quickly, because each branch of the rule needs its own test cases and sign-off. The main cost drivers are the number of rules, how many loan states they touch, whether the step writes to accounting, and how much of the rule must be proven against real product configuration. Ask any partner to break the quote into rule analysis, implementation, test data, performance checks on a production-sized dataset and deployment, and to say which of these recur after go-live.

Can our in-house team write a custom COB step without a partner?

A team with strong Java and Spring Batch experience and a clear owner for the business rule can do it, provided it has a non-production Fineract environment it can run COB against. The harder part is usually not the code but the evidence: reproducing the end-of-day outcome on accounts in each product state, confirming ordering against the built-in steps, and proving the job finishes within the operating window. Teams with no prior Fineract customization experience should plan for a learning period and a review by someone who has delivered Fineract extensions before. Be honest about who will maintain the step after the first release, since that work continues for as long as the step is in use.

What does the institution need to provide for this work?

The institution has to supply the business rule in writing, with worked examples for each product and each exception it wants the step to handle. It also needs named approvers from finance or risk who can confirm the expected results, a staging environment that mirrors production configuration, and representative test data covering loans in arrears, restructured loans, closed accounts and accounts with pending transactions. Without a staging environment that can run COB against realistic volumes, results cannot be trusted. Confirm with your Fineract operations team which database platform, tenant layout and job scheduling settings the staging environment will use, so the test results carry over to production.

How long does COB run, and why does that change the step design?

The project's README notes that the Close of Business Day Spring Batch job can run for several hours on deployments with millions of accounts, and that it supports remote partitioning across worker nodes coordinated through ActiveMQ or Kafka. A custom step runs inside that window, so any slow query, per-account external call or unbatched write is multiplied across every account it touches. Design the step to read in chunks, avoid calls to external systems inside the loop, and keep its writes predictable. Measure its duration on a dataset close to production size, because a step that is fast on a few thousand accounts can still push the job past the time your operations team has available.

What should we do when a Fineract upgrade changes the COB job?

Treat the step as code that depends on the job's internal structure, and test it on every candidate release before production. Fineract releases are created quarterly under the ASF release policy, so a planned upgrade cycle should include a step-by-step check of the job's ordering, its registration migration and any changed step names or interfaces. Keep the custom step in its own module so the diff against upstream is small and easy to review. Ask the partner or internal owner to document which Fineract version the step was tested against, which steps it must run before or after, and what the rollback path is if an upgrade changes the job.

Should a custom COB step be in the same module as other customizations?

Usually not. Keeping the step in its own module makes it easier to review, test and remove, and it limits the blast radius when Fineract changes the job in a later release. The registration database migration, the step class and its configuration should travel together, so that a rollback removes all three. Teams that mix COB logic with repayment processors or custom APIs tend to find upgrades slower, because a change to one area forces a full regression of the others.

What controls should a regulated institution expect around an end-of-day change?

Expect change control, a documented rule owner, test evidence tied to each rule, and a record of who approved the step for production. The step's effect on balances and accounting should be reviewed by finance, not only by engineering. Confirm with your internal audit or compliance function which evidence they need, such as test results, peer review records and deployment logs, because the format they accept determines how much work goes into the release. This page does not cover certification. Independent auditors and certification bodies decide whether controls meet a given framework.

What DeployOpen delivers for a custom COB step engagement

A custom COB step engagement delivers four things in writing before any code is written: the business rule specification, the custom module, the registration migration and the test evidence. The written scope comes first. It states which end-of-day behavior is being added, which products and accounts it applies to, what data it reads and writes, and how it must behave when a step fails partway through a run. Scope, deliverables and timelines are agreed in writing before work starts, so the business owner, the risk function and the engineering team sign off on the same rule before a line of Java is written.

The engineering deliverables are a custom module that implements the business step and its tasklet, a database migration that registers the step, and a configuration change that places it in the ordering set through the steps API. The test plan covers ordering against the standard COB steps, behavior on a business date with real loan states, rerun behavior after a failure and the effect on accounting entries. The test evidence is delivered with the code so your audit and release teams can see what was run, against which Fineract version and with which test data. Deployment notes cover the migration run on the write instance, the Liquibase step and any required tenant configuration, and handover covers the runbook for operators who will troubleshoot the COB job later.

Ask any partner to show the exact list of deliverables, the acceptance criteria for each one and who owns the decision if the business rule changes mid-build. Ongoing support after handover, such as upgrades to later 1.x releases, regression runs and changes to the rule, is available as a retainer and is priced separately from the fixed-scope build. Confirm with your partner which of these items sit inside the fixed scope and which would be a change request, because most cost overruns on COB work come from rule changes that were not written down at the start.

How DeployOpen scopes and delivers COB customization

DeployOpen approaches custom Loan COB business steps as a scoped engineering change to a self-hosted Apache Fineract deployment inside your own infrastructure. Each step is specified, built as a module outside the core sources, tested against your products and handed over with documentation your team can run and upgrade.

How we scope

  • Written scope lists each business step, its trigger point in the Loan COB job and the loan products it applies to.
  • Scope records the country or institution rule, its inputs, expected outputs and the accounting or status effects it must produce.
  • Engagements are fixed-scope, with deliverables and timelines agreed in writing before any build work starts.

How we build

  • Steps are implemented in a custom module with a database migration that registers them, keeping Fineract core sources unmodified.
  • Ordering is set through the steps API, and each step's position is documented against the steps around it.
  • Test cases cover business date runs, repeated job executions and loans in mixed states before any environment receives the change.

How we hand over

  • Handover includes the source, migration scripts, ordering configuration and the test suite used for acceptance.
  • Runbooks explain how to check step order, rerun the job safely and read the logs when a step fails.
  • Your team receives a short record of the rule logic, its assumptions and the items to confirm with your compliance owner.

How we support

  • Ongoing support, upgrades and continuous testing are available as retainers after handover.
  • Retainer work can re-run the step tests when Fineract releases or your database platform changes.
  • Support requests are handled against the agreed written scope, with changes to rule logic quoted separately.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.