Skip to content

Commit bd26f0d

Browse files
Merge branch 'master' into db-contrib/waltz-7351-prep
2 parents 2c463eb + 3235cf1 commit bd26f0d

110 files changed

Lines changed: 6777 additions & 96 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Waltz Proposed Flow Workflow
2+
3+
## Overview
4+
5+
The Waltz Proposed Flow workflow is designed to bring robust governance and data quality (DQ) control to the management
6+
of data flows. This workflow ensures that all critical changes to logical and physical flows pass through a two-step
7+
approval process, supporting compliance and audit requirements while increasing metadata coverage as required by Data
8+
Owners (DOs) and DQ standards.
9+
10+
---
11+
12+
## Challenges With Existing Logical/Physical Flow Creation
13+
14+
1. **No Approval Mechanism for Flow Creation**
15+
Currently the logical and/or physical flows can be created without seeking any approval between the source and target
16+
system owners.
17+
18+
2. **Logical Flows With No Physical Flows Attached**
19+
There are often hundreds of logical flows with no physical flows attached, making governance challenging.
20+
21+
3. **Tight Data Model Coupling**
22+
The data model's reliance on logical flows means changes must be carefully managed to avoid system-wide impacts.
23+
24+
4. **Controlled Logical Flow Creation**
25+
Logical flows must exist for system integrity, but user-initiated creation should be restricted.
26+
27+
---
28+
29+
## Workflow Actions
30+
31+
| Action | Maker | Checker (Approver) | Notes |
32+
|----------------------------|------------------|----------------------------------|-----------------------------------------|
33+
| Create Manual Logical Flow | Propose | Source Approver, Target Approver | Drafted, then routed for approvals |
34+
| Approve Logical Flow | - | Source/Target Approver | Moves to Approved state |
35+
| Create Physical Flow | (After Approval) | - | Allowed only for approved logical flows |
36+
37+
---
38+
39+
## Proposed Flow Workflow States & Transitions
40+
41+
All state transitions are handled by a state machine, validating actions and determining allowed next states.
42+
43+
![Possible Transitions](images\proposed_flow_workflow.png)
44+
45+
## State Machine & Transitions
46+
47+
All state transitions are handled by a state machine, validating actions and determining allowed next states.
48+
49+
![Possible Transitions](images\proposed_flow_transitions.png)
50+
---
51+
52+
## Benefits
53+
54+
- **Comprehensive Governance:** All changes are audited and approved.
55+
- **Improved Data Quality:** Ensures flows are validated before activation.
56+
- **Scalability:** Designed for high volumes of flows and flexible for future enhancements.
57+
- **Extensible:** New states, transitions, and roles can be added as requirements grow.
58+
59+
---
60+
61+
> **Contributions and feedback are welcome!**
62+
63+
---
24.6 KB
Loading
75.5 KB
Loading

