FINCN-351 Make the scorecard integration into a plugin

  - Credit Scorecard module:

     - Credit Scorecard organisational module API
     - Rule Based and ML Scoring Entities
     - Credit Scorecard Validators and JSON assemblers
     - Credit Scorecard Read and Write Services
     - Credit Scorecard Flyway Migration
     - Credit scorecard Loan Product Feature Configurations
     - Credit Scorecard integration in Loan Account Creation
     - FINCN-331 Statistical Credit Scorecard
diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
index b21dfa8..5fe9490 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
@@ -3442,4 +3442,28 @@
         return this;
     }
 
+    public CommandWrapperBuilder createCreditScorecardFeature() {
+        this.actionName = "CREATE";
+        this.entityName = "CREDIT_SCORECARD_FEATURE";
+        this.entityId = null;
+        this.href = "/scorecard/features/template";
+        return this;
+    }
+
+    public CommandWrapperBuilder updateCreditScorecardFeature(Long featureId) {
+        this.actionName = "UPDATE";
+        this.entityName = "CREDIT_SCORECARD_FEATURE";
+        this.entityId = featureId;
+        this.href = "/scorecard/features/" + featureId;
+        return this;
+    }
+
+    public CommandWrapperBuilder deleteCreditScorecardFeature(Long featureId) {
+        this.actionName = "DELETE";
+        this.entityName = "CREDIT_SCORECARD_FEATURE";
+        this.entityId = featureId;
+        this.href = "/scorecard/features/" + featureId;
+        return this;
+    }
+
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/provider/ReportingProcessServiceProvider.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/provider/ReportingProcessServiceProvider.java
index 84e812a..f6feae9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/provider/ReportingProcessServiceProvider.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/provider/ReportingProcessServiceProvider.java
@@ -49,6 +49,7 @@
                 mapBuilder.put(type, s);
             }
             LOGGER.info("Registered report service '{}' for type/s '{}'", s, reportTypes);
+            LOGGER.warn("Registered report service '{}' for type/s '{}'", s, reportTypes);
         }
         this.reportingProcessServices = mapBuilder.build();
     }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/domain/AccountTransferTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/domain/AccountTransferTransaction.java
index a4c34bf..312b486 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/domain/AccountTransferTransaction.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/domain/AccountTransferTransaction.java
@@ -25,6 +25,7 @@
 import javax.persistence.Column;
 import javax.persistence.Embedded;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Table;
