Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0182ee6
Introduce new website module with submodules for various REST APIs.
gjong Sep 27, 2025
3cb3909
Update the test for profile patching and creating.
gjong Sep 28, 2025
6be3ed2
Fix the security test by adding filter to authenticate users.
gjong Sep 30, 2025
7314a1f
Change formatting rule
gjong Oct 1, 2025
5be2cff
Update bank account tests.
gjong Oct 3, 2025
8315e94
Update tests for saving goals
gjong Oct 4, 2025
48d1122
Reformat using plantir with aosp
gjong Oct 4, 2025
c82b000
Add the category end point implementations.
gjong Oct 4, 2025
66a32eb
Add contract-related features and documentation.
gjong Oct 4, 2025
b74eb96
Introduce Tag API functionalities.
gjong Oct 5, 2025
819b24b
Introduce System Information API.
gjong Oct 5, 2025
b3fd410
Add the insight controller.
gjong Oct 5, 2025
0814243
Introduce Export API and transaction mappings.
gjong Oct 5, 2025
7445f30
Introduce Schedule API with command and fetcher endpoints.
gjong Oct 5, 2025
a308de3
Introduce Statistics Balance API and schema updates.
gjong Oct 5, 2025
01d910d
Migrate APIs to `/v2` namespace and add support for schedule-related …
gjong Oct 8, 2025
fbeab4a
Enhance Schedule API tests and fix schedule end date validation.
gjong Oct 8, 2025
77b029e
Introduce Transaction API and schema updates.
gjong Oct 10, 2025
fefb651
Enhance runtime API with task and variable controllers, schema update…
gjong Oct 10, 2025
76f8dd9
Changes needed to better support the UI.
gjong Oct 12, 2025
01cb65a
Add timers, logging enhancements, schema updates, and dependency impr…
gjong Oct 15, 2025
cddbb06
Fix transaction mapping, balance filter logic, and expense name filte…
gjong Oct 19, 2025
5978974
Add API enhancements, schema updates, and improved controllers.
gjong Nov 2, 2025
cc4c94b
add the contract for transaction rules.
gjong Nov 3, 2025
9d42b64
Introduce Learning Rule API and update AuthenticationFacade mocks.
gjong Nov 11, 2025
5a876ba
Fallbacks for booleans
gjong Nov 12, 2025
5929178
Fix tests
gjong Nov 26, 2025
bc272b4
Fix for bigdecimal parsing
gjong Dec 1, 2025
3aa740c
Improve coverage for system-api
gjong Dec 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ root = true

[*.java]
indent_style = space
indent_size = 2
indent_size = 4
ij_java_continuation_indent_size = 4
57 changes: 30 additions & 27 deletions bpmn-process/src/main/java/com/jongsoft/finance/ProcessMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,42 @@

import com.jongsoft.lang.Control;
import com.jongsoft.lang.control.Try;

import io.micronaut.serde.ObjectMapper;