pom.xml

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -522,9 +522,9 @@
522522
<database.url>jdbc:h2:mem:waltz;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DATABASE_TO_UPPER=TRUE</database.url>
523523
<database.user>sa</database.user>
524524
<database.password>sa</database.password>
525-
<!-- <database.url>jdbc:h2:file:~/data/waltz/h2/waltzdb;DATABASE_TO_UPPER=false</database.url>-->
526-
<!-- <database.user>root</database.user>-->
527-
<!-- <database.password></database.password>-->
525+
<!-- <database.url>jdbc:h2:file:~/data/waltz/h2/waltzdb;DATABASE_TO_UPPER=false</database.url>-->
526+
<!-- <database.user>root</database.user>-->
527+
<!-- <database.password></database.password>-->
528528
<database.schema>PUBLIC</database.schema>
529529
<database.catalog></database.catalog>
530530
</properties>
@@ -661,22 +661,22 @@
661661
<reporting>
662662
<plugins>
663663
<!-- DISABLING: causes a build failure with message: "Unable to download NVD CVE 2022" -->
664-
<!-- <plugin>-->
665-
<!-- <groupId>org.owasp</groupId>-->
666-
<!-- <artifactId>dependency-check-maven</artifactId>-->
667-
<!-- <configuration>-->
668-
<!-- <cveValidForHours>48</cveValidForHours>-->
669-
<!-- &lt;!&ndash;<failBuildOnCVSS>7</failBuildOnCVSS>&ndash;&gt;-->
670-
<!-- &lt;!&ndash;mavenSettingsProxyId>artifactory</mavenSettingsProxyId&ndash;&gt;-->
671-
<!-- </configuration>-->
672-
<!-- <reportSets>-->
673-
<!-- <reportSet>-->
674-
<!-- <reports>-->
675-
<!-- <report>aggregate</report>-->
676-
<!-- </reports>-->
677-
<!-- </reportSet>-->
678-
<!-- </reportSets>-->
679-
<!-- </plugin>-->
664+
<!-- <plugin>-->
665+
<!-- <groupId>org.owasp</groupId>-->
666+
<!-- <artifactId>dependency-check-maven</artifactId>-->
667+
<!-- <configuration>-->
668+
<!-- <cveValidForHours>48</cveValidForHours>-->
669+
<!-- &lt;!&ndash;<failBuildOnCVSS>7</failBuildOnCVSS>&ndash;&gt;-->
670+
<!-- &lt;!&ndash;mavenSettingsProxyId>artifactory</mavenSettingsProxyId&ndash;&gt;-->
671+
<!-- </configuration>-->
672+
<!-- <reportSets>-->
673+
<!-- <reportSet>-->
674+
<!-- <reports>-->
675+
<!-- <report>aggregate</report>-->
676+
<!-- </reports>-->
677+
<!-- </reportSet>-->
678+
<!-- </reportSets>-->
679+
<!-- </plugin>-->
680680
<plugin>
681681
<groupId>org.apache.maven.plugins</groupId>
682682
<artifactId>maven-surefire-report-plugin</artifactId>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.finos.waltz.common.exception;
2+
3+
public class FlowCreationException extends Exception{
4+
5+
public FlowCreationException(String message, Exception ex) {
6+
super(message);
7+
}
8+
}

waltz-data/src/main/java/org/finos/waltz/data/entity_workflow/EntityWorkflowDefinitionDao.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,11 @@ public List<EntityWorkflowDefinition> findAll() {
6161
.from(ENTITY_WORKFLOW_DEFINITION)
6262
.fetch(TO_DOMAIN_MAPPER);
6363
}
64+
65+
public EntityWorkflowDefinition searchByName(String name){
66+
return dsl.select(ENTITY_WORKFLOW_DEFINITION.fields())
67+
.from(ENTITY_WORKFLOW_DEFINITION)
68+
.where(ENTITY_WORKFLOW_DEFINITION.NAME.eq(name))
69+
.fetchOne(TO_DOMAIN_MAPPER);
70+
}
6471
}

waltz-data/src/main/java/org/finos/waltz/data/entity_workflow/EntityWorkflowStateDao.java

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,28 @@
1919
package org.finos.waltz.data.entity_workflow;
2020

2121

22-
import org.finos.waltz.schema.tables.records.EntityWorkflowStateRecord;
22+
import org.finos.waltz.common.DateTimeUtilities;
2323
import org.finos.waltz.model.EntityKind;
2424
import org.finos.waltz.model.EntityReference;
2525
import org.finos.waltz.model.ImmutableEntityReference;
2626
import org.finos.waltz.model.entity_workflow.EntityWorkflowState;
2727
import org.finos.waltz.model.entity_workflow.ImmutableEntityWorkflowState;
28+
import org.finos.waltz.schema.tables.records.EntityWorkflowStateRecord;
2829
import org.jooq.DSLContext;
2930
import org.jooq.Record;
3031
import org.jooq.RecordMapper;
3132
import org.springframework.beans.factory.annotation.Autowired;
3233
import org.springframework.stereotype.Repository;
3334

34-
import static org.finos.waltz.schema.tables.EntityWorkflowState.ENTITY_WORKFLOW_STATE;
35+
import java.sql.Timestamp;
36+
3537
import static org.finos.waltz.common.Checks.checkNotNull;
38+
import static org.finos.waltz.common.DateTimeUtilities.nowUtc;
39+
import static org.finos.waltz.schema.tables.EntityWorkflowState.ENTITY_WORKFLOW_STATE;
3640

