Reading the repo
Reading the repo
Saved setup from 8 h ago
Will it work on my device?
CONTRIBUTING.mdHello there!
First of all, Thank You for contributing to Apache Fineract! We are grateful for your interest in this project.
Please join the developer mailing list, if you have not already done so, as this is where discussions about this project take place - say Hi there! Please also have a quick look at the Code of Conduct.
The JIRA Dashboard shows what's going on. Create a login - it can take a day or two. If you face difficulties, ask on the mailing list.
You don't need to be a committer to provide pull requests, but Becoming a Committer explains the process of becoming one - just in case...
We need a lot of help besides code changes. For example, we also welcome wiki edits! If you wish to make non-code contributions, please first get involved on the developer mailing list and in chat. Around the time you request wiki access, tell us something like:
Hello! I'm Adam from Seattle, USA and I'd like to help improve the FSIP-78 wiki page. I've submitted a request for wiki edit access.
Here's how to run the set of relatively fast and independent Fineract tests:
./gradlew test -x :twofactor-tests:test -x :oauth2-tests:test -x :integration-tests:test -x :fineract-e2e-tests-runner:test
This runs over 1,500 tests and completes in ~5 minutes on decent hardware. They shouldn't need any special servers/services running.
The integration, two-factor, OAuth2 and Cucumber E2E suites all require a live Fineract instance over HTTP, and the build does not start one for you. Start one first, or every API-dependent test will fail.
The Cucumber E2E tests run against a live Fineract instance. You must start Fineract yourself. Before running them locally, create the required databases and start Fineract:
# Create required databases
./gradlew createPGDB -PdbName=fineract_tenants
./gradlew createPGDB -PdbName=fineract_default
# Start Fineract in another terminal
./gradlew bootRun -Dspring.profiles.active=test
The default E2E test connection settings live in fineract-e2e-tests-core/src/test/resources/fineract-test-application.properties.
By default, the test suite connects to https://localhost:8443.
Many E2E tests require seeded test data.
That setup is controlled by the INITIALIZATION_ENABLED environment variable, which maps to fineract-test.initialization.enabled.
For a fresh database, run the suite from fineract-e2e-tests-runner with initialization enabled first:
cd fineract-e2e-tests-runner
INITIALIZATION_ENABLED=true ../gradlew cucumber
After the initialization data already exists, you can run all E2E tests without it:
cd fineract-e2e-tests-runner
../gradlew cucumber
To run a single feature file:
cd fineract-e2e-tests-runner
../gradlew cucumber -Pcucumber.features="src/test/resources/features/Loan.feature"
See Cucumber E2E Tests for more details and additional options.
Like the Cucumber tests, the integration tests also require a live Fineract instance. Bring one up first. The Docker stack is what CI uses, so it is the configuration these suites are verified against:
# Build the image once
./gradlew :fineract-provider:jibDockerBuild -Djib.to.image=fineract -x test -x cucumber
# Start Fineract plus its database, LocalStack and the mock OAuth2 server
docker compose -f docker-compose-postgresql-test.yml up -d
./gradlew :integration-tests:waitForFineract
./gradlew :integration-tests:test --tests ClientLoanIntegrationTest
Docker is not required, though.
Starting ServerApplication from your IDE or ./gradlew devRun from the command line both work too provided you have a running, initialized database as shown above for the Cucumber tests (and have customized BACKEND_PROTOCOL, BACKEND_HOST, and BACKEND_PORT environment variables as necessary).
:twofactor-tests and :oauth2-tests need the server started in a different authentication mode, and docker-compose-war-test.yml runs the WAR in a stock Tomcat instead of the Spring Boot jar; see Integration Testing for those and for the BACKEND_* variables that point the suites at a non-default address.
Running tests with external dependencies is a multi-step process with many moving parts. Sometimes there are arbitrary failures and the prerequisite setup can be daunting. A full local integration test run (on a developer workstation) covering every possible test using every external service and every supported relational database engine could take an entire day - and that's assuming everything is properly configured and runs as expected.
Right now we depend on GitHub to know if "the build" is passing (it's actually multiple builds).
The authoritative source of truth for what commands/services/tests to run, how, and when are the files in .github/workflows/.
Output from runs based on those configuration files appears at https://github.com/apache/fineract/actions.
Incorrect default Java-related executables may cause test failures. To fix this on Debian and Ubuntu systems, run the following:
export JAVA_HOME=/usr/lib/jvm/zulu25
sudo update-alternatives --set java $JAVA_HOME/bin/java
sudo update-alternatives --set javac $JAVA_HOME/bin/javac
sudo update-alternatives --set javadoc $JAVA_HOME/bin/javadoc
This would correct, for example, a class file version error. You might see something like this if a Java 11 executable (class file format version 56) was the system default, but the integration tests were using Java 25 (class file format version 69):
UnsupportedClassVersionError: com.example.package/ClassName has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 55.0
The GitHub builds are run in short-lived virtual machines, so locally reproducing the same may require additional effort, such as these extra clean-up procedures:
# Might fix `error: cannot find symbol` or other intermittent failures.
# `doc` here is a placeholder for any task(s) you are trying to run.
# 💚 This is generally very safe to run between builds.
./gradlew --refresh-dependencies doc
# Destroy anything untracked by git.
# ⚠️ This may delete something important, e.g. a finely-tuned IDE configuration.
git clean --force -dx
# Destroy various caches and configs.
# ⚠️ This may delete gibibytes of cached data, making the next build very slow.
rm -rf ~/.gradle ~/.m2
# Tear down the test stack, including its database volume.
# ⚠️ This discards the data of the instance the integration tests were running against.
docker compose -f docker-compose-postgresql-test.yml down -v
Integration test runs such as
./gradlew --no-daemon --console=plain test -x :twofactor-tests:test \
-x :oauth2-tests:test -x :fineract-e2e-tests-runner:test
in .github/workflows/run-integration-test-sequentially-postgresql.yml often take an hour or longer to complete.
If you notice the :integration-tests:test task taking significantly less time, say, one minute, gradle may be skipping it.
Look for something like this in the test output:
Task :integration-tests:test UP-TO-DATE 👀 Custom actions are attached to task ':integration-tests:test'. Build cache key for task ':integration-tests:test' is 6aeeec3f58bf9703d4c100fbaa657f5c Skipping task ':integration-tests:test' as it is up-to-date.
(This is with the --info gradle argument with eyeballs added for emphasis.)
The --rerun-tasks gradle argument may help, or you can try destroying ~/.gradle and other clean-up procedures as indicated above, then re-running tests.
This is useful for repeated test runs (say, for timing) when gradle would otherwise assume a task is "up-to-date" and not re-run it.
See the next section for testing in Eclipse and here for testing in IntelliJ.
./gradlew rat. A report will be generated under build/reports/rat/rat-report.txtRun the following command:
./gradlew doc
Some dependencies are required (e.g. Ghostscript, Graphviz), see .github/workflows/build-documentation.yml for hints.
IDEs such as IntelliJ are useful for editing the AsciiDoc source files while providing a live rendered preview.
HTML rendered from the AsciiDoc source files is also available online at https://fineract.apache.org/docs/develop/.
Apache Fineract can be developed using multiple IDEs. The most commonly used and supported IDEs are:
The sections below provide setup guidance for each IDE.
It is possible to run Fineract in Eclipse IDE and also to debug Fineract using Eclipse's debugging facilities. To do this, you need to create the Eclipse project files and import the project into an Eclipse workspace:
./gradlew cleanEclipse eclipseIf you change the project settings (dependencies etc) in Gradle, you should redo step 1 and refresh the project in Eclipse.
You can also use Eclipse JUnit support to run tests in Eclipse (Run As->JUnit Test)
Finally, modifying source code in Eclipse automatically triggers hot code replace to a running instance, allowing you to immediately test your changes
IntelliJ IDEA provides strong Gradle integration and is recommended for most new contributors.
fineract directorygradlew) when askedorg.apache.fineract.ServerApplication as a Java Application./gradlew clean build from the terminalThis project enforces its code conventions using checkstyle.xml through Checkstyle and fineractdev-formatter.xml through Spotless. They are configured to run automatically during the normal Gradle build, and fail if there are any violations detected. You can run the following command to automatically fix spotless violations:
./gradlew spotlessApply
Since some checks are present in both Checkstyle and Spotless, the same command can help you fix some of the Checkstyle violations too.
You can also check solely for Spotless violations, but normally don't have to, because regular builds already include this:
./gradlew spotlessCheck
We recommend that you configure your favourite Java IDE to match those conventions. For Eclipse, you can go to Window > Java > Code Style and import the aforementioned config/fineractdev-formatter.xml under formatter section and config/fineractdev-cleanup.xml under cleanup section.
You could also use Checkstyle directly in your IDE, but you don't have to: it may just be more convenient for you. For Eclipse, use https://checkstyle.org/eclipse-cs/ and load our checkstyle.xml into it. For IntelliJ you can use CheckStyle-IDEA.
Changed or added code should ideally have test coverage.
The project uses Jacoco to measure unit tests code coverage. To generate a report run the following command:
./gradlew clean build jacocoTestReport
Generated reports can be found in the build/code-coverage directory.
The project uses Lombok to reduce boilerplate code. Configuration is in lombok.config.
@Getter / @Setter / @NoArgsConstructor on JPA entities. Never use @Data on entities (causes JPA lazy loading issues).@RequiredArgsConstructor on service classes for constructor-based dependency injection.@Slf4j for logging instead of manually declaring loggers.@Data for simple DTOs (includes getters, setters, toString, equals, hashCode).@Builder with @Builder.Default for configuration classes and complex object construction.@SneakyThrows - handle exceptions explicitly.catch (SomeException e) and then either throw AnotherException("..details..", e) or LOG.error("...context...", e).@Test void testXYZ() throws SomeException, AnotherException..., so that the test fails if the exception happens. Unless you actually really want to test for the occurrence of a problem - in that case, use JUnit's Assert.assertThrows() (but not @Test(expected = SomeException.class)).NullPointerException & Co.System.out and System.err or printStackTrace() anywhere, but always LOG.info() or LOG.error() instead.LOG.error("Could not... details: {}", something, exception)) and never String concatenation (LOG.error("Could not... details: " + something, exception))LOG.error() should be used to inform an "operator" running Fineract who supervises error logs of an unexpected condition. This includes technical problems with an external "environment" (e.g. can't reach a database), and situations which are likely bugs which need to be fixed in the code. They do NOT include e.g. validation errors for incoming API requests - that is signaled through the API response - and does (should) not be logged as an error. (Note that there is no FATAL level in SLF4J; a "FATAL" event should just be logged as an ERROR.)LOG.warn() should be using sparingly. Make up your mind if it's an error (above) - or not!LOG.info() can be used notably for one-time actions taken during start-up. It should typically NOT be used to print out "regular" application usage information. The default logging configuration always outputs the application INFO logs, and in production under load, there's really no point to constantly spew out lots of information from frequently traversed paths in the code about what's going on. (Metrics are a better way.) LOG.info() can be used freely in tests though.LOG.debug() can be used anywhere in the code to log things that may be useful during investigations of specific problems. They are not shown in the default logging configuration, but can be enabled for troubleshooting. Developers should typically "turn down" most LOG.info() which they used while writing a new feature to "follow along what happens during local testing" to LOG.debug() for production before we merge their PRs.LOG.trace() is not used in Fineract.Assisted-By: TOOL-MODEL-VERSION trailer(s) in commit log messages, e.g. Assisted-By: botcoder-poem-5.1.This project uses a number of 3rd-party libraries. We have set up Renovate's bot to automatically raise Pull Requests for our review when new dependencies are available.
Our ClasspathHellDuplicatesCheckRuleTest detects classes that appear in more than 1 JAR. If a version bump in build.gradle causes changes in transitives dependencies, then you may have to add related exclude to our dependencies.gradle. Running ./gradlew dependencies helps to understand what is required.
Your PR title must include a JIRA issue and a one-liner that describes the changes. Start your one-liner after the JIRA issue id. Use an upper case present-tense imperative verb and a short but concise clear description. (E.g. "FINERACT-821: Add enforced HideUtilityClassConstructor checkstyle").
If your PR is failing to pass our CI build due to a test failure, then:
AccountingScenarioIntegrationTest you would find FINERACT-899.Then run bash setup.sh. It stops at the first error and is safe to run again. Servers and tests aren't started; it lists them at the end. Read it first.
Needs Git: xcode-select --install
git clone https://github.com/apache/fineract.git cd fineract
JDK 25
brew install openjdk@25
./gradlew build -x test
./gradlew bootRun
Alternatively, you can run fineract on a local kubernetes cluster using minikube.
As prerequisite you must have minikube and kubectl installed on your machine; see
Minikube & Kubectl install.
To run a new Fineract instance on Minikube you can simply:
git clone https://github.com/apache/fineract.git
cd fineract/kubernetes
minikube start
./kubectl-startup.sh
Wait for all pods to be ready:
kubectl get pods -w
Once all pods are running, access the Mifos web application:
minikube service mifos-community
This opens the Mifos X web application in your browser. The nginx reverse proxy in the mifos-community pod forwards API requests to the fineract-server backend.
Default credentials:
mifospasswordYou can also access the Fineract API directly:
minikube service fineract-server --url --https
Fineract is now running at the printed URL, which you can check e.g. using:
http --verify=no --timeout 240 --check-status get $(minikube service fineract-server --url --https)/fineract-provider/actuator/health
To check the status of your containers on your local minikube Kubernetes cluster, run:
minikube dashboard
You can check Fineract logs using:
kubectl logs deployment/fineract-server
You can check Mifos web app logs using:
kubectl logs deployment/mifos-community
To shutdown and reset your cluster, run:
./kubectl-shutdown.sh
There are two use-cases where external message broker is needed:
External Events are business events, e.g.: ClientCreated, which might be important for third party systems. Apache Fineract supports ActiveMQ (or other JMS compliant brokers) and Apache Kafka endpoints for sending out Business Events. By default, they are not emitted.
In case of a large deployment with millions of accounts, the Close of Business Day Spring Batch job may run several hours. In order to speed up this task, remote partitioning of the job is supported. The Manager node partitions breaks up the COB job into smaller pieces (sub tasks), which then can be executed on multiple Worker nodes in parallel. The worker nodes are notified either by ActiveMQ or Kafka regarding their new sub tasks.
No reports for macOS yet.
Claude reads the 10 key files and writes a step-by-step guide for macOS. Once written, it's saved for everyone.