import jakarta.inject.Singleton;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Singleton
public class ProcessMapper {

private final ObjectMapper objectMapper;

public ProcessMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

public <T> String writeSafe(T entity) {
return Control.Try(() -> objectMapper.writeValueAsString(entity))
.recover(x -> {
log.warn("Could not serialize entity {}", entity, x);
return null;
})
.get();
}

public <T> T readSafe(String json, Class<T> clazz) {
return Control.Try(() -> objectMapper.readValue(json, clazz))
.recover(x -> {
log.warn("Could not deserialize json {}", json, x);
return null;
})
.get();
}

public <T> Try<T> read(String json, Class<T> clazz) {
return Control.Try(() -> objectMapper.readValue(json, clazz));
}
private final ObjectMapper objectMapper;

public ProcessMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

public <T> String writeSafe(T entity) {
return Control.Try(() -> objectMapper.writeValueAsString(entity))
.recover(x -> {
log.warn("Could not serialize entity {}", entity, x);
return null;
})
.get();
}

public <T> T readSafe(String json, Class<T> clazz) {
return Control.Try(() -> objectMapper.readValue(json, clazz))
.recover(x -> {
log.warn("Could not deserialize json {}", json, x);
return null;
})
.get();
}

public <T> Try<T> read(String json, Class<T> clazz) {
return Control.Try(() -> objectMapper.readValue(json, clazz));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

public class KnownProcesses {

private KnownProcesses() {
// private constructor
}
private KnownProcesses() {
// private constructor
}

/**
* The process identifier for the process that monitors for contract ending and sends the user a
* notification before hand.
*/
public static final String CONTRACT_WARN_EXPIRY = "ContractEndWarning";
/**
* The process identifier for the process that monitors for contract ending and sends the user a
* notification before hand.
*/
public static final String CONTRACT_WARN_EXPIRY = "ContractEndWarning";

/** The process identifier for the process that handles any type of scheduling. */
public static final String PROCESS_SCHEDULE = "ProcessScheduler";
/** The process identifier for the process that handles any type of scheduling. */
public static final String PROCESS_SCHEDULE = "ProcessScheduler";
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
import com.jongsoft.finance.ProcessVariable;
import com.jongsoft.finance.bpmn.camunda.*;
import com.jongsoft.finance.importer.api.TransactionDTO;

import io.micronaut.context.ApplicationContext;
import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Requires;
import io.micronaut.serde.ObjectMapper;
import java.io.IOException;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.RuntimeService;
Expand All @@ -21,89 +22,93 @@
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;
import java.util.List;

@Slf4j
@Factory
@Requires(notEnv = "no-camunda")
public class ProcessEngineConfiguration {

private final ApplicationContext applicationContext;
private final CamundaDatasourceConfiguration camundaDatasourceConfiguration;

public ProcessEngineConfiguration(
ApplicationContext applicationContext,
CamundaDatasourceConfiguration camundaDatasourceConfiguration) {
this.applicationContext = applicationContext;
this.camundaDatasourceConfiguration = camundaDatasourceConfiguration;
}

@Bean
public ProcessEngine processEngine() throws IOException {
var configuration = new StandaloneProcessEngineConfiguration();

configuration
.setHistory(camundaDatasourceConfiguration.getHistoryLevel())
.setJobExecutorActivate(true)
.setMetricsEnabled(true)
.setJdbcDriver(camundaDatasourceConfiguration.getDriverClassName())
.setJdbcUrl(camundaDatasourceConfiguration.getUrl())
.setJdbcUsername(camundaDatasourceConfiguration.getUsername())
.setJdbcPassword(camundaDatasourceConfiguration.getPassword())
.setDatabaseSchemaUpdate(camundaDatasourceConfiguration.getAutoUpdate())
.setProcessEngineName("fintrack")
.setHistoryCleanupEnabled(true)
.setSkipIsolationLevelCheck(true)
.setExpressionManager(
new MicronautExpressionManager(new MicronautElResolver(applicationContext)));

configuration.setHistoryCleanupBatchSize(250);
configuration.setHistoryCleanupBatchWindowStartTime("01:00");
configuration.setHistoryCleanupBatchWindowEndTime("03:00");
configuration.setHistoryTimeToLive("P1D");
configuration.setResolverFactories(List.of(new MicronautBeanResolver(applicationContext)));
configuration.setCustomPreVariableSerializers(List.of(
new JsonRecordSerializer<>(
applicationContext.getBean(ObjectMapper.class), ProcessVariable.class),
new JsonRecordSerializer<>(
applicationContext.getBean(ObjectMapper.class), TransactionDTO.class)));

var processEngine = configuration.buildProcessEngine();
log.info("Created camunda process engine");

deployResources(processEngine);
return processEngine;
}

@Bean
public HistoryService historyService(ProcessEngine processEngine) {
return processEngine.getHistoryService();
}

@Bean
public TaskService taskService(ProcessEngine processEngine) {
return processEngine.getTaskService();
}

@Bean
public RuntimeService runtimeService(ProcessEngine processEngine) {
return processEngine.getRuntimeService();
}

private void deployResources(ProcessEngine processEngine) throws IOException {
log.info("Searching for deployable camunda processes");

PathMatchingResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
for (String extension : List.of("dmn", "cmmn", "bpmn")) {
for (Resource resource :
resourceLoader.getResources(CLASSPATH_ALL_URL_PREFIX + extension + "/*/*." + extension)) {
log.info("Deploying model: {}", resource.getFilename());
processEngine
.getRepositoryService()
.createDeployment()
.name("MicronautAutoDeployment")
.addInputStream(resource.getFilename(), resource.getInputStream())
.enableDuplicateFiltering(true)
.deploy();
}
private final ApplicationContext applicationContext;
private final CamundaDatasourceConfiguration camundaDatasourceConfiguration;

public ProcessEngineConfiguration(
ApplicationContext applicationContext,
CamundaDatasourceConfiguration camundaDatasourceConfiguration) {
this.applicationContext = applicationContext;
this.camundaDatasourceConfiguration = camundaDatasourceConfiguration;
}

@Bean
public ProcessEngine processEngine() throws IOException {
var configuration = new StandaloneProcessEngineConfiguration();

configuration
.setHistory(camundaDatasourceConfiguration.getHistoryLevel())
.setJobExecutorActivate(true)
.setMetricsEnabled(true)
.setJdbcDriver(camundaDatasourceConfiguration.getDriverClassName())
.setJdbcUrl(camundaDatasourceConfiguration.getUrl())
.setJdbcUsername(camundaDatasourceConfiguration.getUsername())
.setJdbcPassword(camundaDatasourceConfiguration.getPassword())
.setDatabaseSchemaUpdate(camundaDatasourceConfiguration.getAutoUpdate())
.setProcessEngineName("fintrack")
.setHistoryCleanupEnabled(true)
.setSkipIsolationLevelCheck(true)
.setExpressionManager(new MicronautExpressionManager(
new MicronautElResolver(applicationContext)));

configuration.setHistoryCleanupBatchSize(250);
configuration.setHistoryCleanupBatchWindowStartTime("01:00");
configuration.setHistoryCleanupBatchWindowEndTime("03:00");
configuration.setHistoryTimeToLive("P1D");
configuration.setResolverFactories(List.of(new MicronautBeanResolver(applicationContext)));
configuration.setCustomPreVariableSerializers(List.of(
new JsonRecordSerializer<>(
applicationContext.getBean(ObjectMapper.class), ProcessVariable.class),
new JsonRecordSerializer<>(
applicationContext.getBean(ObjectMapper.class), TransactionDTO.class)));

var processEngine = configuration.buildProcessEngine();
log.info("Created camunda process engine");

deployResources(processEngine);
return processEngine;
}

@Bean
public HistoryService historyService(ProcessEngine processEngine) {
return processEngine.getHistoryService();
}

@Bean
public TaskService taskService(ProcessEngine processEngine) {
return processEngine.getTaskService();
}

@Bean
public RuntimeService runtimeService(ProcessEngine processEngine) {
return processEngine.getRuntimeService();
}

private void deployResources(ProcessEngine processEngine) throws IOException {
log.info("Searching for deployable camunda processes");

PathMatchingResourcePatternResolver resourceLoader =
new PathMatchingResourcePatternResolver();
for (String extension : List.of("dmn", "cmmn", "bpmn")) {
for (Resource resource : resourceLoader.getResources(
CLASSPATH_ALL_URL_PREFIX + extension + "/*/*." + extension)) {
log.info("Deploying model: {}", resource.getFilename());
processEngine
.getRepositoryService()
.createDeployment()
.name("MicronautAutoDeployment")
.addInputStream(resource.getFilename(), resource.getInputStream())
.enableDuplicateFiltering(true)
.deploy();
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,33 @@

import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.core.bind.annotation.Bindable;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

@ConfigurationProperties("datasources.default")
public interface CamundaDatasourceConfiguration {

@Bindable(defaultValue = "jdbc:h2:mem:fintrack;DB_CLOSE_DELAY=1000")
@NotBlank
String getUrl();
@Bindable
@NotBlank
String getUrl();

@Bindable(defaultValue = "sa")
@NotBlank
String getUsername();
@Bindable
@NotBlank
String getUsername();

@Bindable(defaultValue = "")
@NotNull
String getPassword();
@Bindable
@NotNull
String getPassword();

@Bindable(defaultValue = "org.h2.Driver")
@NotBlank
String getDriverClassName();
@Bindable
@NotBlank
String getDriverClassName();

@Bindable(defaultValue = "false")
@NotBlank
String getAutoUpdate();
@Bindable(defaultValue = "false")
@NotBlank
String getAutoUpdate();

@Bindable(defaultValue = "auto")
String getHistoryLevel();
@Bindable(defaultValue = "auto")
String getHistoryLevel();
}
Loading
Loading