FINERACT-1470: Fineract release plugin
This commit is contained in:
committed by
Aleksandar Vidakovic
parent
b185937962
commit
40eb547a5c
@@ -0,0 +1,42 @@
|
||||
= Design Overview
|
||||
|
||||
NOTE: The implementation of the platform code to process commands through handlers whilst supporting maker-checker and authorisation checks is a little bit convoluted at present and is an area pin-pointed for clean up to make it easier to on board new platform developers. In the mean time below content is used to explain its workings at present.
|
||||
|
||||
.CQRS
|
||||
image::{imagesdir}/command-query.png[]
|
||||
|
||||
Taking into account example shown above for the *users* resource.
|
||||
|
||||
* Query: GET /users
|
||||
* HTTPS API: retrieveAll method on *org.apache.fineract.useradministration.api.UsersApiResource* invoked
|
||||
* UsersApiResource.retrieveAll: Check user has permission to access this resources data.
|
||||
* UsersApiResource.retrieveAll: Use 'read service' to fetch all users data ('read services' execute simple SQL queries against Database using JDBC)
|
||||
* UsersApiResource.retrieveAll: Data returned to coverted into JSON response
|
||||
* Command: POST /users (Note: data passed in request body)
|
||||
* HTTPS API: create method on org.apache.fineract.useradministration.api.UsersApiResource invoked
|
||||
|
||||
.UsersApiResource.create
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/useradministration/api/UsersApiResource.java[lines=168..188]
|
||||
----
|
||||
|
||||
.Create a CommandWrapper object that represents this create user command and JSON request body. Pass off responsiblity for processing to PortfolioCommandSourceWritePlatformService.logCommandSource
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java[lines=69..129]
|
||||
----
|
||||
|
||||
.Check user has permission for this action. if ok, a) parse the json request body, b) create a JsonCommand object to wrap the command details, c) use CommandProcessingService to handle command
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/fineract-provider/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java[lines=84..150]
|
||||
----
|
||||
|
||||
NOTE: if a RollbackTransactionAsCommandIsNotApprovedByCheckerException occurs at this point. The original transaction will of been aborted and we only log an entry for the command in the audit table setting its status as 'Pending'.
|
||||
|
||||
* Check that if maker-checker configuration enabled for this action. If yes and this is not a 'checker' approving the command - rollback at the end. We rollback at the end in order to test if the command will pass 'domain validation' which requires commit to database for full check.
|
||||
* findCommandHandler - Find the correct Hanlder to process this command.
|
||||
* Process command using handler (In transactional scope).
|
||||
* CommandSource object created/updated with all details for logging to 'm_portfolio_command_source' table.
|
||||
* In update scenario, we check to see if there where really any changes/updates. If so only JSON for changes is stored in audit log.
|
||||
@@ -0,0 +1,41 @@
|
||||
= Functional Overview
|
||||
|
||||
As ALL capabilities of the platform are exposed through an API, The API docs are the best place to view a detailed breakdown of what the platform does. See online API Documentation.
|
||||
|
||||
.Platform Functional Overview
|
||||
image::{imagesdir}/platform-categories.png[]
|
||||
|
||||
At a higher level though we see the capabilities fall into the following categories:
|
||||
|
||||
* Infrastructure
|
||||
** Codes
|
||||
** Extensible Data Tables
|
||||
** Reporting
|
||||
|
||||
* User Administration
|
||||
** Users
|
||||
** Roles
|
||||
** Permissions
|
||||
|
||||
* Organisation Modelling
|
||||
** Offices
|
||||
** Staff
|
||||
** Currency
|
||||
|
||||
* Product Configuration
|
||||
** Charges
|
||||
** Loan Products
|
||||
** Deposit Products
|
||||
|
||||
* Client Data
|
||||
** Know Your Client (KYC)
|
||||
|
||||
* Portfolio Management
|
||||
** Loan Accounts
|
||||
** Deposit Accounts
|
||||
** Client/Groups
|
||||
|
||||
* GL Account Management
|
||||
** Chart of Accounts
|
||||
** General Ledger
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
= History
|
||||
|
||||
== The Idea
|
||||
|
||||
Fineract was an idea born out of a wish to create and deploy technology that allows the microfinance industry to scale. The goal is to:
|
||||
|
||||
* Produce a gold standard management information system suitable for microfinance operations
|
||||
* Acts as the basis of a platform for microfinance
|
||||
* Open source, owned and driven by member organisations in the community
|
||||
* Enabling potential for eco-system of providers located near to MFIs
|
||||
|
||||
== Timeline
|
||||
|
||||
* 2006: Project intiated by Grameen Foundation
|
||||
* Late 2011: Grameen Foundation handed over full responsibility to open source community.
|
||||
* 2012: Mifos X platform started. Previous members of project come together under the name of Community for Open Source Microfinance (COSM / OpenMF)
|
||||
* 2013: COSM / OpenMF officially rebranded to Mifos Initiative and receive US 501c3 status.
|
||||
* 2016: Fineract 1.x began incubation at Apache
|
||||
@@ -0,0 +1,25 @@
|
||||
= Architecture
|
||||
|
||||
This document captures the major architectural decisions in platform. The purpose of the document is to provide a guide to the overall structure of the platform; where it fits in the overall context of an MIS solution and its internals so that contributors can more effectively understand how changes that they are considering can be made, and the consequences of those changes.
|
||||
|
||||
The target audience for this report is both system integrators (who will use the document to gain an understanding of the structure of the platform and its design rationale) and platform contributors who will use the document to reason about future changes and who will update the document as the system evolves.
|
||||
|
||||
include::history.adoc[leveloffset=+1]
|
||||
|
||||
include::resources.adoc[leveloffset=+1]
|
||||
|
||||
include::system.adoc[leveloffset=+1]
|
||||
|
||||
include::functional.adoc[leveloffset=+1]
|
||||
|
||||
include::principles.adoc[leveloffset=+1]
|
||||
|
||||
include::design.adoc[leveloffset=+1]
|
||||
|
||||
include::persistence.adoc[leveloffset=+1]
|
||||
|
||||
include::validation.adoc[leveloffset=+1]
|
||||
|
||||
include::technology.adoc[leveloffset=+1]
|
||||
|
||||
include::modules.adoc[leveloffset=+1]
|
||||
@@ -0,0 +1,250 @@
|
||||
= Modules
|
||||
|
||||
Currently modules are a proof of concept feature in Fineract.
|
||||
|
||||
== How to create a Fineract module
|
||||
|
||||
NOTE: At the moment the only module we have that follows these stricter guidelines is the example module we describe in detail in the next section. In the future we will try to split up Fineract's monolithic code base and move features (like loan product, accounts etc.) to separate modules as described here. Before that happens we need to do some code cleanups first.
|
||||
|
||||
1. Create a folder under `module` and name it _mymodule_.
|
||||
1. Create a folder named _core_ under `module/mymodule`.
|
||||
1. Create a folder named _service_ under `module/mymodule`.
|
||||
1. Create a folder named _starter_ under `module/mymodule`.
|
||||
1. Setup folders and Gradle build files for a Java project under `core`, `service` and `starter`.
|
||||
1. Create a text file called _spring.factories in folder `modules/mymodule/starter/src/main/resources/META-INF`.
|
||||
+
|
||||
The final folder and file structure should look somewhat like this:
|
||||
+
|
||||
[plantuml, format=svg]
|
||||
----
|
||||
include::{diagramsdir}/modules-folder-structure.puml[]
|
||||
----
|
||||
|
||||
1. Make sure that your new modules are present in settings.gradle:
|
||||
+
|
||||
[source,groovy]
|
||||
----
|
||||
rootProject.name='fineract'
|
||||
include ':module:mymodule:core' // <.>
|
||||
include ':module:mymodule:service'
|
||||
include ':module:mymodule:starter'
|
||||
include ':fineract-provider'
|
||||
include ':fineract-war'
|
||||
include ':integration-tests'
|
||||
include ':twofactor-tests'
|
||||
include ':oauth2-tests'
|
||||
include ':fineract-client'
|
||||
include ':fineract-doc'
|
||||
----
|
||||
<.> The `settings.gradle` file should contain something like this (and following).
|
||||
|
||||
== How to replace an existing Fineract service
|
||||
|
||||
Creating customizations for Fineract services is easy. The method described here will work both with our future module guidelines (aka "clean room" modules) and with the intermediary solution we will put in place to avoid major refactorings.
|
||||
|
||||
You can of course choose whatever folder/project structure you like for your custom modules. But we'll describe here some best practices to avoid merge conflicts when fetching updates from Fineract's upstream Git repository. For the time being we suggest to create your custom modules in the same folder as Fineract in a forked Git repo.
|
||||
|
||||
As soon as we can publish Fineract module JARs to Maven Central you'll have more freedom to setup your projects (including to setup separate Git repos).
|
||||
|
||||
1. Create a folder under `custom` and name it _mycustom_.
|
||||
1. Create a folder named _service_ under `custom/mycustom`.
|
||||
1. Setup folders and Gradle build files for a Java project under `service`.
|
||||
1. Create a text file called _spring.factories in folder `modules/mymodule/starter/src/main/resources/META-INF`:
|
||||
+
|
||||
[source,properties]
|
||||
----
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.apache.fineract.mymodule.starter.MyAutoConfiguration
|
||||
----
|
||||
+
|
||||
The final folder and file structure should look somewhat like this:
|
||||
+
|
||||
[plantuml, format=svg]
|
||||
----
|
||||
include::{diagramsdir}/custom-folder-structure.puml[]
|
||||
----
|
||||
+
|
||||
Please make sure that your `service` module's build.gradle file has a unique group:
|
||||
+
|
||||
[source,groovy]
|
||||
----
|
||||
description = 'My Company: Fineract My Custom Service'
|
||||
|
||||
group = 'com.mycompany.fineract.custom.service' // <.>
|
||||
|
||||
apply from: 'dependencies.gradle'
|
||||
----
|
||||
+
|
||||
<.> The best choice here is to name it like you would name your JAR artifact on Maven Central.
|
||||
|
||||
1. Make sure that your custom modules are present in settings.gradle: :
|
||||
+
|
||||
[source,groovy]
|
||||
----
|
||||
rootProject.name='fineract'
|
||||
include ':custom:mycustom:service' // <.>
|
||||
include ':fineract-provider'
|
||||
include ':fineract-war'
|
||||
include ':integration-tests'
|
||||
include ':twofactor-tests'
|
||||
include ':oauth2-tests'
|
||||
include ':fineract-client'
|
||||
include ':fineract-doc'
|
||||
----
|
||||
<.> The `settings.gradle` file should contain something like this.
|
||||
1. The dependency.gradle file could look something like this:
|
||||
[source,groovy]
|
||||
----
|
||||
dependencies {
|
||||
implementation(project(':module:mymodule:core'), // <.>
|
||||
'org.springframework:spring-context')
|
||||
compileOnly project(':fineract-provider') // <.>
|
||||
}
|
||||
----
|
||||
<.> If you are replacing a "clean room" module then you just need to include a dependency on the modules `core` library.
|
||||
<.> If you are replacing a service that is not yet extracted from `fineract-provider` then you need to add a dependency on it (only needed during compilation).
|
||||
1. When the custom module is built then you can add the JAR in your Fineract's libs folder (or in Tomcat's libs folder if you are deploying as a WAR app).
|
||||
|
||||
IMPORTANT: Do not include your custom module in `fineract-provider`'s dependency.gradle file. This creates a circular dependency and will fail your build. Instead you have to add your JAR file e. g. to the Docker image (in Fineract's libs folder; similar like we do it with Pentaho reporting). This setup will give you the best developer experience for now with proper source references until we have separate JAR files ready on Maven Central. In the next section we describe the "clean room" (read: where we want to go) type of modules and their customization/replacement; so don't be confused if you see the dependency appearing in `fineract-provider`'s dependency.gradle, in the future you'll be able to do that.
|
||||
|
||||
== Example
|
||||
|
||||
=== Dummy Module Structure
|
||||
|
||||
We've created a demonstration how modules are supposed to be used. A module has usually at least two sub-modules:
|
||||
|
||||
1. a _core_ module that contains mostly Java interfaces of the services and/or other components that we'd like to make replacable. The _core_ module could also contain data (DTO) or domain (entity) classes if necessary.
|
||||
2. a _service_ module
|
||||
|
||||
IMPORTANT: Replacing parts of the existing REST API and extending it with custom endpoints is at the moment out of scope. Probably we'll need to cleanup and improve the REST layer quite a bit (remove boilerplate code as much as possible, use Jackson for JSON de-/serialization instead of the manual GSON mappers/helper everywhere) before this can happen. For now we'll concentrate primarily on service classes.
|
||||
|
||||
Let's assume we have a service `DummyService` in our system. The service is outlined as a Java interface in module folder `module/dummy/core`.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/module/dummy/core/src/main/java/org/apache/fineract/dummy/core/service/DummyService.java[lines=19..]
|
||||
----
|
||||
|
||||
To make it a little bit more interesting the service's only function returns a simple data object that has one string attribute:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/module/dummy/core/src/main/java/org/apache/fineract/dummy/core/data/DummyMessage.java[lines=19..]
|
||||
----
|
||||
|
||||
A default implementation of `DummyService` is provided with `DummyServiceImpl`:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/module/dummy/service/src/main/java/org/apache/fineract/dummy/service/DummyServiceImpl.java[lines=19..]
|
||||
----
|
||||
|
||||
As you can see there are no annotations like `@Service` or `@Component`. To have full control over the instantiation and dependency injection we provide a so called _starter_ module. This module just contains one or more (auto-) configuration classes. In this case it's just one configuration class. This is basically a very simple Spring Java configuration class annotated with `@Configuration` containing one method that instantiates our default service implementation (annotated with `@Bean`):
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/module/dummy/starter/src/main/java/org/apache/fineract/dummy/starter/DummyAutoConfiguration.java[lines=19..]
|
||||
----
|
||||
|
||||
The interesting part is this line:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/module/dummy/starter/src/main/java/org/apache/fineract/dummy/starter/DummyAutoConfiguration.java[lines=28..28]
|
||||
----
|
||||
|
||||
This annotation ensures that our default implementation is only instantiated if no other implementation for `DummyService` is provided. There's only one piece missing to make auto configuration work seamlessly and without any explicit configuration in `fineract-provider`:
|
||||
|
||||
[source,properties]
|
||||
----
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.apache.fineract.dummy.starter.DummyAutoConfiguration
|
||||
----
|
||||
|
||||
This means if we would only include the following dependencies in our main project (e. g. `fineract-provider`)...
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
dependencies {
|
||||
implementation project(':module:dummy:core')
|
||||
implementation project(':module:dummy:service')
|
||||
implementation project(':module:dummy:starter')
|
||||
}
|
||||
----
|
||||
|
||||
\... then the message object would contain
|
||||
|
||||
[source,text]
|
||||
----
|
||||
Hello: DEFAULT DUMMY!
|
||||
----
|
||||
|
||||
=== Replace the default implementation of DummyService
|
||||
|
||||
This is why we created module `foo` in folder `module/foo`. There's only only one sub-module that contains an implementation of `DummyService` that will replace the default implementation:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/custom/foo/service/src/main/java/com/acmecorp/fineract/foo/service/FooDummyServiceImpl.java[lines=19..]
|
||||
----
|
||||
|
||||
As you can see we have no other sub-modules (e. g. there's no starter module) and this implementation contains the well known `@Service` annotation. If we add this dependency to our main project...
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
dependencies {
|
||||
implementation project(':module:dummy:core')
|
||||
implementation project(':module:dummy:service')
|
||||
implementation project(':module:dummy:starter')
|
||||
implementation project(':custom:foo:service')
|
||||
}
|
||||
----
|
||||
|
||||
\... then the expected behavior is that we'll get the message
|
||||
|
||||
[source,text]
|
||||
----
|
||||
Hello: Foo!
|
||||
----
|
||||
|
||||
=== Testing
|
||||
|
||||
There's a simple unit test in `fineract-provider` that demonstrates both scenarios (without any override of the default implementation and with an overriding alternative implementation)
|
||||
|
||||
[source,gherkin]
|
||||
----
|
||||
include::{rootdir}/fineract-provider/src/test/resources/features/module/modules.example.feature[]
|
||||
----
|
||||
|
||||
Here's the Spring Java configuration that does *NOT* load the `foo` module:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/fineract-provider/src/test/java/org/apache/fineract/module/example/TestDefaultConfiguration.java[lines=19..]
|
||||
----
|
||||
|
||||
\... and here's the configuration that loads the `foo` module (and overrides the deefault implementation)
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/fineract-provider/src/test/java/org/apache/fineract/module/example/TestFooConfiguration.java[lines=19..]
|
||||
----
|
||||
|
||||
The important part in the `foo` configuration is this line:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{rootdir}/fineract-provider/src/test/java/org/apache/fineract/module/example/TestFooConfiguration.java[lines=26..26]
|
||||
----
|
||||
|
||||
=== Deployment
|
||||
|
||||
Modules (better: the JAR files) only need to be dropped in Fineract's `libs` folder. Dynamic loading of external JARs is provided since Fineract version 1.5.0.
|
||||
|
||||
=== How can I start replacing services now
|
||||
|
||||
As said the "clean room" modules will take a while to arrive. In the meanwhile we'll prepare the existing monolithic code base for pluggability. As a proof of concept the services `org.apache.fineract.portfolio.note.service.NoteReadPlatformService` and `org.apache.fineract.portfolio.note.service.NoteWritePlatformService` can be replaced/overriden by custom implementations. We'll add more shortly and will list them here. Reach out on the mailing list if you need a specific service to be replaceable.
|
||||
|
||||
=== Outlook
|
||||
|
||||
If this proof of concept is accepted we could refactor Fineract's services one by one and rearrange them in the proposed module structure. As discussed at ApacheCon 2021 there will be most likely some work to do to properly extract those modules (loan product, client, savings account etc.) from the monolithic code base. The main challenge are cross-dependencies between the _modules_, but there are major benefits if we split up the code like this. One - as demonstrated - is the replacement of existing default functionality. But with modules we'll also be able to finally publish Fineract JAR files to Maven Central. Those JAR files can be used to write extensions and customizations *WITHOUT* forking the whole Fineract Github repository. With modules users will also be able to create custom Fineract distributions, e. g. slimmed down to contain only the bare minimum needed in production.
|
||||
@@ -0,0 +1,64 @@
|
||||
= Persistence
|
||||
|
||||
TBD
|
||||
|
||||
== Database support
|
||||
|
||||
Fineract supports multiple databases:
|
||||
|
||||
* MySQL compatible databases (e.g. MariaDB)
|
||||
* PostgreSQL
|
||||
|
||||
The platform differentiates between these database types in certain cases when there's a need to use some database specific tooling. To do so, the platform examines the JDBC driver used for running the platform and tries to determine which database is being used.
|
||||
|
||||
The currently supported JDBC driver and corresponding mappings can be found below.
|
||||
|
||||
[cols="1,1"]
|
||||
|===
|
||||
|*JDBC driver class name*
|
||||
|*Resolved database type*
|
||||
|
||||
|`org.mariadb.jdbc.Driver`
|
||||
|MySQL
|
||||
|
||||
|`com.mysql.jdbc.Driver`
|
||||
|MySQL
|
||||
|
||||
|`org.postgresql.Driver`
|
||||
|PostgreSQL
|
||||
|
||||
|===
|
||||
|
||||
The actual code can be found in the `DatabaseTypeResolver` class.
|
||||
|
||||
== Data-access layer
|
||||
|
||||
The data-access layer of Fineract is implemented by using JPA (Java Persistence API) with the EclipseLink provider.
|
||||
Despite the fact that JPA is used quite extensively in the system, there are cases where the performance is a key element for an operation therefore you can easily find native SQLs as well.
|
||||
|
||||
The data-access layer of Fineract is compatible with different databases. Since a lot of the native queries are using specific database functions, a wrapper class - `DatabaseSpecificSQLGenerator` - has been introduced to handle these database specifics. Whenever there's a need to rely on new database level functions, make sure to extend this class and implement the specific functions provided by the database.
|
||||
|
||||
Fineract has been developed for 10+ years by the community and unfortunately there are places where entity relationships are configured with `EAGER` fetching strategy. This must not confuse anybody. The long-term goal is to use the `LAZY` fetching strategy for every single relationship. If you're about to introduce a new one, make sure to use `LAZY` as a fetching strategy, otherwise your PR will be rejected.
|
||||
|
||||
== Database schema migration
|
||||
|
||||
As for every system, the database structure will and need to evolve over time. Fineract is no different. Originally for Fineract, Flyway was used until Fineract 1.6.x.
|
||||
|
||||
After 1.6.x, PostgreSQL support was added to the platform hence there was a need to make the data-access layer and the schema migration as database independent as possible. Becuase of that, from Fineract 1.7.0, Flyway is not used anymore but Liquibase is.
|
||||
|
||||
Some of the changesets in the Liquibase changelogs have database specifics into it but they only run for the relevant databases. This is controller by Liquibase contexts.
|
||||
|
||||
The currently available Liquibase contexts are:
|
||||
|
||||
* `mysql` - only set when the database is a MySQL compatible database (e.g. MariaDB)
|
||||
* `postgresql` - only set when the database is a PostgreSQL database
|
||||
* configured Spring active profiles
|
||||
* `tenant_store_db` - only set when the database migration runs the Tenant Store upgrade
|
||||
* `tenant_db` - only set when the database migration runs the Tenant upgrade
|
||||
* `initial_switch` - this is a technical context and should *NOT* be used
|
||||
|
||||
The switch from Flyway (1.6.x) to Liquibase (1.7.x) was planned to be as smooth as possible so there's no need for manual work hence the behavior is described as following:
|
||||
|
||||
* If the database is empty, Liquibase will create the database schema from scratch
|
||||
* If the database contains the latest Fineract 1.6.x database structure which was previously migrated with Flyway. Liquibase will seamlessly upgrade it to the latest version. Note: the Flyway related 2 database tables are left as they are and are not deleted.
|
||||
* If the database contains an earlier version of the database structure than Fineract 1.6.x. Liquibase will *NOT* do anything and *will fail the application during startup*. The proper approach in this case is to first upgrade your application version to the latest Fineract 1.6.x so that the latest Flyway changes are executed and then upgrade to the newer Fineract version where Liquibase will seamlessly take over the database upgrades.
|
||||
@@ -0,0 +1,63 @@
|
||||
= Principles
|
||||
|
||||
== RESTful API
|
||||
|
||||
The platform exposes all its functionality via a *practically-RESTful API*, that communicates using JSON.
|
||||
|
||||
We use the term *practically-RESTful* in order to make it clear we are not trying to be fully REST compliant but still maintain important RESTful attributes like:
|
||||
|
||||
* Stateless: platform maintains no conversational or session-based state. The result of this is ability to scale horizontally with ease.
|
||||
* Resource-oriented: API is focussed around set of resources using HTTP vocabulary and conventions e.g GET, PUT, POST, DELETE, HTTP status codes. This results in a simple and consistent API for clients.
|
||||
|
||||
See online API Documentation for more detail.
|
||||
|
||||
== Multi-tenanted
|
||||
|
||||
The Fineract platform has been developed with support for multi-tenancy at the core of its design. This means that it is just as easy to use the platform for Software-as-a-Service (SaaS) type offerings as it is for local installations.
|
||||
|
||||
The platform uses an approach that isolates an FIs data per database/schema (See Separate Databases and Shared Database, Separate Schemas).
|
||||
|
||||
== Extensible
|
||||
|
||||
Whilst each tenant will have a set of core tables, the platform tables can be extended in different ways for each tenant through the use of Data tables functionality.
|
||||
|
||||
== Command Query Seperation
|
||||
|
||||
We seperate *commands* (that change data) from *queries* (that read data).
|
||||
|
||||
Why? There are numerous reasons for choosing this approach which at present is not an attempt at full blown CQRS. The main advantages at present are:
|
||||
|
||||
* State changing commands are persisted providing an audit of all state changes.
|
||||
* Used to support a general approach to *maker-checker*.
|
||||
* State changing commands use the Object-Oriented paradign (and hence ORM) whilst querys can stay in the data paradigm.
|
||||
|
||||
== Maker-Checker
|
||||
|
||||
Also known as *four-eyes principal*. Enables apps to support a maker-checker style workflow process. Commands that pass validation will be persisted. Maker-checker can be enabled/disabled at fine-grained level for any state changing API.
|
||||
Fine grained access control
|
||||
|
||||
A fine grained permission is associated with each API. Administrators have fine grained control over what roles or users have access to.
|
||||
|
||||
== Package Structure
|
||||
|
||||
The intention is for platform code to be packaged in a vertical slice way (as opposed to layers).
|
||||
Source code starts from https://github.com/apache/fineract/tree/develop/fineract-provider/src/main/java/org/apache/fineract
|
||||
|
||||
* accounting
|
||||
* useradministration
|
||||
* infrastructure
|
||||
* portfolio
|
||||
** charge
|
||||
** client
|
||||
** fund
|
||||
** loanaccount
|
||||
* accounting
|
||||
|
||||
Within each vertical slice is some common packaging structure:
|
||||
|
||||
* api - XXXApiResource.java - REST api implementation files
|
||||
* handler - XXXCommandHandler.java - specific handlers invoked
|
||||
* service - contains read + write services for functional area
|
||||
* domain - OO concepts for the functional area
|
||||
* data - Data concepts for the area
|
||||
* serialization - ability to convert from/to API JSON for functional area
|
||||
@@ -0,0 +1,5 @@
|
||||
= Resources
|
||||
|
||||
* Project URL is https://github.com/apache/fineract
|
||||
* Issue tracker is https://issues.apache.org/jira/projects/FINERACT/summary
|
||||
* Download from http://fineract.apache.org/
|
||||
@@ -0,0 +1,18 @@
|
||||
= System Overview
|
||||
|
||||
.Platform System Overview
|
||||
image::{imagesdir}/platform-systemview.png[]
|
||||
|
||||
Financial institutions deliver their services to customers through a variety of means today.
|
||||
|
||||
* Customers can call direct into branches (teller model)
|
||||
* Customers can organise into groups (or centers) and agree to meetup at a location and time with FI staff (traditional microfinance).
|
||||
* An FI might have a public facing information portal that customers can use for variety of reasons including account management (online banking).
|
||||
* An FI might be integrated into a ATM/POS/Card services network that the customer can use.
|
||||
* An FI might be integrated with a mobile money operator and support mobile money services for customer (present/future microfinance).
|
||||
* An FI might use third party agents to sell on products/services from other banks/FIs.
|
||||
|
||||
As illustrated in the above diagram, the various stakeholders leverage business apps to perform specific customer or FI related actions. The functionality contained in these business apps can be bundled up and packaged in any way. In the diagram, several of the apps may be combined into one app or any one of the blocks representing an app could be further broken up as needed.
|
||||
|
||||
The platform is the core engine of the MIS. It hides alot of the complexity that exists in the business and technical domains needed for an MIS in FIs behind a relatively simple API. It is this API that frees up app developers to innovate and produce apps that can be as general or as bespoke as FIs need them to be.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
= Technology
|
||||
|
||||
* Java: http://www.oracle.com/technetwork/java/javase/downloads/index.html
|
||||
* JAX-RS using Jersey
|
||||
* JSON using Google GSON
|
||||
* Spring I/O Platform: http://spring.io/platform
|
||||
** Spring Framework
|
||||
** Spring Boot
|
||||
** Spring Security
|
||||
** Spring Data (JPA) backed by EclipseLink
|
||||
* MySQL: http://www.oracle.com/us/products/mysql/overview/index.html
|
||||
* PostgreSQL
|
||||
|
||||
TBD
|
||||
@@ -0,0 +1,32 @@
|
||||
= Validation
|
||||
|
||||
== Programmatic
|
||||
|
||||
Use the https://github.com/apache/fineract/search?q=%22class+DataValidatorBuilder%22[DataValidatorBuilder], e.g. like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
new DataValidatorBuilder().resource("fileUpload")
|
||||
.reset().parameter("Content-Length").value(contentLength).notBlank().integerGreaterThanNumber(0)
|
||||
.reset().parameter("FormDataContentDisposition").value(fileDetails).notNull()
|
||||
.throwValidationErrors();
|
||||
----
|
||||
|
||||
Such code is often encapsulated in https://github.com/apache/fineract/search?q=Validator[`*Validator`] classes (if more than a few lines, and/or reused from several places; avoid copy/paste), like so:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
public class YourThingValidator {
|
||||
|
||||
public void validate(YourThing thing) {
|
||||
new DataValidatorBuilder().resource("yourThing")
|
||||
...
|
||||
.throwValidationErrors();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
== Declarative
|
||||
|
||||
[FINERACT-1229](https://issues.apache.org/jira/browse/FINERACT-1229) is an open issue about adopting Bean Validation for _declarative_ instead of _programmatic_ (as above) validation. Contributions welcome!
|
||||
Reference in New Issue
Block a user