@@ -40,23 +41,23 @@
 @Table(name = "m_account_transfer_transaction")
 public class AccountTransferTransaction extends AbstractPersistableCustom {
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "account_transfer_details_id", nullable = true)
     private AccountTransferDetails accountTransferDetails;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "from_savings_transaction_id", nullable = true)
     private SavingsAccountTransaction fromSavingsTransaction;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "to_savings_transaction_id", nullable = true)
     private SavingsAccountTransaction toSavingsTransaction;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "to_loan_transaction_id", nullable = true)
     private LoanTransaction toLoanTransaction;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "from_loan_transaction_id", nullable = true)
     private LoanTransaction fromLoanTransaction;
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/annotation/ScorecardService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/annotation/ScorecardService.java
new file mode 100644
index 0000000..0d7e1d4
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/annotation/ScorecardService.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.springframework.stereotype.Service;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+@Service
+public @interface ScorecardService {
+
+    /**
+     * @return the name of the service
+     */
+    String name();
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/api/CreditScorecardApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/api/CreditScorecardApiResource.java
new file mode 100644
index 0000000..40b3e24
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/api/CreditScorecardApiResource.java
@@ -0,0 +1,237 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+import org.apache.fineract.commands.domain.CommandWrapper;
+import org.apache.fineract.commands.service.CommandWrapperBuilder;
+import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
+import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
+import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardFeature;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardReadPlatformService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Path("/creditScorecard")
+@Component
+@Scope("singleton")
+@Tag(name = "CreditScorecard", description = "")
+public class CreditScorecardApiResource {
+
+    private final Set<String> featuresDataParameters = new HashSet<>(
+            Arrays.asList("id", "name", "valueType", "dataType", "category", "valueTypeOptions", "dataTypeOptions", "categoryOptions"));
+
+    private final String resourceNameForPermissions = "CREDIT_SCORECARD";
+
+    private final PlatformSecurityContext context;
+    private final ScorecardServiceProvider scorecardServiceProvider;
+    private final ScorecardServiceProvider serviceProvider;
+    private final DefaultToApiJsonSerializer<CreditScorecardFeatureData> toApiJsonSerializer;
+    private final ApiRequestParameterHelper apiRequestParameterHelper;
+    private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
+
+    @Autowired
+    public CreditScorecardApiResource(final PlatformSecurityContext context, final ScorecardServiceProvider scorecardServiceProvider,
+            final ScorecardServiceProvider serviceProvider,
+            final DefaultToApiJsonSerializer<CreditScorecardFeatureData> toApiJsonSerializer,
+            final ApiRequestParameterHelper apiRequestParameterHelper,
+            final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
+        this.context = context;
+        this.scorecardServiceProvider = scorecardServiceProvider;
+        this.serviceProvider = serviceProvider;
+        this.toApiJsonSerializer = toApiJsonSerializer;
+        this.apiRequestParameterHelper = apiRequestParameterHelper;
+        this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
+    }
+
+    @GET
+    @Path("features")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieve Scorecard Features", description = "Returns the list of defined scorecard features.\n" + "\n"
+            + "Example Requests:\n" + "\n" + "features")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = CreditScorecardApiResourceSwagger.GetScorecardFeatureResponse.class)))) })
+    public String retrieveAllScoringFeatures(@Context final UriInfo uriInfo) {
+
+        this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
+
+        final String serviceName = "CreditScorecardReadPlatformService";
+        final CreditScorecardReadPlatformService scorecardService = (CreditScorecardReadPlatformService) scorecardServiceProvider
+                .getScorecardService(serviceName);
+
+        if (scorecardService == null) {
+            throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                    ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+        }
+
+        final Collection<CreditScorecardFeatureData> scoringFeatures = scorecardService.findAllFeaturesWithNotFoundDetection().stream()
+                .map(CreditScorecardFeature::toData).collect(Collectors.toList());
+
+        final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+        return this.toApiJsonSerializer.serialize(settings, scoringFeatures, this.featuresDataParameters);
+    }
+
+    @GET
+    @Path("features/{featureId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieve a Scorecard Feature", description = "Returns the details of a defined Scorecard Feature.\n" + "\n"
+            + "Example Requests:\n" + "\n" + "scorecard/features/1")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CreditScorecardApiResourceSwagger.GetScorecardFeatureResponse.class))) })
+    public String retrieveScoringFeature(@PathParam("featureId") @Parameter(description = "featureId") final Long featureId,
+            @Context final UriInfo uriInfo) {
+
+        this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
+
+        final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+
+        CreditScorecardFeatureData scorecardFeature = null;
+        if (settings.isTemplate()) {
+
+            final String serviceName = "CreditScorecardReadPlatformService";
+            final CreditScorecardReadPlatformService scorecardService = (CreditScorecardReadPlatformService) scorecardServiceProvider
+                    .getScorecardService(serviceName);
+
+            if (scorecardService == null) {
+                throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                        ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+            }
+
+            scorecardFeature = scorecardService.findOneFeatureWithNotFoundDetection(featureId).toData();
+            final CreditScorecardFeatureData templateData = scorecardService.retrieveNewScorecardFeatureDetails();
+            scorecardFeature = CreditScorecardFeatureData.withTemplate(scorecardFeature, templateData);
+        }
+
+        return this.toApiJsonSerializer.serialize(settings, scorecardFeature, this.featuresDataParameters);
+    }
+
+    @GET
+    @Path("features/template")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieve Scorecard Feature Template", description = "This is a convenience resource. It can be useful when building maintenance user interface screens for client applications. The template data returned consists of any or all of:\n"
+            + "\n" + "Field Defaults\n" + "Allowed description Lists\n" + "Example Request:\n" + "\n" + "scorecard/features/template\n")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CreditScorecardApiResourceSwagger.GetScorecardFeaturesTemplateResponse.class))) })
+    public String retrieveNewScorecardFeatureDetails(@Context final UriInfo uriInfo) {
+
+        this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
+
+        final String serviceName = "CreditScorecardReadPlatformService";
+        final CreditScorecardReadPlatformService scorecardService = (CreditScorecardReadPlatformService) scorecardServiceProvider
+                .getScorecardService(serviceName);
+
+        if (scorecardService == null) {
+            throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                    ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+        }
+
+        final CreditScorecardFeatureData scorecardFeature = scorecardService.retrieveNewScorecardFeatureDetails();
+
+        final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+        return this.toApiJsonSerializer.serialize(settings, scorecardFeature, this.featuresDataParameters);
+    }
+
+    @POST
+    @Path("features")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Create/Define a Scorecard Feature", description = "Define a new scorecard feature that can later be associated with loans and savings through their respective product definitions or directly on each account instance.")
+    @RequestBody(required = true, content = @Content(schema = @Schema(implementation = CreditScorecardApiResourceSwagger.PostScorecardFeatureRequest.class)))
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CreditScorecardApiResourceSwagger.PostScorecardFeatureResponse.class))) })
+    public String createScoringFeature(@Parameter(hidden = true) final String apiRequestBodyAsJson) {
+
+        final CommandWrapper commandRequest = new CommandWrapperBuilder().createCreditScorecardFeature().withJson(apiRequestBodyAsJson)
+                .build();
+
+        final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+
+        return this.toApiJsonSerializer.serialize(result);
+    }
+
+    @PUT
+    @Path("features/{featureId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Update a Scorecard Feature", description = "Updates the details of a Scorecard Feature.")
+    @RequestBody(required = true, content = @Content(schema = @Schema(implementation = CreditScorecardApiResourceSwagger.PutScorecardFeaturesFeatureIdRequest.class)))
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CreditScorecardApiResourceSwagger.PutScorecardFeaturesFeatureIdResponse.class))) })
+    public String updateScoringFeature(@PathParam("featureId") @Parameter(description = "featureId") final Long featureId,
+            @Parameter(hidden = true) final String apiRequestBodyAsJson) {
+
+        final CommandWrapper commandRequest = new CommandWrapperBuilder().updateCreditScorecardFeature(featureId)
+                .withJson(apiRequestBodyAsJson).build();
+
+        final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+
+        return this.toApiJsonSerializer.serialize(result);
+    }
+
+    @DELETE
+    @Path("features/{featureId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Delete a Scorecard Feature", description = "Deletes a Scorecard Feature.")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CreditScorecardApiResourceSwagger.DeleteScorecardFeaturesFeatureIdResponse.class))) })
+    public String deleteScoringFeature(@PathParam("featureId") @Parameter(description = "featureId") final Long featureId) {
+
+        final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteCreditScorecardFeature(featureId).build();
+
+        final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+
+        return this.toApiJsonSerializer.serialize(result);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/api/CreditScorecardApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/api/CreditScorecardApiResourceSwagger.java
new file mode 100644
index 0000000..92af466
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/api/CreditScorecardApiResourceSwagger.java
@@ -0,0 +1,133 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.api;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.util.Set;
+
+public class CreditScorecardApiResourceSwagger {
+
+    @Schema(description = "GetScorecardFeatureResponse")
+    public static final class GetScorecardFeatureResponse {
+
+        private GetScorecardFeatureResponse() {
+            //
+        }
+
+        static final class GetScorecardFeatureValueTypeResponse {
+
+            @Schema(example = "1")
+            public Integer id;
+            @Schema(example = "valueType.nominal")
+            public String code;
+            @Schema(example = "Nominal")
+            public String description;
+        }
+
+        static final class GetScorecardFeatureDataTypeResponse {
+
+            @Schema(example = "1")
+            public Integer id;
+            @Schema(example = "dataType.string")
+            public String code;
+            @Schema(example = "String")
+            public String description;
+        }
+
+        static final class GetScorecardFeatureCategoryResponse {
+
+            @Schema(example = "0")
+            public Integer id;
+            @Schema(example = "category.individual")
+            public String code;
+            @Schema(example = "Individual")
+            public String description;
+        }
+    }
+
+    @Schema(description = "PostScorecardFeatureRequest")
+    public static final class PostScorecardFeatureRequest {
+
+        private PostScorecardFeatureRequest() {}
+
+        @Schema(example = "Gender")
+        public String name;
+        @Schema(example = "1")
+        public Integer valueType;
+        @Schema(example = "1")
+        public String dataType;
+        @Schema(example = "1")
+        public Integer category;
+        @Schema(example = "true")
+        public String active;
+        @Schema(example = "en")
+        public String locale;
+    }
+
+    @Schema(description = "PostScorecardFeatureResponse")
+    public static final class PostScorecardFeatureResponse {
+
+        private PostScorecardFeatureResponse() {}
+
+        @Schema(example = "1")
+        public Integer resourceId;
+    }
+
+    @Schema(description = "PutScorecardFeaturesFeatureIdRequest")
+    public static final class PutScorecardFeaturesFeatureIdRequest {
+
+        private PutScorecardFeaturesFeatureIdRequest() {}
+
+        @Schema(example = "Loan service fee(changed)")
+        public String name;
+    }
+
+    @Schema(description = "PutScorecardFeaturesFeatureIdResponse")
+    public static final class PutScorecardFeaturesFeatureIdResponse {
+
+        private PutScorecardFeaturesFeatureIdResponse() {}
+
+        @Schema(example = "1")
+        public Integer resourceId;
+        public PutScorecardFeaturesFeatureIdResponse changes;
+    }
+
+    @Schema(description = "DeleteScorecardFeaturesFeatureIdResponse")
+    public static final class DeleteScorecardFeaturesFeatureIdResponse {
+
+        private DeleteScorecardFeaturesFeatureIdResponse() {}
+
+        @Schema(example = "1")
+        public Integer resourceId;
+    }
+
+    @Schema(description = "GetScorecardFeaturesTemplateResponse")
+    public static final class GetScorecardFeaturesTemplateResponse {
+
+        private GetScorecardFeaturesTemplateResponse() {}
+
+        @Schema(example = "false")
+        public String active;
+        @Schema(example = "false")
+        public String penalty;
+        public Set<GetScorecardFeatureResponse.GetScorecardFeatureValueTypeResponse> valueTypeOptions;
+        public Set<GetScorecardFeatureResponse.GetScorecardFeatureDataTypeResponse> dataTypeOptions;
+        public Set<GetScorecardFeatureResponse.GetScorecardFeatureCategoryResponse> categoryOptions;
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/CreditScorecardData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/CreditScorecardData.java
new file mode 100644
index 0000000..118c985
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/CreditScorecardData.java
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+
+public final class CreditScorecardData implements Serializable {
+
+    private final Long id;
+    private final String scoringMethod;
+    private final String scoringModel;
+
+    private final MLScorecardData mlScorecard;
+    private final StatScorecardData statScorecard;
+    private final RuleBasedScorecardData ruleBasedScorecard;
+
+    // Options
+    private final Collection<Map<String, Object>> scoringMethods;
+
+    private CreditScorecardData(final Long id, final String scoringMethod, final String scoringModel, final MLScorecardData mlScorecard,
+            final StatScorecardData statScorecard, final RuleBasedScorecardData ruleBasedScorecard,
+            final Collection<Map<String, Object>> scoringMethods) {
+        this.id = id;
+        this.scoringMethod = scoringMethod;
+        this.scoringModel = scoringModel;
+
+        this.mlScorecard = mlScorecard;
+        this.statScorecard = statScorecard;
+        this.ruleBasedScorecard = ruleBasedScorecard;
+
+        this.scoringMethods = scoringMethods;
+    }
+
+    public static CreditScorecardData instance(final Long id, final String scoringMethod, final String scoringModel) {
+        final MLScorecardData mlScorecardData = null;
+        final StatScorecardData statScorecardData = null;
+        final RuleBasedScorecardData ruleBasedScorecardData = null;
+
+        final Collection<Map<String, Object>> scoringMethods = null;
+
+        return new CreditScorecardData(id, scoringMethod, scoringModel, mlScorecardData, statScorecardData, ruleBasedScorecardData,
+                scoringMethods);
+    }
+
+    public static CreditScorecardData ruleBasedInstance(final Long id, final String scoringMethod, final String scoringModel,
+            final RuleBasedScorecardData ruleBasedScorecard) {
+        final MLScorecardData mlScorecardData = null;
+        final StatScorecardData statScorecardData = null;
+
+        final Collection<Map<String, Object>> scoringMethods = null;
+
+        return new CreditScorecardData(id, scoringMethod, scoringModel, mlScorecardData, statScorecardData, ruleBasedScorecard,
+                scoringMethods);
+    }
+
+    public static CreditScorecardData statInstance(Long id, String scoringMethod, String scoringModel,
+            StatScorecardData statScorecardData) {
+        final MLScorecardData mlScorecardData = null;
+        final RuleBasedScorecardData ruleBasedScorecardData = null;
+
+        final Collection<Map<String, Object>> scoringMethods = null;
+
+        return new CreditScorecardData(id, scoringMethod, scoringModel, mlScorecardData, statScorecardData, ruleBasedScorecardData,
+                scoringMethods);
+    }
+
+    public static CreditScorecardData mlInstance(final Long id, final String scoringMethod, final String scoringModel,
+            final MLScorecardData mlScorecard) {
+        final StatScorecardData statScorecardData = null;
+        final RuleBasedScorecardData ruleBasedScorecardData = null;
+
+        final Collection<Map<String, Object>> scoringMethods = null;
+
+        return new CreditScorecardData(id, scoringMethod, scoringModel, mlScorecard, statScorecardData, ruleBasedScorecardData,
+                scoringMethods);
+    }
+
+    public static CreditScorecardData loanTemplate() {
+        final Long id = null;
+        final String scoringMethod = null;
+        final String scoringModel = null;
+
+        final MLScorecardData mlScorecardData = MLScorecardData.template();
+        final StatScorecardData statScorecardData = StatScorecardData.template();
+        final RuleBasedScorecardData ruleBasedScorecardData = RuleBasedScorecardData.template();
+
+        final Collection<Map<String, Object>> scoringMethods = new ArrayList<>(
+                Arrays.asList(Map.of("code", "ruleBased", "value", "Rule Based"), Map.of("code", "stat", "value", "Statistical"),
+                        Map.of("code", "ml", "value", "Machine Learning")));
+
+        return new CreditScorecardData(id, scoringMethod, scoringModel, mlScorecardData, statScorecardData, ruleBasedScorecardData,
+                scoringMethods);
+    }
+
+    public static CreditScorecardData loanScorecardWithTemplate(CreditScorecardData sc) {
+
+        final Collection<Map<String, Object>> scoringMethods = new ArrayList<>(
+                Arrays.asList(Map.of("code", "ruleBased", "value", "Rule Based"), Map.of("code", "stat", "value", "Statistical"),
+                        Map.of("code", "ml", "value", "Machine Learning")));
+
+        final StatScorecardData statScorecardData = StatScorecardData.template();
+        final RuleBasedScorecardData ruleBasedScorecardData = RuleBasedScorecardData.template();
+
+        if (sc == null) {
+            return null;
+        }
+
+        return new CreditScorecardData(sc.id, sc.scoringMethod, sc.scoringModel, sc.mlScorecard, sc.statScorecard, sc.ruleBasedScorecard,
+                scoringMethods);
+    }
+
+    public Long getId() {
+        return id;
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/CreditScorecardFeatureData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/CreditScorecardFeatureData.java
new file mode 100644
index 0000000..07788c0
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/CreditScorecardFeatureData.java
@@ -0,0 +1,203 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.jetbrains.annotations.NotNull;
+
+public final class CreditScorecardFeatureData implements Comparable<CreditScorecardFeatureData>, Serializable {
+
+    private final Long id;
+    private final Long featureId;
+    private final String name;
+    private final EnumOptionData valueType;
+    private final EnumOptionData dataType;
+    private final EnumOptionData category;
+    private final Boolean active;
+
+    private final BigDecimal weightage;
+    private final Integer greenMin;
+    private final Integer greenMax;
+    private final Integer amberMin;
+    private final Integer amberMax;
+    private final Integer redMin;
+    private final Integer redMax;
+
+    private final Collection<ScorecardFeatureCriteriaData> criteria;
+
+    private final Collection<EnumOptionData> valueTypeOptions;
+    private final Collection<EnumOptionData> dataTypeOptions;
+    private final Collection<EnumOptionData> categoryOptions;
+
+    public CreditScorecardFeatureData(final Long id, final Long featureId, final String name, final EnumOptionData valueType,
+            final EnumOptionData dataType, final EnumOptionData category, final Boolean active, final BigDecimal weightage,
+            final Integer greenMin, final Integer greenMax, final Integer amberMin, final Integer amberMax, final Integer redMin,
+            final Integer redMax, final Collection<ScorecardFeatureCriteriaData> criteria,
+            final Collection<EnumOptionData> valueTypeOptions, final Collection<EnumOptionData> dataTypeOptions,
+            final Collection<EnumOptionData> categoryOptions) {
+        this.id = id;
+
+        this.featureId = featureId;
+        this.name = name;
+        this.valueType = valueType;
+        this.dataType = dataType;
+        this.category = category;
+        this.active = active;
+
+        this.weightage = weightage;
+        this.greenMin = greenMin;
+        this.greenMax = greenMax;
+        this.amberMin = amberMin;
+        this.amberMax = amberMax;
+        this.redMin = redMin;
+        this.redMax = redMax;
+
+        this.criteria = criteria;
+
+        this.valueTypeOptions = valueTypeOptions;
+        this.dataTypeOptions = dataTypeOptions;
+        this.categoryOptions = categoryOptions;
+    }
+
+    public static CreditScorecardFeatureData instance(final Long id, final Long featureId, final String name,
+            final EnumOptionData valueType, final EnumOptionData dataType, final EnumOptionData category, final Boolean active,
+            final BigDecimal weightage, final Integer greenMin, final Integer greenMax, final Integer amberMin, final Integer amberMax,
+            final Integer redMin, final Integer redMax) {
+
+        final Collection<ScorecardFeatureCriteriaData> criteria = new ArrayList<>();
+
+        final Collection<EnumOptionData> valueTypeOptions = null;
+        final Collection<EnumOptionData> dataTypeOptions = null;
+        final Collection<EnumOptionData> categoryOptions = null;
+
+        return new CreditScorecardFeatureData(id, featureId, name, valueType, dataType, category, active, weightage, greenMin, greenMax,
+                amberMin, amberMax, redMin, redMax, criteria, valueTypeOptions, dataTypeOptions, categoryOptions);
+    }
+
+    public static CreditScorecardFeatureData template(final Collection<EnumOptionData> valueTypeOptions,
+            final Collection<EnumOptionData> dataTypeOptions, final Collection<EnumOptionData> categoryOptions) {
+
+        final Long id = null;
+        final Long featureId = null;
+        final String name = null;
+        final EnumOptionData valueType = null;
+        final EnumOptionData dataType = null;
+        final EnumOptionData category = null;
+        final Boolean active = null;
+
+        final BigDecimal weightage = null;
+        final Integer greenMin = null;
+        final Integer greenMax = null;
+        final Integer amberMin = null;
+        final Integer amberMax = null;
+        final Integer redMin = null;
+        final Integer redMax = null;
+
+        final Collection<ScorecardFeatureCriteriaData> criteria = null;
+
+        return new CreditScorecardFeatureData(id, featureId, name, valueType, dataType, category, active, weightage, greenMin, greenMax,
+                amberMin, amberMax, redMin, redMax, criteria, valueTypeOptions, dataTypeOptions, categoryOptions);
+    }
+
+    public static CreditScorecardFeatureData withTemplate(CreditScorecardFeatureData scf, CreditScorecardFeatureData template) {
+
+        return new CreditScorecardFeatureData(scf.id, scf.featureId, scf.name, scf.valueType, scf.dataType, scf.category, scf.active,
+                scf.weightage, scf.greenMin, scf.greenMax, scf.amberMin, scf.amberMax, scf.redMin, scf.redMax, scf.criteria,
+                template.valueTypeOptions, template.dataTypeOptions, template.categoryOptions);
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public EnumOptionData getValueType() {
+        return valueType;
+    }
+
+    public EnumOptionData getDataType() {
+        return dataType;
+    }
+
+    public EnumOptionData getCategory() {
+        return category;
+    }
+
+    public Boolean getActive() {
+        return active;
+    }
+
+    public BigDecimal getWeightage() {
+        return weightage;
+    }
+
+    public Integer getGreenMin() {
+        return greenMin;
+    }
+
+    public Integer getGreenMax() {
+        return greenMax;
+    }
+
+    public Integer getAmberMin() {
+        return amberMin;
+    }
+
+    public Integer getAmberMax() {
+        return amberMax;
+    }
+
+    public Integer getRedMin() {
+        return redMin;
+    }
+
+    public Integer getRedMax() {
+        return redMax;
+    }
+
+    public Collection<ScorecardFeatureCriteriaData> getCriteria() {
+        return criteria;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (!(obj instanceof CreditScorecardFeatureData)) {
+            return false;
+        }
+        final CreditScorecardFeatureData creditScorecardFeatureData = (CreditScorecardFeatureData) obj;
+        return this.id.equals(creditScorecardFeatureData.id);
+    }
+
+    @Override
+    public int hashCode() {
+        return this.id.hashCode();
+    }
+
+    @Override
+    public int compareTo(@NotNull CreditScorecardFeatureData obj) {
+        return obj.id.compareTo(this.id);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/FeatureCriteriaScoreData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/FeatureCriteriaScoreData.java
new file mode 100644
index 0000000..1ff799d
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/FeatureCriteriaScoreData.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureCriteriaScore;
+
+public final class FeatureCriteriaScoreData implements Serializable {
+
+    private final Long id;
+    private final String feature;
+    private final String value;
+    private final BigDecimal score;
+    private final String color;
+
+    private FeatureCriteriaScoreData(final Long id, final String feature, final String value, final BigDecimal score, final String color) {
+        this.id = id;
+        this.feature = feature;
+        this.value = value;
+        this.score = score;
+        this.color = color;
+    }
+
+    public static FeatureCriteriaScoreData instance(final FeatureCriteriaScore ctScore) {
+        final String feature = ctScore.getFeature().getScorecardFeature().getName();
+
+        return new FeatureCriteriaScoreData(ctScore.getId(), feature, ctScore.getValue(), ctScore.getScore(), ctScore.getColor());
+    }
+
+    public BigDecimal getScore() {
+        return score;
+    }
+
+    public String getColor() {
+        return color;
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/MLScorecardData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/MLScorecardData.java
new file mode 100644
index 0000000..9add0b4
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/MLScorecardData.java
@@ -0,0 +1,126 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import org.apache.fineract.portfolio.creditscorecard.domain.MLScorecard;
+import org.apache.fineract.portfolio.creditscorecard.domain.MLScorecardFields;
+
+public class MLScorecardData implements Serializable {
+
+    private final Long id;
+    private final Integer age;
+    private final String sex;
+    private final String job;
+    private final String housing;
+    private final BigDecimal creditAmount;
+    private final Integer duration;
+    private final String purpose;
+
+    private final String risk;
+    private final BigDecimal accuracy;
+
+    private final Collection<Map<String, Object>> scoringModels;
+
+    private final Collection<Map<String, Object>> jobOptions;
+    private final Collection<Map<String, Object>> genderOptions;
+    private final Collection<Map<String, Object>> purposeOptions;
+    private final Collection<Map<String, Object>> housingOptions;
+
+    public MLScorecardData(Long id, Integer age, String sex, String job, String housing, BigDecimal creditAmount, Integer duration,
+            String purpose, String risk, BigDecimal accuracy, Collection<Map<String, Object>> scoringModels,
+            Collection<Map<String, Object>> jobOptions, Collection<Map<String, Object>> genderOptions,
+            Collection<Map<String, Object>> purposeOptions, Collection<Map<String, Object>> housingOptions) {
+        this.id = id;
+        this.age = age;
+        this.sex = sex;
+        this.job = job;
+        this.housing = housing;
+        this.creditAmount = creditAmount;
+        this.duration = duration;
+        this.purpose = purpose;
+
+        this.risk = risk;
+        this.accuracy = accuracy;
+
+        this.jobOptions = jobOptions;
+        this.genderOptions = genderOptions;
+        this.purposeOptions = purposeOptions;
+        this.housingOptions = housingOptions;
+        this.scoringModels = scoringModels;
+    }
+
+    public static MLScorecardData instance(final MLScorecard sc) {
+        final MLScorecardFields scf = sc.getScorecardFields();
+
+        final Collection<Map<String, Object>> scoringModels = null;
+
+        final Collection<Map<String, Object>> jobOptions = null;
+        final Collection<Map<String, Object>> genderOptions = null;
+        final Collection<Map<String, Object>> purposeOptions = null;
+        final Collection<Map<String, Object>> housingOptions = null;
+
+        return new MLScorecardData(sc.getId(), scf.getAge(), scf.getSex(), scf.getJob(), scf.getHousing(), scf.getCreditAmount(),
+                scf.getDuration(), scf.getPurpose(), sc.getPredictedRisk(), sc.getAccuracy(), scoringModels, jobOptions, genderOptions,
+                purposeOptions, housingOptions);
+    }
+
+    public static MLScorecardData template() {
+
+        final Long id = null;
+        final Integer age = null;
+        final String sex = null;
+        final String job = null;
+        final String housing = null;
+
+        final BigDecimal creditAmount = null;
+        final Integer duration = null;
+        final String purpose = null;
+
+        final String risk = null;
+        final BigDecimal accuracy = null;
+
+        final Collection<Map<String, Object>> scoringModels = new ArrayList<>(
+                Arrays.asList(Map.of("code", "RandomForestClassifier", "value", "Random Forest Classifier"),
+                        Map.of("code", "GradientBoostClassifier", "value", "Gradient Boost Classifier"),
+                        Map.of("code", "SVC", "value", "SVC"), Map.of("code", "MLP", "value", "MLP")));
+
+        final Collection<Map<String, Object>> jobOptions = new ArrayList<>(
+                Arrays.asList(Map.of("code", 2, "value", "Unemployed"), Map.of("code", 3, "value", "Self-employed")));
+
+        final Collection<Map<String, Object>> purposeOptions = new ArrayList<>(
+                Arrays.asList(Map.of("code", "radio/TV", "value", "Radio/TV"), Map.of("code", "repairs", "value", "Repairs"),
+                        Map.of("code", "business", "value", "Business"), Map.of("code", "education", "value", "Education")));
+
+        final Collection<Map<String, Object>> housingOptions = new ArrayList<>(Arrays.asList(Map.of("code", "own", "value", "Own"),
+                Map.of("code", "free", "value", "Free"), Map.of("code", "rent", "value", "Rent")));
+
+        final Collection<Map<String, Object>> genderOptions = new ArrayList<>(
+                Arrays.asList(Map.of("code", "male", "value", "Male"), Map.of("code", "female", "value", "Female")));
+
+        return new MLScorecardData(id, age, sex, job, housing, creditAmount, duration, purpose, risk, accuracy, scoringModels, jobOptions,
+                genderOptions, purposeOptions, housingOptions);
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/RuleBasedScorecardData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/RuleBasedScorecardData.java
new file mode 100644
index 0000000..c4a10b7
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/RuleBasedScorecardData.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureCriteriaScore;
+import org.apache.fineract.portfolio.creditscorecard.domain.RuleBasedScorecard;
+
+public final class RuleBasedScorecardData implements Serializable {
+
+    private final Long id;
+    private final Collection<FeatureCriteriaScoreData> criteriaScores;
+    private final BigDecimal overallScore;
+    private final String overallColor;
+
+    private final Collection<Map<String, Object>> scoringModels;
+
+    private RuleBasedScorecardData(final Long id, final Collection<FeatureCriteriaScoreData> criteriaScores, final BigDecimal overallScore,
+            final String overallColor, final Collection<Map<String, Object>> scoringModels) {
+        this.id = id;
+        this.criteriaScores = criteriaScores;
+        this.overallScore = overallScore;
+        this.overallColor = overallColor;
+        this.scoringModels = scoringModels;
+    }
+
+    public static RuleBasedScorecardData instance(RuleBasedScorecard rbs) {
+        final List<FeatureCriteriaScore> ctScores = rbs.getCriteriaScores();
+        final List<FeatureCriteriaScoreData> ctScoresData = ctScores.stream().map(FeatureCriteriaScoreData::instance)
+                .collect(Collectors.toList());
+
+        final Collection<Map<String, Object>> scoringModels = null;
+
+        return new RuleBasedScorecardData(rbs.getId(), ctScoresData, rbs.getOverallScore(), rbs.getOverallColor(), scoringModels);
+    }
+
+    public static RuleBasedScorecardData template() {
+        final Long id = null;
+        final Collection<FeatureCriteriaScoreData> criteriaScores = null;
+        final BigDecimal overallScore = null;
+        final String overallColor = null;
+
+        final Collection<Map<String, Object>> scoringModels = new ArrayList<>(
+                Arrays.asList(Map.of("code", "ruleBased", "value", "Rule Based")));
+
+        return new RuleBasedScorecardData(id, criteriaScores, overallScore, overallColor, scoringModels);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/ScorecardFeatureCriteriaData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/ScorecardFeatureCriteriaData.java
new file mode 100644
index 0000000..bc94a3b
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/ScorecardFeatureCriteriaData.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+public final class ScorecardFeatureCriteriaData implements Serializable {
+
+    private final Long id;
+    private final String criteria;
+    private final BigDecimal score;
+
+    private ScorecardFeatureCriteriaData(Long id, String criteria, BigDecimal score) {
+        this.id = id;
+        this.criteria = criteria;
+        this.score = score;
+    }
+
+    public static ScorecardFeatureCriteriaData instance(final Long id, final String criteria, final BigDecimal score) {
+        return new ScorecardFeatureCriteriaData(id, criteria, score);
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/StatScorecardData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/StatScorecardData.java
new file mode 100644
index 0000000..e600246
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/data/StatScorecardData.java
@@ -0,0 +1,117 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import org.apache.fineract.portfolio.creditscorecard.domain.MLScorecardFields;
+import org.apache.fineract.portfolio.creditscorecard.domain.StatScorecard;
+
+public final class StatScorecardData implements Serializable {
+
+    private final Long id;
+    private final Integer age;
+    private final String sex;
+    private final String job;
+    private final String housing;
+    private final BigDecimal creditAmount;
+    private final Integer duration;
+    private final String purpose;
+
+    private final String method;
+
+    private final String color;
+    private final BigDecimal prediction;
+
+    private final BigDecimal wilkisLambda;
+    private final BigDecimal pillaisTrace;
+    private final BigDecimal hotellingLawley;
+    private final BigDecimal roysGreatestRoots;
+
+    private final Collection<Map<String, Object>> scoringModels;
+
+    public StatScorecardData(Long id, Integer age, String sex, String job, String housing, BigDecimal creditAmount, Integer duration,
+            String purpose, String method, String color, BigDecimal prediction, BigDecimal wilkisLambda, BigDecimal pillaisTrace,
+            BigDecimal hotellingLawley, BigDecimal roysGreatestRoots, Collection<Map<String, Object>> scoringModels) {
+        this.id = id;
+        this.age = age;
+        this.sex = sex;
+        this.job = job;
+        this.housing = housing;
+        this.creditAmount = creditAmount;
+        this.duration = duration;
+        this.purpose = purpose;
+
+        this.method = method;
+
+        this.color = color;
+        this.prediction = prediction;
+
+        this.wilkisLambda = wilkisLambda;
+        this.pillaisTrace = pillaisTrace;
+        this.hotellingLawley = hotellingLawley;
+        this.roysGreatestRoots = roysGreatestRoots;
+
+        this.scoringModels = scoringModels;
+    }
+
+    public static StatScorecardData instance(final StatScorecard sc) {
+        final MLScorecardFields scf = sc.getScorecardFields();
+
+        final Collection<Map<String, Object>> scoringModels = null;
+
+        return new StatScorecardData(sc.getId(), scf.getAge(), scf.getSex(), scf.getJob(), scf.getHousing(), scf.getCreditAmount(),
+                scf.getDuration(), scf.getPurpose(), sc.getMethod(), sc.getColor(), sc.getPrediction(), sc.getWilkisLambda(),
+                sc.getPillaisTrace(), sc.getHotellingLawley(), sc.getRoysGreatestRoots(), scoringModels);
+    }
+
+    public static StatScorecardData template() {
+
+        final Long id = null;
+        final Integer age = null;
+        final String sex = null;
+        final String job = null;
+        final String housing = null;
+
+        final BigDecimal creditAmount = null;
+        final Integer duration = null;
+        final String purpose = null;
+
+        final String method = null;
+
+        final String color = null;
+        final BigDecimal prediction = null;
+
+        final BigDecimal wilkisLambda = null;
+        final BigDecimal pillaisTrace = null;
+        final BigDecimal hotellingLawley = null;
+        final BigDecimal roysGreatestRoots = null;
+
+        final Collection<Map<String, Object>> scoringModels = new ArrayList<>(
+                Arrays.asList(Map.of("code", "manova", "value", "Manova"), Map.of("code", "linearRegression", "value", "Linear Regression"),
+                        Map.of("code", "polynomialRegression", "value", "Polynomial Regression")));
+
+        return new StatScorecardData(id, age, sex, job, housing, creditAmount, duration, purpose, method, color, prediction, wilkisLambda,
+                pillaisTrace, hotellingLawley, roysGreatestRoots, scoringModels);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecard.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecard.java
new file mode 100644
index 0000000..b743cc0
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecard.java
@@ -0,0 +1,114 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.util.Objects;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+
+@Entity
+@Table(name = "m_credit_scorecard")
+public class CreditScorecard extends AbstractPersistableCustom {
+
+    @Column(name = "scorecard_scoring_method")
+    private String scoringMethod;
+
+    @Column(name = "scorecard_scoring_model")
+    private String scoringModel;
+
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name = "rule_based_scorecard_id", referencedColumnName = "id")
+    private RuleBasedScorecard ruleBasedScorecard;
+
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name = "stat_scorecard_id", referencedColumnName = "id")
+    private StatScorecard statScorecard;
+
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name = "ml_scorecard_id", referencedColumnName = "id")
+    private MLScorecard mlScorecard;
+
+    public CreditScorecard() {
+        //
+    }
+
+    public CreditScorecard(String scoringMethod, String scoringModel) {
+        this.scoringMethod = scoringMethod;
+        this.scoringModel = scoringModel;
+    }
+
+    public CreditScorecard(String scoringMethod, String scoringModel, RuleBasedScorecard ruleBasedScorecard, StatScorecard statScorecard,
+            MLScorecard mlScorecard) {
+        this.scoringMethod = scoringMethod;
+        this.scoringModel = scoringModel;
+        this.ruleBasedScorecard = ruleBasedScorecard;
+        this.statScorecard = statScorecard;
+        this.mlScorecard = mlScorecard;
+    }
+
+    public String getScoringMethod() {
+        return scoringMethod;
+    }
+
+    public String getScoringModel() {
+        return scoringModel;
+    }
+
+    public RuleBasedScorecard getRuleBasedScorecard() {
+        return ruleBasedScorecard;
+    }
+
+    public StatScorecard getStatScorecard() {
+        return statScorecard;
+    }
+
+    public MLScorecard getMlScorecard() {
+        return mlScorecard;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof CreditScorecard)) {
+            return false;
+        }
+        CreditScorecard that = (CreditScorecard) o;
+        return Objects.equals(scoringMethod, that.scoringMethod) && Objects.equals(scoringModel, that.scoringModel)
+                && Objects.equals(ruleBasedScorecard, that.ruleBasedScorecard) && Objects.equals(statScorecard, that.statScorecard)
+                && Objects.equals(mlScorecard, that.mlScorecard);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(scoringMethod, scoringModel, ruleBasedScorecard, statScorecard, mlScorecard);
+    }
+
+    @Override
+    public String toString() {
+        return "CreditScorecard{" + "scoringMethod='" + scoringMethod + '\'' + ", scoringModel='" + scoringModel + '\''
+                + ", ruleBasedScorecard=" + ruleBasedScorecard + ", statScorecard=" + statScorecard + ", mlScorecard=" + mlScorecard + '}';
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecardFeature.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecardFeature.java
new file mode 100644
index 0000000..2cdb705
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecardFeature.java
@@ -0,0 +1,178 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardEnumerations;
+
+@Entity
+@Table(name = "m_credit_scorecard_feature")
+public class CreditScorecardFeature extends AbstractPersistableCustom implements Serializable {
+
+    @Column(name = "name", length = 100, unique = true, nullable = false)
+    private String name;
+
+    @Column(name = "value_type_enum", nullable = false)
+    private Integer valueType;
+
+    @Column(name = "data_type_enum", nullable = false)
+    private Integer dataType;
+
+    @Column(name = "category_enum", nullable = false)
+    private Integer category;
+
+    @Column(name = "is_active", nullable = false)
+    private Boolean active = false;
+
+    @Column(name = "is_deleted", nullable = false)
+    private boolean deleted = false;
+
+    public CreditScorecardFeature() {
+        //
+    }
+
+    public CreditScorecardFeature(String name, org.apache.fineract.portfolio.creditscorecard.domain.FeatureValueType valueType,
+            org.apache.fineract.portfolio.creditscorecard.domain.FeatureDataType dataType,
+            org.apache.fineract.portfolio.creditscorecard.domain.FeatureCategory category, Boolean active) {
+        this.name = name;
+        this.valueType = valueType.getValue();
+        this.dataType = dataType.getValue();
+        this.category = category.getValue();
+        this.active = active;
+    }
+
+    public static CreditScorecardFeature fromJson(JsonCommand command) {
+        final String name = command.stringValueOfParameterNamed("name");
+        final org.apache.fineract.portfolio.creditscorecard.domain.FeatureValueType valueType = org.apache.fineract.portfolio.creditscorecard.domain.FeatureValueType
+                .fromInt(command.integerValueOfParameterNamed("valueType"));
+        final org.apache.fineract.portfolio.creditscorecard.domain.FeatureDataType dataType = org.apache.fineract.portfolio.creditscorecard.domain.FeatureDataType
+                .fromInt(command.integerValueOfParameterNamed("dataType"));
+        final org.apache.fineract.portfolio.creditscorecard.domain.FeatureCategory category = org.apache.fineract.portfolio.creditscorecard.domain.FeatureCategory
+                .fromInt(command.integerValueOfParameterNamed("category"));
+        final boolean active = command.booleanPrimitiveValueOfParameterNamed("active");
+
+        return new CreditScorecardFeature(name, valueType, dataType, category, active);
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public EnumOptionData getValueType() {
+        return CreditScorecardEnumerations.featureValueType(valueType);
+    }
+
+    public EnumOptionData getDataType() {
+        return CreditScorecardEnumerations.featureDataType(dataType);
+    }
+
+    public EnumOptionData getCategory() {
+        return CreditScorecardEnumerations.featureCategory(category);
+    }
+
+    public boolean isActive() {
+        return this.active;
+    }
+
+    public boolean isDeleted() {
+        return this.deleted;
+    }
+
+    /**
+     * Delete is a <i>soft delete</i>. Updates flag on feature so it wont appear in query/report results.
+     *
+     * Any fields with unique constraints and prepended with id of record.
+     */
+    public void delete() {
+        this.deleted = true;
+        this.name = getId() + "_" + this.name;
+    }
+
+    public CreditScorecardFeatureData toData() {
+        final Long id = null;
+        final Long featureId = getId();
+        final String name = this.name;
+        final EnumOptionData valueType = CreditScorecardEnumerations.featureValueType(this.valueType);
+        final EnumOptionData dataType = CreditScorecardEnumerations.featureDataType(this.dataType);
+        final EnumOptionData category = CreditScorecardEnumerations.featureCategory(this.category);
+        final Boolean active = this.active;
+        final BigDecimal weightage = null;
+        final Integer greenMin = null;
+        final Integer greenMax = null;
+        final Integer amberMin = null;
+        final Integer amberMax = null;
+        final Integer redMin = null;
+        final Integer redMax = null;
+
+        return CreditScorecardFeatureData.instance(id, featureId, name, valueType, dataType, category, active, weightage, greenMin,
+                greenMax, amberMin, amberMax, redMin, redMax);
+    }
+
+    public Map<String, Object> update(final JsonCommand command) {
+        final Map<String, Object> actualChanges = new LinkedHashMap<>(6);
+
+        final String nameParamName = "name";
+        if (command.isChangeInStringParameterNamed(nameParamName, this.name)) {
+            final String newValue = command.stringValueOfParameterNamed(nameParamName);
+            actualChanges.put(nameParamName, newValue);
+            this.name = newValue;
+        }
+
+        final String valueTypeParamName = "valueType";
+        if (command.isChangeInIntegerParameterNamed(valueTypeParamName, this.valueType)) {
+            final Integer newValue = command.integerValueOfParameterNamed(valueTypeParamName);
+            actualChanges.put(valueTypeParamName, newValue);
+            this.valueType = newValue;
+        }
+
+        final String dataTypeParamName = "dataType";
+        if (command.isChangeInIntegerParameterNamed(dataTypeParamName, this.dataType)) {
+            final Integer newValue = command.integerValueOfParameterNamed(dataTypeParamName);
+            actualChanges.put(dataTypeParamName, newValue);
+            this.dataType = newValue;
+        }
+
+        final String categoryParamName = "category";
+        if (command.isChangeInIntegerParameterNamed(categoryParamName, this.category)) {
+            final Integer newValue = command.integerValueOfParameterNamed(categoryParamName);
+            actualChanges.put(categoryParamName, newValue);
+            this.category = newValue;
+        }
+
+        final String activeParamName = "active";
+        if (command.isChangeInBooleanParameterNamed(activeParamName, this.active)) {
+            final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(activeParamName);
+            actualChanges.put(activeParamName, newValue);
+            this.active = newValue;
+        }
+
+        return actualChanges;
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecardFeatureRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecardFeatureRepository.java
new file mode 100644
index 0000000..243bbaa
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecardFeatureRepository.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface CreditScorecardFeatureRepository
+        extends JpaRepository<CreditScorecardFeature, Long>, JpaSpecificationExecutor<CreditScorecardFeature> {}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecardRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecardRepository.java
new file mode 100644
index 0000000..afc379d
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/CreditScorecardRepository.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface CreditScorecardRepository extends JpaRepository<CreditScorecard, Long>, JpaSpecificationExecutor<CreditScorecard> {}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCannotBeDeletedException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCannotBeDeletedException.java
new file mode 100644
index 0000000..9366159
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCannotBeDeletedException.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
+
+public class FeatureCannotBeDeletedException extends AbstractPlatformDomainRuleException {
+
+    public FeatureCannotBeDeletedException(final String globalisationMessageCode, final String defaultUserMessage,
+            final Object... defaultUserMessageArgs) {
+
+        super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCategory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCategory.java
new file mode 100644
index 0000000..f76add9
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCategory.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public enum FeatureCategory {
+
+    INDIVIDUAL(0, "featureCategory.individual"), ORGANISATION(1, "featureCategory.organisation"), COUNTRY(2,
+            "featureCategory.country"), CREDIT_HISTORY(3,
+                    "featureCategory.creditHistory"), LOAN(3, "featureCategory.loan"), INVALID(4, "featureCategory.invalid");
+
+    private final Integer value;
+    private final String code;
+
+    FeatureCategory(final Integer value, final String code) {
+        this.value = value;
+        this.code = code;
+    }
+
+    public Integer getValue() {
+        return this.value;
+    }
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public static FeatureCategory fromInt(final Integer selectedType) {
+        FeatureCategory featureCategory = INVALID;
+        if (selectedType != null) {
+            switch (selectedType) {
+                case 0:
+                    featureCategory = INDIVIDUAL;
+                break;
+                case 1:
+                    featureCategory = ORGANISATION;
+                break;
+                case 2:
+                    featureCategory = COUNTRY;
+                break;
+                case 3:
+                    featureCategory = CREDIT_HISTORY;
+                break;
+                case 4:
+                    featureCategory = LOAN;
+                break;
+            }
+        }
+        return featureCategory;
+    }
+
+    public boolean isIndividual() {
+        return this.value.equals(INDIVIDUAL.getValue());
+    }
+
+    public boolean isOrganisation() {
+        return this.value.equals(ORGANISATION.getValue());
+    }
+
+    public boolean isCountry() {
+        return this.value.equals(COUNTRY.getValue());
+    }
+
+    public boolean isCreditHistory() {
+        return this.value.equals(CREDIT_HISTORY.getValue());
+    }
+
+    public boolean isLoan() {
+        return this.value.equals(LOAN.getValue());
+    }
+
+    public boolean isInvalid() {
+        return this.value.equals(INVALID.getValue());
+    }
+
+    public static Object[] integerValues() {
+        final List<Integer> values = new ArrayList<>();
+        for (final FeatureCategory enumType : values()) {
+            if (!enumType.isInvalid()) {
+                values.add(enumType.getValue());
+            }
+        }
+        return values.toArray();
+    }
+
+    public static Object[] validValues() {
+        return new Integer[] { INDIVIDUAL.getValue(), ORGANISATION.getValue(), COUNTRY.getValue(), CREDIT_HISTORY.getValue(),
+                LOAN.getValue() };
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureConfiguration.java
new file mode 100644
index 0000000..d7f3564
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureConfiguration.java
@@ -0,0 +1,184 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Locale;
+import java.util.Map;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
+
+@Embeddable
+public class FeatureConfiguration implements Serializable {
+
+    @Column(name = "weightage", scale = 6, precision = 5, nullable = false)
+    private BigDecimal weightage;
+
+    @Column(name = "green_min", nullable = false)
+    private Integer greenMin;
+
+    @Column(name = "green_max", nullable = false)
+    private Integer greenMax;
+
+    @Column(name = "amber_min", nullable = false)
+    private Integer amberMin;
+
+    @Column(name = "amber_max", nullable = false)
+    private Integer amberMax;
+
+    @Column(name = "red_min", nullable = false)
+    private Integer redMin;
+
+    @Column(name = "red_max", nullable = false)
+    private Integer redMax;
+
+    protected FeatureConfiguration() {
+        //
+    }
+
+    public FeatureConfiguration(final BigDecimal weightage, final Integer greenMin, final Integer greenMax, final Integer amberMin,
+            final Integer amberMax, final Integer redMin, final Integer redMax) {
+        this.weightage = weightage;
+        this.greenMin = greenMin;
+        this.greenMax = greenMax;
+        this.amberMin = amberMin;
+        this.amberMax = amberMax;
+        this.redMin = redMin;
+        this.redMax = redMax;
+    }
+
+    public static FeatureConfiguration from(final BigDecimal weightage, final Integer greenMin, final Integer greenMax,
+            final Integer amberMin, final Integer amberMax, final Integer redMin, final Integer redMax) {
+        return new FeatureConfiguration(weightage, greenMin, greenMax, amberMin, amberMax, redMin, redMax);
+    }
+
+    public void update(final JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator,
+            final Locale locale) {
+
+        validateConfiguration(baseDataValidator);
+
+        if (command.isChangeInBigDecimalParameterNamed("weightage", this.weightage, locale)) {
+            final BigDecimal newValue = command.bigDecimalValueOfParameterNamed("weightage", locale);
+            actualChanges.put("weightage", newValue);
+            this.weightage = newValue;
+        }
+
+        if (command.isChangeInIntegerParameterNamed("greenMin", this.greenMin, locale)) {
+            final Integer newValue = command.integerValueOfParameterNamed("greenMin", locale);
+            actualChanges.put("greenMin", newValue);
+            this.greenMin = newValue;
+        }
+
+        if (command.isChangeInIntegerParameterNamed("greenMax", this.greenMax, locale)) {
+            final Integer newValue = command.integerValueOfParameterNamed("greenMax", locale);
+            actualChanges.put("greenMax", newValue);
+            this.greenMax = newValue;
+        }
+
+        if (command.isChangeInIntegerParameterNamed("amberMin", this.amberMin, locale)) {
+            final Integer newValue = command.integerValueOfParameterNamed("amberMin", locale);
+            actualChanges.put("amberMin", newValue);
+            this.amberMin = newValue;
+        }
+
+        if (command.isChangeInIntegerParameterNamed("amberMax", this.amberMax, locale)) {
+            final Integer newValue = command.integerValueOfParameterNamed("amberMax", locale);
+            actualChanges.put("amberMax", newValue);
+            this.amberMax = newValue;
+        }
+
+        if (command.isChangeInIntegerParameterNamed("redMin", this.greenMin, locale)) {
+            final Integer newValue = command.integerValueOfParameterNamed("redMin", locale);
+            actualChanges.put("redMin", newValue);
+            this.redMin = newValue;
+        }
+
+        if (command.isChangeInIntegerParameterNamed("redMax", this.greenMin, locale)) {
+            final Integer newValue = command.integerValueOfParameterNamed("redMax", locale);
+            actualChanges.put("redMax", newValue);
+            this.redMax = newValue;
+        }
+
+    }
+
+    public void validateConfiguration(final DataValidatorBuilder baseDataValidator) {
+
+        baseDataValidator.reset().parameter("weightage").value(this.weightage).notNull().inMinMaxRange(0, 1);
+
+        baseDataValidator.reset().parameter("greenMin").value(this.greenMin).notNull().integerGreaterThanZero();
+        baseDataValidator.reset().parameter("greenMax").value(this.greenMax).notNull().integerGreaterThanZero();
+
+        baseDataValidator.reset().parameter("amberMin").value(this.amberMin).notNull().integerGreaterThanZero();
+        baseDataValidator.reset().parameter("amberMax").value(this.amberMax).notNull().integerGreaterThanZero();
+
+        baseDataValidator.reset().parameter("redMin").value(this.redMin).notNull().integerGreaterThanZero();
+        baseDataValidator.reset().parameter("redMax").value(this.redMax).notNull().integerGreaterThanZero();
+
+    }
+
+    public String getColorFromScore(final BigDecimal score) {
+        String color;
+        if (score.longValue() >= this.greenMin.longValue() && score.longValue() <= this.greenMax.longValue()) {
+            color = "green";
+
+        } else if (score.longValue() >= this.amberMin.longValue() && score.longValue() <= this.amberMax.longValue()) {
+            color = "amber";
+
+        } else if (score.longValue() >= this.redMin.longValue() && score.longValue() <= this.redMax.longValue()) {
+            color = "red";
+
+        } else {
+            color = "orange";
+
+        }
+
+        return color;
+    }
+
+    public BigDecimal getWeightage() {
+        return weightage;
+    }
+
+    public Integer getGreenMin() {
+        return greenMin;
+    }
+
+    public Integer getGreenMax() {
+        return greenMax;
+    }
+
+    public Integer getAmberMin() {
+        return amberMin;
+    }
+
+    public Integer getAmberMax() {
+        return amberMax;
+    }
+
+    public Integer getRedMin() {
+        return redMin;
+    }
+
+    public Integer getRedMax() {
+        return redMax;
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCriteria.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCriteria.java
new file mode 100644
index 0000000..1bb4f7e
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCriteria.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.math.BigDecimal;
+import java.util.Objects;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+import org.apache.fineract.portfolio.creditscorecard.data.ScorecardFeatureCriteriaData;
+
+@Entity
+@Table(name = "m_scorecard_feature_criteria")
+public class FeatureCriteria extends AbstractPersistableCustom {
+
+    @Column(name = "criteria", nullable = false)
+    private String criteria;
+
+    @Column(name = "score", nullable = false)
+    private BigDecimal score;
+
+    public FeatureCriteria() {
+        //
+    }
+
+    public FeatureCriteria(String criteria, BigDecimal score) {
+        this.criteria = criteria;
+        this.score = score;
+    }
+
+    public String getCriteria() {
+        return criteria;
+    }
+
+    public void setCriteria(String criteria) {
+        this.criteria = criteria;
+    }
+
+    public BigDecimal getScore() {
+        return score;
+    }
+
+    public void setScore(BigDecimal score) {
+        this.score = score;
+    }
+
+    public ScorecardFeatureCriteriaData toData() {
+        return ScorecardFeatureCriteriaData.instance(this.getId(), this.criteria, this.score);
+    }
+
+    @Override
+    public String toString() {
+        return "ScorecardFeatureCriteria{" + "criteria='" + criteria + '\'' + ", score=" + score + '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof FeatureCriteria)) {
+            return false;
+        }
+        FeatureCriteria that = (FeatureCriteria) o;
+        return Objects.equals(criteria, that.criteria) && Objects.equals(score, that.score);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(criteria, score);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCriteriaScore.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCriteriaScore.java
new file mode 100644
index 0000000..c6a0519
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureCriteriaScore.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.math.BigDecimal;
+import java.util.Objects;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+import org.apache.fineract.portfolio.loanproduct.domain.LoanProductScorecardFeature;
+
+@Entity
+@Table(name = "m_scorecard_feature_criteria_score")
+public class FeatureCriteriaScore extends AbstractPersistableCustom {
+
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name = "product_loan_scorecard_feature_id", referencedColumnName = "id")
+    private LoanProductScorecardFeature feature;
+
+    @Column(name = "value", nullable = false)
+    private String value;
+
+    @Column(name = "score")
+    private BigDecimal score;
+
+    @Column(name = "color")
+    private String color;
+
+    public FeatureCriteriaScore() {
+        //
+    }
+
+    public FeatureCriteriaScore(LoanProductScorecardFeature feature, String value) {
+        this.feature = feature;
+        this.value = value;
+    }
+
+    public FeatureCriteriaScore(LoanProductScorecardFeature feature, BigDecimal score, String color) {
+        this.feature = feature;
+        this.score = score;
+        this.color = color;
+    }
+
+    public LoanProductScorecardFeature getFeature() {
+        return feature;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public BigDecimal getScore() {
+        return score;
+    }
+
+    public String getColor() {
+        return color;
+    }
+
+    public void setScore(final BigDecimal score, final String color) {
+        this.score = score;
+        this.color = color;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof FeatureCriteriaScore)) {
+            return false;
+        }
+        FeatureCriteriaScore that = (FeatureCriteriaScore) o;
+        return Objects.equals(feature, that.feature) && Objects.equals(value, that.value) && Objects.equals(score, that.score)
+                && Objects.equals(color, that.color);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(feature, value, score, color);
+    }
+
+    @Override
+    public String toString() {
+        return "FeatureCriteriaScore{" + "feature=" + feature + ", value='" + value + '\'' + ", score=" + score + ", color='" + color + '\''
+                + '}';
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureDataType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureDataType.java
new file mode 100644
index 0000000..cdeb935
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureDataType.java
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public enum FeatureDataType {
+
+    NUMERIC(0, "featureDataType.numeric"), STRING(1, "featureDataType.string"), DATE(2, "featureDataType.date"), INVALID(3,
+            "featureDataType.invalid");
+
+    private final Integer value;
+    private final String code;
+
+    FeatureDataType(final Integer value, final String code) {
+        this.value = value;
+        this.code = code;
+    }
+
+    public Integer getValue() {
+        return this.value;
+    }
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public static FeatureDataType fromInt(final Integer selectedType) {
+        FeatureDataType featureDataType = INVALID;
+        if (selectedType != null) {
+            switch (selectedType) {
+                case 0:
+                    featureDataType = NUMERIC;
+                break;
+                case 1:
+                    featureDataType = STRING;
+                break;
+                case 2:
+                    featureDataType = DATE;
+                break;
+            }
+        }
+        return featureDataType;
+    }
+
+    public boolean isNumeric() {
+        return this.value.equals(NUMERIC.getValue());
+    }
+
+    public boolean isString() {
+        return this.value.equals(STRING.getValue());
+    }
+
+    public boolean isDate() {
+        return this.value.equals(DATE.getValue());
+    }
+
+    public boolean isInvalid() {
+        return this.value.equals(INVALID.getValue());
+    }
+
+    public static Object[] integerValues() {
+        final List<Integer> values = new ArrayList<>();
+        for (final FeatureDataType enumType : values()) {
+            if (!enumType.isInvalid()) {
+                values.add(enumType.getValue());
+            }
+        }
+        return values.toArray();
+    }
+
+    public static Object[] validValues() {
+        return new Integer[] { NUMERIC.getValue(), STRING.getValue(), DATE.getValue() };
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureNotFoundException.java
new file mode 100644
index 0000000..5844ca8
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureNotFoundException.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
+import org.springframework.dao.EmptyResultDataAccessException;
+
+public class FeatureNotFoundException extends AbstractPlatformResourceNotFoundException {
+
+    public FeatureNotFoundException(final Long id) {
+        super("error.msg.scorecard.feature.id.invalid", "Scorecard Feature with identifier " + id + " does not exist", id);
+    }
+
+    public FeatureNotFoundException(Long id, EmptyResultDataAccessException e) {
+        super("error.msg.scorecard.feature.id.invalid", "Scorecard Feature with identifier " + id + " does not exist", id, e);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureValueType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureValueType.java
new file mode 100644
index 0000000..0dc4f32
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/FeatureValueType.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public enum FeatureValueType {
+
+    BINARY(0, "featureValueType.binary"), NOMINAL(1, "featureValueType.nominal"), INTERVAL(2, "featureValueType.interval"), RATIO(3,
+            "featureValueType.ratio"), INVALID(4, "featureValueType.invalid");
+
+    private final Integer value;
+    private final String code;
+
+    FeatureValueType(final Integer value, final String code) {
+        this.value = value;
+        this.code = code;
+    }
+
+    public Integer getValue() {
+        return this.value;
+    }
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public static FeatureValueType fromInt(final Integer selectedType) {
+        FeatureValueType featureValueType = INVALID;
+        if (selectedType != null) {
+            switch (selectedType) {
+                case 0:
+                    featureValueType = BINARY;
+                break;
+                case 1:
+                    featureValueType = NOMINAL;
+                break;
+                case 2:
+                    featureValueType = INTERVAL;
+                break;
+                case 3:
+                    featureValueType = RATIO;
+                break;
+            }
+        }
+        return featureValueType;
+    }
+
+    public boolean isBinary() {
+        return this.value.equals(BINARY.getValue());
+    }
+
+    public boolean isNominal() {
+        return this.value.equals(NOMINAL.getValue());
+    }
+
+    public boolean isInterval() {
+        return this.value.equals(INTERVAL.getValue());
+    }
+
+    public boolean isRatio() {
+        return this.value.equals(RATIO.getValue());
+    }
+
+    public boolean isInvalid() {
+        return this.value.equals(INVALID.getValue());
+    }
+
+    public static Object[] integerValues() {
+        final List<Integer> values = new ArrayList<>();
+        for (final FeatureValueType enumType : values()) {
+            if (!enumType.isInvalid()) {
+                values.add(enumType.getValue());
+            }
+        }
+        return values.toArray();
+    }
+
+    public static Object[] validValues() {
+        return new Integer[] { BINARY.getValue(), NOMINAL.getValue(), INTERVAL.getValue(), RATIO.getValue() };
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/MLScorecard.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/MLScorecard.java
new file mode 100644
index 0000000..c32ccee
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/MLScorecard.java
@@ -0,0 +1,136 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.math.BigDecimal;
+import java.util.Objects;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+
+@Entity
+@Table(name = "m_ml_scorecard")
+public class MLScorecard extends AbstractPersistableCustom {
+
+    @Embedded
+    private MLScorecardFields scorecardFields;
+
+    @Column(name = "predicted_risk")
+    private String predictedRisk;
+
+    @Column(name = "accuracy")
+    private BigDecimal accuracy;
+
+    @Column(name = "actual_risk")
+    private String actualRisk;
+
+    @Column(name = "prediction_request_id")
+    private Integer predictionRequestId;
+
+    public MLScorecard() {
+
+    }
+
+    public MLScorecard(final MLScorecardFields scorecardFields, final String predictedRisk, final String actualRisk,
+            final Integer predictionRequestId) {
+        this.scorecardFields = scorecardFields;
+        this.predictedRisk = predictedRisk;
+        this.actualRisk = actualRisk;
+        this.predictionRequestId = predictionRequestId;
+    }
+
+    public MLScorecard(final MLScorecardFields mlScorecardFields) {
+        this.scorecardFields = mlScorecardFields;
+    }
+
+    public MLScorecard scorecardFields(final MLScorecardFields scorecardFields) {
+        this.scorecardFields = scorecardFields;
+        return this;
+    }
+
+    public MLScorecardFields getScorecardFields() {
+        return scorecardFields;
+    }
+
+    public void setScorecardFields(MLScorecardFields scorecardFields) {
+        this.scorecardFields = scorecardFields;
+    }
+
+    public BigDecimal getAccuracy() {
+        return accuracy;
+    }
+
+    public String getPredictedRisk() {
+        return predictedRisk;
+    }
+
+    public void setPredictedRisk(final String predictedRisk) {
+        this.predictedRisk = predictedRisk;
+    }
+
+    public String getActualRisk() {
+        return actualRisk;
+    }
+
+    public void setActualRisk(final String actualRisk) {
+        this.actualRisk = actualRisk;
+    }
+
+    public Integer getPredictionRequestId() {
+        return predictionRequestId;
+    }
+
+    public void setPredictionRequestId(final Integer predictionRequestId) {
+        this.predictionRequestId = predictionRequestId;
+    }
+
+    public MLScorecard setPredictionResponse(BigDecimal accuracy, String predictedRisk, Integer predictionRequestId) {
+        this.accuracy = accuracy;
+        this.predictedRisk = predictedRisk;
+        this.predictionRequestId = predictionRequestId;
+        return this;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof MLScorecard)) {
+            return false;
+        }
+        MLScorecard loanScorecard = (MLScorecard) o;
+        return Objects.equals(scorecardFields, loanScorecard.scorecardFields) && Objects.equals(predictedRisk, loanScorecard.predictedRisk)
+                && Objects.equals(actualRisk, loanScorecard.actualRisk)
+                && Objects.equals(predictionRequestId, loanScorecard.predictionRequestId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(scorecardFields, predictedRisk, actualRisk, predictionRequestId);
+    }
+
+    @Override
+    public String toString() {
+        return "MLScorecard{" + "scorecardFields=" + scorecardFields + ", predictedRisk='" + predictedRisk + '\'' + ", actualRisk='"
+                + actualRisk + '\'' + ", predictionRequestId=" + predictionRequestId + '}';
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/MLScorecardFields.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/MLScorecardFields.java
new file mode 100644
index 0000000..e005d86
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/MLScorecardFields.java
@@ -0,0 +1,146 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Objects;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class MLScorecardFields implements Serializable {
+
+    @Column(name = "age")
+    private Integer age;
+
+    @Column(name = "sex")
+    private String sex;
+
+    @Column(name = "job")
+    private String job;
+
+    @Column(name = "housing")
+    private String housing;
+
+    @Column(name = "credit_amount", scale = 6, precision = 19)
+    private BigDecimal creditAmount;
+
+    @Column(name = "duration")
+    private Integer duration;
+
+    @Column(name = "purpose")
+    private String purpose;
+
+    public MLScorecardFields() {
+
+    }
+
+    public MLScorecardFields(Integer age, String sex, String job, String housing, BigDecimal creditAmount, Integer duration,
+            String purpose) {
+        this.age = age;
+        this.sex = sex;
+        this.job = job;
+        this.housing = housing;
+        this.creditAmount = creditAmount;
+        this.duration = duration;
+        this.purpose = purpose;
+    }
+
+    public Integer getAge() {
+        return age;
+    }
+
+    public void setAge(Integer age) {
+        this.age = age;
+    }
+
+    public String getSex() {
+        return sex;
+    }
+
+    public void setSex(String sex) {
+        this.sex = sex;
+    }
+
+    public String getJob() {
+        return job;
+    }
+
+    public void setJob(String job) {
+        this.job = job;
+    }
+
+    public String getHousing() {
+        return housing;
+    }
+
+    public void setHousing(String housing) {
+        this.housing = housing;
+    }
+
+    public BigDecimal getCreditAmount() {
+        return creditAmount;
+    }
+
+    public void setCreditAmount(BigDecimal creditAmount) {
+        this.creditAmount = creditAmount;
+    }
+
+    public Integer getDuration() {
+        return duration;
+    }
+
+    public void setDuration(Integer duration) {
+        this.duration = duration;
+    }
+
+    public String getPurpose() {
+        return purpose;
+    }
+
+    public void setPurpose(String purpose) {
+        this.purpose = purpose;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof MLScorecardFields)) {
+            return false;
+        }
+        MLScorecardFields that = (MLScorecardFields) o;
+        return Objects.equals(age, that.age) && Objects.equals(sex, that.sex) && Objects.equals(job, that.job)
+                && Objects.equals(housing, that.housing) && Objects.equals(creditAmount, that.creditAmount)
+                && Objects.equals(duration, that.duration) && Objects.equals(purpose, that.purpose);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(age, sex, job, housing, creditAmount, duration, purpose);
+    }
+
+    @Override
+    public String toString() {
+        return "MLScorecardFields{" + "age=" + age + ", sex='" + sex + '\'' + ", job='" + job + '\'' + ", housing='" + housing + '\''
+                + ", creditAmount=" + creditAmount + ", duration=" + duration + ", purpose='" + purpose + '\'' + '}';
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/MLScorecardRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/MLScorecardRepository.java
new file mode 100644
index 0000000..066d8c5
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/MLScorecardRepository.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface MLScorecardRepository extends JpaRepository<MLScorecard, Long>, JpaSpecificationExecutor<MLScorecard> {
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/RuleBasedScorecard.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/RuleBasedScorecard.java
new file mode 100644
index 0000000..b3477ed
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/RuleBasedScorecard.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.math.BigDecimal;
+import java.util.List;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+
+@Entity
+@Table(name = "m_rule_based_scorecard")
+public class RuleBasedScorecard extends AbstractPersistableCustom {
+
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
+    @JoinColumn(name = "rule_based_scorecard_id", referencedColumnName = "id")
+    private List<FeatureCriteriaScore> criteriaScores;
+
+    @Column(name = "overall_score")
+    private BigDecimal overallScore;
+
+    @Column(name = "overall_color")
+    private String overallColor;
+
+    public RuleBasedScorecard() {
+        //
+    }
+
+    public BigDecimal getOverallScore() {
+        return overallScore;
+    }
+
+    public String getOverallColor() {
+        return overallColor;
+    }
+
+    public void setScore(final BigDecimal overallScore, final String overallColor) {
+        this.overallScore = overallScore;
+        this.overallColor = overallColor;
+    }
+
+    public void setCriteriaScores(final List<FeatureCriteriaScore> criteriaScores) {
+        this.criteriaScores = criteriaScores;
+    }
+
+    public List<FeatureCriteriaScore> getCriteriaScores() {
+        return criteriaScores;
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/RuleBasedScorecardRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/RuleBasedScorecardRepository.java
new file mode 100644
index 0000000..2839bed
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/RuleBasedScorecardRepository.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface RuleBasedScorecardRepository
+        extends JpaRepository<RuleBasedScorecard, Long>, JpaSpecificationExecutor<RuleBasedScorecard> {}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/ScorecardFeatureCriteriaRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/ScorecardFeatureCriteriaRepository.java
new file mode 100644
index 0000000..84e69f2
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/ScorecardFeatureCriteriaRepository.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ScorecardFeatureCriteriaRepository
+        extends JpaRepository<org.apache.fineract.portfolio.creditscorecard.domain.FeatureCriteria, Long>,
+        JpaSpecificationExecutor<org.apache.fineract.portfolio.creditscorecard.domain.FeatureCriteria> {}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/StatScorecard.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/StatScorecard.java
new file mode 100644
index 0000000..8a5928e
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/StatScorecard.java
@@ -0,0 +1,147 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import java.math.BigDecimal;
+import java.util.Objects;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+
+@Entity
+@Table(name = "m_stat_scorecard")
+public class StatScorecard extends AbstractPersistableCustom {
+
+    @Embedded
+    private MLScorecardFields scorecardFields;
+
+    @Column(name = "method")
+    private String method;
+
+    @Column(name = "color")
+    private String color;
+
+    @Column(name = "prediction")
+    private BigDecimal prediction;
+
+    @Column(name = "wilki_s_lambda")
+    private BigDecimal wilkisLambda;
+
+    @Column(name = "pillai_s_trace")
+    private BigDecimal pillaisTrace;
+
+    @Column(name = "hotelling_lawley_trace")
+    private BigDecimal hotellingLawley;
+
+    @Column(name = "roy_s_greatest_roots")
+    private BigDecimal roysGreatestRoots;
+
+    public StatScorecard() {
+        //
+    }
+
+    public StatScorecard(String method, String color, BigDecimal prediction, BigDecimal wilkisLambda, BigDecimal pillaisTrace,
+            BigDecimal hotellingLawley, BigDecimal roysGreatestRoots) {
+        this.method = method;
+        this.color = color;
+        this.prediction = prediction;
+        this.wilkisLambda = wilkisLambda;
+        this.pillaisTrace = pillaisTrace;
+        this.hotellingLawley = hotellingLawley;
+        this.roysGreatestRoots = roysGreatestRoots;
+    }
+
+    public StatScorecard(final MLScorecardFields mlScorecardFields) {
+        this.scorecardFields = mlScorecardFields;
+    }
+
+    public void setPredictionResponse(String method, String color, BigDecimal prediction, BigDecimal wilkisLambda, BigDecimal pillaisTrace,
+            BigDecimal hotellingLawley, BigDecimal roysGreatestRoots) {
+        this.method = method;
+        this.color = color;
+        this.prediction = prediction;
+        if (this.method.equalsIgnoreCase("manova")) {
+            this.wilkisLambda = wilkisLambda;
+            this.pillaisTrace = pillaisTrace;
+            this.hotellingLawley = hotellingLawley;
+            this.roysGreatestRoots = roysGreatestRoots;
+        }
+    }
+
+    public MLScorecardFields getScorecardFields() {
+        return scorecardFields;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public String getColor() {
+        return color;
+    }
+
+    public BigDecimal getPrediction() {
+        return prediction;
+    }
+
+    public BigDecimal getWilkisLambda() {
+        return wilkisLambda;
+    }
+
+    public BigDecimal getPillaisTrace() {
+        return pillaisTrace;
+    }
+
+    public BigDecimal getHotellingLawley() {
+        return hotellingLawley;
+    }
+
+    public BigDecimal getRoysGreatestRoots() {
+        return roysGreatestRoots;
+    }
+
+    @Override
+    public String toString() {
+        return "StatScorecard{" + "scorecardFields=" + scorecardFields + ", method='" + method + '\'' + ", color='" + color + '\''
+                + ", prediction=" + prediction + ", wilkisLambda=" + wilkisLambda + ", pillaisTrace=" + pillaisTrace + ", hotellingLawley="
+                + hotellingLawley + ", roysGreatestRoots=" + roysGreatestRoots + '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof StatScorecard)) {
+            return false;
+        }
+        StatScorecard that = (StatScorecard) o;
+        return Objects.equals(scorecardFields, that.scorecardFields) && Objects.equals(method, that.method)
+                && Objects.equals(color, that.color) && Objects.equals(prediction, that.prediction)
+                && Objects.equals(wilkisLambda, that.wilkisLambda) && Objects.equals(pillaisTrace, that.pillaisTrace)
+                && Objects.equals(hotellingLawley, that.hotellingLawley) && Objects.equals(roysGreatestRoots, that.roysGreatestRoots);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(scorecardFields, method, color, prediction, wilkisLambda, pillaisTrace, hotellingLawley, roysGreatestRoots);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/StatScorecardRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/StatScorecardRepository.java
new file mode 100644
index 0000000..516bf2d
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/domain/StatScorecardRepository.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.domain;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface StatScorecardRepository extends JpaRepository<StatScorecard, Long>, JpaSpecificationExecutor<StatScorecard> {}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/exception/FeatureCannotBeDeletedException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/exception/FeatureCannotBeDeletedException.java
new file mode 100644
index 0000000..158dd27
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/exception/FeatureCannotBeDeletedException.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
+
+public class FeatureCannotBeDeletedException extends AbstractPlatformDomainRuleException {
+
+    public FeatureCannotBeDeletedException(final String globalisationMessageCode, final String defaultUserMessage,
+            final Object... defaultUserMessageArgs) {
+
+        super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/exception/FeatureNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/exception/FeatureNotFoundException.java
new file mode 100644
index 0000000..d960d31
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/exception/FeatureNotFoundException.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
+import org.springframework.dao.EmptyResultDataAccessException;
+
+public class FeatureNotFoundException extends AbstractPlatformResourceNotFoundException {
+
+    public FeatureNotFoundException(final Long id) {
+        super("error.msg.scorecard.feature.id.invalid", "Scorecard Feature with identifier " + id + " does not exist", id);
+    }
+
+    public FeatureNotFoundException(Long id, EmptyResultDataAccessException e) {
+        super("error.msg.scorecard.feature.id.invalid", "Scorecard Feature with identifier " + id + " does not exist", id, e);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/handler/CreateCreditScorecardFeatureDefinitionCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/handler/CreateCreditScorecardFeatureDefinitionCommandHandler.java
new file mode 100644
index 0000000..08ec7a8
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/handler/CreateCreditScorecardFeatureDefinitionCommandHandler.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardWritePlatformService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "CREDIT_SCORECARD_FEATURE", action = "CREATE")
+public class CreateCreditScorecardFeatureDefinitionCommandHandler implements NewCommandSourceHandler {
+
+    private final ScorecardServiceProvider serviceProvider;
+
+    @Autowired
+    public CreateCreditScorecardFeatureDefinitionCommandHandler(final ScorecardServiceProvider serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Transactional
+    @Override
+    public CommandProcessingResult processCommand(final JsonCommand command) {
+        final String serviceName = "CreditScorecardWritePlatformService";
+        final CreditScorecardWritePlatformService scorecardWritePlatformService = (CreditScorecardWritePlatformService) this.serviceProvider
+                .getScorecardService(serviceName);
+        if (scorecardWritePlatformService == null) {
+            throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                    ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+        }
+
+        return scorecardWritePlatformService.createScoringFeature(command);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/handler/DeleteCreditScorecardFeatureDefinitionCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/handler/DeleteCreditScorecardFeatureDefinitionCommandHandler.java
new file mode 100644
index 0000000..7241749
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/handler/DeleteCreditScorecardFeatureDefinitionCommandHandler.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardWritePlatformService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "CREDIT_SCORECARD_FEATURE", action = "DELETE")
+public class DeleteCreditScorecardFeatureDefinitionCommandHandler implements NewCommandSourceHandler {
+
+    private final ScorecardServiceProvider serviceProvider;
+
+    @Autowired
+    public DeleteCreditScorecardFeatureDefinitionCommandHandler(final ScorecardServiceProvider serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Transactional
+    @Override
+    public CommandProcessingResult processCommand(final JsonCommand command) {
+        final String serviceName = "CreditScorecardWritePlatformService";
+        final CreditScorecardWritePlatformService scorecardWritePlatformService = (CreditScorecardWritePlatformService) this.serviceProvider
+                .getScorecardService(serviceName);
+        if (scorecardWritePlatformService == null) {
+            throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                    ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+        }
+
+        return scorecardWritePlatformService.deleteScoringFeature(command.entityId());
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/handler/UpdateCreditScorecardFeatureDefinitionCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/handler/UpdateCreditScorecardFeatureDefinitionCommandHandler.java
new file mode 100644
index 0000000..5d8daa2
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/handler/UpdateCreditScorecardFeatureDefinitionCommandHandler.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardWritePlatformService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "CREDIT_SCORECARD_FEATURE", action = "UPDATE")
+public class UpdateCreditScorecardFeatureDefinitionCommandHandler implements NewCommandSourceHandler {
+
+    private final ScorecardServiceProvider serviceProvider;
+
+    @Autowired
+    public UpdateCreditScorecardFeatureDefinitionCommandHandler(final ScorecardServiceProvider serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Transactional
+    @Override
+    public CommandProcessingResult processCommand(final JsonCommand command) {
+        final String serviceName = "CreditScorecardWritePlatformService";
+        final CreditScorecardWritePlatformService scorecardWritePlatformService = (CreditScorecardWritePlatformService) this.serviceProvider
+                .getScorecardService(serviceName);
+        if (scorecardWritePlatformService == null) {
+            throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                    ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+        }
+
+        return scorecardWritePlatformService.updateScoringFeature(command.entityId(), command);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/provider/ScorecardServiceProvider.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/provider/ScorecardServiceProvider.java
new file mode 100644
index 0000000..9ab2cb9
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/provider/ScorecardServiceProvider.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.provider;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.fineract.portfolio.creditscorecard.annotation.ScorecardService;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Component
+@Scope("singleton")
+public class ScorecardServiceProvider {
+
+    public static final String SERVICE_MISSING = "There is no ScorecardService registered in the ScorecardServiceProvider for this report name: ";
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ScorecardServiceProvider.class);
+
+    private final Map<String, CreditScorecardService> scorecardServices;
+
+    @SuppressWarnings("unchecked")
+    @Autowired
+    public ScorecardServiceProvider(List<CreditScorecardService> scorecardServices) {
+
+        var mapBuilder = ImmutableMap.<String, CreditScorecardService>builder();
+        for (CreditScorecardService s : scorecardServices) {
+            Class<? extends CreditScorecardService> serviceClass = s.getClass();
+
+            if (!serviceClass.isAnnotationPresent(ScorecardService.class)) {
+                serviceClass = (Class<? extends CreditScorecardService>) serviceClass.getGenericSuperclass();
+            }
+
+            final String name = serviceClass.getAnnotation(ScorecardService.class).name();
+            mapBuilder.put(name, s);
+
+            LOGGER.warn("Registered credit scorecard service '{}' for name '{}'", s, name);
+
+        }
+        this.scorecardServices = mapBuilder.build();
+    }
+
+    public CreditScorecardService getScorecardService(final String serviceName) {
+        return scorecardServices.getOrDefault(serviceName, null);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/serialization/CreditScorecardApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/serialization/CreditScorecardApiJsonHelper.java
new file mode 100644
index 0000000..f3f118c
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/serialization/CreditScorecardApiJsonHelper.java
@@ -0,0 +1,350 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.serialization;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.reflect.TypeToken;
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
+import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
+import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureCategory;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureDataType;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureValueType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CreditScorecardApiJsonHelper {
+
+    private final Set<String> supportedParameters = new HashSet<>(
+            Arrays.asList("name", "valueType", "dataType", "category", "active", "locale"));
+
+    private final FromJsonHelper fromApiJsonHelper;
+
+    @Autowired
+    public CreditScorecardApiJsonHelper(final FromJsonHelper fromApiJsonHelper) {
+        this.fromApiJsonHelper = fromApiJsonHelper;
+    }
+
+    public void validateFeatureForCreate(final String json) {
+        if (StringUtils.isBlank(json)) {
+            throw new InvalidJsonException();
+        }
+
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("credit_scorecard_feature");
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final String name = this.fromApiJsonHelper.extractStringNamed("name", element);
+        baseDataValidator.reset().parameter("name").value(name).notBlank().notExceedingLengthOf(100);
+
+        final Integer valueType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("valueType", element);
+        baseDataValidator.reset().parameter("valueType").value(valueType).notNull();
+        if (valueType != null) {
+            baseDataValidator.reset().parameter("valueType").value(valueType).isOneOfTheseValues(FeatureValueType.validValues());
+        }
+
+        final Integer dataType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("dataType", element);
+        baseDataValidator.reset().parameter("dataType").value(dataType).notNull();
+        if (valueType != null) {
+            baseDataValidator.reset().parameter("dataType").value(dataType).isOneOfTheseValues(FeatureDataType.validValues());
+        }
+
+        final Integer category = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("category", element);
+        baseDataValidator.reset().parameter("category").value(category).notNull();
+        if (valueType != null) {
+            baseDataValidator.reset().parameter("category").value(category).isOneOfTheseValues(FeatureCategory.validValues());
+        }
+
+        if (this.fromApiJsonHelper.parameterExists("active", element)) {
+            final Boolean active = this.fromApiJsonHelper.extractBooleanNamed("active", element);
+            baseDataValidator.reset().parameter("active").value(active).notNull();
+        }
+
+    }
+
+    public void validateFeatureForUpdate(final String json) {
+        if (StringUtils.isBlank(json)) {
+            throw new InvalidJsonException();
+        }
+
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("credit_scorecard_feature");
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final String name = this.fromApiJsonHelper.extractStringNamed("name", element);
+        baseDataValidator.reset().parameter("name").value(name).notBlank().notExceedingLengthOf(100);
+
+        final Integer valueType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("valueType", element);
+        baseDataValidator.reset().parameter("valueType").value(valueType).notNull();
+        if (valueType != null) {
+            baseDataValidator.reset().parameter("valueType").value(valueType).isOneOfTheseValues(FeatureValueType.validValues());
+        }
+
+        final Integer dataType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("dataType", element);
+        baseDataValidator.reset().parameter("dataType").value(dataType).notNull();
+        if (valueType != null) {
+            baseDataValidator.reset().parameter("dataType").value(dataType).isOneOfTheseValues(FeatureDataType.validValues());
+        }
+
+        final Integer category = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("category", element);
+        baseDataValidator.reset().parameter("category").value(category).notNull();
+        if (valueType != null) {
+            baseDataValidator.reset().parameter("category").value(category).isOneOfTheseValues(FeatureCategory.validValues());
+        }
+
+        if (this.fromApiJsonHelper.parameterExists("active", element)) {
+            final Boolean active = this.fromApiJsonHelper.extractBooleanNamed("active", element);
+            baseDataValidator.reset().parameter("active").value(active).notNull();
+        }
+
+    }
+
+    public void validateScorecardJson(final JsonElement element) {
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("creditScorecard");
+
+        final String scorecardParameterName = "scorecard";
+        final JsonObject topLevelJsonElement = element.getAsJsonObject();
+
+        if (topLevelJsonElement.get(scorecardParameterName).isJsonObject()) {
+            final Type arrayObjectParameterTypeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+            final Set<String> supportedParameters = new HashSet<>(Arrays.asList("scoringMethod", "scoringModel", "mlScorecard",
+                    "statScorecard", "ruleBasedScorecard", "locale", "dateFormat"));
+
+            final JsonObject scorecardElement = topLevelJsonElement.getAsJsonObject(scorecardParameterName);
+            this.fromApiJsonHelper.checkForUnsupportedParameters(arrayObjectParameterTypeOfMap,
+                    this.fromApiJsonHelper.toJson(scorecardElement), supportedParameters);
+
+            final String dateFormat = this.fromApiJsonHelper.extractDateFormatParameter(scorecardElement);
+            final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(scorecardElement);
+
+            final String scoringMethod = this.fromApiJsonHelper.extractStringNamed("scoringMethod", scorecardElement);
+
+            if (scoringMethod != null) {
+                baseDataValidator.reset().parameter("scoringMethod").value(scoringMethod).notNull().notExceedingLengthOf(100);
+
+                final String scoringModel = this.fromApiJsonHelper.extractStringNamed("scoringModel", scorecardElement);
+                baseDataValidator.reset().parameter("scoringModel").value(scoringModel).notNull().notExceedingLengthOf(100);
+
+                if (!dataValidationErrors.isEmpty()) {
+                    throw new PlatformApiDataValidationException(dataValidationErrors);
+                }
+
+                switch (scoringMethod) {
+                    case "ml":
+                        this.validateMLScorecardJson(scorecardElement);
+                    break;
+
+                    case "stat":
+                        this.validateStatScorecardJson(scorecardElement);
+                    break;
+
+                    case "ruleBased":
+                        this.validateRuleBasedScorecardJson(scorecardElement);
+                    break;
+                }
+            }
+        }
+    }
+
+    private void validateRuleBasedScorecardJson(final JsonElement element) {
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("ruleBasedScorecard");
+
+        final String rbScorecardParameterName = "ruleBasedScorecard";
+        if (element.isJsonObject() && this.fromApiJsonHelper.parameterExists(rbScorecardParameterName, element)) {
+            final JsonObject topLevelJsonElement = element.getAsJsonObject();
+
+            if (topLevelJsonElement.get(rbScorecardParameterName).isJsonObject()) {
+                final Type arrayObjectParameterTypeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+                final Set<String> supportedParameters = new HashSet<>(Arrays.asList("criteriaScores", "scorecardScore", "scorecardColor"));
+
+                final JsonObject rbScorecardElement = topLevelJsonElement.getAsJsonObject(rbScorecardParameterName);
+                this.fromApiJsonHelper.checkForUnsupportedParameters(arrayObjectParameterTypeOfMap,
+                        this.fromApiJsonHelper.toJson(rbScorecardElement), supportedParameters);
+
+                final String criteriaScoresParameterName = "criteriaScores";
+                if (rbScorecardElement.get(criteriaScoresParameterName).isJsonArray()) {
+                    final Type criteriaScoreArrayObjectParameterTypeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+                    final Set<String> criteriaScoreSupportedParameters = new HashSet<>(
+                            Arrays.asList("featureId", "value", "score", "color"));
+
+                    final JsonArray array = rbScorecardElement.getAsJsonArray(criteriaScoresParameterName);
+                    for (int i = 1; i <= array.size(); i++) {
+
+                        final JsonObject criteriaScoreElement = array.get(i - 1).getAsJsonObject();
+                        this.fromApiJsonHelper.checkForUnsupportedParameters(criteriaScoreArrayObjectParameterTypeOfMap,
+                                this.fromApiJsonHelper.toJson(criteriaScoreElement), criteriaScoreSupportedParameters);
+
+                        final Long featureId = this.fromApiJsonHelper.extractLongNamed("featureId", criteriaScoreElement);
+                        baseDataValidator.reset().parameter(criteriaScoresParameterName).parameterAtIndexArray("featureId", i)
+                                .value(featureId).notNull().integerGreaterThanZero();
+
+                        final String feature = this.fromApiJsonHelper.extractStringNamed("feature", criteriaScoreElement);
+                        baseDataValidator.reset().parameter(criteriaScoresParameterName).parameterAtIndexArray("feature", i).value(feature)
+                                .ignoreIfNull().notExceedingLengthOf(100);
+
+                        final String value = this.fromApiJsonHelper.extractStringNamed("value", criteriaScoreElement);
+                        baseDataValidator.reset().parameter(criteriaScoresParameterName).parameterAtIndexArray("value", i).value(value)
+                                .notNull().notExceedingLengthOf(100);
+
+                        if (this.fromApiJsonHelper.parameterExists("score", criteriaScoreElement)) {
+                            final BigDecimal score = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("score", criteriaScoreElement);
+                            baseDataValidator.reset().parameter(criteriaScoresParameterName).parameterAtIndexArray("score", i).value(score)
+                                    .ignoreIfNull().positiveAmount();
+                        }
+
+                        if (this.fromApiJsonHelper.parameterExists("color", criteriaScoreElement)) {
+                            final String color = this.fromApiJsonHelper.extractStringNamed("color", criteriaScoreElement);
+                            baseDataValidator.reset().parameter(criteriaScoresParameterName).parameterAtIndexArray("color", i).value(color)
+                                    .ignoreIfNull().notExceedingLengthOf(100);
+                        }
+                    }
+                }
+            }
+        }
+
+        if (!dataValidationErrors.isEmpty()) {
+            throw new PlatformApiDataValidationException(dataValidationErrors);
+        }
+
+    }
+
+    private void validateStatScorecardJson(final JsonElement element) {
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("statScorecard");
+
+        final String statScorecardParameterName = "statScorecard";
+        if (element.isJsonObject() && this.fromApiJsonHelper.parameterExists(statScorecardParameterName, element)) {
+            final JsonObject topLevelJsonElement = element.getAsJsonObject();
+
+            if (topLevelJsonElement.get(statScorecardParameterName).isJsonObject()) {
+                final Type arrayObjectParameterTypeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+                final Set<String> supportedParameters = new HashSet<>(
+                        Arrays.asList("age", "sex", "job", "housing", "creditAmount", "duration", "purpose", "locale", "dateFormat"));
+
+                final JsonObject statScorecardElement = topLevelJsonElement.getAsJsonObject(statScorecardParameterName);
+                this.fromApiJsonHelper.checkForUnsupportedParameters(arrayObjectParameterTypeOfMap,
+                        this.fromApiJsonHelper.toJson(statScorecardElement), supportedParameters);
+
+                final Integer age = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("age", statScorecardElement);
+                baseDataValidator.reset().parameter("age").value(age).ignoreIfNull().integerGreaterThanZero();
+
+                final String sex = this.fromApiJsonHelper.extractStringNamed("sex", statScorecardElement);
+                baseDataValidator.reset().parameter("sex").value(sex).ignoreIfNull().notExceedingLengthOf(100);
+
+                final String job = this.fromApiJsonHelper.extractStringNamed("job", statScorecardElement);
+                baseDataValidator.reset().parameter("job").value(job).ignoreIfNull().notExceedingLengthOf(100);
+
+                final String housing = this.fromApiJsonHelper.extractStringNamed("housing", statScorecardElement);
+                baseDataValidator.reset().parameter("housing").value(housing).ignoreIfNull().notExceedingLengthOf(100);
+
+                final BigDecimal creditAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("creditAmount",
+                        statScorecardElement);
+                baseDataValidator.reset().parameter("creditAmount").value(creditAmount).notNull().positiveAmount();
+
+                final Integer duration = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("duration", statScorecardElement);
+                baseDataValidator.reset().parameter("duration").value(duration).ignoreIfNull().integerGreaterThanZero();
+
+                final String purpose = this.fromApiJsonHelper.extractStringNamed("purpose", statScorecardElement);
+                baseDataValidator.reset().parameter("purpose").value(purpose).ignoreIfNull().notExceedingLengthOf(100);
+
+            }
+        }
+
+        if (!dataValidationErrors.isEmpty()) {
+            throw new PlatformApiDataValidationException(dataValidationErrors);
+        }
+
+    }
+
+    private void validateMLScorecardJson(final JsonElement element) {
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("mlScorecard");
+
+        final String mlScorecardParameterName = "mlScorecard";
+        if (element.isJsonObject() && this.fromApiJsonHelper.parameterExists(mlScorecardParameterName, element)) {
+            final JsonObject topLevelJsonElement = element.getAsJsonObject();
+
+            if (topLevelJsonElement.get(mlScorecardParameterName).isJsonObject()) {
+                final Type arrayObjectParameterTypeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+                final Set<String> supportedParameters = new HashSet<>(
+                        Arrays.asList("age", "sex", "job", "housing", "creditAmount", "duration", "purpose", "locale", "dateFormat"));
+
+                final JsonObject mlScorecardElement = topLevelJsonElement.getAsJsonObject(mlScorecardParameterName);
+                this.fromApiJsonHelper.checkForUnsupportedParameters(arrayObjectParameterTypeOfMap,
+                        this.fromApiJsonHelper.toJson(mlScorecardElement), supportedParameters);
+
+                final Integer age = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("age", mlScorecardElement);
+                baseDataValidator.reset().parameter("age").value(age).ignoreIfNull().integerGreaterThanZero();
+
+                final String sex = this.fromApiJsonHelper.extractStringNamed("sex", mlScorecardElement);
+                baseDataValidator.reset().parameter("sex").value(sex).ignoreIfNull().notExceedingLengthOf(100);
+
+                final String job = this.fromApiJsonHelper.extractStringNamed("job", mlScorecardElement);
+                baseDataValidator.reset().parameter("job").value(job).ignoreIfNull().notExceedingLengthOf(100);
+
+                final String housing = this.fromApiJsonHelper.extractStringNamed("housing", mlScorecardElement);
+                baseDataValidator.reset().parameter("housing").value(housing).ignoreIfNull().notExceedingLengthOf(100);
+
+                final BigDecimal creditAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("creditAmount", mlScorecardElement);
+                baseDataValidator.reset().parameter("creditAmount").value(creditAmount).notNull().positiveAmount();
+
+                final Integer duration = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("duration", mlScorecardElement);
+                baseDataValidator.reset().parameter("duration").value(duration).ignoreIfNull().integerGreaterThanZero();
+
+                final String purpose = this.fromApiJsonHelper.extractStringNamed("purpose", mlScorecardElement);
+                baseDataValidator.reset().parameter("purpose").value(purpose).ignoreIfNull().notExceedingLengthOf(100);
+
+            }
+        }
+
+        if (!dataValidationErrors.isEmpty()) {
+            throw new PlatformApiDataValidationException(dataValidationErrors);
+        }
+
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardAssembler.java
new file mode 100644
index 0000000..0274866
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardAssembler.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+import com.google.gson.JsonElement;
+import java.util.List;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecard;
+import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
+import org.apache.fineract.portfolio.loanproduct.domain.LoanProductScorecardFeature;
+
+public interface CreditScorecardAssembler extends CreditScorecardService {
+
+    CreditScorecard assembleFrom(JsonElement element);
+
+    List<LoanProductScorecardFeature> assembleListOfProductScoringFeatures(JsonCommand command, LoanProduct loanProduct);
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardEnumerations.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardEnumerations.java
new file mode 100644
index 0000000..c42b6c9
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardEnumerations.java
@@ -0,0 +1,137 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureCategory;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureDataType;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureValueType;
+
+public final class CreditScorecardEnumerations {
+
+    public static final String FEATURE_VALUE_TYPE = "valueType";
+    public static final String FEATURE_DATA_TYPE = "dataType";
+    public static final String FEATURE_CATEGORY = "category";
+
+    private CreditScorecardEnumerations() {
+        //
+    }
+
+    public static EnumOptionData scorecardEnumueration(final String typeName, final int id) {
+        switch (typeName) {
+            case FEATURE_VALUE_TYPE:
+                return featureValueType(id);
+            case FEATURE_DATA_TYPE:
+                return featureDataType(id);
+            case FEATURE_CATEGORY:
+                return featureCategory(id);
+        }
+        return null;
+    }
+
+    public static EnumOptionData featureValueType(final Integer id) {
+        return featureValueType(FeatureValueType.fromInt(id));
+    }
+
+    public static EnumOptionData featureValueType(final FeatureValueType valueType) {
+        EnumOptionData optionData = null;
+        switch (valueType) {
+            case BINARY:
+                optionData = new EnumOptionData(FeatureValueType.BINARY.getValue().longValue(), FeatureValueType.BINARY.getCode(),
+                        "Binary");
+            break;
+            case NOMINAL:
+                optionData = new EnumOptionData(FeatureValueType.NOMINAL.getValue().longValue(), FeatureValueType.NOMINAL.getCode(),
+                        "Nominal");
+            break;
+            case INTERVAL:
+                optionData = new EnumOptionData(FeatureValueType.INTERVAL.getValue().longValue(), FeatureValueType.INTERVAL.getCode(),
+                        "Interval");
+            break;
+            case RATIO:
+                optionData = new EnumOptionData(FeatureValueType.RATIO.getValue().longValue(), FeatureValueType.RATIO.getCode(), "Ratio");
+            break;
+            default:
+                optionData = new EnumOptionData(FeatureValueType.INVALID.getValue().longValue(), FeatureValueType.INVALID.getCode(),
+                        "Invalid");
+            break;
+        }
+        return optionData;
+    }
+
+    public static EnumOptionData featureDataType(final Integer id) {
+        return featureDataType(FeatureDataType.fromInt(id));
+    }
+
+    public static EnumOptionData featureDataType(final FeatureDataType valueType) {
+        EnumOptionData optionData = null;
+        switch (valueType) {
+            case NUMERIC:
+                optionData = new EnumOptionData(FeatureDataType.NUMERIC.getValue().longValue(), FeatureDataType.NUMERIC.getCode(),
+                        "Numeric");
+            break;
+            case STRING:
+                optionData = new EnumOptionData(FeatureDataType.STRING.getValue().longValue(), FeatureDataType.STRING.getCode(), "String");
+            break;
+            case DATE:
+                optionData = new EnumOptionData(FeatureDataType.DATE.getValue().longValue(), FeatureDataType.DATE.getCode(), "Date");
+            break;
+            default:
+                optionData = new EnumOptionData(FeatureValueType.INVALID.getValue().longValue(), FeatureValueType.INVALID.getCode(),
+                        "Invalid");
+            break;
+        }
+        return optionData;
+    }
+
+    public static EnumOptionData featureCategory(final Integer id) {
+        return featureCategory(FeatureCategory.fromInt(id));
+    }
+
+    public static EnumOptionData featureCategory(final FeatureCategory category) {
+        EnumOptionData optionData = null;
+        switch (category) {
+            case INDIVIDUAL:
+                optionData = new EnumOptionData(FeatureCategory.INDIVIDUAL.getValue().longValue(), FeatureCategory.INDIVIDUAL.getCode(),
+                        "Individual");
+            break;
+            case ORGANISATION:
+                optionData = new EnumOptionData(FeatureCategory.ORGANISATION.getValue().longValue(), FeatureCategory.ORGANISATION.getCode(),
+                        "Organisation");
+            break;
+            case COUNTRY:
+                optionData = new EnumOptionData(FeatureCategory.COUNTRY.getValue().longValue(), FeatureCategory.COUNTRY.getCode(),
+                        "Country");
+            break;
+            case CREDIT_HISTORY:
+                optionData = new EnumOptionData(FeatureCategory.CREDIT_HISTORY.getValue().longValue(),
+                        FeatureCategory.CREDIT_HISTORY.getCode(), "Credit History");
+            break;
+            case LOAN:
+                optionData = new EnumOptionData(FeatureCategory.LOAN.getValue().longValue(), FeatureCategory.LOAN.getCode(), "Loan");
+            break;
+            default:
+                optionData = new EnumOptionData(FeatureValueType.INVALID.getValue().longValue(), FeatureValueType.INVALID.getCode(),
+                        "Invalid");
+            break;
+        }
+        return optionData;
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardReadPlatformService.java
new file mode 100644
index 0000000..9c16889
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardReadPlatformService.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+import java.util.Collection;
+import java.util.List;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardData;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardFeature;
+
+public interface CreditScorecardReadPlatformService extends CreditScorecardService {
+
+    CreditScorecardFeatureData retrieveNewScorecardFeatureDetails();
+
+    Collection<CreditScorecardFeatureData> retrieveLoanProductFeatures(Long productId);
+
+    CreditScorecardData retrieveCreditScorecard(Long scorecardId);
+
+    CreditScorecardData loanScorecardTemplate();
+
+    CreditScorecardData loanScorecardTemplate(CreditScorecardData scorecard);
+
+    CreditScorecardFeature findOneFeatureWithNotFoundDetection(Long id);
+
+    List<CreditScorecardFeature> findAllFeaturesWithNotFoundDetection();
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardService.java
new file mode 100644
index 0000000..2efad9f
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardService.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+public interface CreditScorecardService {
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardWritePlatformService.java
new file mode 100644
index 0000000..38c0012
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardWritePlatformService.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecard;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+
+public interface CreditScorecardWritePlatformService extends CreditScorecardService {
+
+    CommandProcessingResult createScoringFeature(JsonCommand command);
+
+    CommandProcessingResult deleteScoringFeature(Long entityId);
+
+    CommandProcessingResult updateScoringFeature(Long entityId, JsonCommand command);
+
+    CreditScorecard assessCreditRisk(Loan loan);
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
index 0bac357..2db0407 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
@@ -136,5 +136,8 @@
     String lastApplication = "lastApplication";
 
     String fixedPrincipalPercentagePerInstallmentParamName = "fixedPrincipalPercentagePerInstallment";
+    String recalculationCompoundingFrequencyDate = "recalculationCompoundingFrequencyDate";
+
+    String scorecard = "scorecard";
 
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
index 702cb56..f7171ec 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
@@ -100,6 +100,10 @@
 import org.apache.fineract.portfolio.collateral.service.CollateralReadPlatformService;
 import org.apache.fineract.portfolio.collateralmanagement.data.LoanCollateralResponseData;
 import org.apache.fineract.portfolio.collateralmanagement.service.LoanCollateralManagementReadPlatformService;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardData;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardReadPlatformService;
 import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
 import org.apache.fineract.portfolio.fund.data.FundData;
 import org.apache.fineract.portfolio.fund.service.FundReadPlatformService;
@@ -259,6 +263,7 @@
     private final DefaultToApiJsonSerializer<GlimRepaymentTemplate> glimTemplateToApiJsonSerializer;
     private final GLIMAccountInfoReadPlatformService glimAccountInfoReadPlatformService;
     private final LoanCollateralManagementReadPlatformService loanCollateralManagementReadPlatformService;
+    private final ScorecardServiceProvider scorecardServiceProvider;
 
     public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
             final LoanProductReadPlatformService loanProductReadPlatformService,
@@ -284,7 +289,8 @@
             final ConfigurationDomainService configurationDomainService,
             final DefaultToApiJsonSerializer<GlimRepaymentTemplate> glimTemplateToApiJsonSerializer,
             final GLIMAccountInfoReadPlatformService glimAccountInfoReadPlatformService,
-            final LoanCollateralManagementReadPlatformService loanCollateralManagementReadPlatformService) {
+            final LoanCollateralManagementReadPlatformService loanCollateralManagementReadPlatformService,
+            final ScorecardServiceProvider scorecardServiceProvider) {
         this.context = context;
         this.loanReadPlatformService = loanReadPlatformService;
         this.loanProductReadPlatformService = loanProductReadPlatformService;
@@ -317,6 +323,7 @@
         this.glimTemplateToApiJsonSerializer = glimTemplateToApiJsonSerializer;
         this.glimAccountInfoReadPlatformService = glimAccountInfoReadPlatformService;
         this.loanCollateralManagementReadPlatformService = loanCollateralManagementReadPlatformService;
+        this.scorecardServiceProvider = scorecardServiceProvider;
     }
 
     /*
@@ -454,10 +461,20 @@
                 accountLinkingOptions = getaccountLinkingOptions(newLoanAccount, clientId, groupId);
             }
 
+            CreditScorecardData scorecard = null;
+
+            final String serviceName = "CreditScorecardReadPlatformService";
+            final CreditScorecardReadPlatformService scorecardService = (CreditScorecardReadPlatformService) scorecardServiceProvider
+                    .getScorecardService(serviceName);
+
+            if (scorecardService != null) {
+                scorecard = scorecardService.loanScorecardTemplate();
+            }
+
             // add product options, allowed loan officers and calendar options
             // (calendar options will be null in individual loan)
             newLoanAccount = LoanAccountData.associationsAndTemplate(newLoanAccount, productOptions, allowedLoanOfficers, calendarOptions,
-                    accountLinkingOptions, isRatesEnabled);
+                    accountLinkingOptions, isRatesEnabled, scorecard);
         }
         final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
                 .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.LOAN.getName(), productId);
@@ -499,6 +516,19 @@
         this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
 
         LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveOne(loanId);
+
+        CreditScorecardData scorecard = null;
+
+        final String serviceName = "CreditScorecardReadPlatformService";
+        final CreditScorecardReadPlatformService scorecardService = (CreditScorecardReadPlatformService) scorecardServiceProvider
+                .getScorecardService(serviceName);
+
+        if (scorecardService != null) {
+            scorecard = scorecardService.retrieveCreditScorecard(loanBasicDetails.getScorecardId());
+        }
+
+        loanBasicDetails = LoanAccountData.populateScorecardDetails(loanBasicDetails, scorecard);
+
         if (loanBasicDetails.isInterestRecalculationEnabled()) {
             Collection<CalendarData> interestRecalculationCalendarDatas = this.calendarReadPlatformService.retrieveCalendarsByEntity(
                     loanBasicDetails.getInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue(),
@@ -749,14 +779,24 @@
             rates = this.rateReadService.retrieveLoanRates(loanId);
         }
 
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+
+        final Collection<CreditScorecardFeatureData> scorecardFeatureOptions = null;
+
+        CreditScorecardData scorecardWithTemplate = null;
+
+        if (scorecardService != null) {
+            scorecardWithTemplate = scorecardService.loanScorecardTemplate(scorecard);
+        }
+
         final LoanAccountData loanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, loanRepayments,
                 charges, loanCollateralManagementData, guarantors, meeting, productOptions, loanTermFrequencyTypeOptions,
                 repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions,
                 repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
                 interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
                 loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
-                overdueCharges, paidInAdvanceTemplate, interestRatesPeriods, clientActiveLoanOptions, rates, isRatesEnabled,
-                collectionData);
+                overdueCharges, paidInAdvanceTemplate, interestRatesPeriods, clientActiveLoanOptions, rates, isRatesEnabled, collectionData,
+                scorecardFeatures, scorecardFeatureOptions, scorecardWithTemplate);
 
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
                 mandatoryResponseParameters);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
index 4bc706a..7a62839 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
@@ -38,6 +38,8 @@
 import org.apache.fineract.portfolio.calendar.data.CalendarData;
 import org.apache.fineract.portfolio.charge.data.ChargeData;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardData;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
 import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
 import org.apache.fineract.portfolio.fund.data.FundData;
 import org.apache.fineract.portfolio.group.data.GroupGeneralData;
@@ -189,6 +191,7 @@
     private final Long closureLoanId;
     private final String closureLoanAccountNo;
     private final BigDecimal topupAmount;
+    private final CreditScorecardData scorecard;
 
     private LoanProductData product;
 
@@ -239,6 +242,8 @@
     private LocalDate expectedDisbursementDate;
 
     private final CollectionData delinquent;
+    private final Collection<CreditScorecardFeatureData> scorecardFeatures;
+    private final Collection<CreditScorecardFeatureData> scorecardFeatureOptions;
 
     public static LoanAccountData importInstanceIndividual(EnumOptionData loanTypeEnumOption, Long clientId, Long productId,
             Long loanOfficerId, LocalDate submittedOnDate, Long fundId, BigDecimal principal, Integer numberOfRepayments,
@@ -255,7 +260,7 @@
                 nominalInterestRate, expectedDisbursementDate, amortizationEnumOption, interestMethodEnum,
                 interestCalculationPeriodTypeEnum, inArrearsTolerance, transactionProcessingStrategyId, graceOnPrincipalPayment,
                 graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, repaymentsStartingFromDate, rowIndex, externalId,
-                null, charges, linkAccountId, locale, dateFormat, loanCollateralManagementData);
+                null, charges, linkAccountId, locale, dateFormat, loanCollateralManagementData, null, null);
     }
 
     public static LoanAccountData importInstanceGroup(EnumOptionData loanTypeEnumOption, Long groupIdforGroupLoan, Long productId,
@@ -272,7 +277,7 @@
                 nominalInterestRate, null, amortizationEnumOption, interestMethodEnum, interestCalculationPeriodEnum, arrearsTolerance,
                 transactionProcessingStrategyId, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
                 interestChargedFromDate, repaymentsStartingFromDate, rowIndex, externalId, null, null, linkAccountId, locale, dateFormat,
-                null);
+                null, null, null);
     }
 
     private LoanAccountData(EnumOptionData loanType, Long clientId, Long productId, Long loanOfficerId, LocalDate submittedOnDate,
@@ -283,7 +288,8 @@
             Integer graceOnPrincipalPayment, Integer graceOnInterestPayment, Integer graceOnInterestCharged,
             LocalDate interestChargedFromDate, LocalDate repaymentsStartingFromDate, Integer rowIndex, String externalId, Long groupId,
             Collection<LoanChargeData> charges, String linkAccountId, String locale, String dateFormat,
-            Collection<LoanCollateralManagementData> loanCollateralManagementData) {
+            Collection<LoanCollateralManagementData> loanCollateralManagementData, CreditScorecardData scorecard,
+            Collection<CreditScorecardFeatureData> scorecardFeatures) {
         this.dateFormat = dateFormat;
         this.locale = locale;
         this.rowIndex = rowIndex;
@@ -426,6 +432,41 @@
         this.isRatesEnabled = false;
         this.fixedPrincipalPercentagePerInstallment = null;
         this.delinquent = null;
+
+        this.scorecard = scorecard;
+
+        this.scorecardFeatures = scorecardFeatures;
+        this.scorecardFeatureOptions = null;
+
+    }
+
+    public static LoanAccountData populateScorecardDetails(LoanAccountData acc, CreditScorecardData scorecard) {
+        return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
+                acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
+                acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
+                acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.netDisbursalAmount,
+                acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments,
+                acc.repaymentEvery, acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType,
+                acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod,
+                acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate,
+                acc.interestRateDifferential, acc.interestCalculationPeriodType, acc.allowPartialPeriodInterestCalcualtion,
+                acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment, acc.recurringMoratoriumOnPrincipalPeriods,
+                acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary,
+                acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
+                acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
+                acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions,
+                acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
+                acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
+                acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
+                acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
+                acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount,
+                acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
+                acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
+                acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
+                acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
+                acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
+                acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
+                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.scorecardFeatures, acc.scorecardFeatureOptions, scorecard);
     }
 
     public Integer getRowIndex() {
@@ -593,6 +634,11 @@
         final BigDecimal fixedPrincipalPercentagePerInstallment = null;
         final CollectionData delinquent = CollectionData.template();
 
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+        final Collection<CreditScorecardFeatureData> scorecardFeatureOptions = null;
+
+        final CreditScorecardData scorecard = null;
+
         return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
                 loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
                 loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, principal,
@@ -613,7 +659,8 @@
                 interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
                 isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
                 closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
-                fixedPrincipalPercentagePerInstallment, delinquent);
+                fixedPrincipalPercentagePerInstallment, delinquent, scorecardFeatures, scorecardFeatureOptions, scorecard);
+
     }
 
     /**
@@ -739,6 +786,11 @@
         final BigDecimal fixedPrincipalPercentagePerInstallment = null;
         final CollectionData delinquent = CollectionData.template();
 
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+        final Collection<CreditScorecardFeatureData> scorecardFeatureOptions = null;
+
+        final CreditScorecardData scorecard = null;
+
         return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
                 loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
                 loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, principal,
@@ -759,7 +811,8 @@
                 originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
                 isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
                 closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
-                fixedPrincipalPercentagePerInstallment, delinquent);
+                fixedPrincipalPercentagePerInstallment, delinquent, scorecardFeatures, scorecardFeatureOptions, scorecard);
+
     }
 
     public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
@@ -790,7 +843,8 @@
                 acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
                 acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
                 acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
-                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
+                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.scorecardFeatures, acc.scorecardFeatureOptions,
+                acc.scorecard);
     }
 
     /**
@@ -918,6 +972,11 @@
         final BigDecimal fixedPrincipalPercentagePerInstallment = null;
         final CollectionData delinquent = CollectionData.template();
 
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+        final Collection<CreditScorecardFeatureData> scorecardFeatureOptions = null;
+
+        final CreditScorecardData scorecard = null;
+
         return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
                 loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
                 loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, principal,
@@ -938,7 +997,8 @@
                 originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
                 isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
                 closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
-                fixedPrincipalPercentagePerInstallment, delinquent);
+                fixedPrincipalPercentagePerInstallment, delinquent, scorecardFeatures, scorecardFeatureOptions, scorecard);
+
     }
 
     public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
@@ -968,7 +1028,9 @@
                 acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
                 acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
                 acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
-                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
+                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.scorecardFeatures, acc.scorecardFeatureOptions,
+                acc.scorecard);
+
     }
 
     public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
@@ -980,7 +1042,8 @@
             final Collection<EnumOptionData> interestTypeOptions, final Collection<EnumOptionData> interestCalculationPeriodTypeOptions,
             final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions,
             final Collection<CodeValueData> loanPurposeOptions, final Collection<CodeValueData> loanCollateralOptions,
-            final Integer loanCycleNumber, final Collection<LoanAccountSummaryData> clientActiveLoanOptions) {
+            final Integer loanCycleNumber, final Collection<LoanAccountSummaryData> clientActiveLoanOptions,
+            final Collection<CreditScorecardFeatureData> scorecardFeatureOptions) {
 
         final Long id = null;
         final String accountNo = null;
@@ -1111,6 +1174,10 @@
         final Boolean isRatesEnabled = false;
         final CollectionData delinquent = CollectionData.template();
 
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = product.scorecardFeatures();
+        // final Collection<CreditScorecardFeatureData> scorecardFeatureOptions = scorecardFeatureOptions;
+        final CreditScorecardData scorecard = null;
+
         return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
                 loanType, product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(),
                 product.getFundId(), product.getFundName(), loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
@@ -1136,7 +1203,7 @@
                 product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
                 product.getMaximumGapBetweenInstallments(), subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId,
                 closureLoanAccountNo, topupAmount, product.isEqualAmortization(), rates, isRatesEnabled,
-                product.getFixedPrincipalPercentagePerInstallment(), delinquent);
+                product.getFixedPrincipalPercentagePerInstallment(), delinquent, scorecardFeatures, scorecardFeatureOptions, scorecard);
     }
 
     public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
@@ -1179,6 +1246,8 @@
             }
         }
         final CollectionData delinquent = CollectionData.template();
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = product.scorecardFeatures();
+        final Collection<CreditScorecardFeatureData> scorecardFeatureOptions = null;
 
         return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
                 acc.clientOfficeId, acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(),
@@ -1206,7 +1275,8 @@
                 product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
                 product.getMaximumGapBetweenInstallments(), acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
                 acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, product.isEqualAmortization(), acc.rates, acc.isRatesEnabled,
-                product.getFixedPrincipalPercentagePerInstallment(), delinquent);
+                product.getFixedPrincipalPercentagePerInstallment(), delinquent, scorecardFeatures, scorecardFeatureOptions, acc.scorecard);
+
     }
 
     /*
@@ -1237,7 +1307,8 @@
             final LoanInterestRecalculationData interestRecalculationData, final Boolean createStandingInstructionAtDisbursement,
             final Boolean isVariableInstallmentsAllowed, Integer minimumGap, Integer maximumGap, final EnumOptionData subStatus,
             final boolean canUseForTopup, final boolean isTopup, final Long closureLoanId, final String closureLoanAccountNo,
-            final BigDecimal topupAmount, final boolean isEqualAmortization, final BigDecimal fixedPrincipalPercentagePerInstallment) {
+            final BigDecimal topupAmount, final boolean isEqualAmortization, final BigDecimal fixedPrincipalPercentagePerInstallment,
+            final CreditScorecardData scorecard) {
 
         final LoanScheduleData repaymentSchedule = null;
         final Collection<LoanTransactionData> transactions = null;
@@ -1278,6 +1349,9 @@
         final Boolean isRatesEnabled = false;
         final CollectionData delinquent = CollectionData.template();
 
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+        final Collection<CreditScorecardFeatureData> scorecardFeatureOptions = null;
+
         return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
                 loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
                 loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal,
@@ -1297,7 +1371,8 @@
                 isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
                 createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap,
                 maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount,
-                isEqualAmortization, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquent);
+                isEqualAmortization, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquent, scorecardFeatures,
+                scorecardFeatureOptions, scorecard);
     }
 
     /*
@@ -1321,7 +1396,9 @@
             final Collection<LoanTermVariationsData> emiAmountVariations, final Collection<ChargeData> overdueCharges,
             final PaidInAdvanceData paidInAdvance, Collection<InterestRatePeriodData> interestRatesPeriods,
             final Collection<LoanAccountSummaryData> clientActiveLoanOptions, final List<RateData> rates, final Boolean isRatesEnabled,
-            final CollectionData delinquent) {
+            final CollectionData delinquent, final Collection<CreditScorecardFeatureData> scorecardFeatures,
+            final Collection<CreditScorecardFeatureData> scorecardFeatureOptions, final CreditScorecardData scorecard) {
+
         LoanProductConfigurableAttributes loanProductConfigurableAttributes = null;
         if (acc.product != null) {
             loanProductConfigurableAttributes = acc.product.getloanProductConfigurableAttributes();
@@ -1351,12 +1428,13 @@
                 acc.createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, acc.isVariableInstallmentsAllowed,
                 acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, clientActiveLoanOptions, acc.isTopup, acc.closureLoanId,
                 acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, rates, isRatesEnabled,
-                acc.fixedPrincipalPercentagePerInstallment, delinquent);
+                acc.fixedPrincipalPercentagePerInstallment, delinquent, scorecardFeatures, scorecardFeatureOptions, scorecard);
     }
 
     public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
             final Collection<StaffData> allowedLoanOfficers, final Collection<CalendarData> calendarOptions,
-            final Collection<PortfolioAccountData> accountLinkingOptions, final Boolean isRatesEnabled) {
+            final Collection<PortfolioAccountData> accountLinkingOptions, final Boolean isRatesEnabled,
+            final CreditScorecardData scorecard) {
         return associationsAndTemplate(acc, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
                 acc.meeting, productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
                 acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions,
@@ -1364,7 +1442,8 @@
                 acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
                 allowedLoanOfficers, acc.loanPurposeOptions, acc.loanCollateralOptions, calendarOptions, acc.notes, accountLinkingOptions,
                 acc.linkedAccount, acc.disbursementDetails, acc.emiAmountVariations, acc.overdueCharges, acc.paidInAdvance,
-                acc.interestRatesPeriods, acc.clientActiveLoanOptions, acc.rates, isRatesEnabled, acc.delinquent);
+                acc.interestRatesPeriods, acc.clientActiveLoanOptions, acc.rates, isRatesEnabled, acc.delinquent, acc.scorecardFeatures,
+                acc.scorecardFeatureOptions, scorecard);
     }
 
     public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) {
@@ -1394,7 +1473,8 @@
                 acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
                 acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
                 acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
-                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
+                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.scorecardFeatures, acc.scorecardFeatureOptions,
+                acc.scorecard);
     }
 
     public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
@@ -1460,7 +1540,9 @@
                 acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
                 acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
                 acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
-                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
+                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.scorecardFeatures, acc.scorecardFeatureOptions,
+                acc.scorecard);
+
     }
 
     public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData,
@@ -1494,7 +1576,8 @@
                 acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
                 acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
                 acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
-                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
+                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.scorecardFeatures, acc.scorecardFeatureOptions,
+                acc.scorecard);
     }
 
     public static LoanAccountData withLoanCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
@@ -1523,11 +1606,11 @@
                 acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
                 acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
                 acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
-                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
+                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.scorecardFeatures, acc.scorecardFeatureOptions,
+                acc.scorecard);
     }
 
     public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
-
         return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
                 acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
                 acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
@@ -1553,7 +1636,8 @@
                 acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
                 acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
                 acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
-                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
+                acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.scorecardFeatures, acc.scorecardFeatureOptions,
+                acc.scorecard);
     }
 
     private LoanAccountData(final Long id, //
@@ -1606,7 +1690,9 @@
             final Integer minimumGap, final Integer maximumGap, final EnumOptionData subStatus, final Boolean canUseForTopup,
             final Collection<LoanAccountSummaryData> clientActiveLoanOptions, final boolean isTopup, final Long closureLoanId,
             final String closureLoanAccountNo, final BigDecimal topupAmount, final boolean isEqualAmortization, final List<RateData> rates,
-            final Boolean isRatesEnabled, final BigDecimal fixedPrincipalPercentagePerInstallment, final CollectionData delinquent) {
+            final Boolean isRatesEnabled, final BigDecimal fixedPrincipalPercentagePerInstallment, final CollectionData delinquent,
+            final Collection<CreditScorecardFeatureData> scorecardFeatures,
+            final Collection<CreditScorecardFeatureData> scorecardFeatureOptions, final CreditScorecardData scorecard) {
 
         this.id = id;
         this.accountNo = accountNo;
@@ -1794,6 +1880,16 @@
         this.rates = rates;
         this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
         this.delinquent = delinquent;
+
+        this.scorecardFeatures = scorecardFeatures;
+        if (CollectionUtils.isEmpty(scorecardFeatureOptions)) {
+            this.scorecardFeatureOptions = null;
+        } else {
+            this.scorecardFeatureOptions = scorecardFeatureOptions;
+        }
+
+        this.scorecard = scorecard;
+
     }
 
     public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
@@ -1817,6 +1913,10 @@
         return this.charges;
     }
 
+    public Collection<CreditScorecardFeatureData> getScorecardFeatures() {
+        return this.scorecardFeatures;
+    }
+
     public Long groupOfficeId() {
         return this.group == null ? null : this.group.officeId();
     }
@@ -1953,4 +2053,11 @@
         return this.status.value();
     }
 
+    public Long getScorecardId() {
+        if (scorecard != null) {
+            return scorecard.getId();
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 4ac8c25..3fe845e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -100,6 +100,7 @@
 import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
 import org.apache.fineract.portfolio.common.domain.NthDayType;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecard;
 import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
 import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
 import org.apache.fineract.portfolio.fund.domain.Fund;
@@ -420,6 +421,10 @@
     @Column(name = "fixed_principal_percentage_per_installment", scale = 2, precision = 5, nullable = true)
     private BigDecimal fixedPrincipalPercentagePerInstallment;
 
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name = "loan_credit_scorecard_id", referencedColumnName = "id")
+    private CreditScorecard scorecard;
+
     public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final Integer loanType,
             final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose,
             final LoanTransactionProcessingStrategy transactionProcessingStrategy,
@@ -427,14 +432,15 @@
             final Set<LoanCollateralManagement> collateral, final BigDecimal fixedEmiAmount,
             final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
             final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
-            final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment) {
+            final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment,
+            final CreditScorecard scorecard) {
         final LoanStatus status = null;
         final Group group = null;
         final Boolean syncDisbursementWithMeeting = null;
         return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
                 loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
                 disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
-                interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment);
+                interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment, scorecard);
     }
 
     public static Loan newGroupLoanApplication(final String accountNo, final Group group, final Integer loanType,
@@ -444,13 +450,14 @@
             final Set<LoanCollateralManagement> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
             final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
             final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
-            final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment) {
+            final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment,
+            final CreditScorecard scorecard) {
         final LoanStatus status = null;
         final Client client = null;
         return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
                 loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
                 disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
-                interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment);
+                interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment, scorecard);
     }
 
     public static Loan newIndividualLoanApplicationFromGroup(final String accountNo, final Client client, final Group group,
@@ -460,12 +467,13 @@
             final Set<LoanCollateralManagement> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
             final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
             final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
-            final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment) {
+            final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment,
+            final CreditScorecard scorecard) {
         final LoanStatus status = null;
         return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
                 loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
                 disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
-                interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment);
+                interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment, scorecard);
     }
 
     protected Loan() {
@@ -479,7 +487,7 @@
             final BigDecimal fixedEmiAmount, final List<LoanDisbursementDetails> disbursementDetails,
             final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement,
             final Boolean isFloatingInterestRate, final BigDecimal interestRateDifferential, final List<Rate> rates,
-            final BigDecimal fixedPrincipalPercentagePerInstallment) {
+            final BigDecimal fixedPrincipalPercentagePerInstallment, final CreditScorecard scorecard) {
 
         this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail;
         this.loanRepaymentScheduleDetail.validateRepaymentPeriodWithGraceSettings();
@@ -543,6 +551,7 @@
         // Add net get net disbursal amount from charges and principal
         this.netDisbursalAmount = this.approvedPrincipal.subtract(deriveSumTotalOfChargesDueAtDisbursement());
 
+        this.scorecard = scorecard;
     }
 
     public Integer getNumberOfRepayments() {
@@ -4633,7 +4642,7 @@
             break;
         }
         return dueRepaymentPeriodDate.minusDays(1);// get 2n-1 range date from
-                                                   // startDate
+        // startDate
     }
 
     public void applyHolidayToRepaymentScheduleDates(final Holiday holiday, final LoanUtilService loanUtilService) {
@@ -6841,4 +6850,12 @@
     public void adjustNetDisbursalAmount(BigDecimal adjustedAmount) {
         this.netDisbursalAmount = adjustedAmount.subtract(this.deriveSumTotalOfChargesDueAtDisbursement());
     }
+
+    public CreditScorecard getScorecard() {
+        return scorecard;
+    }
+
+    public boolean hasScorecard() {
+        return this.scorecard != null;
+    }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
index a3e0f14..711373d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
@@ -1,3 +1,4 @@
+
 /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements. See the NOTICE file
@@ -43,6 +44,7 @@
 import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
 import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement;
 import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagementRepositoryWrapper;
+import org.apache.fineract.portfolio.creditscorecard.serialization.CreditScorecardApiJsonHelper;
 import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
@@ -99,14 +101,17 @@
     private final FromJsonHelper fromApiJsonHelper;
     private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper;
     private final ClientCollateralManagementRepositoryWrapper clientCollateralManagementRepositoryWrapper;
+    private final CreditScorecardApiJsonHelper scorecardApiJsonHelper;
 
     @Autowired
     public LoanApplicationCommandFromApiJsonHelper(final FromJsonHelper fromApiJsonHelper,
             final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper,
-            final ClientCollateralManagementRepositoryWrapper clientCollateralManagementRepositoryWrapper) {
+            final ClientCollateralManagementRepositoryWrapper clientCollateralManagementRepositoryWrapper,
+            final CreditScorecardApiJsonHelper scorecardApiJsonHelper) {
         this.fromApiJsonHelper = fromApiJsonHelper;
         this.apiJsonHelper = apiJsonHelper;
         this.clientCollateralManagementRepositoryWrapper = clientCollateralManagementRepositoryWrapper;
+        this.scorecardApiJsonHelper = scorecardApiJsonHelper;
     }
 
     public void validateForCreate(final String json, final boolean isMeetingMandatoryForJLGLoans, final LoanProduct loanProduct) {
@@ -439,6 +444,12 @@
          * accounts. (loanType.isJLG() || loanType.isGLIM())
          */
 
+        // Scorecard
+        final String scorecardParameterName = "scorecard";
+        if (element.isJsonObject() && this.fromApiJsonHelper.parameterExists(scorecardParameterName, element)) {
+            this.scorecardApiJsonHelper.validateScorecardJson(element);
+        }
+
         if (!StringUtils.isBlank(loanTypeStr)) {
             final AccountType loanType = AccountType.fromName(loanTypeStr);
 
@@ -861,6 +872,13 @@
             baseDataValidator.reset().parameter(linkAccountIdParameterName).value(linkAccountId).ignoreIfNull().longGreaterThanZero();
         }
 
+        // Scorecard
+        final String scorecardParameterName = "scorecard";
+        if (element.isJsonObject() && this.fromApiJsonHelper.parameterExists(scorecardParameterName, element)) {
+            atLeastOneParameterPassedForUpdate = true;
+            this.scorecardApiJsonHelper.validateScorecardJson(element);
+        }
+
         // charges
         final String chargesParameterName = "charges";
         if (element.isJsonObject() && this.fromApiJsonHelper.parameterExists(chargesParameterName, element)) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
index fe97760..5e8bc40 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
@@ -50,6 +50,7 @@
 import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
+import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
 import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
@@ -88,6 +89,8 @@
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BusinessEvents;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardWritePlatformService;
 import org.apache.fineract.portfolio.fund.domain.Fund;
 import org.apache.fineract.portfolio.group.domain.Group;
 import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
@@ -199,6 +202,8 @@
     private final LoanCollateralManagementRepository loanCollateralManagementRepository;
     private final ClientCollateralManagementRepository clientCollateralManagementRepository;
 
+    private final ScorecardServiceProvider scorecardServiceProvider;
+
     @Autowired
     public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
             final LoanApplicationTransitionApiJsonValidator loanApplicationTransitionApiJsonValidator,
@@ -226,7 +231,8 @@
             final LoanRepository loanRepository, final GSIMReadPlatformService gsimReadPlatformService, final RateAssembler rateAssembler,
             final LoanProductReadPlatformService loanProductReadPlatformService,
             final LoanCollateralManagementRepository loanCollateralManagementRepository,
-            final ClientCollateralManagementRepository clientCollateralManagementRepository) {
+            final ClientCollateralManagementRepository clientCollateralManagementRepository,
+            final ScorecardServiceProvider scorecardServiceProvider) {
         this.context = context;
         this.fromJsonHelper = fromJsonHelper;
         this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
@@ -269,6 +275,7 @@
         this.gsimReadPlatformService = gsimReadPlatformService;
         this.loanCollateralManagementRepository = loanCollateralManagementRepository;
         this.clientCollateralManagementRepository = clientCollateralManagementRepository;
+        this.scorecardServiceProvider = scorecardServiceProvider;
     }
 
     private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -530,6 +537,17 @@
                 }
             }
 
+            if (newLoanApplication.hasScorecard()) {
+                final String serviceName = "CreditScorecardWritePlatformService";
+                final CreditScorecardWritePlatformService scorecardService = (CreditScorecardWritePlatformService) this.scorecardServiceProvider
+                        .getScorecardService(serviceName);
+                if (scorecardService == null) {
+                    throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                            ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+                }
+                scorecardService.assessCreditRisk(newLoanApplication);
+            }
+
             // Save linked account information
             SavingsAccount savingsAccount;
             final boolean backdatedTxnsAllowedTill = false;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
index 60f31d1..4b197ab 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
@@ -19,6 +19,7 @@
 package org.apache.fineract.portfolio.loanaccount.service;
 
 import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.ZoneId;
@@ -35,6 +36,7 @@
 import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.organisation.holiday.domain.Holiday;
 import org.apache.fineract.organisation.holiday.domain.HolidayRepository;
@@ -52,6 +54,9 @@
 import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
 import org.apache.fineract.portfolio.collateralmanagement.domain.CollateralManagementDomain;
 import org.apache.fineract.portfolio.collateralmanagement.service.LoanCollateralAssembler;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecard;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardAssembler;
 import org.apache.fineract.portfolio.fund.domain.Fund;
 import org.apache.fineract.portfolio.fund.domain.FundRepository;
 import org.apache.fineract.portfolio.fund.exception.FundNotFoundException;
@@ -115,6 +120,7 @@
     private final WorkingDaysRepositoryWrapper workingDaysRepository;
     private final LoanUtilService loanUtilService;
     private final RateAssembler rateAssembler;
+    private final ScorecardServiceProvider scorecardServiceProvider;
 
     @Autowired
     public LoanAssembler(final FromJsonHelper fromApiJsonHelper, final LoanRepositoryWrapper loanRepository,
@@ -126,7 +132,8 @@
             final LoanCollateralAssembler collateralAssembler, final LoanSummaryWrapper loanSummaryWrapper,
             final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
             final HolidayRepository holidayRepository, final ConfigurationDomainService configurationDomainService,
-            final WorkingDaysRepositoryWrapper workingDaysRepository, final LoanUtilService loanUtilService, RateAssembler rateAssembler) {
+            final WorkingDaysRepositoryWrapper workingDaysRepository, final LoanUtilService loanUtilService, RateAssembler rateAssembler,
+            final ScorecardServiceProvider scorecardServiceProvider) {
         this.fromApiJsonHelper = fromApiJsonHelper;
         this.loanRepository = loanRepository;
         this.loanProductRepository = loanProductRepository;
@@ -146,6 +153,7 @@
         this.workingDaysRepository = workingDaysRepository;
         this.loanUtilService = loanUtilService;
         this.rateAssembler = rateAssembler;
+        this.scorecardServiceProvider = scorecardServiceProvider;
     }
 
     public Loan assembleFrom(final Long accountId) {
@@ -270,6 +278,23 @@
         BigDecimal fixedPrincipalPercentagePerInstallment = fromApiJsonHelper
                 .extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, element);
 
+        final JsonObject scorecardElement = this.fromApiJsonHelper.extractJsonObjectNamed("scorecard", element);
+        CreditScorecard scorecard = null;
+
+        if (scorecardElement != null) {
+            final String scoringMethod = scorecardElement.get("scoringMethod").getAsString();
+            if (scoringMethod != null) {
+                final String serviceName = "CreditScorecardAssembler";
+                final CreditScorecardAssembler scorecardAssembler = (CreditScorecardAssembler) this.scorecardServiceProvider
+                        .getScorecardService(serviceName);
+                if (scorecardAssembler == null) {
+                    throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                            ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+                }
+                scorecard = scorecardAssembler.assembleFrom(scorecardElement);
+            }
+        }
+
         Loan loanApplication = null;
         Client client = null;
         Group group = null;
@@ -308,21 +333,21 @@
                     fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, null,
                     syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
                     createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates,
-                    fixedPrincipalPercentagePerInstallment);
+                    fixedPrincipalPercentagePerInstallment, scorecard);
 
         } else if (group != null) {
             loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer,
                     loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, null,
                     syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
                     createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates,
-                    fixedPrincipalPercentagePerInstallment);
+                    fixedPrincipalPercentagePerInstallment, scorecard);
 
         } else if (client != null) {
 
             loanApplication = Loan.newIndividualLoanApplication(accountNo, client, loanType.getId().intValue(), loanProduct, fund,
                     loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
                     fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement,
-                    isFloatingInterestRate, interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment);
+                    isFloatingInterestRate, interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment, scorecard);
 
         }
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index 0d8e305..3939908 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -73,6 +73,10 @@
 import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.apache.fineract.portfolio.common.service.CommonEnumerations;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardData;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardReadPlatformService;
 import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
 import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
 import org.apache.fineract.portfolio.fund.data.FundData;
@@ -150,7 +154,7 @@
     private final CalendarReadPlatformService calendarReadPlatformService;
     private final StaffReadPlatformService staffReadPlatformService;
     private final PaginationHelper paginationHelper;
-    private final LoanMapper loaanLoanMapper;
+    private final LoanMapper loanMapper;
     private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
     private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
     private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
@@ -161,6 +165,7 @@
     private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
     private final ColumnValidator columnValidator;
     private final DatabaseSpecificSQLGenerator sqlGenerator;
+    private final ScorecardServiceProvider scorecardServiceProvider;
 
     @Autowired
     public LoanReadPlatformServiceImpl(final PlatformSecurityContext context,
@@ -175,7 +180,8 @@
             final FloatingRatesReadPlatformService floatingRatesReadPlatformService, final LoanUtilService loanUtilService,
             final ConfigurationDomainService configurationDomainService,
             final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final LoanRepositoryWrapper loanRepositoryWrapper,
-            final ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
+            final ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper,
+            final ScorecardServiceProvider scorecardServiceProvider) {
         this.context = context;
         this.loanRepositoryWrapper = loanRepositoryWrapper;
         this.applicationCurrencyRepository = applicationCurrencyRepository;
@@ -197,9 +203,10 @@
         this.configurationDomainService = configurationDomainService;
         this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
         this.columnValidator = columnValidator;
-        this.loaanLoanMapper = new LoanMapper(sqlGenerator);
+        this.loanMapper = new LoanMapper(sqlGenerator);
         this.sqlGenerator = sqlGenerator;
         this.paginationHelper = paginationHelper;
+        this.scorecardServiceProvider = scorecardServiceProvider;
     }
 
     @Override
@@ -301,7 +308,7 @@
 
         final StringBuilder sqlBuilder = new StringBuilder(200);
         sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
-        sqlBuilder.append(this.loaanLoanMapper.loanSchema());
+        sqlBuilder.append(this.loanMapper.loanSchema());
 
         // TODO - for time being this will data scope list of loans returned to
         // only loans that have a client associated.
@@ -365,7 +372,7 @@
         }
         final Object[] objectArray = extraCriterias.toArray();
         final Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
-        return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.loaanLoanMapper);
+        return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.loanMapper);
     }
 
     @Override
@@ -671,7 +678,11 @@
                     + " lpvi.minimum_gap as minimuminstallmentgap, lpvi.maximum_gap as maximuminstallmentgap, "
                     + " lp.can_use_for_topup as canUseForTopup, " + " l.is_topup as isTopup, " + " topup.closure_loan_id as closureLoanId, "
                     + " l.total_recovered_derived as totalRecovered" + ", topuploan.account_no as closureLoanAccountNo, "
-                    + " topup.topup_amount as topupAmount " + " from m_loan l" //
+                    + " topup.topup_amount as topupAmount, "
+                    + " csc.id as scorecardId, csc.scorecard_scoring_method as scoringMethod, csc.scorecard_scoring_model as scoringModel "
+
+                    + " from m_loan l" //
+
                     + " join m_product_loan lp on lp.id = l.product_id" //
                     + " left join m_loan_recalculation_details lir on lir.loan_id = l.id " + " join m_currency rc on rc."
                     + sqlGenerator.escape("code") + " = l.currency_code" //
@@ -690,7 +701,8 @@
                     + " left join ref_loan_transaction_processing_strategy lps on lps.id = l.loan_transaction_strategy_id"
                     + " left join m_product_loan_variable_installment_config lpvi on lpvi.loan_product_id = l.product_id"
                     + " left join m_loan_topup as topup on l.id = topup.loan_id"
-                    + " left join m_loan as topuploan on topuploan.id = topup.closure_loan_id";
+                    + " left join m_loan as topuploan on topuploan.id = topup.closure_loan_id"
+                    + " left join m_credit_scorecard as csc on csc.id = l.loan_credit_scorecard_id";
 
         }
 
@@ -995,6 +1007,11 @@
             final String closureLoanAccountNo = rs.getString("closureLoanAccountNo");
             final BigDecimal topupAmount = rs.getBigDecimal("topupAmount");
 
+            final Long scorecardId = rs.getLong("scorecardId");
+            final String scoringMethod = rs.getString("scoringMethod");
+            final String scoringModel = rs.getString("scoringModel");
+            final CreditScorecardData loanScorecardDetails = CreditScorecardData.instance(scorecardId, scoringMethod, scoringModel);
+
             return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName,
                     clientOfficeId, groupData, loanType, loanProductId, loanProductName, loanProductDescription,
                     isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
@@ -1009,7 +1026,7 @@
                     isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
                     createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap, maximumGap, loanSubStatus,
                     canUseForTopup, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization,
-                    fixedPrincipalPercentagePerInstallment);
+                    fixedPrincipalPercentagePerInstallment, loanScorecardDetails);
         }
     }
 
@@ -1458,10 +1475,21 @@
             activeLoanOptions = this.accountDetailsReadPlatformService.retrieveGroupActiveLoanAccountSummary(groupId);
         }
 
+        Collection<CreditScorecardFeatureData> scorecardFeatureOptions = null;
+
+        final String serviceName = "CreditScorecardReadPlatformService";
+        final CreditScorecardReadPlatformService scorecardService = (CreditScorecardReadPlatformService) scorecardServiceProvider
+                .getScorecardService(serviceName);
+
+        if (scorecardService != null) {
+            scorecardFeatureOptions = scorecardService.retrieveLoanProductFeatures(productId);
+        }
+
         return LoanAccountData.loanProductWithTemplateDefaults(loanProduct, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
                 repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDaysOfWeekTypeOptions, repaymentStrategyOptions,
                 interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
-                fundOptions, chargeOptions, loanPurposeOptions, loanCollateralOptions, loanCycleCounter, activeLoanOptions);
+                fundOptions, chargeOptions, loanPurposeOptions, loanCollateralOptions, loanCycleCounter, activeLoanOptions,
+                scorecardFeatureOptions);
     }
 
     @Override
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
index 0799ebf..12f7228 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
@@ -33,6 +33,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -65,6 +66,10 @@
 import org.apache.fineract.portfolio.charge.data.ChargeData;
 import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
 import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardFeature;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardReadPlatformService;
 import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData;
 import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
 import org.apache.fineract.portfolio.fund.data.FundData;
@@ -130,6 +135,7 @@
     private final FloatingRatesReadPlatformService floatingRateReadPlatformService;
     private final RateReadService rateReadService;
     private final ConfigurationDomainService configurationDomainService;
+    private final ScorecardServiceProvider scorecardServiceProvider;
 
     @Autowired
     public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
@@ -145,7 +151,7 @@
             final DropdownReadPlatformService commonDropdownReadPlatformService,
             PaymentTypeReadPlatformService paymentTypeReadPlatformService,
             final FloatingRatesReadPlatformService floatingRateReadPlatformService, final RateReadService rateReadService,
-            final ConfigurationDomainService configurationDomainService) {
+            final ConfigurationDomainService configurationDomainService, final ScorecardServiceProvider scorecardServiceProvider) {
         this.context = context;
         this.loanProductReadPlatformService = readPlatformService;
         this.chargeReadPlatformService = chargeReadPlatformService;
@@ -164,6 +170,7 @@
         this.floatingRateReadPlatformService = floatingRateReadPlatformService;
         this.rateReadService = rateReadService;
         this.configurationDomainService = configurationDomainService;
+        this.scorecardServiceProvider = scorecardServiceProvider;
     }
 
     @POST
@@ -366,13 +373,24 @@
                 .retrivePreCloseInterestCalculationStrategyOptions();
         final List<FloatingRateData> floatingRateOptions = this.floatingRateReadPlatformService.retrieveLookupActive();
 
+        Collection<CreditScorecardFeatureData> scorecardFeatureOptions = null;
+
+        final String serviceName = "CreditScorecardReadPlatformService";
+        final CreditScorecardReadPlatformService scorecardService = (CreditScorecardReadPlatformService) scorecardServiceProvider
+                .getScorecardService(serviceName);
+
+        if (scorecardService != null) {
+            scorecardFeatureOptions = scorecardService.findAllFeaturesWithNotFoundDetection().stream().map(CreditScorecardFeature::toData)
+                    .collect(Collectors.toList());
+        }
+
         return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions,
                 interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions,
                 fundOptions, transactionProcessingStrategyOptions, rateOptions, accountOptions, accountingRuleTypeOptions,
                 loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
                 interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
                 preCloseInterestCalculationStrategyOptions, floatingRateOptions, interestRecalculationNthDayTypeOptions,
-                interestRecalculationDayOfWeekTypeOptions, isRatesEnabled);
+                interestRecalculationDayOfWeekTypeOptions, isRatesEnabled, scorecardFeatureOptions);
     }
 
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
index 40077a8..1b42056 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
@@ -39,6 +39,7 @@
 import org.apache.fineract.portfolio.common.domain.DaysInYearType;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.apache.fineract.portfolio.common.service.CommonEnumerations;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
 import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData;
 import org.apache.fineract.portfolio.fund.data.FundData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanInterestRecalculationData;
@@ -198,6 +199,9 @@
     private final boolean isEqualAmortization;
     private final BigDecimal fixedPrincipalPercentagePerInstallment;
 
+    private final Collection<CreditScorecardFeatureData> scorecardFeatures;
+    private final Collection<CreditScorecardFeatureData> scorecardFeatureOptions;
+
     /**
      * Used when returning lookup information about loan product for dropdowns.
      */
@@ -282,6 +286,9 @@
         final Collection<RateData> rateOptions = null;
         final Collection<RateData> rates = null;
         final boolean isRatesEnabled = false;
+
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+
         return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
                 numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
                 minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
@@ -298,7 +305,7 @@
                 floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
                 maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
                 syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
-                fixedPrincipalPercentagePerInstallment);
+                fixedPrincipalPercentagePerInstallment, scorecardFeatures);
 
     }
 
@@ -385,6 +392,8 @@
         final Collection<RateData> rates = null;
         final boolean isRatesEnabled = false;
 
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+
         return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
                 numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
                 minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
@@ -401,7 +410,7 @@
                 floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
                 maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
                 syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
-                fixedPrincipalPercentagePerInstallment);
+                fixedPrincipalPercentagePerInstallment, scorecardFeatures);
 
     }
 
@@ -495,6 +504,8 @@
         final Collection<RateData> rates = null;
         final boolean isRatesEnabled = false;
 
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+
         return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
                 numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
                 minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
@@ -511,7 +522,7 @@
                 floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
                 maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
                 syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
-                fixedPrincipalPercentagePerInstallment);
+                fixedPrincipalPercentagePerInstallment, scorecardFeatures);
 
     }
 
@@ -599,6 +610,8 @@
         final Collection<RateData> rates = null;
         final boolean isRatesEnabled = false;
 
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+
         return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
                 numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
                 minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
@@ -615,7 +628,7 @@
                 floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
                 maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
                 syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
-                fixedPrincipalPercentagePerInstallment);
+                fixedPrincipalPercentagePerInstallment, scorecardFeatures);
 
     }
 
@@ -660,7 +673,7 @@
             final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments,
             final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
             Collection<RateData> rateOptions, Collection<RateData> rates, final boolean isRatesEnabled,
-            final BigDecimal fixedPrincipalPercentagePerInstallment) {
+            final BigDecimal fixedPrincipalPercentagePerInstallment, final Collection<CreditScorecardFeatureData> scorecardFeatures) {
         this.id = id;
         this.name = name;
         this.shortName = shortName;
@@ -775,6 +788,9 @@
         this.canUseForTopup = canUseForTopup;
         this.isEqualAmortization = isEqualAmortization;
 
+        this.scorecardFeatures = scorecardFeatures;
+        this.scorecardFeatureOptions = null;
+
     }
 
     public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
@@ -790,7 +806,8 @@
             final List<EnumOptionData> rescheduleStrategyTypeOptions, final List<EnumOptionData> interestRecalculationFrequencyTypeOptions,
             final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions,
             final List<EnumOptionData> interestRecalculationNthDayTypeOptions,
-            final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions, final boolean isRatesEnabled) {
+            final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions, final boolean isRatesEnabled,
+            final Collection<CreditScorecardFeatureData> scorecardFeatureOptions) {
         this.id = productData.id;
         this.name = productData.name;
         this.shortName = productData.shortName;
@@ -921,6 +938,9 @@
         this.isEqualAmortization = productData.isEqualAmortization;
         this.rates = productData.rates;
         this.isRatesEnabled = isRatesEnabled;
+
+        this.scorecardFeatures = productData.scorecardFeatures;
+        this.scorecardFeatureOptions = scorecardFeatureOptions;
     }
 
     private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
@@ -1343,4 +1363,8 @@
     public BigDecimal getFixedPrincipalPercentagePerInstallment() {
         return fixedPrincipalPercentagePerInstallment;
     }
+
+    public Collection<CreditScorecardFeatureData> scorecardFeatures() {
+        return this.scorecardFeatures;
+    }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
index 4413a4f..1e5ffe1 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
@@ -202,9 +202,13 @@
     @Column(name = "over_applied_number", nullable = true)
     private Integer overAppliedNumber;
 
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
+    @JoinColumn(name = "product_loan_id", referencedColumnName = "id", nullable = false)
+    private List<LoanProductScorecardFeature> scorecardFeatures;
+
     public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
             final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
-            final List<Rate> productRates) {
+            final List<Rate> productRates, List<LoanProductScorecardFeature> scorecardFeatures) {
 
         final String name = command.stringValueOfParameterNamed("name");
         final String shortName = command.stringValueOfParameterNamed(LoanProductConstants.SHORT_NAME);
@@ -392,7 +396,7 @@
                 defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
                 minimumGapBetweenInstallments, maximumGapBetweenInstallments, syncExpectedWithDisbursementDate, canUseForTopup,
                 isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment, disallowExpectedDisbursements,
-                allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber);
+                allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber, scorecardFeatures);
 
     }
 
@@ -629,7 +633,7 @@
             final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
             final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean disallowExpectedDisbursements,
             final boolean allowApprovedDisbursedAmountsOverApplied, final String overAppliedCalculationType,
-            final Integer overAppliedNumber) {
+            final Integer overAppliedNumber, List<LoanProductScorecardFeature> scorecardFeatures) {
         this.fund = fund;
         this.transactionProcessingStrategy = transactionProcessingStrategy;
         this.name = name.trim();
@@ -716,6 +720,11 @@
         if (rates != null) {
             this.rates = rates;
         }
+
+        if (scorecardFeatures != null) {
+            this.scorecardFeatures = scorecardFeatures;
+        }
+
         validateLoanProductPreSave();
     }
 
@@ -939,6 +948,14 @@
             }
         }
 
+        final String scorecardFeaturesParamName = "scorecardFeatures";
+        if (command.hasParameter(scorecardFeaturesParamName)) {
+            final JsonArray jsonArray = command.arrayOfParameterNamed(scorecardFeaturesParamName);
+            if (jsonArray != null) {
+                actualChanges.put(scorecardFeaturesParamName, command.jsonFragment(scorecardFeaturesParamName));
+            }
+        }
+
         final String includeInBorrowerCycleParamName = "includeInBorrowerCycle";
         if (command.isChangeInBooleanParameterNamed(includeInBorrowerCycleParamName, this.includeInBorrowerCycle)) {
             final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(includeInBorrowerCycleParamName);
@@ -1608,4 +1625,28 @@
         this.loanProducTrancheDetails = loanProducTrancheDetails;
     }
 
+    public boolean updateScorecardFeatures(List<LoanProductScorecardFeature> newScorecardFeatures) {
+        if (newScorecardFeatures == null) {
+            return false;
+        }
+
+        boolean updated = false;
+        if (this.scorecardFeatures != null) {
+            final Set<LoanProductScorecardFeature> currentSetOfFeatures = new HashSet<>(this.scorecardFeatures);
+            final Set<LoanProductScorecardFeature> newSetOfFeatures = new HashSet<>(newScorecardFeatures);
+
+            if (!currentSetOfFeatures.equals(newSetOfFeatures)) {
+                updated = true;
+                this.scorecardFeatures = newScorecardFeatures;
+            }
+        } else {
+            updated = true;
+            this.scorecardFeatures = newScorecardFeatures;
+        }
+        return updated;
+    }
+
+    public List<LoanProductScorecardFeature> getScorecardFeatures() {
+        return scorecardFeatures;
+    }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRepository.java
index 143802d..1165164 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRepository.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRepository.java
@@ -28,4 +28,7 @@
 
     @Query("select loanProduct from LoanProduct loanProduct, IN(loanProduct.charges) charge where charge.id = :chargeId")
     List<LoanProduct> retrieveLoanProductsByChargeId(@Param("chargeId") Long chargeId);
+
+    @Query("select loanProduct from LoanProduct loanProduct, IN(loanProduct.scorecardFeatures) feature where feature.id = :featureId")
+    List<LoanProduct> retrieveLoanProductsByScorecardFeatureId(@Param("featureId") Long featureId);
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductScorecardFeature.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductScorecardFeature.java
new file mode 100644
index 0000000..7fa641c
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductScorecardFeature.java
@@ -0,0 +1,95 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanproduct.domain;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Objects;
+import javax.persistence.CascadeType;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardFeature;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureConfiguration;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureCriteria;
+
+@Entity
+@Table(name = "m_product_loan_scorecard_feature")
+public class LoanProductScorecardFeature extends AbstractPersistableCustom {
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "scorecard_feature_id", referencedColumnName = "id", nullable = false)
+    private CreditScorecardFeature scorecardFeature;
+
+    @Embedded
+    private FeatureConfiguration configuration;
+
+    @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.DETACH }, orphanRemoval = true, fetch = FetchType.EAGER)
+    @JoinColumn(name = "product_loan_scorecard_feature_id", referencedColumnName = "id")
+    private List<FeatureCriteria> featureCriteria;
+
+    public LoanProductScorecardFeature() {
+        //
+    }
+
+    public LoanProductScorecardFeature(final CreditScorecardFeature scorecardFeature, final BigDecimal weightage, final Integer greenMin,
+            final Integer greenMax, final Integer amberMin, final Integer amberMax, final Integer redMin, final Integer redMax) {
+        this.scorecardFeature = scorecardFeature;
+        this.configuration = FeatureConfiguration.from(weightage, greenMin, greenMax, amberMin, amberMax, redMin, redMax);
+    }
+
+    public FeatureConfiguration getFeatureConfiguration() {
+        return configuration;
+    }
+
+    public CreditScorecardFeature getScorecardFeature() {
+        return scorecardFeature;
+    }
+
+    public List<FeatureCriteria> getFeatureCriteria() {
+        return featureCriteria;
+    }
+
+    public void setFeatureCriteria(List<FeatureCriteria> featureCriteria) {
+        this.featureCriteria = featureCriteria;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof LoanProductScorecardFeature)) {
+            return false;
+        }
+        LoanProductScorecardFeature that = (LoanProductScorecardFeature) o;
+        return Objects.equals(configuration, that.configuration) && Objects.equals(scorecardFeature, that.scorecardFeature)
+                && Objects.equals(featureCriteria, that.featureCriteria);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(configuration, scorecardFeature, featureCriteria);
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductScorecardFeatureRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductScorecardFeatureRepository.java
new file mode 100644
index 0000000..939b3a6
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductScorecardFeatureRepository.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanproduct.domain;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface LoanProductScorecardFeatureRepository
+        extends JpaRepository<LoanProductScorecardFeature, Long>, JpaSpecificationExecutor<LoanProductScorecardFeature> {}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductScorecardFeatureRepositoryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductScorecardFeatureRepositoryWrapper.java
new file mode 100644
index 0000000..ee2a940
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductScorecardFeatureRepositoryWrapper.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanproduct.domain;
+
+import java.util.List;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureNotFoundException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * <p>
+ * Wrapper for {@link LoanProductScorecardFeatureRepository} that adds NULL checking and Error handling capabilities
+ * </p>
+ */
+@Service
+public class LoanProductScorecardFeatureRepositoryWrapper {
+
+    private final LoanProductScorecardFeatureRepository repository;
+
+    @Autowired
+    public LoanProductScorecardFeatureRepositoryWrapper(final LoanProductScorecardFeatureRepository repository) {
+        this.repository = repository;
+    }
+
+    @Transactional(readOnly = true)
+    public LoanProductScorecardFeature findOneWithNotFoundDetection(final Long id) {
+        return this.repository.findById(id).orElseThrow(() -> new FeatureNotFoundException(id));
+    }
+
+    public LoanProductScorecardFeature saveAndFlush(final LoanProductScorecardFeature scorecardFeature) {
+        return this.repository.saveAndFlush(scorecardFeature);
+    }
+
+    @Transactional
+    public LoanProductScorecardFeature save(final LoanProductScorecardFeature scorecardFeature) {
+        return this.repository.save(scorecardFeature);
+    }
+
+    public List<LoanProductScorecardFeature> save(List<LoanProductScorecardFeature> scorecardFeatures) {
+        return this.repository.saveAll(scorecardFeatures);
+    }
+
+    public void flush() {
+        this.repository.flush();
+    }
+
+    public void delete(final Long featureId) {
+        this.repository.deleteById(featureId);
+    }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
index d428672..e926151 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
@@ -71,7 +71,7 @@
             "graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule", "includeInBorrowerCycle", "startDate",
             "closeDate", "externalId", "isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential",
             "minDifferentialLendingRate", "defaultDifferentialLendingRate", "maxDifferentialLendingRate",
-            "isFloatingInterestRateCalculationAllowed", "syncExpectedWithDisbursementDate",
+            "isFloatingInterestRateCalculationAllowed", "syncExpectedWithDisbursementDate", "scorecardFeatures",
             LoanProductAccountingParams.FEES_RECEIVABLE.getValue(), LoanProductAccountingParams.FUND_SOURCE.getValue(),
             LoanProductAccountingParams.INCOME_FROM_FEES.getValue(), LoanProductAccountingParams.INCOME_FROM_PENALTIES.getValue(),
             LoanProductAccountingParams.INTEREST_ON_LOANS.getValue(), LoanProductAccountingParams.INTEREST_RECEIVABLE.getValue(),
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
index ac60427..6371dfd 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
@@ -36,6 +36,9 @@
 import org.apache.fineract.portfolio.charge.data.ChargeData;
 import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
 import org.apache.fineract.portfolio.common.service.CommonEnumerations;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardReadPlatformService;
 import org.apache.fineract.portfolio.loanproduct.data.LoanProductBorrowerCycleVariationData;
 import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
 import org.apache.fineract.portfolio.loanproduct.data.LoanProductGuaranteeData;
@@ -60,18 +63,20 @@
     private final RateReadService rateReadService;
     private final DatabaseSpecificSQLGenerator sqlGenerator;
     private final FineractEntityAccessUtil fineractEntityAccessUtil;
+    private final ScorecardServiceProvider scorecardServiceProvider;
 
     @Autowired
     public LoanProductReadPlatformServiceImpl(final PlatformSecurityContext context,
             final ChargeReadPlatformService chargeReadPlatformService, final JdbcTemplate jdbcTemplate,
             final FineractEntityAccessUtil fineractEntityAccessUtil, final RateReadService rateReadService,
-            DatabaseSpecificSQLGenerator sqlGenerator) {
+            DatabaseSpecificSQLGenerator sqlGenerator, final ScorecardServiceProvider scorecardServiceProvider) {
         this.context = context;
         this.chargeReadPlatformService = chargeReadPlatformService;
         this.jdbcTemplate = jdbcTemplate;
         this.fineractEntityAccessUtil = fineractEntityAccessUtil;
         this.rateReadService = rateReadService;
         this.sqlGenerator = sqlGenerator;
+        this.scorecardServiceProvider = scorecardServiceProvider;
     }
 
     @Override
@@ -82,7 +87,18 @@
             final Collection<RateData> rates = this.rateReadService.retrieveProductLoanRates(loanProductId);
             final Collection<LoanProductBorrowerCycleVariationData> borrowerCycleVariationDatas = retrieveLoanProductBorrowerCycleVariations(
                     loanProductId);
-            final LoanProductMapper rm = new LoanProductMapper(charges, borrowerCycleVariationDatas, rates);
+
+            final String serviceName = "CreditScorecardReadPlatformService";
+            final CreditScorecardReadPlatformService scorecardService = (CreditScorecardReadPlatformService) scorecardServiceProvider
+                    .getScorecardService(serviceName);
+
+            Collection<CreditScorecardFeatureData> scorecardFeatures = null;
+
+            if (scorecardService != null) {
+                scorecardFeatures = scorecardService.retrieveLoanProductFeatures(loanProductId);
+            }
+
+            final LoanProductMapper rm = new LoanProductMapper(charges, borrowerCycleVariationDatas, rates, scorecardFeatures);
             final String sql = "select " + rm.loanProductSchema() + " where lp.id = ?";
 
             return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanProductId }); // NOSONAR
@@ -104,7 +120,7 @@
 
         this.context.authenticatedUser();
 
-        final LoanProductMapper rm = new LoanProductMapper(null, null, null);
+        final LoanProductMapper rm = new LoanProductMapper(null, null, null, null);
 
         String sql = "select " + rm.loanProductSchema();
 
@@ -183,11 +199,15 @@
 
         private final Collection<RateData> rates;
 
+        private final Collection<CreditScorecardFeatureData> scorecardFeatures;
+
         LoanProductMapper(final Collection<ChargeData> charges,
-                final Collection<LoanProductBorrowerCycleVariationData> borrowerCycleVariationDatas, final Collection<RateData> rates) {
+                final Collection<LoanProductBorrowerCycleVariationData> borrowerCycleVariationDatas, final Collection<RateData> rates,
+                final Collection<CreditScorecardFeatureData> scorecardFeatures) {
             this.charges = charges;
             this.borrowerCycleVariationDatas = borrowerCycleVariationDatas;
             this.rates = rates;
+            this.scorecardFeatures = scorecardFeatures;
         }
 
         public String loanProductSchema() {
@@ -482,7 +502,7 @@
                     floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
                     maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableIntallmentsAllowed, minimumGap,
                     maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
-                    isRatesEnabled, fixedPrincipalPercentagePerInstallment);
+                    isRatesEnabled, fixedPrincipalPercentagePerInstallment, this.scorecardFeatures);
         }
     }
 
@@ -558,7 +578,7 @@
     public Collection<LoanProductData> retrieveAllLoanProductsForCurrency(String currencyCode) {
         this.context.authenticatedUser();
 
-        final LoanProductMapper rm = new LoanProductMapper(null, null, null);
+        final LoanProductMapper rm = new LoanProductMapper(null, null, null, null);
 
         String sql = "select " + rm.loanProductSchema() + " where lp.currency_code= ? ";
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
index 9b0108b..7bf183a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
@@ -32,6 +32,7 @@
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
 import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
+import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
 import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccessType;
 import org.apache.fineract.infrastructure.entityaccess.service.FineractEntityAccessUtil;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
@@ -41,6 +42,8 @@
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BusinessEntity;
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BusinessEvents;
 import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
+import org.apache.fineract.portfolio.creditscorecard.provider.ScorecardServiceProvider;
+import org.apache.fineract.portfolio.creditscorecard.service.CreditScorecardAssembler;
 import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
 import org.apache.fineract.portfolio.floatingrates.domain.FloatingRateRepositoryWrapper;
 import org.apache.fineract.portfolio.fund.domain.Fund;
@@ -53,6 +56,7 @@
 import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
+import org.apache.fineract.portfolio.loanproduct.domain.LoanProductScorecardFeature;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
 import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException;
 import org.apache.fineract.portfolio.loanproduct.exception.LoanProductCannotBeModifiedDueToNonClosedLoansException;
@@ -86,6 +90,7 @@
     private final FloatingRateRepositoryWrapper floatingRateRepository;
     private final LoanRepositoryWrapper loanRepositoryWrapper;
     private final BusinessEventNotifierService businessEventNotifierService;
+    private final ScorecardServiceProvider scorecardServiceProvider;
 
     @Autowired
     public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -95,7 +100,8 @@
             final ChargeRepositoryWrapper chargeRepository, final RateRepositoryWrapper rateRepository,
             final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService,
             final FineractEntityAccessUtil fineractEntityAccessUtil, final FloatingRateRepositoryWrapper floatingRateRepository,
-            final LoanRepositoryWrapper loanRepositoryWrapper, final BusinessEventNotifierService businessEventNotifierService) {
+            final LoanRepositoryWrapper loanRepositoryWrapper, final BusinessEventNotifierService businessEventNotifierService,
+            final ScorecardServiceProvider scorecardServiceProvider) {
         this.context = context;
         this.fromApiJsonDeserializer = fromApiJsonDeserializer;
         this.loanProductRepository = loanProductRepository;
@@ -109,6 +115,7 @@
         this.floatingRateRepository = floatingRateRepository;
         this.loanRepositoryWrapper = loanRepositoryWrapper;
         this.businessEventNotifierService = businessEventNotifierService;
+        this.scorecardServiceProvider = scorecardServiceProvider;
     }
 
     @Transactional
@@ -132,13 +139,29 @@
             final List<Charge> charges = assembleListOfProductCharges(command, currencyCode);
             final List<Rate> rates = assembleListOfProductRates(command);
 
+            List<LoanProductScorecardFeature> scorecardFeatures = null;
+            if (command.parameterExists("scorecardFeatures")) {
+                final JsonArray featuresArray = command.arrayOfParameterNamed("scorecardFeatures");
+                if (!featuresArray.isEmpty()) {
+
+                    final String serviceName = "CreditScorecardAssembler";
+                    final CreditScorecardAssembler scorecardService = (CreditScorecardAssembler) this.scorecardServiceProvider
+                            .getScorecardService(serviceName);
+                    if (scorecardService == null) {
+                        throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                                ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+                    }
+                    scorecardFeatures = scorecardService.assembleListOfProductScoringFeatures(command, null);
+                }
+            }
+
             FloatingRate floatingRate = null;
             if (command.parameterExists("floatingRatesId")) {
                 floatingRate = this.floatingRateRepository
                         .findOneWithNotFoundDetection(command.longValueOfParameterNamed("floatingRatesId"));
             }
             final LoanProduct loanproduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategy, charges, command,
-                    this.aprCalculator, floatingRate, rates);
+                    this.aprCalculator, floatingRate, rates, scorecardFeatures);
             loanproduct.updateLoanProductInRelatedClasses();
 
             this.loanProductRepository.saveAndFlush(loanproduct);
@@ -251,6 +274,29 @@
                 }
             }
 