3741
@Repository
3842
public class EntityWorkflowStateDao {
39-
40-
private static final RecordMapper<? super Record, EntityWorkflowState> TO_DOMAIN_MAPPER = record -> {
43+
public static final RecordMapper<? super Record, EntityWorkflowState> TO_DOMAIN_MAPPER = record -> {
4144
EntityWorkflowStateRecord r = record.into(ENTITY_WORKFLOW_STATE);
4245

4346
return ImmutableEntityWorkflowState
@@ -55,16 +58,13 @@ public class EntityWorkflowStateDao {
5558
.build();
5659
};
5760

58-
5961
private final DSLContext dsl;
6062

61-
6263
@Autowired
6364
public EntityWorkflowStateDao(DSLContext dsl) {
6465
this.dsl = dsl;
6566
}
6667

67-
6868
public EntityWorkflowState getByEntityReferenceAndWorkflowId(long workflowId, EntityReference ref) {
6969
checkNotNull(ref, "ref cannot be null");
7070

@@ -76,4 +76,33 @@ public EntityWorkflowState getByEntityReferenceAndWorkflowId(long workflowId, En
7676
.and(ENTITY_WORKFLOW_STATE.ENTITY_KIND.eq(ref.kind().name()))
7777
.fetchOne(TO_DOMAIN_MAPPER);
7878
}
79+
80+
public void createWorkflowState(Long workflowDefId,
81+
EntityReference ref,
82+
String username,
83+
String workflowState,
84+
String description) {
85+
EntityWorkflowStateRecord stateRecord = dsl.newRecord(ENTITY_WORKFLOW_STATE);
86+
stateRecord.setWorkflowId(workflowDefId);
87+
stateRecord.setEntityId(ref.id());
88+
stateRecord.setEntityKind(ref.kind().name());
89+
stateRecord.setState(workflowState);
90+
stateRecord.setDescription(description);
91+
stateRecord.setProvenance("waltz");
92+
stateRecord.setLastUpdatedBy(username);
93+
stateRecord.setLastUpdatedAt(Timestamp.valueOf(DateTimeUtilities.nowUtc()));
94+
stateRecord.insert();
95+
}
96+
97+
public long updateState(Long workflowDefId, EntityReference ref, String user, String workflowState) {
98+
return dsl
99+
.update(ENTITY_WORKFLOW_STATE)
100+
.set(ENTITY_WORKFLOW_STATE.STATE, workflowState)
101+
.set(ENTITY_WORKFLOW_STATE.LAST_UPDATED_AT, Timestamp.valueOf(nowUtc()))
102+
.set(ENTITY_WORKFLOW_STATE.LAST_UPDATED_BY, user)
103+
.where(ENTITY_WORKFLOW_STATE.WORKFLOW_ID.eq(workflowDefId)
104+
.and(ENTITY_WORKFLOW_STATE.ENTITY_ID.eq(ref.id()))
105+
.and(ENTITY_WORKFLOW_STATE.ENTITY_KIND.eq(ref.kind().name())))
106+
.execute();
107+
}
79108
}

waltz-data/src/main/java/org/finos/waltz/data/entity_workflow/EntityWorkflowTransitionDao.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,29 @@
1919
package org.finos.waltz.data.entity_workflow;
2020

2121

22-
import org.finos.waltz.schema.tables.records.EntityWorkflowTransitionRecord;
22+
import org.finos.waltz.common.DateTimeUtilities;
2323
import org.finos.waltz.model.EntityKind;
2424
import org.finos.waltz.model.EntityReference;
2525
import org.finos.waltz.model.ImmutableEntityReference;
2626
import org.finos.waltz.model.entity_workflow.EntityWorkflowTransition;
2727
import org.finos.waltz.model.entity_workflow.ImmutableEntityWorkflowTransition;
28+
import org.finos.waltz.schema.tables.records.EntityWorkflowTransitionRecord;
2829
import org.jooq.DSLContext;
2930
import org.jooq.Record;
3031
import org.jooq.RecordMapper;
3132
import org.springframework.beans.factory.annotation.Autowired;
3233
import org.springframework.stereotype.Repository;
3334

35+
import java.sql.Timestamp;
3436
import java.util.List;
3537

36-
import static org.finos.waltz.schema.tables.EntityWorkflowTransition.ENTITY_WORKFLOW_TRANSITION;
3738
import static org.finos.waltz.common.Checks.checkNotNull;
39+
import static org.finos.waltz.schema.tables.EntityWorkflowTransition.ENTITY_WORKFLOW_TRANSITION;
3840

3941
@Repository
4042
public class EntityWorkflowTransitionDao {
4143

42-
private static final RecordMapper<? super Record, EntityWorkflowTransition> TO_DOMAIN_MAPPER = record -> {
44+
public static final RecordMapper<? super Record, EntityWorkflowTransition> TO_DOMAIN_MAPPER = record -> {
4345
EntityWorkflowTransitionRecord r = record.into(ENTITY_WORKFLOW_TRANSITION);
4446

4547
return ImmutableEntityWorkflowTransition
@@ -58,7 +60,6 @@ public class EntityWorkflowTransitionDao {
5860
.build();
5961
};
6062

61-
6263
private final DSLContext dsl;
6364

6465

@@ -79,4 +80,29 @@ public List<EntityWorkflowTransition> findForEntityReferenceAndWorkflowId(long w
7980
.and(ENTITY_WORKFLOW_TRANSITION.ENTITY_KIND.eq(ref.kind().name()))
8081
.fetch(TO_DOMAIN_MAPPER);
8182
}
83+
84+
public void createWorkflowTransition(Long entityWorkflowDefId, EntityReference ref, String username,
85+
String from, String to, String reason) {
86+
EntityWorkflowTransitionRecord transitionRecord = dsl.newRecord(ENTITY_WORKFLOW_TRANSITION);
87+
transitionRecord.setWorkflowId(entityWorkflowDefId);
88+
transitionRecord.setEntityId(ref.id());
89+
transitionRecord.setEntityKind(ref.kind().name());
90+
transitionRecord.setFromState(from);
91+
transitionRecord.setToState(to);
92+
transitionRecord.setReason(reason);
93+
transitionRecord.setProvenance("waltz");
94+
transitionRecord.setLastUpdatedAt(Timestamp.valueOf(DateTimeUtilities.nowUtc()));
95+
transitionRecord.setLastUpdatedBy(username);
96+
transitionRecord.insert();
97+
}
98+
99+
public List<EntityWorkflowTransition> findForWorkflowId(long workflowId) {
100+
101+
return dsl
102+
.select(ENTITY_WORKFLOW_TRANSITION.fields())
103+
.from(ENTITY_WORKFLOW_TRANSITION)
104+
.where(ENTITY_WORKFLOW_TRANSITION.WORKFLOW_ID.eq(workflowId))
105+
.orderBy(ENTITY_WORKFLOW_TRANSITION.LAST_UPDATED_AT.desc())
106+
.fetch(TO_DOMAIN_MAPPER);
107+
}
82108
}

waltz-data/src/main/java/org/finos/waltz/data/person/PersonIdSelectorFactory.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@
2121

2222
import org.finos.waltz.data.entity_hierarchy.AbstractIdSelectorFactory;
2323
import org.finos.waltz.model.IdSelectionOptions;
24+
import org.finos.waltz.schema.Tables;
2425
import org.jooq.Record1;
2526
import org.jooq.Select;
27+
import org.jooq.SelectConditionStep;
28+
import org.jooq.impl.DSL;
2629

2730
import static org.finos.waltz.model.EntityKind.PERSON;
2831

@@ -40,4 +43,18 @@ protected Select<Record1<Long>> mkForOptions(IdSelectionOptions options) {
4043
throw new UnsupportedOperationException("Cannot create person selector from kind: " + options.entityReference().kind());
4144
}
4245
}
46+
47+
public SelectConditionStep<Record1<String>> getEmployeeIdForPerson(IdSelectionOptions options) {
48+
return DSL
49+
.select(Tables.PERSON.EMPLOYEE_ID)
50+
.from(Tables.PERSON)
51+
.where(Tables.PERSON.ID.eq(options.entityReference().id()));
52+
}
53+
54+
public SelectConditionStep<Record1<String>> getEmailForPerson(IdSelectionOptions options) {
55+
return DSL
56+
.select(Tables.PERSON.EMAIL)
57+
.from(Tables.PERSON)
58+
.where(Tables.PERSON.ID.eq(options.entityReference().id()));
59+
}
4360
}

0 commit comments

Comments
 (0)