+            if (changes.containsKey("scorecardFeatures")) {
+
+                List<LoanProductScorecardFeature> scorecardFeatures = null;
+                if (command.parameterExists("scorecardFeatures")) {
+                    final JsonArray featuresArray = command.arrayOfParameterNamed("scorecardFeatures");
+                    if (!featuresArray.isEmpty()) {
+                        final String serviceName = "CreditScorecardAssembler";
+                        final CreditScorecardAssembler scorecardService = (CreditScorecardAssembler) this.scorecardServiceProvider
+                                .getScorecardService(serviceName);
+                        if (scorecardService == null) {
+                            throw new PlatformServiceUnavailableException("err.msg.credit.scorecard.service.implementation.missing",
+                                    ScorecardServiceProvider.SERVICE_MISSING + serviceName, serviceName);
+                        }
+                        scorecardFeatures = scorecardService.assembleListOfProductScoringFeatures(command, product);
+                    }
+                }
+
+                final boolean updated = product.updateScorecardFeatures(scorecardFeatures);
+                if (!updated) {
+                    changes.remove("scorecardFeatures");
+                }
+            }
+
             if (!changes.isEmpty()) {
                 product.validateLoanProductPreSave();
                 this.loanProductRepository.saveAndFlush(product);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/domain/Note.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/domain/Note.java
index f52a7d9..9bda3c7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/domain/Note.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/domain/Note.java
@@ -22,6 +22,7 @@
 import java.util.Map;
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Table;
@@ -40,19 +41,19 @@
 @Table(name = "m_note")
 public class Note extends AbstractAuditableCustom {
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "client_id", nullable = true)
     private Client client;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "group_id", nullable = true)
     private Group group;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "loan_id", nullable = true)
     private Loan loan;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "loan_transaction_id", nullable = true)
     private LoanTransaction loanTransaction;
 
@@ -62,15 +63,15 @@
     @Column(name = "note_type_enum")
     private Integer noteTypeId;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "savings_account_id", nullable = true)
     private SavingsAccount savingsAccount;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "savings_account_transaction_id", nullable = true)
     private SavingsAccountTransaction savingsTransaction;
 
-    @ManyToOne
+    @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "share_account_id", nullable = true)
     private ShareAccount shareAccount;
 
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index 7dc8189..e02cfba 100644
--- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -30,4 +30,5 @@
     <include file="parts/0008_loan_charge_add_external_id.xml" relativeToChangelogFile="true"/>
     <include file="parts/0009_hold_reason_savings_account.xml" relativeToChangelogFile="true"/>
     <include file="parts/0010_lien_allowed_on_savings_account_products.xml" relativeToChangelogFile="true"/>
+    <include file="parts/0011_credit_scorecard.xml" relativeToChangelogFile="true"/>
 </databaseChangeLog>
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0011_credit_scorecard.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0011_credit_scorecard.xml
new file mode 100644
index 0000000..819d8b3
--- /dev/null
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0011_credit_scorecard.xml
@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements. See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership. The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied. See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                   xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
+    <changeSet author="xurror" id="1">
+        <createTable tableName="m_credit_scorecard_feature">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints nullable="false" primaryKey="true"/>
+            </column>
+            <column name="name" type="VARCHAR(100)">
+                <constraints unique="true" nullable="false"/>
+            </column>
+            <column name="value_type_enum" type="SMALLINT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="data_type_enum" type="SMALLINT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="category_enum" type="SMALLINT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="is_active" type="boolean">
+                <constraints nullable="false"/>
+            </column>
+            <column defaultValueBoolean="false" name="is_deleted" type="boolean">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+    </changeSet>
+
+    <changeSet author="xurror" id="2">
+        <insert tableName="m_permission">
+            <column name="grouping" value="portfolio"/>
+            <column name="code" value="READ_CREDIT_SCORECARD_FEATURE"/>
+            <column name="entity_name" value="CREDIT_SCORECARD_FEATURE"/>
+            <column name="action_name" value="READ"/>
+            <column name="can_maker_checker" valueBoolean="false"/>
+        </insert>
+        <insert tableName="m_permission">
+            <column name="grouping" value="portfolio"/>
+            <column name="code" value="CREATE_CREDIT_SCORECARD_FEATURE"/>
+            <column name="entity_name" value="CREDIT_SCORECARD_FEATURE"/>
+            <column name="action_name" value="CREATE"/>
+            <column name="can_maker_checker" valueBoolean="false"/>
+        </insert>
+        <insert tableName="m_permission">
+            <column name="grouping" value="portfolio"/>
+            <column name="code" value="UPDATE_CREDIT_SCORECARD_FEATURE"/>
+            <column name="entity_name" value="CREDIT_SCORECARD_FEATURE"/>
+            <column name="action_name" value="UPDATE"/>
+            <column name="can_maker_checker" valueBoolean="false"/>
+        </insert>
+        <insert tableName="m_permission">
+            <column name="grouping" value="portfolio"/>
+            <column name="code" value="DELETE_CREDIT_SCORECARD_FEATURE"/>
+            <column name="entity_name" value="CREDIT_SCORECARD_FEATURE"/>
+            <column name="action_name" value="DELETE"/>
+            <column name="can_maker_checker" valueBoolean="false"/>
+        </insert>
+    </changeSet>
+
+    <changeSet author="xurror" id="3">
+        <createTable tableName="m_product_loan_scorecard_feature">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints nullable="false" primaryKey="true"/>
+            </column>
+            <column name="product_loan_id" type="BIGINT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="scorecard_feature_id" type="BIGINT">
+                <constraints nullable="false"/>
+            </column>
+            <column defaultValueNumeric="0.000000" name="weightage" type="DECIMAL(6, 5)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="green_min" type="INT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="green_max" type="INT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="amber_min" type="INT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="amber_max" type="INT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="red_min" type="INT">
+                <constraints nullable="false"/>
+            </column>
+            <column name="red_max" type="INT">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+    </changeSet>
+
+    <changeSet author="xurror" id="4">
+        <addForeignKeyConstraint baseColumnNames="product_loan_id" baseTableName="m_product_loan_scorecard_feature"
+                                 constraintName="m_product_loan_scorecard_feature_ibfk_1" deferrable="false"
+                                 initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
+                                 referencedColumnNames="id" referencedTableName="m_product_loan" validate="true"/>
+
+        <addForeignKeyConstraint baseColumnNames="scorecard_feature_id" baseTableName="m_product_loan_scorecard_feature"
+                                 constraintName="m_product_loan_scorecard_feature_ibfk_2" deferrable="false"
+                                 initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
+                                 referencedColumnNames="id" referencedTableName="m_credit_scorecard_feature" validate="true"/>
+    </changeSet>
+
+    <changeSet author="xurror" id="5">
+        <createTable tableName="m_scorecard_feature_criteria">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints nullable="false" primaryKey="true"/>
+            </column>
+            <column name="name" type="VARCHAR(20)">
+                <constraints nullable="false"/>
+            </column>
+            <column defaultValueNumeric="0.000000" name="score" type="DECIMAL(6, 5)">
+                <constraints nullable="false"/>
+            </column>
+            <column defaultValueComputed="NULL" name="product_loan_scorecard_feature_id" type="BIGINT"/>
+        </createTable>
+    </changeSet>
+
+    <changeSet author="xurror" id="6">
+        <addForeignKeyConstraint baseColumnNames="product_loan_scorecard_feature_id"
+                                 baseTableName="m_scorecard_feature_criteria"
+                                 constraintName="m_scorecard_feature_criteria_ibfk_1" deferrable="false"
+                                 initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
+                                 referencedColumnNames="id" referencedTableName="m_product_loan_scorecard_feature" validate="true"/>
+    </changeSet>
+
+    <changeSet author="xurror" id="7">
+        <createTable tableName="m_rule_based_scorecard">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints nullable="false" primaryKey="true"/>
+            </column>
+            <column name="overall_score" type="DECIMAL(6, 5)"/>
+            <column name="overall_color" type="VARCHAR(20)"/>
+        </createTable>
+    </changeSet>
+
+    <changeSet author="xurror" id="8">
+        <createTable tableName="m_scorecard_feature_criteria_score">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints nullable="false" primaryKey="true"/>
+            </column>
+            <column name="value" type="VARCHAR(20)"/>
+            <column name="score" type="DECIMAL(6, 5)"/>
+            <column name="color" type="VARCHAR(20)"/>
+            <column defaultValueComputed="NULL" name="rule_based_scorecard_id" type="BIGINT"/>
+            <column defaultValueComputed="NULL" name="product_loan_scorecard_feature_id" type="BIGINT"/>
+        </createTable>
+    </changeSet>
+
+    <changeSet author="xurror" id="9">
+        <addForeignKeyConstraint baseColumnNames="rule_based_scorecard_id" baseTableName="m_scorecard_feature_criteria_score"
+                                 constraintName="m_scorecard_feature_criteria_score_ibfk_1" deferrable="false"
+                                 initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
+                                 referencedColumnNames="id" referencedTableName="m_rule_based_scorecard" validate="true"/>
+
+        <addForeignKeyConstraint baseColumnNames="product_loan_scorecard_feature_id" baseTableName="m_scorecard_feature_criteria_score"
+                                 constraintName="m_scorecard_feature_criteria_score_ibfk_2" deferrable="false"
+                                 initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
+                                 referencedColumnNames="id" referencedTableName="m_product_loan_scorecard_feature" validate="true"/>
+    </changeSet>
+
+    <changeSet author="xurror" id="10">
+        <createTable tableName="m_stat_scorecard">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints nullable="false" primaryKey="true"/>
+            </column>
+            <column defaultValueComputed="NULL" name="age" type="INT"/>
+            <column defaultValueComputed="NULL" name="sex" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="job" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="housing" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="credit_amount" type="DECIMAL(19, 6)"/>
+            <column defaultValueComputed="NULL" name="duration" type="INT"/>
+            <column defaultValueComputed="NULL" name="purpose" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="method" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="color" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="prediction" type="DECIMAL(19, 6)"/>
+            <column defaultValueComputed="NULL" name="wilki_s_lambda" type="DECIMAL(19, 6)"/>
+            <column defaultValueComputed="NULL" name="pillai_s_trace" type="DECIMAL(19, 6)"/>
+            <column defaultValueComputed="NULL" name="hotelling_lawley_trace" type="DECIMAL(19, 6)"/>
+            <column defaultValueComputed="NULL" name="roy_s_greatest_roots" type="DECIMAL(19, 6)"/>
+        </createTable>
+    </changeSet>
+
+    <changeSet author="xurror" id="11">
+        <createTable tableName="m_ml_scorecard">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints nullable="false" primaryKey="true"/>
+            </column>
+            <column defaultValueComputed="NULL" name="age" type="INT"/>
+            <column defaultValueComputed="NULL" name="sex" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="job" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="housing" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="credit_amount" type="DECIMAL(19, 6)"/>
+            <column defaultValueComputed="NULL" name="duration" type="INT"/>
+            <column defaultValueComputed="NULL" name="purpose" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="predicted_risk" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="accuracy" type="DECIMAL(19, 6)"/>
+            <column defaultValueComputed="NULL" name="actual_risk" type="VARCHAR(50)"/>
+            <column defaultValueComputed="NULL" name="prediction_request_id" type="INT"/>
+        </createTable>
+    </changeSet>
+
+    <changeSet author="xurror" id="12">
+        <createTable tableName="m_credit_scorecard">
+            <column autoIncrement="true" name="id" type="BIGINT">
+                <constraints nullable="false" primaryKey="true"/>
+            </column>
+            <column name="scorecard_scoring_method" type="VARCHAR(100)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="scorecard_scoring_model" type="VARCHAR(100)">
+                <constraints nullable="false"/>
+            </column>
+            <column defaultValueComputed="NULL" name="rule_based_scorecard_id" type="BIGINT"/>
+            <column defaultValueComputed="NULL" name="stat_scorecard_id" type="BIGINT"/>
+            <column defaultValueComputed="NULL" name="ml_scorecard_id" type="BIGINT"/>
+        </createTable>
+    </changeSet>
+
+    <changeSet author="xurror" id="13">
+        <addForeignKeyConstraint baseColumnNames="rule_based_scorecard_id" baseTableName="m_credit_scorecard"
+                                 constraintName="m_credit_scorecard_ibfk_1" deferrable="false"
+                                 initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
+                                 referencedColumnNames="id" referencedTableName="m_rule_based_scorecard" validate="true"/>
+
+        <addForeignKeyConstraint baseColumnNames="stat_scorecard_id" baseTableName="m_credit_scorecard"
+                                 constraintName="m_credit_scorecard_ibfk_2" deferrable="false"
+                                 initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
+                                 referencedColumnNames="id" referencedTableName="m_stat_scorecard" validate="true"/>
+
+        <addForeignKeyConstraint baseColumnNames="ml_scorecard_id" baseTableName="m_credit_scorecard"
+                                 constraintName="m_credit_scorecard_ibfk_3" deferrable="false"
+                                 initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
+                                 referencedColumnNames="id" referencedTableName="m_ml_scorecard" validate="true"/>
+    </changeSet>
+
+    <changeSet author="xurror" id="14">
+        <addColumn tableName="m_loan">
+            <column defaultValueComputed="NULL" name="loan_credit_scorecard_id" type="BIGINT"/>
+        </addColumn>
+
+        <addForeignKeyConstraint baseColumnNames="loan_credit_scorecard_id"
+                                 baseTableName="m_loan"
+                                 constraintName="FK_credit_scorecard_m_loan_m_credit_scorecard" deferrable="false"
+                                 initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
+                                 referencedColumnNames="id" referencedTableName="m_credit_scorecard" validate="true"/>
+    </changeSet>
+</databaseChangeLog>